Prevent cmake to run cpack - cmake

I have a CMake project where I want to prevent make package to do anything more than print a message on some platforms.
I know how to add a message, even a fatal one, but that runs during cmake-generation, not during builds. Do I have to resort to some add_custom_command? And that won't give me what I want, since that creates a new build target...
How can I override the package target for some platforms to just show a message?

why include cpack in your cmake list at all?
In order for a cmake project to have a cpack controlled package target, your project should include a line like:
include(CPack)
and also setting up some cpack-related properties. If you don't want that, you can just take out that line.

As shu pointed out, you can do something like this:
if (! WIN32)
include(cpack)
else()
cmake_policy(SET CMP0037 OLD)
add_custom_target(package
#add dependencies on other targets here
#[[DEPENDS install]]
COMMAND ${CMAKE_COMMAND} -E echo "custom target for non windows platforms!"
)
endif()
Note that by default, you will not be allowed to override reserved targets like test and package. We are turning off that policy here to write our own package target.

Related

CMake: how to make execute_process wait for subdirectory to finish?

Part of my source code is generated by a tool which is also built under our main project with a add_subdirectory. We execute this tool with a execute_process command. Clearly, if the tool is not built before we reach the execute_process statement it will fail.
I use a GLOB (file(GLOB...)) to find the source files generated. I do this because it is not possible to know beforehand how many files are generated, neither their names.
How do I force cmake to wait for the subproject to be compiled before the execute process? I would need something like a DEPENDS property for the execute_process but this option is not available.
# This subproject will source generator the tool
add_subdirectory(generator)
# I need something like: wait_for(generator)
execute_process(COMMAND generator ${CMAKE_SOURCE_DIR}/src)
file(GLOB GeneratedSources ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(mainprject.exe ${ProcessorSourceFiles}
Command execute_process executes its COMMAND immediately, at configuration stage. So it cannot be arranged after the executable is created with add_executable command: that executable will be built only at build stage.
You need to build subproject at configuration stage too. E.g. with
execute_process(COMMAND ${CMAKE_COMMAND}
-S ${CMAKE_SOURCE_DIR}/generator
-B ${CMAKE_BINARY_DIR}/generator
-G ${CMAKE_GENERATOR}
)
execute_process(COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}/generator
)
The first command invokes cmake for configure the 'generator' project, located under ${CMAKE_SOURCE_DIR}/generator directory. With -G option we use for subproject the same CMake generator, as one used for the main project.
The second command builds that project, so it produces generator executable.
After generator executable is created, you may use it for your project:
execute_process(COMMAND ${CMAKE_BINARY_DIR}/generator/<...>/generator ${CMAKE_SOURCE_DIR}/src)
Here you need to pass absolute path to the generator executable as the first parameter to COMMAND: CMake no longer have generator executable target, so it won't substitute its path automatically.
You will need to model this with target dependencies. The tool "generator" should be a cmake target. In that case use add_custom_target instead of execute_process somthing like this:
add_custom_target(generate_sources ALL COMMAND generator ${CMAKE_SOURCE_DIR}/src))
Then add a target dependency to "generator" using add_dependencies:
add_dependencies(generate_sources generator)
This will make sure your target "generate_sources", which runs the tool will only run during build after the target "generator" has been compiled.
The following is false, see the comments for more info:
Use add_dependencies to add a dependency from "mainproject.exe" to "generate_sources". Now this I have never tested, so take with a grain of salt: With CMake more recent than version 3.12, according to the entry on file, you should then be able to change your file command to:
file(GLOB GeneratedSources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/src/*.cpp)
Which I interpret as this will re-glob the files during build if the directory changes.

How to run Clang-based tool as a separate CMake target

I have written a Clang-based tool and I want to run it on existing CMake executable target. I want this to be a separate Makefile target, so I can run it without builiding exe target.
There is a solution to run it during exe target build (described in cmake clang-tidy (or other script) as custom target)
set(CLANG_TIDY_EXE ${MY_CLANG_BASED_TOOL} )
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" " --my-additional-options")
set_target_properties(
my_exe_target PROPERTIES
CXX_CLANG_TIDY "${DO_CLANG_TIDY}"
)
CMake runs my tool during my_exe_target build. In build log I see:
...
cmake -E __run_co_compile --tidy=my_tool --source=main.cpp -- ..
But is it possible to create a separate target?
Maybe you could use add_custom_command, e.g. (adjust according to your vars and other needs):
add_custom_target(tidyup
COMMAND ${DO_CLANG_TIDY} [...] ${SOURCES}
DEPENDS [...]
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
edit (to address OP question):
A good starting point is to search for __run_co_compile and try to recreate the command from the Makefile rule (if your generator is make). There's no "automatic" propagation of the attributes, because a custom target or command can be anything. You could use the corresponding cmake variables (e.g. CMAKE_CXX_FLAGS, etc) or target properties (e.g. COMPILE_DEFINITIONS) to emulate that.

CMake, multiple targets (asan tsan..) without having to recompile everything

Goal
I want to define several targets:
make msan: compiles the code with clang with memory sanitizer
make tsan: compiles the code with clang with thread sanitizer
make : compiles the code with gcc
And be able to easily switch between them.
For example I don't want each time I switch rebuild all my objects, (I will have to do it the first time of course, but later if I modify a file and I do make and then make asan it should recompile only this file for each target)
What I have done so far
I have managed to create these targets and from the root directory, but each time I have to do a make clean and recompile.
option(CLANG_MSAN "Enable Clang memory sanitizer" OFF)
if (CLANG_MSAN)
set (CMAKE_CXX_FLAGS "-g -fsanitize=address -fno-omit-frame-pointer")
endif()
add_custom_target(asan
COMMAND ${CMAKE_COMMAND}
-DCLANG_MSAN=ON
-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_COMPILER=clang)
Is it possible to do such a thing with CMake?
Yes, but use multiple build directories:
Create a build directory per configuration.
Configure your project in your build directories with the parameters you need. E.g. cmake -DCMAKE_COMPILER=clang -DCMAKE_C_FLAGS="-fsanitize=thread" .. or the stuff from your question.
If you switch the build directory, you changed your setup.
This implies out-of-source builds, which are encouraged by CMake anyway.
I believe you should be able to achieve this with the ExternalProject module. You could add three external projects, one for msan, one for tsan, and one for the basic GCC build. The two sanitiser builds would be marked as EXCLUDE_FROM_ALL 1.
The CMakeLists for all three of them could share the common part via include().
Something like this:
Root CMakeLists.txt
ExternalProject_Add(msan
EXCLUDE_FROM_ALL 1
SOURCE_DIR msan
CMAKE_GENERATOR ...
)
ExternalProject_Add(tsan
EXCLUDE_FROM_ALL 1
SOURCE_DIR tsan
CMAKE_GENERATOR ...
)
ExternalProject_Add(normal
SOURCE_DIR src
CMAKE_GENERATOR ...
)
src/CMakeLists.txt
include(common.cmake)
src/common.cmake
# Normal CMake code for your project
add_library(...)
msan/CMakeLists.txt
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fsanitize=address -fno-omit-frame-pointer")
include(../src/common.cmake)

install(FILES "${CMAKE_CFG_INTDIR}/Abc_Win.dll" DESTINATION "Bin")

Because the 'Abc_Win.dll' is shared ('dll') and needs to be copied to the target-EXE I added a custom target - like this. I'm working with MS-VisualStudio 2005-2011 and using cmake 2.8.8.
add_custom_target( "Abc_Win.dll" )
add_custom_command( TARGET "Abc_Win.dll" POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"MyDllSource/${CMAKE_CFG_INTDIR}/Abc_Win.dll"
"MyExeDest/${MWEB_CMAKE_CFG_INTDIR}/Abc_Win.dll" )
set_property(Abc_Win.dll" PROPERTY FOLDER ${MWEB_FOLDER_ADDON}/${MWEB_FOLDER_RTE})
All above working like I expect and the 'Abc_Win.dll' get on the right place when I build.
Now I add an the following install command - expecting 'Abc_Win.dll' in "Bin"-Directory beside my EXE.
install(FILES "MyDllSource/${CMAKE_CFG_INTDIR}/Abc_Win.dll" DESTINATION "Bin")
When I build now the CMakePredefinedTargets->INSTALL (doesn't matter which MS-StudioVersion I use) I get always a build error in the cmake generated file 'cmake_install.cmake':
file INSTALL cannot find
"MyDllSource/$(Configuration)/Abc_Win.dll"
I understand that cmake does not uses build-rules from MS-VS - like it does it for add_custom_command. It also seems to be that this cmake-file has no glue from the Content $(CONFIGRATION) which is set actual to 'Debug'.
Has anybody an idea how to solve this Problem? Help would be very appreciated. Thanks.
There's an undocumented variable you can use here: CMAKE_INSTALL_CONFIG_NAME.
Unless you happen to have defined this yourself in your CMakeLists.txt, it will be undefined when CMake runs.
However, when you use install commands in your CMakeLists.txt, CMake generates a file called "cmake_install.cmake" in the root of your build tree (same place as CMakeCache.txt). This is executed at install time, and it sets CMAKE_INSTALL_CONFIG_NAME to your current configuration in Visual Studio.
There's another slight twist; to avoid CMake expanding ${CMAKE_INSTALL_CONFIG_NAME} in the install command (it would expand to an empty string), you need to escape it with a \.
So, you just need to change your install command to:
install(FILES "MyDllSource/\${CMAKE_INSTALL_CONFIG_NAME}/Abc_Win.dll"
DESTINATION "Bin")

CMake depend.make file empty

I start using CMake to build my c++ source files, I see a strange comportament when I build inicially:
'cmake ../' will gerate the directory structure
'make' will build all
any successive make command will build nothing, as expected
'cmake ../' will apparent do nothing
'make' WILL REBUILD all
any successive make command will build nothing, as expected
There is my CMakelists.txt:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-Wall -pipe")
set(var_target CommonBase)
set(var_path_source base)
project(Prj_${var_target})
file(GLOB_RECURSE var_sources ${var_path_source}/*.cpp)
add_library(${var_target} SHARED ${var_sources})
install(TARGETS ${var_target} DESTINATION ${PROJECT_SOURCE_DIR}/install)
Looking better, at first 'cmake ../' command the file 'CMakeFiles/CommonBase.dir/depend.make' is empty, and the successive make command will insert the list of file dependencies
There is something wrong with my CMakelists.txt?
Thanks
There are a couple of issues here.
The actual cause of your problem is having the line set(CMAKE_CXX_FLAGS ...) before the project command.
The project command does quite a lot of work the first time it is run, and actually clears out this variable as a side-effect. So on your first run of CMake, the compiler flags are empty, and thereafter always contain what you set them to. (It's only the second time you run CMake which causes make to recompile all, not subsequent runs of CMake).
Try wrapping your project call with messages to see the effect:
message("CMAKE_CXX_FLAGS - ${CMAKE_CXX_FLAGS}")
project(Prj_${var_target})
message("CMAKE_CXX_FLAGS - ${CMAKE_CXX_FLAGS}")
Delete your CMakeCache.txt file (in your build root), then just run cmake .. repeatedly.
To fix this, move your set(CMAKE_CXX_FLAGS ...) to after the project command.
The second issue is that it's not recommended to set CMAKE_CXX_COMPILER in a CMakeLists.txt. Have a look at the comment below "Setting default compiler in CMake", and also the link there to CMake's FAQ entry How do I use a different compiler?