Run Command after generation step in CMake - cmake

I have a command line tool that should be run after CMake created my .sln-file. Is there any way to do that using CMake?
Using execute_process(COMMAND ..) at the end of the CMakeLists.txt does not help because this is executed after the Configure step, however, the .sln-file is created in the generation step.
Thanks a lot!

A rather horrifying way to do it is by calling cmake from cmake and doing the post-generate stuff on the way out of the parent script.
option(RECURSIVE_GENERATE "Recursive call to cmake" OFF)
if(NOT RECURSIVE_GENERATE)
message(STATUS "Recursive generate started")
execute_process(COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-T "${CMAKE_GENERATOR_TOOLSET}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-DRECURSIVE_GENERATE:BOOL=ON
${CMAKE_SOURCE_DIR})
message(STATUS "Recursive generate done")
# your post-generate steps here
# exit without doing anything else, since it already happened
return()
endif()
# The rest of the script is only processed by the executed cmake, as it
# sees RECURSIVE_GENERATE true
# all your normal configuration, targets, etc go here
This method doesn't work well if you need to invoke cmake with various combinations of command line options like "-DTHIS -DTHAT", but is probably acceptable for many projects. It works fine with the persistently cached variables, including all the cmake compiler detection when they're initially generated.

From the following links, it seems like there is no such command to specify execution after CMake generated .sln files.
https://cmake.org/pipermail/cmake/2010-May/037128.html
https://cmake.org/pipermail/cmake/2013-April/054317.html
https://cmake.org/Bug/view.php?id=15725
An alternative is to write a wrapper script as described in one of the above links.
cmake ..
DoWhatYouWant.exe

Yes, add_custom_command paired with add_custom_target got this covered
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_command
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_target
For an example take a look at my answer to another question
cmake add_custom_command

Related

CMake call add_subdirectory within custom command

I'm working with a code generator that produces C++ and a CMakeLists.txt file, unfortunately I cannot use this in my main CMakeLists.txt file for testing purposes.
For example you have the following CMakeLists.txt file:
project(SomeProject CXX C)
add_custom_command(OUTPUT ${SRCS}
COMMAND ${CODEGEN_CLI_PATH} -i "${INPUT}" -o "${OUT}"
COMMENT "Generating sources"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
VERBATIM
)
add_custom_target(CODEGEN
DEPENDS
${SRCS}
)
# Needs to be executed after the custom command
add_subdirectory(${GENERATED_CMAKE_LISTS_LOCATION})
Is it possible to use functions such as add_subdirectory only after you execute custom commands for a particular target, such as CODEGEN?
I've already tried to execute it by adding an extra line to the existing custom command:
COMMAND ${CMAKE_COMMAND} -D DIR=${GENERATED_CMAKE_LISTS_LOCATION} -P add_subdirectories.cmake
Unfortuantly this doesn't work because it isn't allowed to execute functions like add_subdirectory in script mode.
Neither I can manage to call custom made functions (that are executing add_subdirectory) from add_custom_command that are located in the same file.
Nope, it is not possible. The add_subdirectory command is run during configuration step, while CODEGEN is a target that runs during build.
You seem to be doing something wrong, so the only advice I can give you is to use execute_process command to run commands you need. The execute_process command is executed during configuration stage, so it will be able to generate files you need before add_subdirectory.
But again, please describe your problem, why do you want CMake to do that.
I have a huge fixed unsigned char array that I compiled into a static library. The way I work around it is by:
if(NOT EXISTS ${PATH_TO_FOLDER}/smeagol.a)
add_subdirectory(smeagol)
endif()
I'm still looking for a nicer kung-fu way to do it using cmake. I feel that its out there, and I will update this answer once i find it.

How to define a variable during build with cmake?

I would like to define a CMake variable BUILD_TIME_VAR in CMakeLists.txt:
computed with a python script during build phase
I can then access its content with ${VAR}
In other words, the equivalent during build phase of:
execute_process(COMMAND bash -c "python $SCRIPT $FILE" OUTPUT_VARIABLE GEN_TIME_VAR)
The variable is then used to generate a file which is a dependency to make binaries.
The goal is to make the code more easy to read since otherwise, the computation occur several times.
Rather than calling n times, the python script, to compute BUILD_TIME_VAR, I would like to use the script once, to factor the code in this way:
if(expression_1)
add_custom_command(OUTPUT foo
COMMAND cmd_1(${BUILD_TIME_VAR}))
...
elseif(expression_2)
# elseif section.
add_custom_command(OUTPUT foo
COMMAND cmd_2(${BUILD_TIME_VAR}))
...
else(expression_n)
# else section.
add_custom_command(OUTPUT foo
COMMAND cmd_n(${BUILD_TIME_VAR}))
...
endif(expression)
add_custom_target(${BINARY} ALL
DEPENDS foo)
Thanks you for your help.
If I understand your question correctly, you're effectively trying to create a "build-time variable." That is something that the build tool (actually all the build tools supported by CMake) would have to support. I know of no such functionality in build tools (make, ninja, VS, ...), and hence of no support for such a thing in CMake either.
You could emulate this by writing the results to a file and reading that file in all subsequent build steps using it.
I believe you've misinterpreted the role of CMake. In short, CMake generates build files for the back-end system of your choice (Make, ninja, etc.). This is concisely reviewed here, where the configure/generate step is briefly documented along with how it precedes the actual build step.
It's not clear what you're trying to achieve exactly, but maybe defining custom commands and using their outputs to link them to custom targets for further dependency chaining (see DEPENDS here) might be helpful, e.g.
cmake_minimum_required(VERSION 3.11)
project(foobar)
set(FOO_FILES "foo.txt")
add_custom_command(OUTPUT ${FOO_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${FOO_FILES}
COMMAND echo hello >> ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Creating ${FOO_FILES}"
VERBATIM)
add_custom_target(foo DEPENDS ${FOO_FILES})
set(BAR_FILES "bar_dummy.txt") # this is only use to link the custom command to the corresponding custom target
add_custom_command(OUTPUT ${BAR_FILES}
COMMAND ${CMAKE_COMMAND} -E touch ${BAR_FILES}
COMMAND cat ${FOO_FILES}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
COMMENT "Displaying ${FOO_FILES}"
VERBATIM)
add_custom_target(bar DEPENDS ${BAR_FILES})
add_dependencies(bar foo)
However, you might need to consider the probability of going against the tool, and thus, it might be clearer to have a required step prior to the configuration of your project.

Display CMake variables without running CMake on a CMakeLists.txt file or manually inspecting config.cmake?

Suppose I have a package called Foo. If I run CMake on a CMakeLists.txt file that contains find_package(Foo), then I can print out the values of variables such as ${Foo_LIBRARIES} and ${Foo_INCLUDES}.
Is there an easy way to display these variables without having to run CMake on a CMakeLists.txt file, and without having to manually inspect the config.cmake file?
You asked: (1) Is there an easy way to display these variables without having to run cmake on a CMakeLists.txt file, and (2) without having to manually inspect the config.cmake file?
I can give you a yes answer to (2) but it does require that you (re)run cmake. But since you can re-run your cmake configure step by simply executing cmake . in the build directory, re-running cmake should not keep you from trying this approach. My answer is given in this SO answer and uses the get_cmake_property command. Here is that code encapsulated into a cmake macro, print_all_variables, so I can use it when debugging my cmake scripts.
macro(print_all_variables)
message(STATUS "print_all_variables------------------------------------------{")
get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
message(STATUS "${_variableName}=${${_variableName}}")
endforeach()
message(STATUS "print_all_variables------------------------------------------}")
endmacro()
The macros are invoked with same syntax as cmake functions:
print_all_variables()
To simply print a value, you could do something like this:
message(STATUS "foo include dir: ${foo_INCLUDE}")
where ${foo_INCLUDE} is the value you desire to print.
Note: I'm using cmake > 3.14
Run CMake and have a look at the cache with the ccmake GUI tool. Then you'll get all the variables.
Or run CMake with -LH then you will get all variables printed after configuration.
So I think it is not possible to get the variables without running CMake.
Run cmake in find-package mode. Example to display a package`s include directories:
cmake -DNAME=ZLIB -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=COMPILE --find-package
Example to display the libraries:
cmake -DNAME=ZLIB -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=LINK --find-package
The NAME must be set to the package name. You can obtain your COMPILER_ID on this page. LANGUAGE can be C, CXX or Fortran.
I am always suspicious of variables changing values throughout a script somewhere so I like to see the value of a variable at a particular point in the running script. Combining the ideas from both Phil and Aaron B. this is what I'm using:
function(PRINT_VAR VARNAME)
message(STATUS "${VARNAME}: ${${VARNAME}}")
endfunction()
PRINT_VAR("CMAKE_CXX_COMPILER")
Then I can just litter PRINT_VAR statements around like I'm debugging code back in 1980
These variables are generally hardcoded into FindFoo.cmake so that it is not possible to extract them without running the function first. Note that sometimes the value of Foo_LIBRARIES depends on the system configuration, which is unknown until find_package(Foo) is run.

Silence custom command depending on CMAKE_VERBOSE_MAKEFILE

I've a custom command in my CMake script which generates a lot of output. I'd like to take advantage of CMAKE_VERBOSE_MAKEFILE so I can decide if I want to see this output or not.
Is there a common way for doing this?
The one way I see is to redirect output to /dev/null depending on this CMake's flag, but what about Windows and other OSes?
Is there a portable or recommended way? What about default rules for C/C++ compiling commands?
Technically speaking, CMAKE_VERBOSE_MAKEFILE exists for the purpose of hiding and showing command lines, not command output.
If I had to do this, I would use a custom variable.
But on the main topic, here is how you should do:
if (COMMAND_VERBOSE)
execute_process(COMMAND "mycustom_command")
else (COMMAND_VERBOSE)
execute_process(COMMAND "mycustom_command" OUTPUT_QUIET)
endif (COMMAND_VERBOSE)
This is the most portable way to do so.
There is also an ERROR_QUIET flag, however it is a bad idea to disable error messages, else the user would be unable to see why the command failed if it failed.
If you are using add_custom_command or add_custom_target instead, such a flag does not exist.
You'll have to provide a manual redirection to /dev/null (Unix), or NUL (Windows).
As SirDarius pointed out, execute_process() has an option to silence tool output, while add_custom_command() / add_custom_target() do not.
But there is a way to work around this: By putting the actual call to your tool in a separate CMake script wrapper, using execute_process() with OUTPUT_QUIET enabled or disabled depending on a switch:
# mycustom_command.cmake
if ( OUTPUT )
execute_process( COMMAND mycustom_command )
else()
execute_process( COMMAND mycustom_command OUTPUT_QUIET )
endif()
Then, use add_custom_command() and the CMake script processing mode (-P) to call that script from your main CMakeLists.txt, with the script switch enabled / disabled by whatever variable you use for that purpose in your CMakeLists.txt file.
add_custom_command( OUTPUT outfile
COMMAND ${CMAKE_COMMAND} -P mycustom_command.cmake -DOUTPUT=${OUTPUT_DESIRED}
)
This is fully portable. If your mycustom_command is build from within your project as a target, just add it as DEPENDENCY to your add_custom_command() to have it build in time for the script call.

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.