Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • CMake CMake
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 4.2k
    • Issues 4.2k
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 10
    • Merge requests 10
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Artifacts
    • Schedules
  • Deployments
    • Deployments
    • Releases
  • Packages and registries
    • Packages and registries
    • Container Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • External wiki
    • External wiki
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • CMakeCMake
  • CMakeCMake
  • Issues
  • #17097
Closed
Open
Issue created Jul 24, 2017 by Mitchell Blank@mitchblank

Ninja: Minimize dependencies of add_custom_command()

I'm filing this bug as a break-out from the discussion on #15555 (closed), starting here: #15555 (comment 292643)

Right now, add_custom_command()-based targets seem to be very conservative about their generated dependencies, beyond the ones that are specified. For example, start with this simple file:

project ( libDependencyTest C )
add_library ( mylib STATIC mylib-a.c )
add_custom_command (
	OUTPUT ${CMAKE_BINARY_DIR}/generated.c
	# The actual command doesn't matter here, just doing a simple
	# copy as a trivial "custom" command
	COMMAND cp ${CMAKE_SOURCE_DIR}/source-dependency ${CMAKE_BINARY_DIR}/generated.c
	MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/source-dependency
	COMMENT "building ${CMAKE_BINARY_DIR}/generated.c"
)
add_executable ( final-binary ${CMAKE_BINARY_DIR}/generated.c extra.c )
target_link_libraries ( final-binary mylib )

and then:

$ cat "int main(){return 0;}" >source-dependency
$ touch mylib-a.c extra.c
$ cmake -G Ninja

and cmake-3.9.0 creates a build.ninja with the following:

build generated.c: CUSTOM_COMMAND source-dependency || libmylib.a

...so this generated file now depends on a add_library()-generated target it had nothing to do with (in a larger cmake setup you could end up with dozens of libraries listed there) delaying how soon this step could start in a parallel build.

Furthermore there are these two lines:

build cmake_object_order_depends_target_final-binary: phony || cmake_object_order_depends_target_mylib generated.c
[...]
build CMakeFiles/final-binary.dir/extra.o: C_COMPILER__final-binary extra.c || cmake_object_order_depends_target_final-binary

...so the other *.o files that make up final-binary can't start compiling until after generated.c is built. Obviously generated.o has to depend on generated.c, but there's no reason for extra.o to depend on it as well.

The effect these dependencies have on build times are quite noticeable for me. I have a large codebase with dozens of libraries and hundreds of other source files that go into a final binary. However, when I do a parallel build it effectively becomes a 4-stage process: (1) The libraries all get built, with hundreds of compiles happening in parallel (this is with a distributed build farm) (2) The single add_custom_command()-based target runs, completely by itself (3) Then all of the non-library source files start building, also in parallel (4) Final executable link

There is no reason the work from (1), (2), and (3) can't all be happening together, but right now cmake is forcing them to happen sequentially. As stage (1) starts to complete there are lots of CPUs idle, so it's very noticeable that the build is taking longer than it should.

I wish there was a way of saying to add_custom_command() "I am telling you the whole truth about your dependencies and outputs, don't add any extra ones"

Edited Jul 25, 2017 by Ben Boeckel
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking