Generator expression in configure_file - cmake

We are porting some rather old code and of course we want to use generator expressions now.
The by configure_file generated .pc files now contain -I$<INSTALL_INTERFACE:include>.
The only hint about how to resolve generator expressions I found was to use
file(GENERATE
Of course this is executed during the configure step so the above expression is resolved to an empty string.
Edit:
here is an example
CMakeLists.txt:
cmake_minimum_required(VERSION 3.11)
project(test CXX)
add_library(foo SHARED main.cpp)
target_include_directories(foo PUBLIC $<INSTALL_INTERFACE:include>)
# now later buried deep in some functions
get_property( _include_dirs TARGET foo PROPERTY INCLUDE_DIRECTORIES )
configure_file(config.in config.out #ONLY)
# content of config.out is "include = -I$<INSTALL_INTERFACE:include>"
file(GENERATE OUTPUT config.out2 INPUT ${CMAKE_CURRENT_BINARY_DIR}/config.out)
# content of config.out2 is "include = -I"
# most likely because the INSTALL_INTERFACE isn't used when the file is generated
config.in:
include = #_include_dirs#
and main.cpp is just empty.

As the CMake documentation states the file (GENERATE ...) command can use generator expressions which are evaluated by the generator.
Generate Files
You can let CMake generate files with custom code directly without the workaround of a configure_file command.
Single-Config Generators
For single-config generators like Makefiles you can use:
file (GENERATE
OUTPUT "config.out"
CONTENT "include = -I$<INSTALL_INTERFACE:include>"
)
As my CMake code has to work with both multi-config and single-config generators I did not test the code specifically.
Single- And Multi-Config Generators
In general for all generators, one can use the following signature:
file (GENERATE
OUTPUT "config_$<CONFIG>.out"
CONTENT "include = -I$<INSTALL_INTERFACE:include>"
)
Due to the nature of the command in relation to multi-config generators like Visual Studio this will generate multiple files in your build folder for each build type specified in this variable CMAKE_CONFIGURATION_TYPES:
config_Debug.out
config_Release.out
config_RelWithDebInfo.out
...
config_< BUILD_TYPE >.out
If you do not specify unique filenames and CMake tries to generate the files it will stop the execution with an error.
Use Generated Files
To use the previously generated files it depends on what you need. First of all the files will exist after the configuration stage.
Single-Config Generators
To use a generated file in a single-config generator scenario with a constant name (e.g. config.out) there should be no additional work necessary.
Single- And Multi-Config Generators
For multi-config generators it is slighty different. As you have to use generator expressions to access the appropriate file at build time. If you have a CMake instruction that supports generator expressions then you can just use the filename config_$<CONFIG>.out.
But if you need the file to be named exactly the same regardless of the build type (like config.out) it gets a little more tricky.
First you have to tell CMake that there should be a file named like config.out by using add_custom_command and specifiying the OUTPUT parameter:
add_custom_command (
COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "config_$<CONFIG>.out" "config.out"
VERBATIM
PRE_BUILD
DEPENDS "config_$<CONFIG>.out"
OUTPUT "config.out"
COMMENT "creating config.out file ({event: PRE_BUILD}, {filename: config.out})"
)
CMake will create a file dependency internally and every time one references the filename config.out it will ensure that the add_custom_command gets executed.
But this will not work in every case as it depends on the further instructions which should use the file.
Depending on the commands you are using you can now specify the file config.out as input for some commands (like target_sources, ...) and CMake will detect on a file-dependency level that it has to ensure the existence of config.out.
If you want to generate a file which is not referenced on a file-dependency level (like versioninfo.txt) then you have to ensure that CMake executes the add_custom_command every time your build target gets executed via a target-dependency:
add_custom_target ("generate_config_out" DEPENDS "config.out")
add_dependencies ("MY_LIBRARY_TARGET" "generate_config_out")
Every time CMake builds the MY_LIBRARY_TARGET target it will previously build the generate_config_out target which in turn depends on the config.out that CMake will process on the file-dependency level.

Related

CMake how to get binary target complete directory and name on Windows

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...

CMake variable contents dependent on build/install

Using the $<INSTALL_INTERFACE:...> and $<BUILD_INTERFACE:...> generator expressions I can set target properties to different values depending on whether the target is exported in the current build directory or installed globally. I am writing a custom macro to accompany my CMake package and targets and would like to make the macro behave differently depending on where it is exported (in the build directory) or installed. The macro is contained in a <package>-macros.cmake.in which is included from my <package>-config.cmake file and is configured into the build directory using configure_file and later installed. I tried using the generator expressions in variables set using the configure_file command, but obviously they are not intended to work that way. I assume my requirement is not that uncommon, how is it usually done using CMake?
Just create different <package>-config.cmake files for export() and for install(EXPORT). In that files you may have a variable which differentiate them.
You may even create both files from the same pattern using configure_file command with different CMake environment(variables):
<package>-config.cmake.in:
set(IS_BUILD_INTERFACE #IS_BUILD_INTERFACE#)
# other commands, inclusion of other files, etc.
<package>-macros.cmake:
if(IS_BUILD_INTERFACE)
# Part of build interface
else()
# Part of install interface
endif()
CMakeLists.txt:
# Prepare the file for build interface exporting
set(IS_BUILD_INTERFACE ON)
configure_file(<package>-config.cmake.in <package>-config.cmake #ONLY)
export(PACKAGE <package>)
# Prepare the file for install interface exporting
set(IS_BUILD_INTERFACE OFF)
configure_file(<package>-config.cmake.in <package>-config.cmake.install #ONLY)
install(FILES <package>-config.cmake.install DESTINATION cmake)

How to run Clang-based tool as a separate CMake target

I have written a Clang-based tool and I want to run it on existing CMake executable target. I want this to be a separate Makefile target, so I can run it without builiding exe target.
There is a solution to run it during exe target build (described in cmake clang-tidy (or other script) as custom target)
set(CLANG_TIDY_EXE ${MY_CLANG_BASED_TOOL} )
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" " --my-additional-options")
set_target_properties(
my_exe_target PROPERTIES
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
)
CMake runs my tool during my_exe_target build. In build log I see:
...
cmake -E __run_co_compile --tidy=my_tool --source=main.cpp -- ..
But is it possible to create a separate target?
Maybe you could use add_custom_command, e.g. (adjust according to your vars and other needs):
add_custom_target(tidyup
COMMAND ${DO_CLANG_TIDY} [...] ${SOURCES}
DEPENDS [...]
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
edit (to address OP question):
A good starting point is to search for __run_co_compile and try to recreate the command from the Makefile rule (if your generator is make). There's no "automatic" propagation of the attributes, because a custom target or command can be anything. You could use the corresponding cmake variables (e.g. CMAKE_CXX_FLAGS, etc) or target properties (e.g. COMPILE_DEFINITIONS) to emulate that.

How to include a cmake Makefile after a target has been executed?

Given the following minimal example.
cmake_minimum_required(VERSION 2.8)
project(include_test)
add_custom_command(OUTPUT OtherCMakeLists.txt
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/create_other_cmakelists")
add_custom_target(do_something DEPENDS OtherCMakeLists.txt)
What do_something should do here is first create OtherCMakeLists.txt. Now, let's assume that do_something has to do something else afterwards, e.g. compiling some code. I'd like that when the targets from something else are executed, the CMakeLists.txt will behave as if OtherCMakeLists.txt was included with include.
Is this possible?
As an example why this could be useful: OtherCMakeLists.txt might add some compiler flags that have influence on further compiling.
To my knowledge, it is not possible to generate CMakeLists.txt file with a custom target/command and use include CMake command with generated CMakeLists.txt
The problem is that the include command is called at so-called "Configuration time" (when cmake executable tries to parse all CMakeLists.txt), but the generation of file (CMakeLists.txt) is performed at "Build time" (when make command is invoked on generated build system)
add_custom_command has 2 different signatures:
add_custom_command(OUTPUT ...) will be executed at build time, too late to apply rules from a generated CMakeLists.txt generated.
add_custom_command(TARGET ...) to attach a specific command to a target. This command can be run on PRE_BUILD, PRE_LINK or POST_BUILD. Probably not what you want to achieve...
If you are trying to add some dynamic to your compile process, adding custom commands or target may not be your best option.
You should try to read doc for some other CMake commands that can be helpful in your case:
configure_file() that can process a file (OtherCMakeLists.txt.in) into another file (OtherCMakeLists.txt) replacing variables by their values. This is achieved at configuration time
execute_process() to run a command a configuration time (thx to #ComicSansMS)
set_target_properties() to set some compiler or link flags to a specific target depending on some conditions
The list of properties you can set on targets

Only run C preprocessor in cmake?

I'm trying to use cmake to simplify distributing my OpenCL program. I have a kernel file which includes several headers and other source files, and I want to have a single self contained executable.
My plan is to have cmake run the C preprocessor on the kernel source, turning the cl file and its includes into a single unit which is easier to work with.
I can use add_custom_command to do it by calling gcc/clang with -E, but then I don't get the flags to include the right directories to find the various header files in the command, and I don't see an easy way to find all current include directories to use in the custom call to the compiler.
Is there a way to run only the C preprocessor on a file with the current cmake environment?
CMake automatically generates make targets for preprocessing files. For each foo.c in your project there's a foo.i make target that will run only the preprocessor (with all the relevant -D and -I flags etc.). Run make help to see all other potentially useful targets that CMake generates in your makefiles.
BTW, I can't see how this "single unit" will be easier to work with for you.
This worked ok so far:
function(add_c_preprocessor_command)
# Add custom command to run C preprocessor.
#
# Arguments
# OUTPUT output file
# SOURCE input file
# TARGET CMake target to inherit compile definitions, include directories, and compile options
# EXTRA_C_FLAGS extra compiler flags added after all flags inherited from the TARGET
set(one_value_args TARGET SOURCE OUTPUT)
set(multi_value_args EXTRA_C_FLAGS)
cmake_parse_arguments(CPP "" "${one_value_args}" "${multi_value_args}" ${ARGN})
string(TOUPPER ${CMAKE_BUILD_TYPE} build_type)
string(REPLACE " " ";" c_flags "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${build_type}}")
add_custom_command(
OUTPUT ${CPP_OUTPUT}
COMMAND ${CMAKE_C_COMPILER}
"-D$<JOIN:$<TARGET_PROPERTY:${CPP_TARGET},COMPILE_DEFINITIONS>,;-D>"
"-I$<JOIN:$<TARGET_PROPERTY:${CPP_TARGET},INCLUDE_DIRECTORIES>,;-I>"
${c_flags}
$<TARGET_PROPERTY:${CPP_TARGET},COMPILE_OPTIONS>
${CPP_EXTRA_C_FLAGS}
-E ${CPP_SOURCE} -o ${CPP_OUTPUT}
COMMAND_EXPAND_LISTS VERBATIM
IMPLICIT_DEPENDS C ${CPP_SOURCE}
DEPENDS ${CPP_SOURCE})
endfunction()
This will be a crude hack, but you can abuse add_definition for that, as "This command can be used to add any flags, but it was originally intended to add preprocessor definitions."
Alternatively you could just set the COMPILE_FLAGS property of the target to "-E", which will achieve the same effect but be local to that target.
I would suggest a different approach.
Build your kernel into a binary (example for ATI Stream: http://developer.amd.com/support/KnowledgeBase/Lists/KnowledgeBase/DispForm.aspx?ID=115 )
Compile this binary data into your program (as a char[] blob) and load it when your program starts.
With cmake and custom targets this should be quite simple.