How to have a variable only in one mode with CMake - c++

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

Related

How to remove /RTC1 from specific target or file in CMake

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

How to create a CMake configuration type that inherits from Release

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

How to use QML_IMPORT_PATH with Qt Cmake Project?

I need to provide some modules for project.
Now, it looks for them in QT directory(I've installed it in $HOME), but instead of it I want to make it search in /usr/lib/x86_64-linux-gnu/qt5/qml/.
What I have tried:
a) Defining QML_IMPORT_PATH in .bashrc - didn't work out
b) Copying needed module in $HOME/Qt5.5.1/Tools/QtCreator/bin/qml/:
Here we have something different. If I open of the .qml files - it wouldn't underscore import line (which is ok). But, If I run executable with console - the same message module org.bla.bla is not installed.
So, If copying didn't help, maybe I had to just make QtCreator(or smth else) search for modules in appropriate folder, but how?
UPD.
Well, you can define path to your modules with QML2_IMPORT_PATH(not just QML, but QML2). As I mentioned above, I've copied module folder in $HOME/Qt5.5.1/Tools/QtCreator/bin/qml/ which is completely wrong! The right way was to copy it in $QT_HOME/5.5/gcc_64/qml/. It runs now fine, but I can't say the same about "how" it works. Unfortunately, this is not related to the question I've asked. Therefore, I'll not ask others to answer my question, but won't close it as well until find real problem and mention it here, so I can help others.
With the new and upcoming QtCreator 4.1 you will be able to do that. Just set QML_IMPORT_PATH in your CMake cache. If you have multiple paths, separate them with a ; which is just how a list is done in CMake.
list(APPEND QML_DIRS "dir1")
list(APPEND QML_DIRS "dir2")
set(QML_IMPORT_PATH "${QML_DIRS}" CACHE STRING "Qt Creator 4.1 extra qml import paths")
Here is an improvement of #Tom Deblauwe's answer that allows to keep system-specific local settings out of the repository's makefile. It assumes you use QT Creator as your IDE.
In Qt Creator, open the "Projects" sidebar tab and there go to "Build & Run → [your build config's entry] → Build → CMake".
In the list of CMake configuration settings you find there, set the value of setting QML_IMPORT_PATH according to your system. Separate multiple directories
with ";".
You can additionally provide some common defaults in the repository's CMakeLists.txt makefile so that users with common setups don't need to set their their QML_IMPORT_PATH. The code below will not overwrite the user's QML_IMPORT_PATH but append to it. You'd add the following to CMakeLists.txt:
# Directories where Qt Creator can find QML files.
# (Not needed for builds, but makes Qt Creator code completion happy.)
list(APPEND QML_IMPORT_PATH "/example/path/to/qml")
list(APPEND QML_IMPORT_PATH "/second/example/path/to/qml")
# Prevent adding duplicate values at each run of CMake.
list(REMOVE_DUPLICATES QML_IMPORT_PATH)
# The variable is cached in ${BUILD_DIR}/CMakeCache.txt. We need FORCE to
# change it there immediately. Also, add a comment to the cache file.
set(QML_IMPORT_PATH ${QML_IMPORT_PATH}
CACHE STRING "Qt Creator 4.1 extra qml import paths"
FORCE
)
After running CMake, QML_IMPORT_PATH is now the user-defined value plus some CMakeLists.txt defined values appended to it. Qt Creator's CMake configuration settings from steps 1-2 will still show the user's value in the table. But when mousing over that value, the full value incl. the appended portion is shown in a popover.

CMake - Removing an option from the GUI set in another cmake file

I'm creating a project (let's call it myProject) that includes macros and CMakefiles defined in another project (let's call it otherProject). Of course, myProject depends on libraries created and compiled in otherProject.
otherProject has an option to set compilation of the libraries in dynamic or static using the standard option command:
option(USE_STATIC_LIBRARIES "Build static libraries?" OFF )
In myProject, I want to force this option to ON all the time and remove it from the GUI so that users will not be able to change it; WITHOUT having to modify the original CMakefile. What I have done so far is force the value to ON by using the following:
set( USE_STATIC_LIBRARIES ON FORCE )
include( otherProjectCmakefile)
This works as intended, forcing the value to ON, but the option still appears in the GUI (user action however is ignored and internally, the value is always ON).
My question is, how can I remove the option from the GUI completely, not display it at all. I want to avoid any possible confusion.
You can start reading from
cmake --help-command SET
and you will probably be interested in this option for SET
INTERNAL = No GUI entry (used for persistent variables).

CMake building targets conditionally based on library existence

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.