CMake: Generated input dependency to configure_file - cmake

I would like to run configure_file() whose input file is generated using add_custom_command, through a custom dependency, before installing the output of configure_file.
I'm in reality using a ruby script to read a cmake formatted file, to extract
a few definitions which i can convert to Ruby constants in a separate library. Thus, i require the configure_file such that cmake can replace its internal variables in the ruby generated file, whose goal is to export these variables.
Thus far, I've attempted the following:
# Custom command to build the out.rb.in
add_custom_command (
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
COMMAND ruby ${CMAKE_CURRENT_SOURCE_DIR}/build_ruby_output.rb
-i ${CMAKE_CURRENT_SOURCE_DIR}/input.cmake
-o ${CMAKE_CURRENT_BINARY_DIR}/output.rb.in
)
# Custom target is required to build it
add_custom_target (
dummy_target_xxx ALL DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
)
configure_file (
"${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
"${CMAKE_CURRENT_BINARY_DIR}/output.rb"
)
install (
FILES "${CMAKE_CURRENT_BINARY_DIR}/output.rb"
DESTINATION "${RUBY_VENDOR_LIBDIR}/myvendor"
)
CMake complains with the error
CMake Error: File /home/user/myproject/build/output.rb.in does not exist.
CMake Error at CMakeLists.txt:35 (configure_file):
configure_file Problem configuring file
when running an out-of-tree build. Any ideas?

configure_file() is executed immediately at configuration step, while add_custom_command() add command to be executed(and dependency to be evaluated) at build step.
You may either replace add_custom_command with appropriate execute_process call, so your ruby script will be executed at configuration step, and its output file will be ready for configure_file.
Or you may replace configure_file with appropriate add_custom_command, so your file will be configured at build step, and will see dependencies. The problem here that you should explicitely pass CMake variables, used in "output.rb.in" file, to the configuration program, which can be, e.g.,
${CMAKE_COMMAND} [-D<var-definition>]+ -P <cmake-script-file-which-calls-configure_file>

In this particular case, it was sufficient to reorder to configuration operation, by performing configure_file() first, and pipe the output of this into the custom command.. I was merely thinking of the ordering all wrong.
I still do not have an answer for adding generated dependency to the input of configure_file()
Complete code
configure_file (
"${CMAKE_CURRENT_SOURCE_DIR}/input.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
)
# Custom command to build the output.rb
add_custom_command (
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output.rb"
COMMAND ruby ${CMAKE_CURRENT_SOURCE_DIR}/build_ruby_output.rb
-i ${CMAKE_CURRENT_BINARY_DIR}/output.rb.in
-o ${CMAKE_CURRENT_BINARY_DIR}/output.rb
)
# Custom target is required to build it
add_custom_target (
dummy_target_xxx ALL DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/output.rb"
)
install (
FILES "${CMAKE_CURRENT_BINARY_DIR}/output.rb"
DESTINATION "${RUBY_VENDOR_LIBDIR}/myvendor"
)

Related

Cmake add_custom_command is never running

My question is very similar to cmake: add_custom_command / add_custom_target ignoring dependency
But the answer specified does not solve my issue, and also it is for a newer version of cmake (3.20)
I want some files (shader files) to be copied to the executable directory every time the shader source changes
So I have the following code in cmake:
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/Shaders.txt
COMMAND ${CMAKE_COMMAND} -E echo "Actually Copying shaders"
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:Editor>/assets
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/Shaders.txt
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/assets
)
add_custom_target(CopyShaders ALL DEPENDS ${CMAKE_BINARY_DIR}/Shaders.txt)
Now, as I understand, CopyShaders will always be built (since it is always out of date), but Shaders.txt should only be built once (after the shader source is changed), after which it is up to date
I'm trying to build the target CopyShaders using cmake --build build --target CopyShaders
If I'm using MinGW, then "Actually copying shaders" never gets printed if Shaders.txt is present, even if the assets folder containing the shaders has been modified
If I'm using MSVC, I get the following warning on the terminal:
warning MSB8064: Custom build for item "D:\Acads\Programming\opengl\SummerOfCode\build\CMakeFiles\05fb3856b7a5e1f6ce1ea66ca9091779\Shaders.txt.rule" succeeded, but specified dependency "d:\acads\programming\opengl\summerofcode\editor\assets" does not exist. This may cause incremental build to work incorrectly. [D:\Acads\Programming\opengl\SummerOfCode\build\Editor\CopyShaders.vcxproj]
Again, I do have the folder existing
I figured it out
DEPENDS should only take as input files, not folders
Replacing it with all the files inside /assets works

Generate script during build with cmake

I have a cmake project with a single source file called main.c. I want to additionally provide a wrapper script which calls main with specific parameters.
My CMakeLists.txt looks as follows:
cmake_minimum_required(VERSION 3.1...3.16)
file(WRITE ${CMAKE_BINARY_DIR}/wrapper "#!/usr/bin/env bash\n")
file(APPEND ${CMAKE_BINARY_DIR}/wrapper "./main options\n")
add_executable(main main.c)
add_custom_target(wrapper_target
ALL DEPENDS wrapper)
add_custom_target(main_target
ALL DEPENDS main wrapper_target)
add_dependencies(main wrapper_target)
install(
TARGETS main
RUNTIME DESTINATION bin/)
install(
PROGRAMS wrapper
DESTINATION bin/)
If I run cmake --install ., the script wrapper is installed together with the binary main. Running cmake --build . produces the script wrapper, but it is not marked as executable (on Linux).
How can I tell cmake to also generate wrapper during build and mark it as executable?
Note: I need this for an automated build system which runs build and not install, and expects a specific file to be available on build.
Try:
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/wrapper.tmp
"#!/usr/bin/env bash
# Note that './main' is relative from whatever directory you are in
# Use just main assuming the install prefix is in your bath
# Or use $<TARGET_FILE:main>
# Or maybe ${CMAKE_INSTALL_PREFIX}/bin/main
./main options
")
# add execute permissions
file(
COPY ${CMAKE_CURRENT_BINARY_DIR}/wrapper.tmp
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
# Rename the file
file(RENAME
${CMAKE_CURRENT_BINARY_DIR}/wrapper.tmp
${CMAKE_CURRENT_BINARY_DIR}/wrapper
)
How can I tell cmake to also generate wrapper during build and mark it as executable?
file( is a in a cmake script - it is executed during configuration phase, when cmake is executed. To generate the file during build use add_custom_command, the most "portable" way in cmake sense would be to run a cmake script inside add_custom_command:
add_custom_command
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/wrapper
COMMAND $(CMAKE_COMMAND)
-D CMAKE_CURRENT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/the_cmake_script.cmake
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/the_cmake_script.cmake
COMMAND Generating wrapper script...
VERBATIM
)
then inside the_cmake_script.cmake you could do the script above - add_custom_command will execute the command cmake -P <the script> during build of you project. That way you can DEPEND properly on the wrapper script.
CMake 3.20 added support for FILE_PERMISSIONS attribute to the FILE command. So one could simply:
FILE(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/wrapper
CONTENT
"#!/usr/bin/env bash
./main options
"
FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ)

Is there a command on CMake to started executable resulted from build?

I'm trying to write generic way to run executable resulted after build using CMake's way.
git clone git#github.com:gargamel/ihatesmurfs.git
cmake -E make_directory build
cmake -Sihatesmurfs -Bbuild
cmake --build build
cmake -E chdir build
Now I want to start executable but on *nix, it's like:
./output
and on Windows:
output.exe
Is there a way to escape this with any possible CMake command?
Expanding on my comment a bit, you can modify the CMakeLists.txt file of the project to include add_custom_command. If your CMake creates an executable named HateSmurfs, you can add the custom command to run the executable after compilation completes:
add_executable(HateSmurfs smurfs.cpp)
# Add this piece of code to run the executable after it is built.
add_custom_command(
TARGET HateSmurfs
POST_BUILD
COMMAND HateSmurfs
)
According to add_custom_command documentation:
COMMAND
If COMMAND specifies an executable target name (created by the add_executable() command) it will automatically be replaced by the location of the executable created at build time.

What is cmake_install.cmake

I wrote a very simple HelloWorld.c program and ran Cmake. It created a cmake_install.cmake file in my build directory. Can somebody explain to me why CMake generated the file cmake_install.cmake? What is it's purpose and how can I use it?
CMakelists.txt :
cmake_minimum_required(VERSION 3.0)
PROJECT(FirstExample)
add_executable(prog first.c)
Thanks!
You generally don't use cmake_install.cmake directly. From the v3.12 page it states:
The install() command generates a file, cmake_install.cmake, inside
the build directory, which is used internally by the generated install
target and by CPack.
With your current CMakeLists.txt, the generated file doesn't do much. To create a useful install you would need to add more INSTALL commands to your CMakeLists.txt using the syntax below.
INSTALL(TARGETS targets... [EXPORT <export-name>]
[[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[INCLUDES DESTINATION [<dir> ...]]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
] [...])
For further reading on this command, check out the documentation site and wiki.
If it's desired to manually execute the script as stated by Nic30g the 3.12 page states that cmake -P accepts the following variables:
COMPONENT
Set this variable to install only a single CPack component as opposed to all of them. For example, if you only want to install the Development component, run
cmake -DCOMPONENT=Development -P cmake_install.cmake
BUILD_TYPE
Set this variable to change the build type if you are using a multi-config generator. For example, to install with the Debug configuration, run
cmake -DBUILD_TYPE=Debug -P cmake_install.cmake.
DESTDIR
This is an environment variable rather than a CMake variable. It allows you to change the installation prefix on UNIX systems. See DESTDIR for details.
As previous answer tells, the cmake_install.cmake contains the commands generated by install command from your CMakeLists.txt.
You can execute it by cmake -P cmake_install.cmake and it performs the installation of your project even on windows.
https://cmake.org/pipermail/cmake/2007-April/013657.html

How to have cmake unpack my compiler

In order to ensure that my Linux builds are identical regardless of the distribution the build host uses, I have packaged up my compiler and the sysroot files into a relocatable tar file and checked that into source control.
So the first step in any build (or at least, a step that must be invoked before any compile step) must be to extract this tar file.
If I was using a makefile, this would be simple to do. However, the project is using cmake and I can't figure out any way to do it with cmake. It might even be that I need this extract step invoked before cmake starts to detect the compiler: I can hard-code the compiler name but if cmake fails if it can't find the compiler then I need the unpack to happen before that test.
Is this possible with cmake?
You can use execute_process to invoke cmake's cross-platform command mode (cmake -E tar). The command would be something like:
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf MyCompiler.bz2)
The command which causes CMake to check for a valid compiler is project, so as long as you have your execute_process call before the project call, the unpacking will be done before the compiler check.