I have a cmake project with a bunch of different targets in it. First it builds an executable that is used to process some data files (lets call this DataProcessor). Then it processes those data files with the executable. Then, a second executable (we'll call this MyApp) is built and it runs with the processed data files.
There is also a target that takes all the processed data files and MyApp and bundles them up in a tar file so we can distribute them.
In my CMakeLists.txt file there I have the following lines:
get_target_property(DATA_PROCESSOR_EXE DataProcessor LOCATION)
get_target_property(MY_APP_EXE MyApp LOCATION)
I need these to run various other commands in my CMakeLists file. For example, the DATA_PROCESSOR_EXE is used in the custom command to process the data files, like so:
add_custom_command(
OUTPUT ${DATA_OUT}
COMMAND ${DATA_PROCESSOR_EXE} -o ${DATA_OUT} ${DATA_IN}
DEPENDS DataProcessor)
And when I bundle everything up I use MyApp's location as well:
# Convert executable paths to relative paths.
string(REPLACE "${CMAKE_SOURCE_DIR}/" "" MY_APP_EXE_RELATIVE
"${MY_APP_EXE}")
string(REPLACE "${CMAKE_SOURCE_DIR}/" "" DATA_PROCESSOR_EXE_RELATIVE
"${DATA_PROCESSOR_EXE}")
# The set of files and folders to export
set(EXPORT_FILES
assets
src/rawdata
${MY_APP_EXE_RELATIVE}
${DATA_PROCESSOR_EXE_RELATIVE})
# Create a zipped tar of all the necessary files to run the game.
add_custom_target(export
COMMAND cd ${CMAKE_SOURCE_DIR} && tar -czvf myapp.tar.gz ${EXPORT_FILES}
DEPENDS splat
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..)
The problem is that trying to get the target's location property now causes a warning saying:
CMake Warning (dev) at CMakeLists.txt:86 (get_target_property):
Policy CMP0026 is not set: Disallow use of the LOCATION target property.
Run "cmake --help-policy CMP0026" for policy details. Use the cmake_policy
command to set the policy and suppress this warning.
The LOCATION property should not be read from target "DataProcessor".
Use the target name directly with add_custom_command, or use the generator
expression $<TARGET_FILE>, as appropriate.
I don't understand how it wants me to use add_custome_command or what it means by use the generator expression $<TARGET_FILE>
add_custom_command knows about target names. You don't need to fetch the location yourself.
Replace code like
add_custom_command(
OUTPUT ${DATA_OUT}
COMMAND ${DATA_PROCESSOR_EXE}
with code like
add_custom_command(
OUTPUT ${DATA_OUT}
COMMAND DataProcessor
ie, use the name of the target.
The final location of the output executables is not known while CMake is running over your imperative code at 'configure time'. However, add_custom_target can be told to create build rules with content which is only known at generate-time (after configure-time). The way to do that is to use a generator expression.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-generator-expressions.7.html#informational-expressions
Use $<TARGET_FILE_DIR:MyApp> instead of ${MY_APP_EXE_RELATIVE} in your add_custom_target call, for example.
Related
Let's assume I have a Cmake C project, and I have something like this in the project:
project(my_project C CXX ASM)
set(my_executable_sources
main.c
file_one.c
)
set(my_executable_sources ${my_executable_sources} file_two.c)
add_executable(my_executable
${my_executable_sources}
file_three.c
)
Let's assume I'm in the ./build subfolder, and cmake ../ -G "Unix Makefiles" has passed successfully.
Can I somehow query build information from the command line using cmake?
For instance, I'm interested here in the final list of source files for my_executable; is there a command that would easily retrieve them? Say, like the following pseudocode:
$ cmake --pseudo-query-build --project="my_project" --target="my_executable" --query="source_files"
my_executable source files:
main.c
file_one.c
file_two.c
file_three.c
I don't see any cmake-generator-independent way of achieving this and even if you know the generator in use the project files generated.
You could modify your project to include a custom target that prints the sources though:
add_custom_target(print_my_executable_sources COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:my_executable,SOURCES>" COMMAND_EXPAND_LISTS)
this allows you to use
cmake --build <binary_dir> [--config <configuration>] --target print_my_executable_sources
to print the sources, even if generator expressions are used in the sources.
Note: This does print all files in a single line; to get all the file names on separate lines, you could instead run cmake with the -P option passing the soures via -D and add logic to print one file name per line in the cmake script file.
Alternatively setting the CMAKE_EXPORT_COMPILE_COMMANDS variable to True during configuration could result in the generation of json files that would allow for the extraction of the information, but you'd need a json parser to extract the info. Furthermore this approach only works for the Makefile and Ninja CMake generators. Also I'm not sure you can tell which target a source file belongs to in all cases.
Start by obtaining the target's sources via this line (after add_executable):
get_target_property(MY_TARGET_SOURCES my_executable SOURCES)
And then proceed with a simple line at the end of the file (after add_executable)
message(STATUS ${MY_TARGET_SOURCES})
EDIT: For a full list of available target properties refer to this link.
EDIT2: As I've noticed now that you probably intend to just use it within the CLI, then for my solution you would also have to encapsulate it with a if/endif that checks for a definition e.g. if(SOURCES_DEBUG_INFO) and then run it with -DSOURCES_DEBUG_INFO=TRUE
Is there a way in CMake to find a binary target complete name (mybin.exe) by inspecting target properties? Like
get_target_property(EXENAME targetname OUTPUT_NAME) (or RUNTIME_OUTPUT_NAME)
Or I have to use a custom command like in How to get library full-native name on cmake?
With get_target_property seems I'm only able to get the "logical" target name out of it (mybin), with no other information. Am I missing something?
Thank you
There's a reason this is not possible without generator expressions: There are multi configuration generators such as the Visual Studio generators that create a build system for multiple build configurations (Release, Debug, ...) in a single CMake configuration run (cmake -S ... -B ...). It's even the default to create binaries in a directory with a name matching the configuration built.
Depending on what you want to do with the information, there are some alternatives:
You may be able to use generator expressions, e.g. if you need the information as part of add_custom_command, add_custom_target, add_test or similar. Several target properties also allow for use of generator expressions.
You may be able to establish the desired directory structure during an install step, see the install() command.
You may be able to get the build system to generate the files in a specific location e.g. by setting the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable in the toplevel CMakeLists.txt. Note that this will still result in configuration dependent subdirectories being created for multi configuration generators, unless the variable value contains a generator expression. (You could, simply be adding $<0:>, but this could easily result in binaries of different configurations overwriting one another.)
If you cannot specify this in the toplevel CMakeLists.txt, via command line or cmake presets, you could still use a path relative to CMAKE_BINARY_DIR; this should make the binaries easy to locate.
In the end that is a matter of doing:
add_custom_command(TARGET ${your_target}
POST_BUILD
WORKING_DIRECTORY ${your_dir}
COMMAND echo "$<TARGET_FILE:${your_target}>" > "exename.txt"
DEPENDS ${your_target} ${another_target}
VERBATIM
)
so that exename.txt contains the full path to the executable target
Didn't find a way to do st like:
set(EXENAME "$<TARGET_FILE:${your_target}>")
anyway...
I am trying to embed the build date into a source file, so that every time a specific target gets built, the embedded date is refreshed, without regenerating every time the overall project built.
I.e. I have a header file builddate.h that is generated by a command that has a set of #defines. This header file is then included from other source files.
My first attempt was this:
add_custom_target(builddate COMMAND <command that generates header file>)
add_library(mylibrary ...)
add_dependencies(mylibrary builddate)
This correctly generates the header file, however the header file is generated every time, regardless of whether the mylibrary target needs to be rebuilt.
Trying with a custom command instead, i.e.
add_custom_command(OUTPUT builddate.h COMMAND <command that generates header file>)
add_library(mylibrary ... builddate.h)
correctly generates the header once, but if the mylibrary target is rebuilt, the header is not regenerated as builddate.h is already up to date.
This feels like something that should be reasonably common, but I cannot figure out what incantation of custom commands and targets will give me the desired effect. What I want is to call the command every time the mylibrary target is built, without spurious rebuilds if nothing has changed or if unrelated targets (such as executables using mylibrary) are built.
Using a PRE_BUILD custom command would sound like a good idea, but the docs state that this gets invoked just prior to PRE_LINK commands for generators other than Visual Studio, i.e. after sources are compiled. This seems like it would make this unsuitable for this purpose, as the header is needed while compiling the sources.
Found an old thread at https://cmake.org/pipermail/cmake/2010-October/040247.html suggesting to call CMake's --build for a target as a PRE_LINK command:
# This is the library that I want to build
add_library(mylibrary ...)
# Set up a library that contains the code depending on the build date
# Use an OBJECT library because we don't need it to be a full static lib
# we just want to build some source that would "normally" have been part of mylibrary
add_library(builddate OBJECT EXCLUDE_FROM_ALL codethatusesbuilddate.cpp)
# Add a PRE_LINK command for mylibrary so that prior to linking we
# 1. Generate the builddate.h header
# 2. Call CMake to build the builddate library we just set up
add_custom_command(
TARGET mylibrary PRE_LINK
COMMAND <command that generates builddate.h>
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target builddate
)
# We also need to link with the library
# NOTE: uses the generator expression to link with the output files rather than the target
# to avoid CMake setting up a dependency from builddate to mylibrary which I think
# would cause builddate to be built prior to building mylibrary, but at that point we
# haven't generated the header yet. Which we could fix, but then we'd just build it twice
target_link_libraries(mylibrary PRIVATE $<TARGET_OBJECTS:builddate>)
This feels a little awkward, but it seems to work.
Footnote: Generating the header is easily done using CMake, i.e. first configure_file or similar to create a CMake script that does the generation, then invoke ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/generated_cmake_file.cmake as the command to generate the header.
Some time ago, I wrote a cmake makro. It adds custom command to generate version.cpp in current build directory by executing Cversion.cmake.
The generation of file is executed only when dependencies have changed.
With cmake-generator-expressions dependencies are set to dependencies of target minus its own (files).
It could be improved by adding libs dependencies to also generate anew version file.
macro(add_versioning T)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
COMMAND ${CMAKE_COMMAND} "-DCMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}"
-P "${PROJECT_SOURCE_DIR}/Version/CVersion.cmake"
MAIN_DEPENDENCY "${PROJECT_SOURCE_DIR}/Version/version.cpp.in"
DEPENDS "$<FILTER:$<TARGET_OBJECTS:${T}>,EXCLUDE,version.cpp.+$>")
target_include_directories(${T} PUBLIC "${PROJECT_SOURCE_DIR}/Version")
target_sources(${T} PUBLIC "${PROJECT_SOURCE_DIR}/Version/version.h" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
endmacro()
In my CMakeLists.txt, I define a custom target and command:
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv
COMMAND python3
${CMAKE_CURRENT_SOURCE_DIR}/tests/genVectors.py)
add_custom_target(TEST_VECTORS
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv)
add_executable(VectorTest tests/VectorTest.cpp)
add_dependencies(VectorTest TEST_VECTORS)
It always generates new CSV files even though the files exist. I only need to generate the vectors (with genVectors.py python file) if they do not exist. Is that something wrong with my configuration?
The OUTPUT option of add_custom_command does not guarantee that the generated files are placed here; it just tells CMake that the generated files are expected to be placed there. It is likely that your python script is generating files at a relative path, so they are just being placed somewhere in your CMake binary directory (your build folder). So while your files may be generated correctly, your custom target doesn't see them because it is looking in CMAKE_CURRENT_SOURCE_DIR. Thus, the custom target will always trigger the custom command to re-run.
CMake runs add_custom_command from the CMAKE_CURRENT_BINARY_DIR by default, but you can change it to run from CMAKE_CURRENT_SOURCE_DIR by adding the WORKING_DIRECTORY option. This way, the generated files will be placed at the expected location, and achieve your desired behavior. Try something like this:
add_custom_command(
OUTPUT
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv
COMMAND python3
${CMAKE_CURRENT_SOURCE_DIR}/tests/genVectors.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(TEST_VECTORS
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/input.csv
${CMAKE_CURRENT_SOURCE_DIR}/output1.csv
${CMAKE_CURRENT_SOURCE_DIR}/output2.csv)
add_executable(VectorTest tests/VectorTest.cpp)
add_dependencies(VectorTest TEST_VECTORS)
You can try to generate your file at time of configuration(i.e. while calling cmake). By this way it will created only once.
You can remove add_custom_command and use execute_process to create your files.
Part of my source code is generated by a tool which is also built under our main project with a add_subdirectory. We execute this tool with a execute_process command. Clearly, if the tool is not built before we reach the execute_process statement it will fail.
I use a GLOB (file(GLOB...)) to find the source files generated. I do this because it is not possible to know beforehand how many files are generated, neither their names.
How do I force cmake to wait for the subproject to be compiled before the execute process? I would need something like a DEPENDS property for the execute_process but this option is not available.
# This subproject will source generator the tool
add_subdirectory(generator)
# I need something like: wait_for(generator)
execute_process(COMMAND generator ${CMAKE_SOURCE_DIR}/src)
file(GLOB GeneratedSources ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(mainprject.exe ${ProcessorSourceFiles}
Command execute_process executes its COMMAND immediately, at configuration stage. So it cannot be arranged after the executable is created with add_executable command: that executable will be built only at build stage.
You need to build subproject at configuration stage too. E.g. with
execute_process(COMMAND ${CMAKE_COMMAND}
-S ${CMAKE_SOURCE_DIR}/generator
-B ${CMAKE_BINARY_DIR}/generator
-G ${CMAKE_GENERATOR}
)
execute_process(COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}/generator
)
The first command invokes cmake for configure the 'generator' project, located under ${CMAKE_SOURCE_DIR}/generator directory. With -G option we use for subproject the same CMake generator, as one used for the main project.
The second command builds that project, so it produces generator executable.
After generator executable is created, you may use it for your project:
execute_process(COMMAND ${CMAKE_BINARY_DIR}/generator/<...>/generator ${CMAKE_SOURCE_DIR}/src)
Here you need to pass absolute path to the generator executable as the first parameter to COMMAND: CMake no longer have generator executable target, so it won't substitute its path automatically.
You will need to model this with target dependencies. The tool "generator" should be a cmake target. In that case use add_custom_target instead of execute_process somthing like this:
add_custom_target(generate_sources ALL COMMAND generator ${CMAKE_SOURCE_DIR}/src))
Then add a target dependency to "generator" using add_dependencies:
add_dependencies(generate_sources generator)
This will make sure your target "generate_sources", which runs the tool will only run during build after the target "generator" has been compiled.
The following is false, see the comments for more info:
Use add_dependencies to add a dependency from "mainproject.exe" to "generate_sources". Now this I have never tested, so take with a grain of salt: With CMake more recent than version 3.12, according to the entry on file, you should then be able to change your file command to:
file(GLOB GeneratedSources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/src/*.cpp)
Which I interpret as this will re-glob the files during build if the directory changes.