Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cmake: struggling with add_custom_command dependencies

Tags:

cmake

I'm trying to get a file produced by an add_custom_command in one directory to be a dependency of an add_custom_command in another directory.

In the first directory (lib/core) I have a build command that looks like this:

add_custom_command(
    OUTPUT libcore.bc
    COMMAND tartln -filetype=bc -link-as-library -o libcore.bc ${STDLIB_BC_FILES}
    DEPENDS ${STDLIB_BC_FILES} tartln
    COMMENT "Linking libcore.bc")

In the second directory, I have a command that uses the output of that command:

add_custom_command(OUTPUT ${OBJ_FILE}
    COMMAND tartln -disable-fp-elim -filetype=obj -o ${OBJ_FILE} ${BC_FILE}
        "${PROJECT_BINARY_DIR}/lib/core/libcore.bc"
    MAIN_DEPENDENCY "${BC_FILE}" 
    DEPENDS "${PROJECT_BINARY_DIR}/lib/core/libcore.bc"
    COMMENT "Linking Tart bitcode file ${BC_FILE}")

However, when I try to build, I get the following error:

make[3]: *** No rule to make target `lib/core/libcore.bc', needed by `test/stdlib/ReflectionTest.o'.  Stop.

One weird thing that I see is that the path in the error message is a relative, not an absolute path, despite the fact that I know that ${PROJECT_BINARY_DIR} is a full, correct path. I don't know if this is a problem or just a strangeness of make.

I've also tried making a top-level target for the libcore library, in the lib/core directory:

add_custom_target(libcore DEPENDS libcore.bc libcore.deps)

And then using that in the DEPENDS clause. The strange thing about that is it works the first time you do a clean build, but gives an error on any subsequent build. In any case, my understanding is DEPENDS is only supposed to work for file dependencies, so this doesn't seem like the correct solution. (How do you have a custom command that depends on a top-level target then?)

I've also tried putting absolute paths everywhere, no effect.

like image 795
Talin Avatar asked Oct 24 '10 20:10

Talin


3 Answers

The cmake documentation says the following about the DEPENDS parameter:

The DEPENDS option specifies files on which the command depends. If any dependency is an OUTPUT of another custom command in the same directory (CMakeLists.txt file) CMake automatically brings the other custom command into the target in which this command is built. If DEPENDS specifies any target (created by an ADD_* command) a target-level dependency is created to make sure the target is built before any target using this custom command.

Therefore I think you will have to define a target using add_custom_target and depend on this.

The documentation for add_custom_target says:

Dependencies listed with the DEPENDS argument may reference files and outputs of custom commands created with add_custom_command() in the same directory (CMakeLists.txt file).

So you will have to use add_custom_command and add_custom_target as follows:

  1. In the first directory generating the bc file you do

    add_custom_command(OUTPUT libcore.bc ... ) # just as in your question add_custom_target (LibCoreBC DEPENDS libcore.bc)

  2. In the second directory you do

    add_custom_command (OUT ${OBJ_FILE} DEPENDS LibCoreBC ....)

like image 118
Martin Avatar answered Oct 03 '22 14:10

Martin


This is a non-answer but a clarification to one of your answers above.

According to the cmake documents, a custom target created by add_custom_target is always considered out of date and is always built.

IMO, the cmake documents should say instead:

A custom target created by add_custom_target is always considered out of date and is always built, but only when requested.

That means that if all of your targets are marked as EXCLUDE_FROM_ALL, and you have add_custom_target commands that create new targets, and you type make from the command line with no targets specified, the targets added with add_custom_target are not built. But if you spell them out on the make command line explicitly, then they are built. Also, there is the ALL keyword that you can specify to the add_custom_target to force those to be built as a part of the all rule, which I believe means when make is executed without arguments.

like image 28
bgoodr Avatar answered Oct 03 '22 14:10

bgoodr


try to add following command into second directory:

set_source_files_properties(${PROJECT_BINARY_DIR}/lib/core/libcore.bc PROPERTIES GENERATED TRUE)

I solved my problem with this command. a relating link: https://cmake.org/cmake/help/latest/prop_sf/GENERATED.html

like image 35
user10422063 Avatar answered Oct 03 '22 15:10

user10422063