typically default to OLD behavior compatible with prior versions of CMake.
automatically sets all the CMake policies to “new” through the minimum CMake version.
For example, a project with cmake_minimum_required(VERSION 3.14) implicitly sets to NEW all CMake policies CMP0088 and older.
New versions of CMake don’t get the benefits of new behaviors until specifying the new behavior is OK, either implicitly via cmake_minimum_required() or explicitly via cmake_policy().
The downsides of a too-old cmake_minimum_required() include that you have to set if(CMAKE_VERSION VERSION_GREATER_EQUAL ...) statements around extra cmake_policy() statements.
Here are a few CMake policies we generally use, typically implicitly by choosing at least CMake 3.13:
GCC on Windows
it’s often useful to have separate development environments for each compiler.
The Powershell script “~/clang.ps1” creates a
We don’t permanently put Clang on our user or system PATH.
Running “~/clang.ps1” in Powershell enables Clang until that Powershell window is closed.
can be used to keep build directories less cluttered and speed up the build process.
The traditional workflow for Makefiles was to create lots of object files (targets) with the relevant compile options, definitions and link flags.
Then the final executable or library targets would be linked from all the object files.
defaults to creating static libraries.
The following stanza creates “libfoo.a” or similar:
With numerous targets, there are a lot of “lib*.a” that may be cluttering the build directory.
Also, there is a finite time consumed in creating all those archive .a files from the object files.
For projects that use Visual Studio, using Object Libraries can help avoid
complications with exporting symbols for MSVC.
CMake object libraries
A cleaner option for most cases where the “lib*.a” artifact is not needed is to create CMake Object Libraries instead:
instead of having files under build/ like “libfoo.a, libbar.a” there will be only “baz.exe”.
The object files will be tucked away under build/CMakeFiles/foo/*.o and build/CMakeFiles/bar/*.o.
of object libraries propagate up to targets linking them as usual.
You may need to modify the PUBLIC / PRIVATE / INTERFACE of object libraries or add them to the “target_link_libraries()” of the top-level targets when going from static or shared libraries to object libraries.
The generator expressions expand to all the object files of “foo” and “bar” like a legacy Makefile.
Using object libraries means that duplicate symbols can cause conflicts that need to be manually resolved.
When linking non-object libraries, the linker typically just uses the first instance seen of a symbol.
Cygwin startup configuration can be easily modified.
While advanced users might modify the
Windows CYGWIN environment variable,
typical needs can be handled from within Cygwin ~/.bashrc or from other Windows environment variables.
A typical need is to not populate Cygwin PATH from Windows PATH.
This is something we typically do to avoid confusion from Windows programs being used instead of Cygwin programs.
To do this, set Windows environment variable:
This will result in a basic Cygwin PATH like:
Look inside Cygwin “/etc/config” file for more environment variables that may be of interest.
Git history can be
with certain caveats.
One reason to rewrite history for feature requests is to have project-specified message formatting.
Another is to add long comments, denoted by adding at least one blank line beneath the minimal summary message.
To edit messages of prior commits, use git rebase -i and then select “r” or “reword” for the desired commits.
This is quicker and easier than “e” or “edit” that is used for editing code or breaking up prior commits.
is an important legacy build system.
system is recommended for new and upgrading projects–Ninja works with CMake and Meson among others.
In general, build systems are used to:
save time on builds, only recompile parts of the code that changed
build in parallel (big compile time speedup)
avoid copy-paste mistakes with excessively long compile commands or piles of Bash scripts
In general, don’t build on FAT or
drives, since if the build script tries to make symbolic (soft) links, it will fail since ExFAT doesn’t allow soft links.
GNU Make parallel builds
By default, GNU Make only uses one thread.
For most programs, speeding up compilation is desirable and accomplished via the -j or --jobs option:
The -j option alone uses all virtual CPU cores.
On a typical laptop, 4 to 8 threads will thus be compiling simultaneously where possible.
On some systems such as Windows Subsystem for Linux, the bare make -j -l2 may overwhelm the computer because WSL1 doesn’t seem to correctly report the load factor.
Thus to do parallel builds with GNU Make on WSL1, manually set the number of parallel build threads perhaps equal to or less than the number of physical cores in your PC.
For example an 8 physical core laptop would compile with make -j8.
In certain special cases like older Raspberry Pi computers, the CPU may go into thermal cutback or suffer undervoltage spikes if using an inadequate power adapter.
While the better solution is to provide adequate DC power and CPU cooling, one may choose to compromise by manually specifying the number of threads.
For example, with the Raspberry Pi I often use 1 or 2 threads.
make -j does not consider system RAM, so your computer may become overwhelmed.
Try make -j2 or so until the system memory isn’t over-consumed.
Keeping system responsive
A possible downside of building large programs with make -j is that the computer can become non-responsive to input including mouse and keyboard.
A symptom of this is that the Caps Lock keyboard light is very slow to respond.
To mitigate the problem automatically, disallow a new thread to start if the system becomes too heavily loaded.
This is accomplished with the -l or --max-load option.
of 0 to 1 means approximately that no tasks are waiting.
So if you want to keep your computer responsible to user input (you can continue using your laptop while big program builds in the background), consider something like -l 1.
You can set the -l factor higher to allow make to have increasingly higher priority over other tasks, including user input.
Instead of writing Makefiles, we use Meson on all projects involving compiled code.
Meson comes with an integrated parallel-executing test suite, which works very well with continuous integration systems for automated self test.
Continuous integration should be a part of all software projects of all sizes, from 50 line programs to operating systems.
for CI in general.
Compilers typically have an option to specify static linking of the compiler libraries.
This can help mitigate “missing libgfortran” errors, particularly on Windows.
This problem arises because the developer may switch compiler environments, or the end user may not have compiler libraries with a compatible ABI installed or on PATH / LD_LIBRARY_PATH.
Build environment switching is especially common on Windows, and relatively few Windows users have compilers installed, so missing DLLs have long been a hallmark of distributing Windows programs in various programming languages.
GCC / Gfortran static link
GCC / Gfortran use the -static command line option to statically link the compiler libraries e.g. libgfortran into the final executable.
This increases the size of the executable, but the extra space may be negligible compared to the nuisances avoided.