Random executable output with CMake - 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.

Related

What is the function of add_custom_target in CMake?

From the CMake Cookbook, I see that we can use the command add_custom_command and add_custom_target to run a custom command at build time. There is a toy example that I want to extract compressed files in subdirectory and link it to the final executable files. We have two CMakeLists.txt files and the following one is in the subdirectory.
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
set(MATH_SRCS
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxBLAS.cpp
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxLAPACK.cpp
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxBLAS.hpp
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK/CxxLAPACK.hpp
)
add_custom_target(BLAS_LAPACK_wrappers
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${MATH_SRCS}
COMMENT
"Intermediate BLAS_LAPACK_wrappers target"
VERBATIM
)
add_custom_command(
OUTPUT
${MATH_SRCS}
COMMAND
${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
COMMENT
"Unpacking C++ wrappers for BLAS/LAPACK"
)
add_library(math "")
target_sources(math
PRIVATE
${MATH_SRCS}
)
target_include_directories(math
INTERFACE
${CMAKE_CURRENT_BINARY_DIR}/wrap_BLAS_LAPACK
)
# BLAS_LIBRARIES are included in LAPACK_LIBRARIES
target_link_libraries(math
PUBLIC
${LAPACK_LIBRARIES}
)
The following CMakeLists.txt is in the main directory.
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# Fortran needed to discover LAPACK with some compilers
project(recipe-04 LANGUAGES CXX Fortran)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(deps)
add_executable(linear-algebra linear-algebra.cpp)
target_link_libraries(linear-algebra
PRIVATE
math
)
I do not know why we need the add_custom_target in this example.
The command add_custom_command cannot be executed without generating any target. That is why we need the custom target to run this command. What's more, it can only execute at the configure time. If we want to run the command after we configure the CMakeLists.txt file, we can create a custom target to achieve that as the following.
add_custom_target(BLAS_LAPACK_wrappers
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${MATH_SRCS}
COMMENT
"Intermediate BLAS_LAPACK_wrappers target"
VERBATIM
)
add_custom_command(
OUTPUT
${MATH_SRCS}
COMMAND
${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/wrap_BLAS_LAPACK.tar.gz
COMMENT
"Unpacking C++ wrappers for BLAS/LAPACK"
)
After we configure the CMakeLists.txt file, we use the Cmake --build . --target=BLAS_LAPACK_wrappers the execute it at the build time.

Error with variables when invoking CMake from CMake

I need to invoke cmake from within cmake so that I can have binaries built before project files are generated. I have the following CmakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(StarEngine)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
#copy the other cmake file into where we'd like to invoke cmake
configure_file(deps-CMakeLists.txt deps/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps)
#eventually binaries will be built, for now this doesn't accomplish anything
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps)
And its friend, deps-CmakeLists.txt, a test script:
set(GENERATED_DIR "test")
MESSAGE( STATUS ${GENERATED_DIR} )
In the following file structure:
Project
build
Code
CmakeLists.txt
deps-CmakeLists.txt
No matter what I put in for the variable value, it is blank when displayed in MESSAGE. I imagine this is weird behavior resulting from invoking cmake from cmake. I had a bunch of other strange errors to, but I suspect if I can figure out this one that will help crack them all.
Thanks to #Florian, the problem was with variable replacement and I needed to add the COPYONLY option to configure_file

How to instruct CMake to use the build architecture compiler

When using CMake for cross compiling, one generally specifies a toolchain file via the CMAKE_TOOLCHAIN_FILE option. In GNU terminology, one can specify the host architecture toolset using this file. However, one can generally not expect to be able to execute anything built with this toolchain. So often enough, some build tools need to be compiled for the build architecture.
Consider the following setup. I have two source files genfoo.c and bar.c. During build, genfoo.c needs to be compiled and run. Its output needs to be written to foo.h. Then I can compile bar.c, which #include "foo.h". Since CMake defaults to using the host architecture toolchain, the instructions for bar.c are easy. But how do I tell it to use the build architecture toolchain for compiling genfoo.c? Simply saying add_executable(genfoo genfoo.c) will result in using the wrong compiler.
CMake can only handle one compiler at a time. So - if you don't go the long way to set up the other compiler as a new language - you will end up with two configuration cycles.
I see the following approaches to automate this process:
Taking the example "CMake Cross Compiling - Using executables in the build created during the build?" from the CMake pages as a starting point I'll get:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# When crosscompiling import the executable targets
if (CMAKE_CROSSCOMPILING)
set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build")
file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE)
include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake)
# Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Only build the generator if not crosscompiling
if (NOT CMAKE_CROSSCOMPILING)
add_executable(genfoo genfoo.cpp)
export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake")
endif()
Then using a script like:
build.sh
#!/bin/bash
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
cmake --build crossBuild
I'll get the desired results by calling ./build.sh.
Splitting the CMakeLists.txt and maybe even replace the export()/include() with something where I know the output path of my build tools e.g. by using CMAKE_RUNTIME_OUTPUT_DIRECTORY would simplify things:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(BuildTools)
add_executable(genfoo genfoo.cpp)
build.sh
#!/bin/bash
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild
fi
cmake --build hostBuild
cmake --build crossBuild
References
Making a CMake library accessible by other CMake packages automatically
CMake build multiple targets in different build directories
How do I make CMake output into a 'bin' dir?
It is possible to do that completely within CMake.
The trick is to run a separate CMake configuring stage within its own space, silently dismissing every crosscompiling setting and using the host's default toolchain, then import the generated outputs into it's parent, crosscompiling build.
First part:
set(host_tools_list wxrc generate_foo)
if(CMAKE_CROSSCOMPILING)
# Pawn off the creation of the host utilities into its own dedicated space
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
execute_process(
COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
add_custom_target(host_tools
COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)
foreach(tgt IN ITEMS ${host_tools_list})
add_dependencies(host${tgt} host_tools)
endforeach()
else()
# Add an empty target, host tools are built inplace
add_custom_target(host_tools
DEPENDS ${host_tools_list}
)
endif()
... then you add the usual add_executable and whatever ...
At the end:
if(NOT CMAKE_CROSSCOMPILING)
foreach(tgt IN ITEMS ${host_tools_list})
add_executable(host${tgt} ALIAS ${tgt})
endforeach()
export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()
When it crosscompiles, it pawns off the creation of the host-run tools into its own dedicated space, and imports the targets as "hostwxrc" and "hostgenerate_foo", with a dependency on generating the host_tools themselves .
When it doesn't crosscompile, it builds wxrc and generate_foo as-is, and aliases them to hostwxrc and hostgenerate_foo.
After this, when you use $<TARGET_FILE:wxrc>, you refer to the wxrc built for the target platform, and $<TARGET_FILE:hostwxrc> refers to the wxrc built for the host platform, regardless whether they are the same or not.

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).

CMake setup advice for complicated build process (including externalProject)

I have an application with a mildly complicated build process, and as a bit of a newb to CMake, I was wondering if anyone could provide me with any pointers.
At preset, the application consists of a single executable, built from a source tree provided in the src and include folders.
It requires a few libraries to work, the big ones being Boost and Python. Python is embedded in the application, and Boost requires knowledge of the custom python install at compile time. I also use Qt, but I'm just linking against the system Qt for this.
What I'd like to have at the end is a stage folder, containing the compiled executable, and a lib folder with the required boost and python libraries.
At present, I have a single CMakeLists.txt file, and I am using ExternalProject to build Boost and Python from bzipped tarballs of their source. It gets a little messy where I copy out the compiled libs from the prefixed install directories.
Things are working, but I have a feeling I'm doing things very backwards. I sometimes see multiple CMakeLists in nested subdirectories but don't know how they would relate to my project. Would anyone who has worked on similarly scoped projects be able to weigh in and give me some pointers?
I should add that I hope to include Windows as a platform in the near future, and that things are currently running on Linux.
Note: This is my current CMakeLists.txt, I realise that boost isn't configured and that things aren't fully moved to the stage folder. I have been doing this manually, but I wanted to ask before I dig myself much deeper :)
Thanks!
CmakeList.txt
cmake_minimum_required(VERSION 2.6)
set(CMAKE_BUILD_TYPE Debug)
set(PROJ_NAME "mwave")
project(${PROJ_NAME})
include_directories("include")
include(ExternalProject)
# Add cmake dir to cmake module path so custom find modules will work
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
#Build Python via External Project
ExternalProject_Add(
Python
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/external/python
URL ${CMAKE_CURRENT_SOURCE_DIR}/extern/Python-3.3.0.tar.bz2
URL_MD5 2dbff60afed2b5f66adf6f77dac9e139
UPDATE_COMMAND ""
CONFIGURE_COMMAND ./configure -q --prefix=${CMAKE_CURRENT_BINARY_DIR}/external/python --enable-shared
BUILD_COMMAND make
BUILD_IN_SOURCE 1
INSTALL_COMMAND make install
)
# Manually copy the compiled python files and dirs to our stage folder
add_custom_command(TARGET Python PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_BINARY_DIR}/external/python/lib/pkgconfig
${CMAKE_CURRENT_BINARY_DIR}/stage/lib/pkgconfig)
add_custom_command(TARGET Python PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_BINARY_DIR}/external/python/lib/python3.3
${CMAKE_CURRENT_BINARY_DIR}/stage/lib/python3.3)
add_custom_command(TARGET Python PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/external/python/lib/libpython3.so
${CMAKE_CURRENT_BINARY_DIR}/stage/lib/libpython3.so)
add_custom_command(TARGET Python PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/external/python/lib/libpython3.3m.so.1.0
${CMAKE_CURRENT_BINARY_DIR}/stage/lib/libpython3.3m.so.1.0)
add_custom_command(TARGET Python PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
libpython3.3m.so.1.0
${CMAKE_CURRENT_BINARY_DIR}/stage/lib/libpython3.3m.so)
#Python
set(PYTHON_INCLUDE_DIRS "${CMAKE_CURRENT_BINARY_DIR}/external/python/include/python3.3m")
set(PYTHON_LIBRARIES "${CMAKE_CURRENT_BINARY_DIR}/external/python/lib/libpython3.3m.so" "pthread" "m" "util" "readline")
#Build boost via External Project
ExternalProject_Add(
Boost
DEPENDS Python
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/external/boost
URL ${CMAKE_CURRENT_SOURCE_DIR}/extern/boost_1_51_0_mwave.tar.bz2
URL_MD5 fe203a243e451b4dd4754c7b283b1db9
UPDATE_COMMAND ./bootstrap.sh --with-libraries=python,system,thread,program_options
CONFIGURE_COMMAND ""
BUILD_COMMAND ./b2
BUILD_IN_SOURCE 1
INSTALL_COMMAND ""
)
#Boost (workaround until external project is working)
set(Boost_INCLUDE_DIRS "/opt/mwave/include")
set(Boost_LIBRARIES "/opt/mwave/lib/libboost_python3.so" "/opt/mwave/lib/libboost_program_options.so")
#OpenImageIO
set(OIIO_PATH "/opt/mwave/oiio/dist/linux64.debug")
find_package(OIIO REQUIRED)
#Qt4
find_package(Qt4 REQUIRED)
set(QT_USE_QTOPENGL TRUE)
include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
#OpenGL
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
# Mwave app
set(HEADERS
"include/Application.h"
"include/ImageChannel.h"
"include/CompDag.h"
"include/Dag.h"
"include/Gui/DagView.h"
"include/Gui/DagScene.h"
"include/Gui/MainWindow.h"
"include/Gui/GLViewer.h"
"include/Gui/Nodes/GNodeEdge.h"
"include/Gui/Nodes/GNodeLabel.h"
"include/Gui/Nodes/GNodeCacheStatus.h"
"include/Gui/Nodes/GNode.h"
"include/Gui/Nodes/GRead.h"
"include/Gui/Nodes/GViewer.h"
"include/MwaveException.h"
"include/Nodes/Node.h"
"include/Nodes/Read.h"
"include/Nodes/Viewer.h"
"include/mwave.h"
"include/main.h"
"include/shaders.h"
)
set(QOBJECT_HEADERS
"include/Gui/QCompDag.h"
"include/Gui/QPythonEditor.h"
"include/Gui/ViewerWidget.h"
)
set(SOURCES
"src/Application.cpp"
"src/CompDag.cpp"
"src/main.cpp"
"src/mwave.cpp"
"src/Dag.cpp"
"src/Gui/DagView.cpp"
"src/Gui/DagScene.cpp"
"src/Gui/MainWindow.cpp"
"src/Gui/QPythonEditor.cpp"
"src/Gui/GLViewer.cpp"
"src/Gui/ViewerWidget.cpp"
"src/Gui/Nodes/GNode.cpp"
"src/Gui/Nodes/GNodeEdge.cpp"
"src/Gui/QCompDag.cpp"
"src/Nodes/Node.cpp"
"src/Nodes/Read.cpp"
"src/Nodes/Viewer.cpp"
)
QT4_WRAP_CPP(HEADERS_MOC ${QOBJECT_HEADERS})
## Compiler flags
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-O2") ## Optimize
set(CMAKE_CXX_FLAGS "-O3") ## Optimize More
endif()
include_directories(${PYTHON_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${GLEW_INCLUDE_PATH}
${OPENGL_INCLUDE_DIR}
${OIIO_INCLUDE_DIR}
)
add_executable(mwave WIN32 ${HEADERS} ${HEADERS_MOC} ${SOURCES})
set_target_properties(mwave PROPERTIES OUTPUT_NAME mwave.bin)
target_link_libraries( mwave
${PYTHON_LIBRARIES}
${Boost_LIBRARIES}
${OIIO_LIBRARIES}
${GLEW_LIBRARY}
${OPENGL_LIBRARIES}
${QT_LIBRARIES})
cmake 2.6, which you are using, does not support ExternalProjects.
ExternalProjects are supported in cmake 2.8 series. Please move to cmake 2.8.
The below link clarifies
http://www.cmake.org/pipermail/cmake/2011-June/044993.html