How to always run command when building regardless

2019-01-18 22:41发布

问题:

I want to run a cmake command that parses the whole source tree, so I can't list all possible dependencies in cmake's add_custom_command/add_custom_target commands.

Is it possible to tell cmake just to run a command without any conditions? I tried all solutions found on the net (including SO) but they all assume that the command is dependent on few known files being up to date.

I found a solution but it does not work reliably:

cmake_minimum_required(VERSION 2.6)

project(main)

add_custom_command(
   OUTPUT file1
   COMMAND echo touching file1
   COMMAND touch file1
   DEPENDS file2)
add_custom_target(dep ALL DEPENDS file1 file2)

# this command re-touches file2 after dep target is "built"
# and thus forces its rebuild
ADD_CUSTOM_COMMAND(TARGET dep
          POST_BUILD
          COMMAND echo touching file2
          COMMAND touch file2
)

and this is output:

queen3@queen3-home:~/testlib$ make
[100%] Generating file1
touching file1
touching file2
[100%] Built target dep
queen3@queen3-home:~/testlib$ make
[100%] Generating file1
touching file1
touching file2
[100%] Built target dep
queen3@queen3-home:~/testlib$ make
touching file2
[100%] Built target dep
queen3@queen3-home:~/testlib$ 

As you can see, on third run it did not generate file1, even though file2 was touched previously. Sometimes it happens every 2nd run, sometimes every 3rd, sometimes every 4th. Is it a bug? Is there another way to run a command without any dependency in cmake?

Strange but if I add TWO commands to re-touch file2, i.e. just copy-paste the post-build command, it works reliably. Or maybe it will fail every 1000th run, I'm not sure yet ;-)

回答1:

A twist on ideasman42's answer is to create a dummy output with an empty echo statement. The advantage is that you can have several custom commands depend on this dummy output.

Also, the cmake build system will know what the output file of your custom command is so that any dependencies on that output can be properly resolved.

# Custom target will always cause its dependencies to be evaluated and is
# run by default
add_custom_target(dummy_target ALL
    DEPENDS
        custom_output
    )

# custom_output will always be rebuilt because it depends on always_rebuild
add_custom_command(
    OUTPUT custom_output
    COMMAND command_that_produces_custom_output
    DEPENDS
        always_rebuild
    )

# Dummy output which is never actually produced. Anything that depends on
# this will always be rebuilt.
add_custom_command(
    OUTPUT always_rebuild
    COMMAND cmake -E echo
    )

The cmake -E echo is as close to a no-op as cmake has.



回答2:

While I'm not at all pleased with this solution, posting since I stumbled on this page and didn't see it mentioned.

You can add a custom target that references a missing file,

eg:

add_custom_target(
    my_custom_target_that_always_runs ALL
    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/__header.h
    )

add_custom_command(
    OUTPUT
        ${CMAKE_CURRENT_BINARY_DIR}/__header.h  # fake! ensure we run!
        ${CMAKE_CURRENT_BINARY_DIR}/header.h    # real header, we write.
    # this command must generate: ${CMAKE_CURRENT_BINARY_DIR}/header.h
    COMMAND some_command
    )

This will keep running the custom command because __header.h is not found.

See a working example where this is used.



回答3:

I searched for exactly the same and I finally found a "notSoWorkaround" solution.

ADD_CUSTOM_TARGET(do_always ALL COMMAND yourCommandRegardlessOfAnyDependency)

This adds a target that will be run after ALL. And as custom targets are always considered out of date it will run always.

You may need DEPENDS yourA.out for running after the build

My sources :

  • cmake documentation
  • a mailing list answer for this question


回答4:

So here's my solution. I add a fake library:

add_subdirectory(fake)
add_dependencies(${PROJECT_NAME} fake)

and there I do this:

cmake_minimum_required (VERSION 2.6)
project(fake CXX)
add_library(${PROJECT_NAME} SHARED fake.cpp)
add_custom_command(TARGET fake
    POST_BUILD
    COMMAND ./mycommand.sh
    COMMAND rm ${ROOT_BIN_DIR}/libfake.so
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

So as you can see I just remove .so file after build, which causes fake lib to be rebuilt each time, with POST_BUILD executed, and all this before the main PROJECT_NAME because it is dependent on fake.



标签: cmake