[CMake] custom command usage requirements?

Walter Gray chrysalisx at gmail.com
Mon Jan 19 19:16:10 EST 2015


Hey All -
I'm trying to add a custom command to some targets to copy files using a 
usage requirements kind of pattern, but I'm running into some 
limitations in CMake that seem somewhat arbitrary.  To set the stage, 
imagine the following toy example:

DirectoryA's CMakeLists File:
include_directory(B)
include_directory(C)

DirectoryB's CMakeLists File:
add_executable(TestEXE ...)
target_link_libraries(TestEXE PUBLIC TestLibrary)
#for each dependency of TestEXE
     add_custom_command(TARGET TestEXE POST_BUILD ...)
     #for each dependency of the dependency...

DirectoryC's CMakeLists File:
add_library(TestLibrary STATIC ...)
find_packge(SharedLib REQUIRED)
target_link_libraries(TestLibrary PUBLIC TestSharedLib::TestSharedLib)

Somewhere in the SharedLib find module:
add_library(TestSharedLib::TestSharedLib SHARED IMPORTED) #A library 
with a dll component that must be copied
set_property(TARGET TestSharedLib::TestSharedLib PROPERTY 
IMPORTED_LOCATION path/to/my/library.dll)

Things I tried:
     -Iterate over all the target's link libraries, and for every 
dependant shared library target, add a custom command to copy the dll.  
This failed because at the point of DirectoryB, it may be that there are 
dependencies (such as TestLibrary in the above example) which are not 
yet defined.  One could impose a strict ordering requirement, but 
nothing else in CMake (AFIK) imposes such a requirement.
   -Add a resolve_dependencies() function call after each library is 
declared, or just once at the very end of the root cmakelists file. 
Using a global property, it keeps track of all exe targets which want 
dll's copied and traverses that list, adding copy commands to targets 
that depend on the newly declared library.  Fails because you cannot 
call add_custom_command on a target outside of it's declaration file.  
Also crappy because it imposes a requirement on the user to call said 
function.
    -As above, but make the custom command reference a property on the 
target in a generator expression, then append any files that need 
copying to that property.  So far the most workable, but the property 
cannot contain generator expressions which may present a problem.

The core of the problem is that within the directory where the exe is 
defined, TestLibrary is unknown, and in DirectoryC or even DirectoryA, I 
cannot call add_custom_command on the TestEXE due to an arbitrary 
limitation cmake imposes (the target is defined, you can edit it, but 
you can't add commands to it.  This means that I can't look up any 
property of TestLibrary to discover it's dependencies, and I can't find 
out that it depends on TestSharedLib, which references a .dll file I 
want to copy into TestEXE's TARGET_DIR.  What I *can* do is make the 
TestEXE's custom command reference a property on TestEXE in a generator 
expression to get the list of dlls it depends on, but that property 
cannot itself contain any generator expressions (as would be ideal to 
deal with differing dlls for debug and release mode or the like).  As it 
stands, I have something that kinda works, but feels kinda ugly. Any one 
of several different things would give me the functionality I need.  In 
order of usefulness:

1) Allow recursive generator expression resolution: 
$<TARGET_PROPERTY:tgt,MY_PROP> where 
MY_PROP=$<$<CONFIG:DEBUG>:mything_d.dll>$<$<CONFIG:RELEASE>:mything.dll>. I 
cannot tell you how many headaches this kind of functionality would save 
me and unless I'm very mistaken I don't think it would involve very much 
work.
2) Generic support for INTERFACE_* properties. Only kinda works, since 
you can't link with MODULE libraries, which contain .dll files I'd want 
to copy.  Could be exposed by an extra argument in define_property() 
Definitely a crappier version of 1, since with 1 I could just append 
$<TARGET_PROPERTY:dependency,MY_PROP> to MY_PROP on the original target.
3) Allow add_custom_command wherever the target is defined.  If you can 
get and set properties on it, it seems weird that you can't do this.
4) Make custom commands inheritable as usage requirements.  This would 
be very weird, but would get the job done.

If anyone has any other ideas or feedback, it would be very welcome.  
I'd be very, very interested in seeing 1) make it into a future cmake 
release regardless though.


More information about the CMake mailing list