Have cmake run command on installed target binary - cmake

I'd like to run a command on a target after installing it. I see "cmake run script for install target?", which appears to be about running a single script after installing everything. My question is a per-target script.
What I want to do is to run patchelf on an installed binary to change the interpreter. This is much like how cmake will change the RPATH on the installed binary. Looking into how this is done, I see stuff this in cmake_install.cmake (edited for brevity):
file(INSTALL DESTINATION "/bin" TYPE EXECUTABLE FILES "program")
file(RPATH_CHANGE
FILE "$ENV{DESTDIR}/bin/program"
OLD_RPATH "build-dir"
NEW_RPATH "")
if(CMAKE_INSTALL_DO_STRIP)
execute_process(COMMAND "/usr/bin/strip" "$ENV{DESTDIR}/bin/program")
endif()
This is changing the rpath and also stripping the binary after it is installed. It seems like all I need to do is get one more execute_process put in there to run my patchelf command. Yet I can't find any way to get cmake to do that.
It appears add_custom_command(POST_BUILD ...) is very close, but I do not want to modify the binary in the build directory, only after install, like how cmake modifies the rpath.

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

Installing no longer existing files

I have a list of various files that I want to install, by executing a resulting INSTALL project. This works, but sometimes files are no longer available, when the install operation is executed. Environment is a build server, where files get moved around -> this causes the build to be faulty.
An easy way to fix this behaviour is in the OPTIONAL parameter of the install command. So my question is: Is there a way to output warnings at runtime, if the install command failed?
Here is my code, to recreate the issue. In the src directory there are files "1.txt" and "2.txt". I build the cmakelists.txt and then delete "2.txt". After that, I execute the INSTALL solution I got.
cmake_minimum_required(VERSION 3.0)
project(documentation)
set(SOURCEDOCUMENTATION "D:/projects/side_master/src/documentation/src")
set(TARGETDOCUMENTATION "D:/projects/side_master/src/documentation/tgt")
file (GLOB files_to_install "${SOURCEDOCUMENTATION}/*")
foreach(file_to_install ${files_to_install})
install(FILES ${file_to_install} DESTINATION ${TARGETDOCUMENTATION} OPTIONAL)
endforeach()
The error (without the OPTIONAL parameter):
-- Install configuration: "Debug"
-- Installing: D:/projects/side_master/src/documentation/tgt/1.txt
CMake Error at cmake_install.cmake:56 (file):
file INSTALL cannot find
"D:/projects/side_master/src/documentation/src/2.txt".
What I want to get is a generated message, like this:
File "D:/projects/side_master/src/documentation/src/2.txt" not found.
You could make use of the install(SCRIPT ...) or install(CODE ...) signatures of the CMake install command, to run custom installation steps specific to your use case. The custom steps here would check for the existence of the files (using CMake's EXISTS logic) to be installed, and print a warning message if the file does not exist. The custom installation command could look something like this:
install(CODE "
if(NOT EXISTS ${file_to_install})
message(WARNING \"File ${file_to_install} not found during installation.\")
endif()
")

Get CMake's Ninja test command

I'm trying to make Ninja work with CMake on FreeBSD 10.3:
cmake -GNinja ..
-- Configuring done
CMake Error:
The detected version of Ninja () is less than the version of Ninja required
by CMake (1.3).
-- Build files have been written to: /home/me/pj/_build
I have put a locally compiled (from Git tag v1.8.2) Ninja in ~/bin/ninja (which is in my $PATH).
$ cmake -version
cmake version 3.4.1
$ ninja --version
1.8.2
I also tried to add -DCMAKE_MAKE_PROGRAM=ninja and -DCMAKE_MAKE_PROGRAM=~/bin/ninja without effect.
I also tried to see if Ninja was really called (by putting a script writing a new file), and it looks like it's never called.
Is there a way to see which commands are used to to check the Ninja version?
By inspecting the generated CMakeCache.txt file, you should be able to tell which Ninja version is picked by CMake.
In CMakeCache.txt you should have something similar to:
// Path to a program.
CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/ninja
which could tell which Ninja version is picked by default and whether -DCMAKE_MAKE_PROGRAM is respected or from some reason ignored.
Also, it is worth looking into the generated CMakeOutput.log and CMakeError.log files.
I would also suggest adding ninja to your PATH, hoping CMake would pick it from there.
I came across this question while getting the same error message. What I forgot to do was delete the CMakeCache.txt file before I ran cmake with the -GNinja or -DCMAKE_GENERATOR=Ninja options. So cmake was pulling the cached variable.
You can also get this error message when forgetting to call project(my_project) before calling add_library or add_executable.

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.