Only run C preprocessor in cmake? - 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.

Related

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.

Generator expression in configure_file

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.

Retrieve all link flags in CMake

In CMake, is it possible to programmatically retrieve the complete list of linker flags that will be used for a given target? The only way I can see to do this is to inspect the link.txt file in the target's CMakeFiles directory. Not ideal.
The use case that I'm interested in is to collect the data to include in something like a pkg-config file. I'm writing a library, and it includes a couple executable utilities that use the library. Building the executables (especially when the library is build statically) requires a non-trivial link line to link to my library and its dependencies. So I'd like to write out the link line necessary for building these executables to a data file included with the package such that other clients can know how to link.
As #Tsyvarev has commented there is no build-in command or property "to programmatically retrieve the complete list of linker flags" in CMake.
But inspired by your hint "so I'd like to write out the link line necessary for building these executables to a data file" I think I found a feasible solution (at least for makefile generators).
And if I understand your request correctly, we are not talking about simple verbose outputs like you get with e.g. CMAKE_VERBOSE_MAKEFILE, which would still need you to copy things manually.
So taking the following into account:
You need to run the generator first to get the real link line
CMake allows you to invent any linker language by name
You can define the link line with CMAKE_>LANG<_LINK_EXECUTABLE using variables and expansion rules
I came up with adding an LinkLine executable using my ECHO "linker" with the single purpose to create a link line file of my choosing:
set(CMAKE_ECHO_STANDARD_LIBRARIES ${CMAKE_CXX_STANDARD_LIBRARIES})
set(CMAKE_ECHO_FLAGS ${CMAKE_CXX_FLAGS})
set(CMAKE_ECHO_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS})
set(CMAKE_ECHO_IMPLICIT_LINK_DIRECTORIES ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
set(
CMAKE_ECHO_LINK_EXECUTABLE
"<CMAKE_COMMAND> -E echo \"<FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>\" > <TARGET>"
)
add_executable(LinkLine "")
target_link_libraries(LinkLine MyLibraryTarget)
set_target_properties(
LinkLine
PROPERTIES
LINKER_LANGUAGE ECHO
SUFFIX ".txt"
)
The nice thing about this approach is, that the output of my LinkLine target can be used as any other "officially generated" executable output (e.g. in install() commands or post-build steps with generator expressions):
add_custom_command(
TARGET LinkLine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:LinkLine> PackageCfg/$<TARGET_FILE_NAME:LinkLine>
)
References
Recursive list of LINK_LIBRARIES in CMake
add_custom_command is not generating a target

Generate assembly for a target

I am trying to pass -S to GCC for one of my executables. I tried this:
set_target_properties(MyTarget PROPERTIES COMPILE_FLAGS "-S")
but I get "file format not recognized; treating as linker script"
(It builds fine without that line)
Is there something wrong with passing -S like this? Or is there another way to have CMake output the assembly .s files?
CMake has targets built in for both assembler and preprocessor output. For a file called src.cpp, CMake generates the target src.s for assembler output and src.i for the preprocessor output. It generates the assembler/preprocessor outputs for each target seperately in case the compile flags are different. Using the make generator for your CMake project, you can get the assembler and preprocessor outputs like this:
make src.s # assembler output
make src.i # preprocessor output
If you're trying to actually build MyTarget and leave the generated assembly, you can replace -S with -save-temps and then do make MyTarget

How to configure CMake target or command to preprocess C file?

I originally asked this question on CMake mailing list: How to configure target or command to preprocess C file?
I'm porting build configuration based on GNU Autotools to CMake and I have to deal with C preprocessing to generate a file.
The input for preprocessor is SQL file with C preprocessor directives used, like #include "another.sql", etc.
Currently, Makefile uses the following rule to generate plain SQL file as output:
myfile.sql: myfile.sql.in.c
cpp -I../common $< | grep -v '^#' > $#
So, the myfile.sql is meant to be one of products of the build process, similar to share libraries or executables.
What CMake tools should I use to achieve the same effect?
It's unclear to me if I should use add_custom_command, add_custom_target or combine both.
Obviously, I'm looking for a portable solution that would work at least with GNU GCC and Visual Studio toolsets. I presume I will have to define platform-specific custom commands, one for cpp preprocessor, one for cl.exe /P.
Or, does CMake provide any kind of abstraction for C preprocessor?
I scanned the archives, but I only found preprocessing of fortran files or solutions based on make capabilities: make myfile.i
So, it's not quite what I'm looking for.
UPDATE: Added answer based on solution received from Petr Kmoch on CMake mailing list.
I'm answering the question to myself by copying essential parts of solution received from Petr Kmoch as response to my post in the mailing list.
First, create a custom command using add_custom_command (version with the OUTPUT signature) to actually do the preprocessing.
For example:
add_custom_command(
OUTPUT myfile.sql
COMMAND "${CMAKE_C_COMPILER}" -E myfile.sql.in -I ../common
MAIN_DEPENDENCY myfile.sql.in
COMMENT "Preprocessing myfile.sql.in"
VERBATIM)
Second, configure the command trigger:
If the command output file (myfile.sql) is used in another target, added as a source
file added to add_library or add_executable, it is enough to specify it in these commands. CMake will find it as a dependency and run the custom command as required.
If the command output file is a final output not used as dependency in
any other targets, then add a custom target to drive the command using add_custom_target
For example:
add_custom_target(
ProcessSQL ALL
DEPENDS myfile.sql
COMMENT "Preprocessing SQL files"
VERBATIM)
Credits: Petr Kmoch
To take advantage of CMake' make myfile.i feature, you can do this:
add_library(sql_cpp_target EXCLUDE_FROM_ALL myfile.sql.in.c)
Now running make myfile.sql.in.c.i will produce preprocessed source for you, using defined CMAKE_C_FLAGS. It might be possible to change output name and dir for preprocessed file.
At any rate, you'd need to wrap these make invocations into add_custom_target(ALL ...) to make CMake run them during build.
Use CMAKE_MAKE_PROGRAM variable in targets definitions.
If you want to abstract from build tool, you can call cmake itself to build a target for you. Use ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target targetname when defining custom target.
Alternatively, you can just add_custom_command() which runs specified compiler to preprocess files and put them at the appropriate place. But this seems to be less flexible, IMO.