MantisBT - CMake
View Issue Details
0012311CMakeCMakepublic2011-06-30 03:522016-06-10 14:31
Marcel Loose 
Marcel Loose 
normalmajoralways
closedmoved 
CMake 2.8.4 
 
0012311: add_custom_command documentation should warn against use in multiple independent targets
When two or more targets depend on a source that is generated by a custom command, then the rule to create this source is executed more than once when doing a parallel build. This may even result in a corrupt source as can be demonstrated (see Steps to Reproduce)
1. Create the following files:

::::::::::::::
CMakeLists.txt
::::::::::::::
cmake_minimum_required(VERSION 2.6)
project(Parallel_Generated)

add_custom_command(OUTPUT hello.cc
  COMMAND ${CMAKE_COMMAND}
          -DINFILE=${CMAKE_SOURCE_DIR}/hello.txt
          -P ${CMAKE_SOURCE_DIR}/generate.cmake
  DEPENDS hello.txt
)

set_source_files_properties(hello.cc PROPERTIES GENERATED TRUE)
include_directories(${CMAKE_BINARY_DIR})

add_executable(one one.cc hello.cc)
add_executable(two two.cc hello.cc)

::::::::::::::
generate.cmake
::::::::::::::
file(WRITE hello.cc "
#include <iostream>
void hello(const char* prefix)
{
")
file(STRINGS "${INFILE}" lines)
foreach(line ${lines})
  file(APPEND hello.cc "
  std::cout << prefix << \": ${line}\" << std::endl;
  ")
endforeach(line)
file(APPEND hello.cc "
}
")
::::::::::::::
hello.txt
::::::::::::::
Hello World.
I'm foo bar baz.

::::::::::::::
one.cc
::::::::::::::
extern void hello(const char*);
int main()
{
  hello("one");
  return 0;
}
::::::::::::::
two.cc
::::::::::::::
extern void hello(const char*);
int main()
{
  hello("two");
  return 0;
}

2. Create a build directory and run cmake from there.

3. Run the following bash-command line

   $ while true; do make clean; make -j2 || break; done

You'll notice that for each build there are two lines "Generating ..."
Sooner or later, after a few (re)builds, the build fail. Checking the generated source will explain why.
References:
http://www.mail-archive.com/cmake@cmake.org/msg37021.html [^]
http://www.mail-archive.com/cmake@cmake.org/msg36403.html [^]
http://www.mail-archive.com/cmake@cmake.org/msg32782.html [^]
No tags attached.
Issue History
2011-06-30 03:52Marcel LooseNew Issue
2011-06-30 08:49Brad KingNote Added: 0026998
2011-06-30 08:49Brad KingAssigned To => Brad King
2011-06-30 08:49Brad KingStatusnew => assigned
2011-06-30 08:49Brad KingSummaryParallel builds may fail when using add_custom_command => add_custom_command documentation should warn against use in multiple independent targets
2011-06-30 08:51Brad KingNote Added: 0026999
2011-06-30 08:51Brad KingStatusassigned => resolved
2011-06-30 08:51Brad KingResolutionopen => fixed
2011-07-01 07:29Marcel LooseNote Added: 0027001
2011-07-01 07:29Marcel LooseStatusresolved => feedback
2011-07-01 07:29Marcel LooseResolutionfixed => reopened
2011-07-01 08:45Brad KingNote Added: 0027002
2011-07-01 08:45Brad KingAssigned ToBrad King => Marcel Loose
2011-07-01 08:45Brad KingStatusfeedback => backlog
2011-07-01 09:31Marcel LooseNote Added: 0027003
2011-07-01 09:35Brad KingNote Added: 0027004
2016-06-10 14:28Kitware RobotNote Added: 0041856
2016-06-10 14:28Kitware RobotStatusbacklog => resolved
2016-06-10 14:28Kitware RobotResolutionreopened => moved
2016-06-10 14:31Kitware RobotStatusresolved => closed

Notes
(0026998)
Brad King   
2011-06-30 08:49   
This comes up somewhat frequently, but CMake does not have enough information to resolve the case in all generators. It must choose a target in which to put the command. It cannot introduce extra inter-target dependencies or new targets arbitrarily.

I consider this a documentation issue, so I've updated the summary accordingly.
(0026999)
Brad King   
2011-06-30 08:51   
Documentation updated:

  http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=0ece8f79 [^]

This warning is now prominent in the documentation. Future mailing list queries about this problem can now be answered by pointing at it.
(0027001)
Marcel Loose   
2011-07-01 07:29   
IMHO, this issue is not resolved by only updating the documentation.

I understand from your note that, although CMake doesn't have enough information to resolve the case, it can at least detect it. A CMake WARNING or ERROR would be more appropriate, because the logic of the CMakeLists.txt files is apparently wrong.
(0027002)
Brad King   
2011-07-01 08:45   
That's like asking Make to warn if it thinks there is a missing dependency.

It may be possible, but will require non-trivial analysis. One will need to extract a subgraph of the target dependency graph consisting only of targets that include a given custom command. Then make sure the graph forms a DAG leading to exactly one "root" target that generates the file. The analysis will need to be repeated for every custom command.

(0027003)
Marcel Loose   
2011-07-01 09:31   
Just out of curiosity. But how does CMake handle situations where two targets depend on the same library to be built. Isn't that situation comparable?
(0027004)
Brad King   
2011-07-01 09:35   
Inter-target dependencies are explicit:

  target_link_libraries(myexe1 mylib)
  target_link_libraries(myexe2 mylib)

The generated build system will not even start evaluating the file-level dependencies of either executable until the mylib target has been fully evaluated and completed. By the time myexe1 and myexe2 even start to build the library is up to date.
(0041856)
Kitware Robot   
2016-06-10 14:28   
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.