I need to be able to stop CMake processing from within a CMake function or macro. I don't want to stop processing just the current file, but stop ALL CMake processing. Right now, I am using message(FATAL_ERROR "Foo"). The documentation for message states it does exactly what I need:
CMake Error, stop processing and generation
However, I would like to be able to do this without generating an error. I really don't need a message either. I just want to completely exit. Is there any way to do this?
If your CMakeLists.txt hierarchy is fairly shallow, you can call return() once or twice (depending on if you called add_subdirectory() or if you're in a macro/function) to return to the calling file or function and exit CMake processing.
If your project hierarchy is more complex, and you want to exit your CMakes from an arbitrary location, there is no native CMake command to support that. However, you could roll your own (admittedly, a bit scary) solution to terminate cmake:
function(exit_cmake)
if(UNIX)
set(KILL_COMMAND "killall")
execute_process(COMMAND ${KILL_COMMAND} -9 cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
else()
set(KILL_COMMAND "taskkill")
execute_process(COMMAND ${KILL_COMMAND} /IM cmake.exe /F
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
endif()
endfunction()
If you include this in your top-level CMake file, you can call this from anywhere in your CMakes to exit silently.
WARNING: This will terminate ALL currently running CMake processes, not just your current process. Because you are forcing the process the terminate, your CMake files/cache may be left in a weird state.
Related
I want to run a few checks on a binary after it's been created, so add_custom_command() and the POST_BUILD flavor of it looked appealing in the sense that it, well, runs post build. But how do I check the exit code of said command?
I was saddened to see that only execute_process() has a RESULT_VARIABLE. The "normal" add_custom_command() has an OUTPUT variable in file format that I guess you can write to, even though that seems ridiculously cumbersome just to get the exit code. But the POST_BUILD version of the add_custom_command() seemingly has nothing.
I have seen some cases where people are doing stuff like COMMAND my_command >> ${RESULT_FILE}, but is that all there is?
I.e. I want to run a command, store it's exit code and then do FATAL_ERROR unless it's what I expect
You can execute any program to do that. So choose your favorite programming language of choice and write a program that will do just that. Then execute that program during build stage post your target build. The build system should pick the exit status of the program and fail the build. One could use cmake as a programming language to write, for example:
# your_script.cmake
cmake_minimum_required(VERSION 3.11)
execute_process(COMMAND a_command RESULT_VARIABLE res)
if (NOT res STREQUAL "0")
message(FATAL_ERROR "")
endif()
Then execute that script with cmake as an interpreter during build:
add_some_target_like_library_or_executable_or_custom_target(target ....)
add_custom_command(POST_BUILD target
COMMAND ${CMAKE_COMMAND} -P path/to/your_script.cmake
)
I am using cmake version 3.14.0-rc3 to make my codes. When I target any code written in C or C++ in my CMakelist.txt as follows, it works pretty and makes the executable file.
cmake_minimum_required(VERSION 3.3)
PROJECT (HELLO)
ADD_EXECUTABLE(hello hello_world.cpp)
but while I am trying to make this code with Tcl scripts, it fails and I receive the following fatal error:
Fatal error while making a tcl script with cmake
Can anyone help me to overcome this issue? It seems that cmake is not normally able to compile Tcl scripts.
Thank in advance for your kind replies and helps.
Bests,
Daryon
You have to watch out for a different path, e.g., running custom commands or adding custom targets to your CMake project. You seem to confuse the nature of libraries, executables, and external commands in the context of CMake, I am afraid.
I think there should be a way to execute Tcl scripts with CMake as
well.
You might want to attempt the following: In CMakeLists.txt, you define a custom target MyTarget that calls out to a TCLSH executable, if available:
CMAKE_MINIMUM_REQUIRED(VERSION 3.3)
PROJECT (HELLO)
find_program (TCLSH tclsh)
if (TCLSH)
add_custom_target(
MyTarget ALL
COMMAND TCLSH myScript.tcl
)
endif (TCLSH)
(1) find_program and if/endif will make the custom target only available under the condition that an executable called tclsh was found.
(2) myScript.tcl is a Tcl script in your project directory.
(3) Running cmake . && make will call out to effectively to: tclsh myScript.tcl, producing:
$cmake . && make
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/hello
This is a message written by Tcl scripts
Built target MyTarget
This is just to get you started, you will have to read more about adding commands, targets, or executing sub-processes from within CMake.
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?
I'm attempting to debug a command line CMake failure. The same CMake file works in Qt Creator, with the arguments in the Qt Creator window matching what I have entered on the command line.
This makes me think Qt Creator is adding some extra arguments, which makes sense since the generator drop down has several options that specify architecture and CMake version.
Is there a way to get the CMake command that Qt Creator executed to produce the desired result, specifically the arguments passed to the CMake executable?
I found one post that talks about viewing the CMakeCache files to do some forensics, but this only proves there are differences, it doesn't quickly show me what arguments to change.
Try adding the following block to the end of your CMakeLists.txt and running CMake from Qt Creator again. The CMake output should list all variables that have been passed via the -D command line argument.
get_cmake_property(CacheVars CACHE_VARIABLES)
foreach(CacheVar ${CacheVars})
get_property(CacheVarHelpString CACHE ${CacheVar} PROPERTY HELPSTRING)
if(CacheVarHelpString STREQUAL "No help, variable specified on the command line.")
get_property(CacheVarType CACHE ${CacheVar} PROPERTY TYPE)
if(CacheVarType STREQUAL "UNINITIALIZED")
set(CacheVarType)
else()
set(CacheVarType :${CacheVarType})
endif()
set(CMakeArgs "${CMakeArgs} -D${CacheVar}${CacheVarType}=\"${${CacheVar}}\"")
endif()
endforeach()
message("CMakeArgs: ${CMakeArgs}")
For more info, see this answer.
This won't show what generator was selected (if any) via the -G arg. To find that, you need to look for CMAKE_GENERATOR:INTERNAL=... in your CMakeCache.txt
If this doesn't help you identify the overall problem, you should probably heed #arrowdodger's advice and post more details about the errors you're getting and your two build environments. For example, an error could be caused simply by running CMake from a subdirectory of the source tree.
I have a command line tool that should be run after CMake created my .sln-file. Is there any way to do that using CMake?
Using execute_process(COMMAND ..) at the end of the CMakeLists.txt does not help because this is executed after the Configure step, however, the .sln-file is created in the generation step.
Thanks a lot!
A rather horrifying way to do it is by calling cmake from cmake and doing the post-generate stuff on the way out of the parent script.
option(RECURSIVE_GENERATE "Recursive call to cmake" OFF)
if(NOT RECURSIVE_GENERATE)
message(STATUS "Recursive generate started")
execute_process(COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-T "${CMAKE_GENERATOR_TOOLSET}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-DRECURSIVE_GENERATE:BOOL=ON
${CMAKE_SOURCE_DIR})
message(STATUS "Recursive generate done")
# your post-generate steps here
# exit without doing anything else, since it already happened
return()
endif()
# The rest of the script is only processed by the executed cmake, as it
# sees RECURSIVE_GENERATE true
# all your normal configuration, targets, etc go here
This method doesn't work well if you need to invoke cmake with various combinations of command line options like "-DTHIS -DTHAT", but is probably acceptable for many projects. It works fine with the persistently cached variables, including all the cmake compiler detection when they're initially generated.
From the following links, it seems like there is no such command to specify execution after CMake generated .sln files.
https://cmake.org/pipermail/cmake/2010-May/037128.html
https://cmake.org/pipermail/cmake/2013-April/054317.html
https://cmake.org/Bug/view.php?id=15725
An alternative is to write a wrapper script as described in one of the above links.
cmake ..
DoWhatYouWant.exe
Yes, add_custom_command paired with add_custom_target got this covered
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_command
http://cmake.org/cmake/help/cmake-2-8-docs.html#command:add_custom_target
For an example take a look at my answer to another question
cmake add_custom_command