[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