I'm modeling dependencies with target_link_libraries
, as is done in this blog post.
target_link_libraries(Foo
LibraryA
LibraryB
)
This is working great, but for various reasons I need to use add_custom_target
to preprocess to a file through a custom command. The problem is, this custom target depends on the includes of LibraryA and LibraryB. I was really hoping to do the following like how target_link_libraries
works (see the LibraryA and LibraryB bit):
add_custom_target(Bar ALL
COMMAND ${CMAKE_C_COMPILER} thing.cpp LibraryA LibraryB /P
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/Path/Here
COMMENT "Preprocessing to a file"
VERBATIM
)
However, this doesn't work. LibraryA and LibraryB are put in as they appear. Even if it did work, I imagine I would get more than the includes, since I think the targets include the library as well. Maybe this is not a good approach.
So, what can I do here? How can I extract the include directories from each target, for use in the custom command? I found if I find_package(Foo REQUIRED)
I get access to Foo_DIR
, but that points to the build directory and not the source directory where the includes are.
You can extract the include directories from each target using get_target_property()
. A target's INCLUDE_DIRECTORIES
property contains the include directories for that target. Since you have two targets, LibraryA
and LibraryB
, we have to call it twice. Then, we can concatenate the list of include directories together using foreach()
. If you are using these as include directories in a compiler command (such as MSVC), you can append the /I
compiler option to each directory in the loop also:
# Get the include directories for the target.
get_target_property(LIBA_INCLUDES LibraryA INCLUDE_DIRECTORIES)
get_target_property(LIBB_INCLUDES LibraryB INCLUDE_DIRECTORIES)
# Construct the compiler string for the include directories.
foreach(dir ${LIBA_INCLUDES} ${LIBB_INCLUDES})
string(APPEND INCLUDE_COMPILER_STRING "/I${dir} ")
endforeach()
Then, you can call the custom target command using the constructed INCLUDE_COMPILER_STRING
variable:
add_custom_target(Bar ALL
COMMAND ${CMAKE_C_COMPILER} thing.cpp ${INCLUDE_COMPILER_STRING} /P
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/Path/Here
COMMENT "Preprocessing to a file"
VERBATIM
)
If you wanted something more concise, you could use the generator expression example here, which gets the targets' include directories and expands them inline, within your custom target command. Something like this could work also:
add_custom_target(Bar ALL
COMMAND ${CMAKE_C_COMPILER} thing.cpp
"/I$<JOIN:$<TARGET_PROPERTY:LibraryA,INCLUDE_DIRECTORIES>,;/I>"
"/I$<JOIN:$<TARGET_PROPERTY:LibraryB,INCLUDE_DIRECTORIES>,;/I>"
/P
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/Path/Here
COMMENT "Preprocessing to a file"
VERBATIM
COMMAND_EXPAND_LISTS
)