Generate shared library name via CMake - cmake

I am trying to add post build event for my project in CMakeLists file.
This post-build event must put Qt libraries near my executable file.
I use add_custom_command to do it:
set(libraryFileName ${QtDir}/bin/${packageName}.dll)
# Copy qt library after build
add_custom_command(
TARGET ${target} POST_BUILD #Path to cmake executable file
COMMAND "${CMAKE_COMMAND}" -E #CMake in command mode
copy #Copy command
"${libraryFileName}" #Path to the file
"$<TARGET_FILE_DIR:${target}>" #Where to copy
COMMENT "Copying to output directory")
The main problem is how to generate libraryFileName correctly for every system? I mean, my soultion works for Windows, but it will fail for other systems types, I guess. Is there any way to get the extension for shared library instead of hardcoding it?

I have found the solution for my case. But it may work for Qt only.
# Get package location
get_target_property(location ${qtVersion}::${shortPackageName} LOCATION)
# Copy qt library after build
add_custom_command(
TARGET ${target} POST_BUILD #Path to cmake executable file
COMMAND "${CMAKE_COMMAND}" -E #CMake in command mode
copy #Copy command
"${location}" #Path to the file
"$<TARGET_FILE_DIR:${target}>" #Where to copy
COMMENT "Copying ${packageName}...")

You can add a platform checker and set the variable depending on that check.
message(STATUS "Current CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}")
if("${CMAKE_SYSTEM_NAME}" STREQUAL "WIN98")
set(libraryFileName ${QtDir}/bin/${packageName}.dll)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "LINUX")
set(libraryFileName ${QtDir}/bin/${packageName}.so)
else
message(ERROR "The system ${CMAKE_SYSTEM_NAME} is not supported.")
endif()

Related

cmake: copy .exe target output to destination fails (file extension problem?)

(cmake version 3.24.1; on Linux with mingw32)
For example, such configuration will fail with "Error copying file /build/path/to/my_program".
How to fix it without changing target name?
add_executable(my_program main.c)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
add_custom_command(TARGET my_program POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:my_program> /path/to/
)
The problem seems to be that cmake cannot match target "my_program" to actual file "my_program.exe".
According to what I tried, dll target works out of box, but exe target needs workaround to append .exe to target name.
Is there anyway to avoid changing target name?
target-type target-name real-output cmake-target-name can-copy
executable basename basename.exe basename No
module basename basename.dll basename.so Yes
executable basename.exe basename.exe basename.exe Yes
Thanks #Tsyvarev for answer in comments above.
Use a cmake toolchain and remove CMAKE_C_COMPILER fixes the problem.
-1 Sample toolchain for mingw32:
https://gist.github.com/peterspackman/8cf73f7f12ba270aa8192d6911972fe8
-2 Change CMakeLists.txt:
+++ set(CMAKE_TOOLCHAIN_FILE mingw-w64-x86_64.cmake)
--- set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
-3 Clean build directory (or maybe delete CMakeCache.txt).

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.

Random executable output with CMake

Can I have a random name for the executable file of each build?
Or, in another words, a different name for the executable of each build action?
I wonder if a random-variable could be inserted into the build-tool-chain.
The reason of such a name is that my company's virus-checking is quite slow -- it took a long long time checking each executable, even longer then the build.
I'm using CLion 2016.2 on Win7, tool-chain is MinGW_w64_5.0, bundled CMake 3.5.2
You could always define POST_BUILD steps that call another CMake script. The only downside in the following approach would be that you can't - since it's random - reuse the executable's output name in CMake itself:
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(RandomExeName)
file(WRITE main.cpp "int main() { return 0; }")
add_executable(${PROJECT_NAME} main.cpp)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -D _file:PATH="$<TARGET_FILE:${PROJECT_NAME}>"
-P ${CMAKE_SOURCE_DIR}/CopyToRandom.cmake
)
set_property(TARGET ${PROJECT_NAME} PROPERTY SUFFIX ".temp")
CopyToRandom.cmake
string(RANDOM _random)
file(GLOB _old_files RELATIVE "${CMAKE_BINARY_DIR}" "*.exe")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E remove ${_old_files}
COMMAND "${CMAKE_COMMAND}" -E copy "${_file}" "${_random}.exe"
)
# generate shortcut
get_filename_component(_name "${_file}" NAME_WE)
file(
WRITE "${_name}.sh"
"#!/bin/bash\n"
"${_random}.exe"
)
No you can't. Or you have to reconfigure for every build.
Regarding your actual problem: Advice the virus checker to exclude your build directories.

cmake add_custom_command not working

I am trying to run gperf from a cmake file.
I created a very minimal CMakeLists.txt below.
When I run it by
$ cmake .
$ make
It does not create the example.hpp file
What could be problem with the below CMakeLists.txt?
cmake_minimum_required( VERSION 2.6 )
function(gperf_generate_new source target)
add_custom_target(${target} echo "Creating ${target}")
add_custom_command(
SOURCE ${source}
TARGET ${target}
COMMAND gperf -L c++ ${source} > ${target}
OUTPUTS ${target}
DEPENDS ${source}
)
endfunction()
gperf_generate_new(command_options.new.gperf example.hpp)
Files, produced by source-files generators(like gpref) are rarely needed as standalone. Instead, these source files are usually used for creating executables or libraries inside a project.
So, standard pattern of using source-file generators in the CMake looks like:
# Call add_custom_command() with appropriate arguments for generate output file
# Note, that *gperf* will work in the build tree,
# so for file in the source tree full path should be used.
function(gperf_generate_new input output)
add_custom_command(
OUTPUT ${output}
COMMAND gperf -L c++ ${input} > ${output}
DEPENDS ${input}
COMMENT "Generate ${output}" # Just for nice message during build
)
endfunction()
# Generate *example.hpp* file ...
gperf_generate_new(${CMAKE_CURRENT_SOURCE_DIR}/command_options.new.gperf example.hpp)
# ... for use it in executable
add_executable(my_program ${CMAKE_CURRENT_BINARY_DIR}/example.hpp <other sources>)
If you want only to test whether example.hpp is generating, instead of add_executable() use
add_custom_target(my_target
ALL # Force target to be built with default build target.
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/example.hpp
)
Note, that linkage between add_custom_command and add_custom_target is expressed using same filename in their OUTPUT and DEPENDS options correspondingly. With such link order of these commands is insignificant (but both commands should be called from the same CMakeLists.txt script).