CMake: How to run a add_custom_command before everything else
Asked Answered
S

2

38

I have a custom command

add_custom_command(
    OUTPUT config.h
    PRE_BUILD
    COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/mk_config_h.py ${CMAKE_CURRENT_BINARY_DIR}/config.h
)

I'm trying to run it before everything else and I generate unix Makefiles.

However PRE_BUILD is only supported for VS2010 which means that config.h is build before linking.

how do I make a custom command before cmake starts compiling sources.

Seedling answered 12/4, 2013 at 13:40 Comment(1)
Is the output file from your custom command (i.e. config.h) used as a source file in another CMake target (i.e. in the list of sources passed via add_executable or add_library)? If so, you shouldn't need to worry about the execution order - CMake will invoke the custom command as and when required.Luxurious
J
56

You should use add_custom_target instead and add_dependencies to make your normal target depend on it:

add_custom_target(
    myCustomTarget
    COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/mk_config_h.py ${CMAKE_CURRENT_BINARY_DIR}/config.h
)
add_dependencies(myTarget myCustomTarget)

This should ensure that the command is run before compiling the sources of myTarget.

Janelljanella answered 12/4, 2013 at 14:15 Comment(5)
It took me a while that add_custom_target is much better for running an executable than add_custom_command. Thank you for that solution!Grenoble
@Grenoble - No, its not better. It has significant drawback, it ALWAYS runs as described in documentation (The target has no output file and is always considered out of date even if the commands try to create a file with the name of the target), even if dependency does not change.Quesnay
Using add_custom_target and add_dependencies as suggested by @Janelljanella worked for me, to force some header and library files from another build to be copied before my normal target builds. I had previously tried to use add_custom_command( ... PRE_BUILD ... ), but it would not execute in the correct order.Breakable
I'm finding that this fails in parallel builds, if the custom target takes a long time to finish. Later build stages will run in the right order, but will use the incompletely-written output files. I have not yet figured out how to force run-to-completion.Flout
@Linas, same issue with Ninja, unable to figure out. But, I have no problems with Makefile since I added the trick explained here : https://mcmap.net/q/266963/-how-to-always-run-command-when-building-regardless-of-any-dependencyMorse
B
3

Usualy build systems which are based on makefiles do not need to mention headers as part of a target. Further more, adding headers to target is considered to be an antipattern. But generating a header is an exception from this rule.

http://voices.canonical.com/jussi.pakkanen/2013/03/26/a-list-of-common-cmake-antipatterns/

You should set your ${CMAKE_CURRENT_BINARY_DIR}/config.h as part of some other compilled target. For example:

set(PROGRAM1_SOURCES main_program1.cpp)
set(PROGRAM1_HEADERS main_program1.h ${CMAKE_CURRENT_BINARY_DIR}/config.h)
add_executable(program1 ${PROGRAM1_SOURCES} ${PROGRAM1_HEADERS})

So that, CMake will know which target actually needs the generated config.h and will be able to insert the generation commands into a right build steps.

Also, see an example at https://cmake.org/cmake-tutorial/#s5

Benson answered 4/2, 2016 at 9:45 Comment(3)
You need headers if you want code analysis from the various IDEs to work.Yasmeen
@zerophase, I agree. Project-files for IDE often need reference to all files of the project. But cmake is able to build the project without header files.Benson
Oh for sure. Just usually headers end up having to be added in to support different end users.Yasmeen

© 2022 - 2024 — McMap. All rights reserved.