MantisBT - CMake
View Issue Details
0014312CMakeCMakepublic2013-07-25 09:142016-06-10 14:31
Wojciech Knapik 
Kitware Robot 
highmajoralways
closedmoved 
x86_64Linux
CMake 2.8.10.2 
 
0014312: Parallel builds using make break when two or more targets that share a dependency (or are dependent) are called explicitly
In the example below, the top level targets for "main" and "empty" have recipes that call make. When make is called with -j, the two instances of make are called in parallel and, knowing nothing about each other, race to finish the same task.

In the real world, this breaks builds in very common use cases. E.g. when you have 3 types of tests - ut, mt and it - it is reasonable to call `make -j24 ut mt it'. If those targets happen to share dependencies, the build will break.

Creating top level targets that cover all such combinations is not an acceptable solution.
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(foo)
add_library(empty STATIC empty.cpp)
add_custom_command(TARGET empty POST_BUILD COMMAND echo whoops)
add_executable(main main.cpp)
target_link_libraries(main empty)
$ cd build
$ cmake ..
$ make -j empty main|grep whoops
whoops
whoops
$
No tags attached.
has duplicate 0015286closed  ExternalProject double build with parallel make and multiple targets 
Issue History
2013-07-25 09:14Wojciech KnapikNew Issue
2013-07-25 09:17Brad KingNote Added: 0033608
2013-07-25 09:17Brad KingStatusnew => backlog
2013-07-25 09:18Brad KingNote Edited: 0033608bug_revision_view_page.php?bugnote_id=33608#r1221
2013-07-25 16:07Wojciech KnapikNote Added: 0033615
2013-07-25 16:20Brad KingNote Added: 0033617
2013-07-26 18:07David ColeNote Added: 0033620
2013-12-14 05:13Robert·LuberdaNote Added: 0034773
2013-12-19 09:55Brad KingNote Added: 0034818
2013-12-20 09:38Brad KingNote Edited: 0034818bug_revision_view_page.php?bugnote_id=34818#r1345
2014-03-24 18:32Ben BoeckelNote Added: 0035501
2014-03-26 11:10Brad KingNote Added: 0035531
2014-12-05 09:14Brad KingRelationship addedhas duplicate 0015286
2015-01-30 05:37raspyNote Added: 0037863
2015-01-30 06:18raspyNote Edited: 0037863bug_revision_view_page.php?bugnote_id=37863#r1689
2015-01-30 08:42Brad KingNote Added: 0037865
2015-01-30 09:13raspyNote Added: 0037866
2015-01-30 09:59Brad KingNote Added: 0037867
2015-03-24 12:01raspyNote Added: 0038285
2016-06-10 14:29Kitware RobotNote Added: 0042327
2016-06-10 14:29Kitware RobotStatusbacklog => resolved
2016-06-10 14:29Kitware RobotResolutionopen => moved
2016-06-10 14:29Kitware RobotAssigned To => Kitware Robot
2016-06-10 14:31Kitware RobotStatusresolved => closed

Notes
(0033608)
Brad King   
2013-07-25 09:17   
(edited on: 2013-07-25 09:18)
This is a known problem that has existed forever. The generated makefiles simply do not support multiple explicit targets on the command line. It is a problem with how the per-directory command-line entry-point/front-end Makefile layout works. No one has been bothered by it enough to propose a solution.

(0033615)
Wojciech Knapik   
2013-07-25 16:07   
I'm bothered enough and I propose never calling make from a recipe instead of using the dependency mechanism.

I get the feeling that the unholy combination of "it's always been like that" and "no one has bothered" will leave this bug with a "wontfix" resolution and that would not be right. Anyone reading make documentation will learn, that it's perfectly correct to call multiple targets at once, but if they do, with a CMake-generated build system, their build will break for no apparent reason. That is simply wrong.

At least add this to the makefiles, so people won't waste time debugging it:

ifeq ($(filter 0 1,$(words $(MAKECMDGOALS))),)
$(error Duuude, two targets at a time ? Such advanced technology does not exist yet)
endif

At least it'll be funny for a moment ;]
(0033617)
Brad King   
2013-07-25 16:20   
The multi-level make invocation is explained in this FAQ entry:

 http://www.cmake.org/Wiki/CMake_FAQ#Why_does_CMake_generate_recursive_Makefiles.3F [^]

It's the first level's invocation of the second level that needs to be re-worked and perhaps combined. However, the first level is what allows one to run "make" from any subdirectory to build the targets their along with dependencies so there must be a separate Makefile in each directory. Supporting both at the same time is not a trivial change from the current design.

Any solution must work with ancient UNIX make and cannot depend on GNU make features.

See also the Ninja generator and ninja build tool as mentioned in the FAQ entry.
(0033620)
David Cole   
2013-07-26 18:07   
You say:

"it is reasonable to call `make -j24 ut mt it'"

It is also reasonable to call "make -j24 ut && make -j24 mt && make -j24 it" and serialize a little bit to get a mostly parallel invocation to work with existing CMake...

Just mentioning it as a possibility for those who might want to take the easy way, but still get most of the gain of a -j24 with multiple targets.

I agree that it would be nice to have something done about this..... but most of my time is spent in Visual Studio anyhow. I certainly wouldn't want to tackle a re-design of the Unix Makefiles parts of CMake personally. ;-)
(0034773)
Robert·Luberda   
2013-12-14 05:13   
I've recently encountered the same issue, and spent some time on investigating it. It seems to me that even if proper fix would require re-desing of entire generator, the work-around is quite simple: just disallow the parallel executions of tasks by adding the .NOTPARALLEL: target into the top-level Makefile.

Thanks to it the `make -j24 ut mt it' command will work as `"make -j24 ut && make -j24 mt && make -j24 it' at least with GNU make; honestly I have no idea if it is a GNU make only feature or not, but my gut feeling is that other make commands will either support it, or ignore it (by treating .NOTPARALLEL as a `doing nothing' target)
(0034818)
Brad King   
2013-12-19 09:55   
(edited on: 2013-12-20 09:38)
Re 0014312:0034773: Wonderful! It is easy to add .NOTPARALLEL to the directory-level Makefile command-line entry points:

 Makefile: Allow "gmake target1 target2 -j"
 http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bd11de08 [^]

It won't solve the problem on make implementations that do not support .NOTPARALLEL but it won't hurt them either. On the popular GNU make it will work as desired. Thanks.

(0035501)
Ben Boeckel   
2014-03-24 18:32   
Should this be closed?
(0035531)
Brad King   
2014-03-26 11:10   
Re 0014312:0035501: Currently the solution only works with GNU make tools. I left the issue open in the backlog in case anyone ever wants to work on a more general solution.
(0037863)
raspy   
2015-01-30 05:37   
(edited on: 2015-01-30 06:18)
This workaround generates Makefiles which are no longer parsable by Clearmake:

$ clearmake
clearmake: Error: Syntax error in file "Makefile", line 10, column 21
syntax error
$ head -n 10 Makefile | tail -n 1
.PHONY : .NOTPARALLEL

I believe the only offending line is the '.PHONY: .NOTPARALLEL' line, not the .NOTPARALLEL itself. I think that at least this one line should be removed and just leave '.NOTPARALLEL:' in Makefile in order to be usable with Clearmake.

As an additional side effect, when I removed this offending line, Clearmake is able to parse the Makefile and starts building, but it seems that .NOTPARALLEL is in effect also for Makefile2 and in effect one is no longer able to use any parallel compilation with Clearmake whatsoever.

Edit: After further investigation it turned out that Clearmake has some strange logic about running in parallel and it does not pass -J flag information to sub-makes. It is possible however to work around this behavior by setting CCASE_CONC environment variable (and it worked the same with CMake 2.8.12.2). Therefore I believe that the only change required to make CMake's 3.0 Makefiles readable by Clearmake is to drop this '.PHONY: .NOTPARALLEL' definition.

(0037865)
Brad King   
2015-01-30 08:42   
Re 0014312:0037863: The .PHONY rule is not specific to .NOTPARALLEL and will be generated for any custom command output file marked with the SYMBOLIC property:

 http://www.cmake.org/cmake/help/v3.1/prop_sf/SYMBOLIC.html [^]

The intention is to tell the make tool that the file will not actually be created and it is not an error for the file to not exist after running its rule. How should that be expressed to clearmake?
(0037866)
raspy   
2015-01-30 09:13   
Yes, I know how the .PHONY target is used and Clearmake does support .PHONY targets. It just seems that its handling of .NOTPARALLEL is broken; apparently it is treated somehow special so it fails on such statement.

Maybe this could be somehow implemented to just generate .NOTPARALLEL, without .PHONY? I believe that if an ancient make does not recognize .NOTPARALLEL as a special target, it will not be really affected even if .NOTPARALLEL file exists.
(0037867)
Brad King   
2015-01-30 09:59   
Re 0014312:0037866: Okay. It is easy to generate .NOTPARALLEL specifically without .PHONY:

 Makefile: Generate .NOTPARALLEL without .PHONY
 http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3cec0c75 [^]
(0038285)
raspy   
2015-03-24 12:01   
I have just checked CMake 3.2.1 with Clearmake and syntax error is no longer reported. The fix seems to be working. Thank you.
(0042327)
Kitware Robot   
2016-06-10 14:29   
Resolving issue as `moved`.

This issue tracker is no longer used. Further discussion of this issue may take place in the current CMake Issues page linked in the banner at the top of this page.