Discussion:
[CMake] add_custom_target dependency list issue
Szilárd Páll
2010-09-26 00:34:21 UTC
Permalink
Hi,

I implemented a custom target which depends on several other targets,
including some that I generate beforehand as custom targets and
collect their names in a variable. However, this seems to behave in a
strange way if I list these dependencies like this:

add_custom_target(foo COMMAND [...]
DEPENDS bar ${MORE_DEPENDENCIES}),

where ${MORE_DEPENDENCIES} contains space separated list of e.g "dep1 dep2 dep3"

The error I get with generated makefiles is:

make[3]: *** No rule to make target `path_to_bar/bar dep1 dep2 dep3',
needed by [...] Stop.

The strange thing is that even if I explicitly list the dependency
names instead of passing them through the value of the
MORE_DEPENDECIES variable, I get an error that there is no rule to
make the respective target:

make[3]: *** No rule to make target `dep1', needed by [...] Stop.

What am I doing wrong? The custom targets dep1,2,3 are generated
right before "foo", and all of them seem to work (make dep1,2,3
succeeds).

Regards,
--
Szilárd
Michael Hertling
2010-09-26 01:58:06 UTC
Permalink
Post by Szilárd Páll
Hi,
I implemented a custom target which depends on several other targets,
including some that I generate beforehand as custom targets and
collect their names in a variable. However, this seems to behave in a
add_custom_target(foo COMMAND [...]
DEPENDS bar ${MORE_DEPENDENCIES}),
where ${MORE_DEPENDENCIES} contains space separated list of e.g "dep1 dep2 dep3"
make[3]: *** No rule to make target `path_to_bar/bar dep1 dep2 dep3',
needed by [...] Stop.
The strange thing is that even if I explicitly list the dependency
names instead of passing them through the value of the
MORE_DEPENDECIES variable, I get an error that there is no rule to
make[3]: *** No rule to make target `dep1', needed by [...] Stop.
What am I doing wrong? The custom targets dep1,2,3 are generated
right before "foo", and all of them seem to work (make dep1,2,3
succeeds).
The DEPENDS option of ADD_CUSTOM_TARGET() is meant for file-level
dependencies only; use ADD_DEPENDENCIES() for target-level ones.

Regards,

Michael
Szilárd Páll
2010-09-26 19:09:37 UTC
Permalink
Post by Michael Hertling
The DEPENDS option of ADD_CUSTOM_TARGET() is meant for file-level
dependencies only; use ADD_DEPENDENCIES() for target-level ones.
Silly mistake, thanks for pointing it out. However, even if I add
target dependencies using ADD_DEPENDENCIES() it seems to take into
account only the dependent the binary targets (bar, see above), but
the custom ones (dep1,2,3) are completely ignored. What could be still
wrong?

Also, strangely enough, if I list the binary target in the
add_custom_target's DEPENDS section (like in my initial example), it
does work. Is this just because I am lucky enough that the the
dependency itself is a binary with the same name as the target I
actually intended to refer to?

--
Szilárd
Szilárd Páll
2010-09-26 19:31:20 UTC
Permalink
I figured out something that makes me even more puzzled. The following
does _not_ work as expected::

set(DEPS "dep1 dep2 dep3")
add_dependencies(foo bar
${DEPS})

Target "foo" gets only dependent on bar and not dep1,2,3. On the other
hand, manually listing the latter instead of using the DEPS variable
works as well as adding them one-by-one in a loop (where also a
variables is used).

This seems to be _extremely_counterintuitive! Is there some sort of
CMake black-magic or basic rule that I don't know of?

--
Szilárd
Post by Szilárd Páll
Post by Michael Hertling
The DEPENDS option of ADD_CUSTOM_TARGET() is meant for file-level
dependencies only; use ADD_DEPENDENCIES() for target-level ones.
Silly mistake, thanks for pointing it out. However, even if I add
target dependencies using ADD_DEPENDENCIES() it seems to take into
account only the dependent the binary targets (bar, see above), but
the custom ones (dep1,2,3) are completely ignored. What could be still
wrong?
Also, strangely enough, if I list the binary target in the
add_custom_target's DEPENDS section (like in my initial example), it
does work. Is this just because I am lucky enough that the the
dependency itself is a binary with the same name as the target I
actually intended to refer to?
--
Szilárd
Andreas Pakulat
2010-09-26 21:30:59 UTC
Permalink
Post by Szilárd Páll
I figured out something that makes me even more puzzled. The following
set(DEPS "dep1 dep2 dep3")
add_dependencies(foo bar
${DEPS})
Target "foo" gets only dependent on bar and not dep1,2,3. On the other
hand, manually listing the latter instead of using the DEPS variable
works as well as adding them one-by-one in a loop (where also a
variables is used).
This seems to be _extremely_counterintuitive! Is there some sort of
CMake black-magic or basic rule that I don't know of?
No black magic, just cmake's rules about variable contents.
Basically CMake has only 1 type of variable value, thats a string. What
you created above is a string variable "DEPS" with the value "dep1 dep2
dep3", i.e. a single string consisting of 3 words separated by spaces.
Some strings are considered to be a list if you use a cmake command that
expects a list, these strings need to separate each list entry with a
semicolon.If you use

set(DEPS dep1 dep2 dep3)

then CMake will create DEPS as a string containing a list with those 3
words. What should also work is

set(DEPS "dep1;dep2;dep3")

as that should create a list in the variable DEPS.

The CMake Manual under the set() command also explains this.

Andreas
--
Your motives for doing whatever good deed you may have in mind will be
misinterpreted by somebody.
Szilárd Páll
2010-09-26 23:48:38 UTC
Permalink
Post by Andreas Pakulat
No black magic, just cmake's rules about variable contents.
Basically CMake has only 1 type of variable value, thats a string. What
you created above is a string variable "DEPS" with the value "dep1 dep2
dep3", i.e. a single string consisting of 3 words separated by spaces.
Some strings are considered to be a list if you use a cmake command that
expects a list, these strings need to separate each list entry with a
semicolon.If you use
Actually I knew about the rules on variable contents as well as the
structure and generation on lists. However I didn't realize that

set(DEPS "dep1 dep2 dep3")
add_dependencies(foo bar
${DEPS})

is not pretty much the same as:

add_dependencies(target-name depend-target1
depend-target2 ...),

which is straight from the documentation.

This is what tricked me and I still think it's counter intuitive, but
after all, it's not the first time cmake makes me sweat with some
trivial stuff :)
I'm realizing that CMake probably generates a list of targets straight
from the command invocation and works on that later on. The/my
confusion roots in the quite weird way that can be used to create
lists (set(var elem1 elem2...)). Correct me if I'm wrong, though!

Thanks a bunch for enlightening me!

Regards,
--
Szilárd
Hendrik Sattler
2010-09-27 05:09:54 UTC
Permalink
Post by Szilárd Páll
Post by Andreas Pakulat
No black magic, just cmake's rules about variable contents.
Basically CMake has only 1 type of variable value, thats a string. What
you created above is a string variable "DEPS" with the value "dep1 dep2
dep3", i.e. a single string consisting of 3 words separated by spaces.
Some strings are considered to be a list if you use a cmake command that
expects a list, these strings need to separate each list entry with a
semicolon.If you use
Actually I knew about the rules on variable contents as well as the
structure and generation on lists. However I didn't realize that
set(DEPS "dep1 dep2 dep3")
add_dependencies(foo bar
${DEPS})
add_dependencies(target-name depend-target1
depend-target2 ...),
That's because you got the quotes wrong, must be
set(DEPS dep1 dep2 dep3)

and _NOT_
set(DEPS "dep1 dep2 dep3")

for this to work.

HS

Michael Hertling
2010-09-27 04:33:08 UTC
Permalink
Post by Szilárd Páll
Post by Michael Hertling
The DEPENDS option of ADD_CUSTOM_TARGET() is meant for file-level
dependencies only; use ADD_DEPENDENCIES() for target-level ones.
Silly mistake, thanks for pointing it out. However, even if I add
target dependencies using ADD_DEPENDENCIES() it seems to take into
account only the dependent the binary targets (bar, see above), but
the custom ones (dep1,2,3) are completely ignored. What could be still
wrong?
The following works for me:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(CUSTOM_TARGETS_1 NONE)
ADD_CUSTOM_TARGET(t0 COMMAND ${CMAKE_COMMAND} -E echo "Building t0")
ADD_CUSTOM_TARGET(t COMMAND ${CMAKE_COMMAND} -E echo "Building t")
ADD_DEPENDENCIES(t t0)

When making "t" I can see "Building t0" followed by "Building t" each
time. If this doesn't work for you, could you perhaps post a minimal
but complete CMakeLists.txt in order to demonstrate the issue?
Post by Szilárd Páll
Also, strangely enough, if I list the binary target in the
add_custom_target's DEPENDS section (like in my initial example), it
does work. Is this just because I am lucky enough that the the
dependency itself is a binary with the same name as the target I
actually intended to refer to?
You don't need to be lucky for this to work, at least on *nix: ;)

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(CUSTOM_TARGETS_2 C)
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
ADD_EXECUTABLE(main main.c)
SET_TARGET_PROPERTIES(main PROPERTIES OUTPUT_NAME "prog")
ADD_CUSTOM_TARGET(t COMMAND ${CMAKE_COMMAND} -E echo "Building t"
DEPENDS main)

After CMaking, ${CMAKE_BINARY_DIR}/CMakeFiles/t.dir/build.make has

CMakeFiles/t: prog

so the custom target actually tracks the executable target's output
name but not the target itself. Anyway, that's not evident from the
documentation and I don't know if it works on every CMake-supported
platform. Maybe, someone can tell us if that behaviour is intended
and reliable.

Regards,

Michael
Continue reading on narkive:
Loading...