So I have a giant project that I joined with a bunch of cmake. Our debug builds run very slow, and we traced it back to both a specific target we are building (allegro legacy), and a specific file (ffscript.cpp). If we enable /O2 for both of these, we can go from an unbearable 30 fps to 300 fps uncapped. The problem is that these are incompatible with /RTC1 (run-time error checks), a flag which is apparently on (though I can't find where it's being set, so I assume CMake itself is setting it).
We figured out how to disable RTC1 for the entire project with STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}"), but realized that /RTC1 sounds pretty useful everywhere else. We want to only disable it for this specific target and file but keep it elsewhere, but I cannot figure out the sanest way to do this that still works. I also want to add the /O2 flags to the specific file; it's already added for the target, but I don't know how to add it to a specific file (though I know how to do it manually via VS2022, I'd prefer to not lose these changes each time the CMake gets updated). I don't know what I should share, but here's the CMake file for this specific target (there's multiple CMakeLists.txt files in this project): https://pastebin.com/gYUJUGpE
Could someone help me out? I don't really know how to CMake at all, and it's pretty daunting. Would greatly appreciate it if someone could help me and explain in a way I could understand. Thanks!
Note: There was one solution I found on Stack Overflow which involved taking the entire global with a macro and applying it to each target individually, but that caused compile errors and I had to revert it.
Note: I am not sure whether it is actually valid/safe to link between targets with different values of /RTC. Don't take this answer as any confirmation that what you want will work out.
As for where the /RTC flag is getting set, your hunch is right. It can be set by CMake. See :/Modules/Platform/Windows-MSVC.cmake and search for "RTC". In particular, see the part which modifies CMAKE_${lang}_FLAGS_DEBUG_INIT.
Achieving what you want (removing /RTC for a specific target) is a bit difficult because unlike GNU compilers, which allow disabling most previously-specified flags with a "no-" prefix, I'm not aware of the CL compiler offering similar functionality, combined with the fact that options in CMAKE_<LANG>_FLAGS_<CONFIG> exist separately from those in the COMPILE_OPTIONS directory property and target property, and is combined into the final list of compile options for a target/source-file near the end of the process of building that compile options list (as opposed to being used to initialize the directory and target properties).
One workaround could be to keep doing what you did (remove /RTC from CMAKE_CXX_FLAGS_DEBUG and CMAKE_C_FLAGS_DEBUG), and then just add /RTC to the COMPILE_OPTIONS directory property of the root CMakeLists.txt via add_compile_options, which initializes the target property for all targets created/defined in subdirectories, and then remove /RTC from the target's COMPILE_OPTIONS property via get_property(TARGET) and set_property(TARGET).
Related
This answer describes how to create a custom configuration type from scratch. How can I make a configuration type that exactly matches the builtin Release, only with some added flags? I'm using this right now:
set(CMAKE_CONFIGURATION_TYPES "Debug;Release;ReleaseWithAssertions" CACHE STRING
"Available build-types: Debug, Release and ReleaseWithAssertions")
set(CMAKE_CXX_FLAGS_RELEASEWITHASSERTIONS "${CMAKE_CXX_FLAGS_RELEASE}
-DENABLE_ASSERTIONS=1")
This seems to do what I want, but I'm only copying the value of CMAKE_CXX_FLAGS_RELEASE, so I'm wondering if there is anything I'm missing that users might expect?
No, not in respect of adding a custom "configuration type that exactly matches the builtin Release". That's more like a feature request for CMake.
Edit: Just have seen that there actually is a "Creating new configurations for MSVC" feature request you could give support.
Here is some background information what's possible and what's not:
There are potentially many configuration specific variables. You could copy those with a script:
get_directory_property(_vars VARIABLES)
foreach(_var IN LISTS _vars)
if (_var MATCHES "_RELEASE$")
string(REPLACE "_RELEASE" "_RELEASEWITHASSERTIONS" _var_new "${_var}")
set(${_var_new} "${${_var}}")
endif()
endforeach()
You need to map imported targets to for your new configuration with setting CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>:
list(APPEND CMAKE_MAP_IMPORTED_CONFIG_RELEASEWITHASSERTIONS "Release" "")
You can't do anything about $<CONFIG:cfg> type generator expressions checking for specific configuration names
You have to check directory/target/source file and configuration specific changes in properties
References
Is Cmake set variable recursive?
What's the CMake syntax to set and use variables?
The only other one you might want would be CMAKE_C_FLAGS_RELEASE in case you're compiling any C files.
See cmake's documentation:
None (CMAKE_C_FLAGS or CMAKE_CXX_FLAGS used)
Debug (CMAKE_C_FLAGS_DEBUG or CMAKE_CXX_FLAGS_DEBUG)
Release (CMAKE_C_FLAGS_RELEASE or CMAKE_CXX_FLAGS_RELEASE)
RelWithDebInfo (CMAKE_C_FLAGS_RELWITHDEBINFO or CMAKE_CXX_FLAGS_RELWITHDEBINFO
MinSizeRel (CMAKE_C_FLAGS_MINSIZEREL or CMAKE_CXX_FLAGS_MINSIZEREL)
From https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-can-i-extend-the-build-modes-with-a-custom-made-one-
It seems you would want to do the same for all of these.
CMAKE_CXX_FLAGS_RELEASEWITHASSERTIONS
CMAKE_C_FLAGS_RELEASEWITHASSERTIONS
CMAKE_EXE_LINKER_FLAGS_RELEASEWITHASSERTIONS
CMAKE_SHARED_LINKER_FLAGS_RELEASEWITHASSERTIONS
I am trying to add a custom target with CMake that executes one command for each given .cpp file. The command should only be re-executed when the source file itself or one of the included source files changes. AFAIK to achieve this I need a list of all the included files and add them to the DEPENDS option of the add_custom_command() calls that belong to my custom target.
So is there a built-in way to get that list of included files?
I know about the IMPLICIT_DEPENDS option of the add_custom_command() function but it only works for Makefile generators. I would like to make this work for all generators.
Thank you for your time
Edit:
As requested I will post some cmake code to show what I want to achieve.
I want to add a custom target, that runs clang-tidy on all the given .cpp files. When incrementally building the custom target the clang-tidy commands should be re-run whenever a .cpp file or one of its directly or indirectly included header files is changed. Just like re-runs of the compiler are handled.
# ----------------------------------------------------------------------------------------
# mainTargetName The name of the target that shall be analyzed
# files A list of all the main targets .cpp files
#
function( addStaticAnalysisTarget mainTargetName files )
set(targetName runStaticAnalysis_${mainTargetName})
set(command "clang-tidy-4.0 -checks=* -p ${CMAKE_BINARY_DIR}")
foreach( file ${files} )
get_filename_component( baseName ${file} NAME_WE)
set(stampFile ${CMAKE_CURRENT_BINARY_DIR}/analyze_${baseName}.stamp )
set(fullFile ${CMAKE_CURRENT_SOURCE_DIR}/${file})
set(commandWithFile "${command} ${fullFile}")
separate_arguments_for_platform( commandList ${commandWithFile})
add_custom_command(
OUTPUT ${stampFile}
DEPENDS "${fullFile}"
IMPLICIT_DEPENDS CXX "${fullFile}"
COMMAND ${commandList}
COMMAND cmake -E touch "${stampFile}" # without creating a file as a touch-stone the command will always be re-run.
WORKING_DIRECTORY ${CPPCODEBASE_ROOT_DIR}
COMMENT "${commandWithFile}"
VERBATIM
)
list(APPEND stampFiles ${stampFile})
endforeach()
set_source_files_properties(${stampFiles} PROPERTIES GENERATED TRUE) # make the stamp files known to cmake as generated files.
add_custom_target(
${targetName}
DEPENDS ${stampFiles}
)
endfunction()
The problem with that is, that it does not seem to work. When I change included files clang-tidy is not re-run for the affected files.
I used the "Unix Makefile" generator for this example so it should work at least with make. Any hints why it doesn't?
My hopes where that I could achieve the desired behavior for all generators by somehow getting the file-dependencies at cmake time and then adding them to the ''''DEPENDS'''' list. But the dependency scanning must be done each time the command is run, so it can not be done at cmake time. This means that the scanning must be implemented by cmake which it currently is not.
A guy with similar problems:
https://gitlab.kitware.com/cmake/cmake/issues/16830
Edit 2:
I think the problem that the IMPLICIT_DEPENDS option was not working was because I did not use correct filenames. I changed that in the code snipped, but I have not yet tested if it works in the project.
I think the answer to my question is ...
No, you can not use cmakes dependency scanner in the cmake code.
That makes sense, because this problem can not be solved at cmake time, because the dependencies of a .cpp file may change without cmake being re-run.
The problem must be solved within cmake itself at make time. This is done when using the IMPLICIT_DEPENDS option.
Also, I tried to solve a Problem that I did not really have, because at this point I can only run clang-tidy on linux anyways. However, clang-tidy may become available on windows as well and then I may have the problem again.
To sum the comments up:
Tambre stated that CMake is not a compiler and therefore can not do that.
I think this is wrong. According to this article, CMake can parse cpp include dependencies because make has no such dependency searcher itself. That was news to me, but I mostly live on Windows so I am not that familiar with make. It could also be possible that in the meantime make was extended to do its own dependency searching. Also this explains why the IMPLICIT_DEPENDS option is only available for make.
Florian pointed out that it is not necessary to create an own custom target for running clang-tidy. Instead, one can use the CXX_CLANG_TIDY target property to run clang-tidy for each file after compiling it. This means however, that static-analysis can not be separated from the build which could lead to inacceptable buildtimes.
There is the cmake -E cmake_depends command line, that could be used to retrieve dependencies at cmake time. But as stated above, I erroneously thought that I needed the dependencies at cmake time, while I needed them at runtime.
The IMPLICIT_DEPENDS options did not work because I had an error in my cmake code.
I have a c++ cmake project. In this project I build (among other) one example, where I need to use another project, call it Foo. This Foo project does not offer a cmake build system. Instead, it has a pre-made Makefile.custom.in. In order to build an executable that uses Foo's features, one needs to copy this makefile in his project, and modify it (typically setting the SOURCES variable and a few compiler flags). Basically, this Makefile ends up having the sources for your executable and also all the source files for the Foo project. You will not end up using Foo as a library.
Now, this is a design I don't like, but for the sake of the question, let's say we stick with it.
To create my example inside my cmake build I added a custom target:
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/Makefile.custom.in Makefile.custom)
ADD_CUSTOM_TARGET(my_target COMMAND $(MAKE) -f Makefile.custom
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
This works. I can specify some variables to cmake, which get resolved in the call to CONFIGURE_FILE, and I end up with a working Makefile.custom. Then, invoking make my_target from the build directory, I can build the executable. I can even add it to the all target (to save me the effort of typing make my_target) with
SET_TARGET_PROPERTIES(my_target PROPERTIES EXCLUDE_FROM_ALL FALSE)
Sweet. However, cmake appears to assign a single job to the custom target, slowing down my compilation time (the Foo source folder contains a couple dozens cpp files). On top of that, the make clean target does not forward to the custom makefile. I end up having to add another target:
ADD_CUSTOM_TARGET(really-clean COMMAND "$(MAKE)" clean
COMMAND "$(MAKE)" -f Makefile.custom clean
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
which, unlike my_target with all, I can't include in the clean target (can I?).
Now, I know that a cleaner solution would be to have the Foo project be built as an external project, and then link to it. However, I've been 'recommended' to use their Makefile.custom.in makefile, modifying the few lines I need (adding my sources, specifying compiler flags, and few other minor modifications). So, regardless of how neat and clean this design pattern is, my questions are:
is there a way to tell cmake that make should use more than 1 job when making the target my_target?
is there a cleaner way to include a pre-existing makefile in a cmake project? Note that I don't want (can't?) use Foo as a library (and link against it). I want (need?) to compile it together with my executable using a makefile not generated by cmake (well, cmake can help a bit, through CONFIGURE_FILE, by resolving some variables, but that's it).
Note: I am aware of ExternalProject (as suggested also in this answer), but I think it's not exactly what I need here (since it would build Foo and then use it as a library). Also, both my project and Foo are written exclusively in C++ (not sure this matter at all).
I hope the question makes sense (regardless of how ugly/annoying/unsatisfactory the resulting design would be).
Edit: I am using cmake version 3.5.2
First, since you define your own target, you can assign more cores to the build process for the target my_target, directly inside your CMakeLists.txt.
You can include the Cmake module ProcessCount to determine the number of cores in your machine and then use this for a parallel build.
include(ProcessorCount)
ProcessorCount(N)
if(NOT N EQUAL 0)
# given that cores != 0 you could modify
# math(EXPR N "${N}+1") # modify (increment/decrement) N at your will, in this case, just incrementing N by one
set(JOBS_IN_PARALLEL -j${N})
endif(NOT N EQUAL 0)
and when you define your custom target have something like the following:
ADD_CUSTOM_TARGET(my_target
COMMAND ${CMAKE_MAKE_PROGRAM} ${JOBS_IN_PARALLEL} -f Makefile.custom
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
by the way, I don't think there's the need for you to include also CMAKE_BUILD_TOOL among the COMMANDs in your target.
I believe that instead of modifying the lines as above, you could call
make -j8 my_target
and it might start 8 jobs (just an example) without modifying the CMakeLists.txt, but I cannot guarantee this works having defined the COMMAND the way you have, just try if that's enough.
For the second point, I cannot think right now of a "cleaner" way.
I have a large cross-platform project which needs to build in various places; in some places, different UI toolkits, sound APIs, etc. may be available, and I am trying to figure out the best way to automatically configure which targets get configured based on which libraries are present.
The code I am trying for that is, for example:
find_library(PC_EGL EGL)
find_library(PC_GLESv2 GLESv2)
find_library(PC_Xxf86vm Xxf86vm)
if (DEFINED PC_EGL AND DEFINED PC_GLESv2 AND DEFINED PC_Xxf86vm)
add_executable(foo foo.cpp)
target_link_libraries(foo ${PC_EGL} ${PC_GLESv2} ${PC_Xxf86vm})
endif()
However, in the case that I build this on a system which doesn't have libGLESv2 available, I get the error:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
PC_GLESv2
linked by target "foo" in directory /path/to/platform
The find_library documentation implies that the variable PC_EGL_NOTFOUND should be getting set, but it isn't (CMake 2.8.5). So, what is the appropriate way to use find_library to determine whether a target should be made to exist at all? It seems like using
if (NOT PC_EGL MATCH "-NOTFOUND")
is a bit fragile and fiddly, so is there a better mechanism for determining a CMake command path based on wheter a library was found at all?
It's simply
if(PC_EGL AND PC_GLESv2 AND PC_GLESv2)
CMake treats 0, FALSE, OFF, ANYTHING-NOTFOUND as false.
I Want to create a new mode (Debug, Release and a new one) in my project. After that I will need a variable that is only used in that new mode, so I can create a variable for all and set different value for Debug/Release (i.e. 0) and for the new one (1).
How can I solve this?
What i have:
set (CMAKE_CONFIGURATION_TYPES "Release;Debug;NewConfig" CACHE STRING "Configurations" FORCE)
SET (VARIABLEX 1)
if (VARIABLEX )
add_definitions (-DVARIABLEX )
endif (VARIABLEX )
First of all, adding new configuration types is not yet well supported in CMake.
Despite the CMake FAQ, looks like there is something still a bit unimplemented for this feature request. There is even an open issue for it:
http://www.cmake.org/Bug/view.php?id=5811
Monitor that bug in the CMake bug tracker to be notified as things are updated.
However, given that you would like to have different definitions for different configurations, you should see the help for the CMake target property COMPILE_DEFINITIONS and COMPILE_DEFINITIONS_DEBUG (for example):
http://cmake.org/cmake/help/v2.8.8/cmake.html#prop_tgt:COMPILE_DEFINITIONS
http://cmake.org/cmake/help/v2.8.8/cmake.html#prop_tgt:COMPILE_DEFINITIONS_CONFIG