Limit parallel execution of command in CMake - cmake

I want a certain command in a CMake rule to be executed in series rather than in parallel. That is because the invoked executable has side-effects. The command is multiplied by a foreach loop with slightly different options. All other commands should be executed in parallel.
Is that easily possible in CMake? Other build systems like Qbs have named job pools for that purpose.
I don't want to set CMAKE_BUILD_PARALLEL_LEVEL because that would serialize all rules.

I assume this is for a custom command.
If you are only using Ninja try JOB_POOLS:
"Specify a pool for the Ninja generator. Incompatible with USES_TERMINAL, which implies the console pool. Using a pool that is not defined by JOB_POOLS causes an error by ninja at build time."

Related

Can cmake configuration run in parallel?

I know that the cmake build stage can be done in parallel, but the initial configuration stage takes too long for large packages. Can that be parallelized?
No, the configuration stage cannot be parallelized.
Nonetheless, here are some things you could do:
Profile the Configuration Phase
CMake has --profiling-output/--profiling-format options, which emits a file that can be opened e.g. in Chromium-based browsers using about:tracing. This visualizes all command that were processes by CMake, how long they took, how they are nested, etc. This information can be used to find bottlenecks in your configuration phase and possibly optimize them to run faster. This is especially useful if you have a lot of custom functions/macros in your CMake files. Example:
$ cmake -G Ninja --profiling-output ./profile.json --profiling-format google-trace ..
Note that the profiling itself poses some additional work on CMake. Therefore, while profiling the CMake run will take longer as usual.
Generate Less Configurations
Running CMake actually does two things: configure and generate. Configure means, all CMakeLists.txt and *.cmake files are read and processes. Generate means, the CMake-internal representation of the build is written to some buildsystem specific format, e.g. Makefile, ninja.build, Visual Studio projects, etc. In case you use a Multi-Config generator like "Ninja Multi-Config", Visual Studio or XCode, it might help to reduce the number of generated configurations. By default CMake generates build files for 4 configurations: Debug, Release, RelWithDebInfo and MinSizeRel. In case you only need a subset of those, you can specify the required ones using the CMAKE_CONFIGURATION_TYPES variable. From my experience (using Ninja Multi-Config) this can reduce the generation phase significantly for large projects.
Superbuild
Use a superbuild structure with ExternalProject. Here you basically have one build that orchestrates the configuration and building of several other projects. This way, the sub-builds including their configuration phases are run in parallel. Note however, that this has other issues like the targets of the other projects not being available at configure time. In my experience, superbuild are only a good choice for special use cases.
Concurrent execute_process()
Someone managed write a ray tracer using CMake. For the parallelization he exploited that execute_process() runs multiple COMMANDs concurrently. This could help, if you have to do some heavy preprocessing that cannot be deferred to the build stage. But then again, it runs as a separate process, so if you call CMake recursively with this you don't have access to targets, variables, etc. of that subprocess.
Do as much as possible in the Build Phase
I don't have insight into your build, but often it help to perform only the things necessary in the configuration phase. Especially for execute_process() calls, one should always evaluate if it could be replaced with add_custom_command()/add_custom_target(), because creating processes is relatively costly.
An example: I had once a large scale project at work where a lot of source files were generated from XML/XSLT files. Since CMake doesn't have any knowledge about the dependencies between XML/XSLT files, we had a script that figured out those dependencies by reading the files and following includes recursively. At first, this script was called using execute_process() at configure time in order to pass the output to the DEPENDS options of add_custom_command(). Later, I optimized this by doing the dependency evaluation at build time and generating a .d dependency file (Makefile syntax) that could be passed to the DEPFILE option of add_custom_command() instead. The speedup in configuration was enormous, while the build time suffered only slightly, because it in parallel.

Waiting for targets in a CMake build

I think I do have a CMake order/parallelism problem.
In my build process, I need to build a tool which is then later used by some other target. This tool is a separate project with a CMakeLists.txt file like this:
project (package-tool LANGUAGES CXX)
set (SOURCES package_tool.cpp)
...
Later in the build, this top level target is referenced by some other target:
...
add_custom_command (OUTPUT "${DST_FILE}"
COMMAND ${PACKAGE_COMMAND} "${DST_FILE}"
COMMAND package-tool.exe -e "${DST_FILE}"
DEPENDS ${PACKAGE_DEPENDENCIES} package-tool)
...
I use ninja for building and the dependencies (ninja -t depends) are looking correctly. Also, the build commands (ninja -t commands) are making sense. But: From time to time, the build fails. The message does not make sense, it reads:
This version of package-tool.exe is not compatible with the version
of Windows you're running.
Because the build runs in parallel (32 processes) I suspect that the package-tool target is not completed when the generated exe is being used in the second target, which might lead to this confusing error message. Again, most of the time the build succeeds but every 10th or 20th run, it fails with that message.
So now my question is:
Is there a way to wait for a tool/target having been finished building in a parallel build in CMake/Ninja ?
Or how do I handle the task of building build tools in the same build process correctly ?
Thank you in advance !
Actually depend on the executable file and run the executable file, not the target. Don't concern yourself with any .exe suffix. Also better don't assume add_custom_command will be run in CMAKE_RUNTIME_OUTPUT_DIRECTORY - if you depend on specific directory explicitly set it with WORKING_DIRECTORY.
add_custom_command (
OUTPUT "${DST_FILE}"
COMMAND ${PACKAGE_COMMAND} "${DST_FILE}"
COMMAND $<TARGET_FILE:package-tool> -e "${DST_FILE}"
DEPENDS ${PACKAGE_DEPENDENCIES} $<TARGET_FILE:package-tool>
)

Evaluate command only when running tests

I need to check if the mpirun command is present and exit with an error message if not present, but only when the user tries to run the tests. When just building the main library or executable, this command need not exist.
More generally, how to execute a cmake script when a specific target is invoked? I.e., only when I type build some_target, cmake should start searching for certain environment variables, commands, etc.
EDIT
Workaround. In my case, the custom target is dependent on an executable, and for the executable I can use add_custom_command with the PRE_LINK flag. The custom command then displays an error message and calls exit 1 if necessary and only when the custom target is invoked. However, the PRE_LINK option only works on real targets such as executables and libraries, and not for a custom target in general, so I'm still curious how to solve this for the general case.

How to do Parallel CMake ExternalProject Builds

When building a CMake project (e.g. on Windows), I can perform a parallel build by executing the following command:
cmake --build . -- /m
The /m switch is passed to msbuild and I get parallelized builds. However, if I have some external project in my CMakeLists, that switch is not passed through to its build command.
What's the best way to ensure my ExternalProject is built in parallel? I don't want to hardcode a BUILD_COMMAND if I can avoid it.
In CMake 3.12, support was added to kick off parallel jobs from within cmake.
The previous versions only supported this via passthrough arguments after the --, which understandably wouldn't pass through to external builds. Though, I'm not sure if the new support works for ExternalProject, it'd be great to try and report back if it works!
I had the same problem with make based external_projects. I ended up with the solution to pass the -j8 flag via a cmake cached variable.
set(EXTERNAL_BUILD_ARGS "/m" CACHE STRING "flags for external project builds")

Force serial execution for specific targets in CMake

In my CMake project I have several targets which simply run a certain set of unit tests (for example, runTestsForA, runTestsForB and runTestsForC).
I also have a target, tests, that depends on all of these unit test targets, so I can run them with a single command.
I'm using CLion is my IDE, which tries to use parallel make builds by default (which I want and am also doing on the Continuous Integration server).
However, it looks like the tests are running in parallel too now and some tests are not made for this (they use a local loopback to do some magic with sockets), which causes them to fail.. sometimes.
That is why I would like to force serial execution for some/all of the dependencies of my tests target.
Unfortunately the CMake documentation did not help me, when I was searching information on how to do this.
Which brings me to my questions: is this at all possible and how can it be done if it is?
Instead of manual tests target declaration you can use CTest tool. Use add_test command to create test targets, then CMake will automatically create tests target that will run all tests:
enable_testing()
add_test(NAME TestsForA COMMAND <command>)
add_test(NAME TestsForB COMMAND <command>)
set_tests_properties(TestsForA TestsForB PROPERTIES RUN_SERIAL TRUE)
After that you can run make tests or ctest -j8 . in your build tree. The tests will be serialized.
More information can be found at:
http://www.cmake.org/cmake/help/v3.2/command/add_test.html
http://www.cmake.org/cmake/help/v3.2/command/enable_testing.html
http://www.cmake.org/cmake/help/v3.2/command/set_tests_properties.html
http://www.cmake.org/cmake/help/v3.2/manual/cmake-properties.7.html#properties-on-tests
http://www.cmake.org/cmake/help/v3.2/manual/ctest.1.html
Perhaps it's not the best solution for controlling test execution, but, generally I believe you can use the CMake JOB_POOLS feature to restrict the amount of parallelism for some of the CMake targets in a project.
First you declare named pool(s) and the number of parallel jobs each pool supports:
set_property(GLOBAL PROPERTY JOB_POOLS two_jobs=2 ten_jobs=10)
You can then assign targets to those pools:
set_property(TARGET myexe PROPERTY JOB_POOL_COMPILE ten_jobs)