Correct me if I'm wrong, but a "build" is a "compile", and not every language compiles. Continuous Integration involves building components to see if they continue to work beyond unit tests, which I might be oversimplifying. But if your project involves a language that does not compile, how do you perform nightly builds or use continuous integration techniques?
Hmm... I'd define "building" as something like "preparing, packaging and deploying all artifacts of a software system". The compilation to machine code is only one of many steps in the build. Others might be checking out the latest version of the code from scm-system, getting external dependencies, setting configuration values depending on the target the software gets deployed to and running some kind of test suite to ensure you've got a "working/running build" before you actually deploy.
"Building" software can/must be done for any software, independent of your programming langugage. Intepreted languages have the "disadvantage" that syntactic or structural (meaning e.g. calling a method with wrong parameters etc.) errors normally will only be detected at runtime (if you don't have a separate step in your build which checks for such errors e.g. with PHPLint).
Thus (automated) Testcases (like Unit-Tests - see PHPUnit or SimpleTest - and Frontend-Tests - see Selenium) are all the more important for big PHP projects to ensure the good health of the code.
There's a great Build-Tool (like Ant for Java or Rake for Ruby) for PHP too: Phing
CI-Systems like Xinc or Hudson are simply used to automagically (like anytime a change is checked into scm) package your code, check it for obvious errors, run your tests (in short: run your build) and report the results back to your development team.
Create a daily tag of your current source control trunk?
Related
I recently implemented serverside-rendering react app with code splitting using loadable-components
But it seems that loadable-components itself dependent on webpack, since loadable replaces jsonp_callback with its own reporter.
So what are the alternative options that we can use when using other bundlers like rollup, esbuild?
Do we have to manually walk through the react tree to pre configure which chunk is needed on which component unless there is no specific bundler targeted library like loadable-components when implementing code splitting on serverside rendering?
Is tsconfig typeRoots unnecessary?
First, let us consult the compiler options reference:
The documentation for typeRoots states (emphasis mine):
By default all visible #types packages are included in your compilation. Packages in node_modules/#types of any enclosing folder are considered visible. For example, that means packages within ./node_modules/#types/, ../node_modules/#types/, ../../node_modules/#types/, and so on.
If typeRoots is specified, only packages under typeRoots will be included.
That second line is important: if you don't set typeRoots then tsc defaults to looking for directories under node_modules containing #types in their directory names.
(The documentation doesn't say if it chooses node_modules because of the moduleResolution parameter though. (I suspect I'd need to dig-in tsc's source-code to find out for sure).)
If you do set a value for typeRoots than that overrides tsc's node_modules/**/#types* lookup logic and it will then only look in the specified directories.
As I know, I have to specify the path of the above file into typeRoots option of tsconfig file since typeRoots defaults to look into the node_modules/#types.
Not necessarily. You could also add your extra typings files' locations to the paths parameter and leave the typeRoots parameter blank/un-set, which means tsc will retain the "node_modules/#types-and-ancestor-walking behavior" but will see your .d.ts files just fine.
This scenario is mentioned in this TypeScript GitHub thread: https://github.com/microsoft/TypeScript/issues/13581
So if you're asking about your specific local environment on your machine: and assuming that you're sticking with the normative, typical (I dare say mainstream) TypeScript working idioms (such as using npm) then yes: you can remove the typeRoots parameter because tsc's (current) default behavior is to look for node_modules directories in the same location as your tsconfig.json.
(I understand that VS Code might also be pulling some strings behind-the-scenes to make tsc "aware" of your project files and dependencies and for its language-server process - but that shouldn't matter as you'll notice tsc should work identically from the command-line outside of VS Code).
If you're asking about the fundamental necessity of the typeRoots compiler option, and supposing that you're thinking "that because practically everyone is using npm and node_modules then why is the TypeScript team spending their time supporting unusual development configurations?"_ - well, for many very good reasons: tools shouldn't be dependent on other tools controlled by third-parties1: Consider the possibility that the npm ecosystem and/or NodeJS software could fall out of fashion overnight and then we'd be stuck with tsc's defaults still using node_modules when everyone is rockin' some new cool JS environment: there'd be headaches for many years to resolve the mess (not that the JS ecosystem isn't a mess as it is).
And there are many good reasons to not use npm and node_modules: people could be using TypeScript in an environment without internet access (think: secure software development, the defence industry, national secrets, etc) - those people in those situations might have a network share full of approved or known-trustworthy libraries that won't be using node_modules's naming convention - in which case if those people want to use d.ts files they'll need to manually configure the typeRoots parameter for themselves.
1 I'm aware that npm (which is legally separate from NodeJS, btw) is maintained by npm Inc, which is a subsidary of Microsoft (by way of being acquired by GitHub, also a Microsoft property), so having tsc depend on npm shouldn't be a problem - but that's a very recent thing: Microsoft only acquired npm 18 months ago in March 2020 - and Microsoft could very well spin-off npm Inc - or run it into the ground and everyone switches to yarn. So regardless of the end legal owners of whatever tooling is currently popular, you don't want unnecessary dependencies like that.
When I was learning how to use premake, I remember reading a wiki page or perhaps a forum post somewhere (I wish I could find the original link) suggesting that project files generated by your premake scripts may ultimately be run on different machines than the one you're running premake on. So, I took this idea and designed premake scripts accordingly to replace the existing autotools/VS/Xcode project files in an open-source project I contribute to. This project uses a variety of third-party libraries, some mandatory and some optional.
What I started to discover, through both my own experience and through feedback from other developers, is that it's pretty tough to generate generic project files (gmake files, especially) that will work on other machines, especially when it comes to finding the location of system libraries to link to. It also seems like you're completely giving up your ability to auto-detect the state of things on the build machine and enable/disable optional build settings in your project accordingly, and in lieu of errors you could have displayed during configuration in a user-friendly format (missing dependencies, etc.), you have to rely on cryptic compiler errors to tell users that they're missing something.
My question is for those have experience using premake in a production environment: is it a reasonable goal to be able to transfer premake-generated project files to other machines and still have them work, or should you design your premake scripts around the assumption that users will run premake locally because build environments are so diverse?
For simple or self-contained projects, certainly—the official Premake releases ship with pre-built project files, for example. But for more complex projects it generally makes more sense to just ship the Premake scripts (i.e. premake5.lua) and ask developers to download and run Premake locally to generate the final project files, for the reasons you specified.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
What is a best practices to write large software projects in OCaml?
How do you structure your projects?
What features of OCaml should and should not be used to simplify code management? Exceptions? First-class modules? GADTs? Object types?
Build system? Testing framework? Library stack?
I found great recommendations for haskell and I think it would be good to have something similar for OCaml.
I am going to answer for a medium-sized project in the conditions that I am familiar with, that is between 100K and 1M lines of source code and up to 10 developers. This is what we are using now, for a project started two months ago in August 2013.
Build system and code organization:
one source-able shell script defines PATH and other variables for our project
one .ocamlinit file at the root of our project loads a bunch of libraries when starting a toplevel session
omake, which is fast (with -j option for parallel builds); but we avoid making crazy custom omake plugins
one root Makefile contains all the essential targets (setup, build, test, clean, and more)
one level of subdirectories, not two
most subdirectories build into an OCaml library
some subdirectories contain other things (setup, scripts, etc.)
OCAMLPATH contains the root of the project; each library subdirectory produces a META file, making all OCaml parts of the projects accessible from the toplevel using #require.
only one OCaml executable is built for the whole project (saves a lot of linking time; still not sure why)
libraries are installed via a setup script using opam
local opam packages are made for software that it not in the official opam repository
we use an opam switch which is an alias named after our project, avoiding conflicts with other projects on the same machine
Source-code editing:
emacs with opam packages ocp-indent and ocp-index
Source control and management:
we use git and github
all new code is peer-reviewed via github pull requests
tarballs for non-opam non-github libraries are stored in a separate git repository (that can be blown away if history gets too big)
bleeding-edge libraries existing on github are forked into our github account and installed via our own local opam package
Use of OCaml:
OCaml will not compensate for bad programming practices; teaching good taste is beyond the scope of this answer. http://ocaml.org/learn/tutorials/guidelines.html is a good starting point.
OCaml 4.01.0 makes it much easier than before to reuse record field labels and variant constructors (i.e. type t1 = {x:int} type t2 = {x:int;y:int} let t1_of_t2 ({x}:t2) : t1 = {x} now works)
we try to not use camlp4 syntax extensions in our own code
we do not use classes and objects unless mandated by some external library
in theory since OCaml 4.01.0 we should prefer classic variants over polymorphic variants
we use exceptions to indicate errors and let them go through happily until our main server loop catches them and interprets them as "internal error" (default), "bad request", or something else
exceptions such as Exit or Not_found can be used locally when it makes sense, but in module interfaces we prefer to use options.
Libraries, protocols, frameworks:
we use Batteries for all commodity functions that are missing from OCaml's standard library; for the rest we have a "util" library
we use Lwt for asynchronous programming, without the syntax extensions, and the bind operator (>>=) is the only operator that we use (if you have to know, we do reluctantly use camlp4 preprocessing for better exception tracking on bind points).
we use HTTP and JSON to communicate with 3rd-party software and we expect every modern service to provide such APIs
for serving HTTP, we run our own SCGI server (ocaml-scgi) behind nginx
as an HTTP client we use Cohttp
for JSON serialization we use atdgen
"Cloud" services:
we use quite a lot of them as they are usually cheap, easy to interact with, and solve scalability and maintenance problems for us.
Testing:
we have one make/omake target for fast tests and one for slow tests
fast tests are unit tests; each module may provide a "test" function; a test.ml file runs the list of tests
slow tests are those that involve running multiple services; these are crafted specifically for our project, but they cover as much as possible as a production service. Everything runs locally either on Linux or MacOS, except for cloud services for which we find ways to not interfere with production.
Setting this all up is quite a bit of work, especially for someone not familiar with OCaml. There is no framework taking care of all that yet, but at least you get the choice of the tools.
OASIS
To add to Pavel answer:
Disclaimer: I am the author of OASIS.
OASIS also has oasis2opam that can help to create OPAM package quickly and oasis2debian to create Debian packages. This is extremly useful if you want to create a 'release' target that automate most of the tasks to upload a package.
OASIS is also shipped with a script called oasis-dist.ml that creates automatically tarball for upload.
Look all this in https://github.com/ocaml.org.
Testing
I use OUnit to do all my tests. This is simple and pretty efficient if you are used to xUnit testing.
Source control/management
Disclaimer: I am the owner/maintainer of forge.ocamlcore.org (aka forge.o.o)
If you want to use git, I recommend to use github. This is really efficient for review.
If you use darcs or subversion, you can create an account on forge.o.o.
In both case having a public mailing list where you send all commit notification is a must have, so that everyone can see them and review them. You can use either Google groups or a mailing list on forge.o.o.
I recommend to have a nice web (github or forge.o.o) page with OCamldoc documentation build everytime you commit. If you have a huge code base this will help you to use the OCamldoc generated documentation right from the beginning (and fix it quickly).
I recommend to create tarballs when you reach a stable stage. Don't just rely on checking out the latest git/svn version. This tip has saved me hours of work in the past. As said by Martin, store all your tarballs in a central place (a git repository is a good idea for that).
This one probably doesn't answer your question completely, but here is my experience regarding build environment:
I really appreciate OASIS. It has a nice set of features, helping not only to build the project, but also to write documentation and support test environment.
Build system
OASIS generates setup.ml file from the specification (_oasis file), which works basically as a building script. It accepts -configure, -build, -test, -distclean flags. I quite used to them while working with different GNU and other projects that usually use Makefiles and I find it convenient that it is possible to use all of them automatically here.
Makefiles. Instead of generating setup.ml, it is also possible to generate Makefile with all options described above available.
Structure
Usually my project that is built by OASIS has at least three directories: src, _build, scripts and tests.
In the former directory all source files are stored in one directory: source (.ml) and interface (.mli) files are stored together. May be if the project is too large, it is worth introducing more subdirectories.
The _build directory is under the influence of OASIS build system. It stores both source and object files there and I like that build files are not interfered with source files, so I can easily delete it in case something goes wrong.
I store multiple shell scripts in the scripts directory. Some of them are for test execution and interface file generation.
All input and output files for tests I store in a separate directory.
Interfaces/Documentation
The use of interface files (.mli) has both advantages and drawbacks for me. It really helps to find type errors, but if you have them, you have to edit them as well when making changes or improvements in your code. Sometimes forgetting this causes nasty errors.
But the main reason why I like interface files is documentation. I use ocamldoc to generate (OASIS supports this feature with -doc flag) html pages with documentation automatically. In my opinion it is enough to write comments describing each function in the interface and not to insert comments in the middle of code. In OCaml functions are usually short and concise and if there is a necessity to insert extra comments there, may be it is better to split the function.
Also be aware of -i flag for ocamlc. The compiler can automatically generate interface file for a module.
Tests
I didn't find a reasonable solution for supporting tests (I would like to have some ocamltest application), that's why I am using my own scripts for executing and verifying use cases. Fortunately, OASIS supports executing custom commands when setup.ml is run with -test flag.
I don't use OASIS for a long time and if anyone knows any other cool features, I would like also to know about them.
Also, it you are not aware of OPAM, it is definitely worth looking at. Without it installing and managing new packages is a nightmare.
Why does every source package that uses a makefile come with a ./configure script, what does it do? As far as I can tell, it actually generates the makefile?
Is there anything that can't be done in the makefile?
configure is usually a result of the 'autoconf' system. It can generate headers, makefiles, really anything. 'Usually,' since some are hand-crafted.
The reason for these things is to allow source code to be compiled in disparate environments. There are many variations on Unix / Linux, with slightly different system headers and libraries. configure scripts allow code to auto-adapt.
The configure step is a sort of meta build. It generates the makefile that will work on the specific hardware / distribution you're running. For instance it determines the name of the C or C++ compiler and embeds that in the makefile.
The configure step will also frequently take a set of parameters, the values of which may determine what libraries need to be linked against. For instance if you compile Apache HTTP with SSL enabled it needs to link against more shared libraries than if you don't. Since linking is handled by the makefile, you need an extra step to create a custom makefile (rather than requiring the make command to require dozens or hundreds of options.
Everything can be done from within the makefile but some build systems were implemented otherwise.
I don't personally use configure files for my projects but I admit I mostly export Erlang & Python based projects.
I don't think of the makefile as a script, I think of it as an input to the make utility.
The configure script (as its name suggests) configures the makefile, including as you say resolving dependencies.
If only from the idea of avoiding self-modifying code, the things in the configure script don't really belong in the makefile.
the point is that autoconf autohdr automake form an integrated system the makes cross platform building on unix relatively str8forward. THe docs are really bad and there are lots of horrible gotchas but on the other hand there are a lot of working samples
When I first came across this stuff I thought - "ha I can do that with a nice clean makefile" and proceeded to rework the source that way. Big mistake. Learn to write and edit configure.ac and makefile.am files, you will be happy in the end
To answer your question. Configure is good for
is function foo available on this platform and if so which include and library do I need
letting the builder choose if they want feature wizzbang included in a nice simple consistent way
We're in the process of streamlining/automating build, integration and unit testing as well as deployment.
Our software is developed in Visual Studio where we have use both C# and VB.NET in our projects. A single project can be contained within multiple solutions (i.e. Utils project is used in both ProductA and ProductB solutions)
For historical reasons our code repository isn't as well structured as one could have hoped for.
E.g. Utils project might be located under ProductA solution (because that's were it was first used) but it was later deemed useful for productB development and merely just included into the solution of productB (but still located in a subdirectory of productA).
I would like to use continous integration testing and have setup a CC.NET build server where I intend to use NAnt for creating the actual builds.
Question 1: How should I structure my builds on the buildserver? Should I instruct CC.NET to retrieve all the projects for productB into a single library e.g. a file structure similar to
-ProductB
--Utils
--BetterUtils
--Data
or should I opt for a filestructure similar to this
-ProductA
--Utils
-ProductB
--BetterUtils
--Data
and then just have the NAnt build scripts handle the references? Our references in VS doesn't match the actual location in the code repository so it's not possible today to just check-out productB solution and build it straight away (unfortunately). I hope this question makes sense?
Question 2: Is it better to check out all the source code located in different projects into a single file folder (whilst retaining some kind of structure) and then build every thing at once or have multiple projects in CC.NET and then let the CC.NET server handle dependencies?
Example:
Should I have a seperate project in CC.NET for monitoring the automated build/test of Utils project when it's never released on it's own? Or should I just build/test it whilst building it as part of ProductB?
I hope the above makes sense and that you can provide me with some arguments for using either option. We're nowhere near an ideal source code repository structure and I would prefer if I can resolve the lack of repository structure on the build server instead of having to clean up the structure of our repository.
Switching away from VSS is (unfortunately) not an option.
Right now our build consists of either deploying via VS clickonce or pressing F5 so just getting the build automated would be a huge step up for us.
Thanks
To answer your first question, I would recommend a separate top-level folder for each build project. The problem with having a single tree matching your source repository is that when your build server is trying to run multiple builds at once, one or more will likely fail due to files in use by other processes. Also, you may run into cases where a build script is pulling an older version of the code. In that instance you don't want a different project to accidentally use the incorrect source version.
If your solutions already reference projects from relative paths, you may end up with a structure like this:
-CCNetBuilds
--ProductASource
---Utils
---...
--ProductBSource
---ProductA
----Utils
---ProductB
----BetterUtils
----Data
In this case, the build for Product B contains part of the Product A source, at the same relative path as your solution already expects. This takes a bit more time to set up in CC.Net, but makes it easier to maintain if the developers have their code set up this way on their machines. The same solution files used in development are used by the build server.
To answer your second question, I prefer Utilities being its own build. If I have unit tests on my Utilities assembly, I would not want them to run for every single product that uses the Utilities. Also, if you have a separate build for Utilities, you can set a dependency in CC.Net so that Product A and B will not attempt to build if the Utilities build is broken. This provides a bit faster feedback that something is wrong.