CMake MSVC variable gets populated only after call to project - if-statement

I want to create my project name per my compiler (different names for MSVC or GNU).
I have the following code:
if(MSVC)
project(Block3Windows ...)
else()
project(Block3Linux ..)
endif()
These are the first commands in my CMakeLists.txt file. However, it always enters the else block.
It seems like the MSVC variable gets populated only after the call to project, to test it I've wrote the following:
if(MSVC)
message(MSVC)
endif()
message(MSVC)
project(Block3Windows ...)
message("After Project")
message(MSVC)
I get the following printed:
First run:
After Project
MSVC
Second and later runs (with cache):
MSVC
After Project
MSVC
Why the MSVC from withing the first condition is never being printed ?
This behavior is not mentioned in the MSVC documentation
Am I missing something? How do I create a project name per logic on my compiler environment?
I'm using CMake 3.17.2

What about just a generic initial call to project, and then choose the name with the second call to project.
project(Block3)
if(MSVC)
project(Block3Windows)
else()
project(Block3Linux)
endif()
But I think that you can determine system by:
include(CMakeDetermineSystem)
if (MSVC)
...

Related

Issues when building C++ using CMake with Intel oneApi

I my library I use boost's float128 wrapper therefore changing the compiler is not an option.
Following Intel's developer guide I added find_package(IntelDPCPP REQUIRED) to my CMakeLists.txt and ran cmake -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icx -GNinja on the VS 2022 terminal. I get the following error message
Found package configuration file:
C:/Program Files (x86)/Intel/oneAPI/compiler/latest/windows/IntelDPCPP/IntelDPCPPConfig.cmake
but it set IntelDPCPP_FOUND to FALSE so package "IntelDPCPP" is considered
to be NOT FOUND. Reason given by package:
Unsupported compiler family and compiler icx!!
Anyone with a similar issue that can help out?
EDIT: as suggested by #Botje here the output information relevant to this case
IntelDPCPPConfig.cmake(84): string(COMPARE EQUAL ${CMAKE_CXX_COMPILER} nocmplr )
IntelDPCPPConfig.cmake(85): if(nocmplr)
IntelDPCPPConfig.cmake(93): if(NOT x${CMAKE_CXX_COMPILER_ID} STREQUAL xClang AND NOT x${CMAKE_CXX_COMPILER_ID} STREQUAL xIntelLLVM )
IntelDPCPPConfig.cmake(95): set(IntelDPCPP_FOUND False )
This is a known issue, it will be fixed in the OneAPI 2023.1 release.
You can try reversing the order of find_package and project or removing find_package(IntelDPCPP REQUIRED) in CMakeLists.txt. Because CMake identifies and sets up all the compiler-related variables when the project() is called.
Also, you can set the compiler option for the DPC++ compiler in CMakeLists.txt using the below command.
set(CMAKE_CXX_COMPILER dpcpp)

CMake command line define macro without value

I have the following line in my CMakeLists.txt
add_compile_definitions(DEBUG=$(DEBUG))
so when I compile my code with Makefile, I can do this
make DEBUG=1
But what I really want is to just define the DEBUG macro without setting any value to it.
Is there a way I can do this on a command line with cmake?
With CMake you can, at configuration time, add some CMake variables. For example you can do this cmake -S <src_folder> -B <build_folder> -DDEBUG=ON. This way you will have access to the variable DEBUG in your CMake.
In your CMake you will have this code
if(DEBUG)
add_compile_definition(DEBUG)
endif()
(Note that instead of add_compile_definitions, it is recommended to use target_compile_definitions which will set your DEBUG macro only for one target and not globally to your project.
Example:
add_executable(my_target main.cpp)
target_compile_definition(my_target PRIVATE DEBUG)
PRIVATE means that this compile_definition will only be used by the target my_target and will not be propagated to others.)
But if you're only concern of the building type, I suggest that you use CMake variables that are already present within CMake. You can use CMAKE_BUILD_TYPE which will contains Debug, Release or whatever depending on what type of build you want. Your code will now be this
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_definition(DEBUG)
endif()
And you can use this command line cmake -S <src_folder> -B <build_folder> -DCMAKE_BUILD_TYPE=Debug
And here the documentation https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
Note that this solution will only works for Mono-config generators like Makefile or Ninja and will not works with Visual Studio or Xcode

CMake won't build without set_source_files_properties with LANGUAGE CXX

I have a small library that I have made (mostly wrappers for a more obtuse library underneath) which I have been compiling and using no problem in a contained project. I am now using this library in another project and have attempted to change the CMakeLists.txt appropriately (see below).
cmake_minimum_required (VERSION 3.5)
set(project "foobar")
project(${project} LANGUAGES CXX)
set(${project}_VERSION_MAJOR 0)
set(${project}_VERSION_MINOR 1)
add_library(${project} SHARED
./driver/foo.h
./driver/foo.c
./bar.cpp
./bar.hpp)
set_source_files_properties(./driver/foo.c PROPERTIES LANGUAGE CXX)
target_compile_features(${project}
PUBLIC
cxx_std_11)
target_include_directories(${project} PUBLIC ./driver/ .)
set_target_properties(${project} PROPERTIES LINKER_LANGUAGE CXX)
add_executable(bno055-test
./testingProject.cpp
)
target_link_libraries(test ${project})
install(
TARGETS ${project}
RUNTIME DESTINATION bin)
The error I have encountered is with the line set_source_files_properties(./driver/foo.c PROPERTIES LANGUAGE CXX). When it comes to compiling this C file with the C++ flag above I get many warnings of the type clang-8: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]. This is expected, as I am using deprecated methods and should not be compiling this file using the C++ flag. However, whenever I remove this line, or alter it to specify C instead of C++, my entire project no longer builds and fails with error:
CMake Error: Error required internal CMake variable not set, cmake may not be built correctly.
Missing variable is:
CMAKE_C_COMPILE_OBJECT
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
Makefile:283: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
"/usr/bin/make -j4 all" terminated with exit code 2. Build might be incomplete.
I'm not familiar enough with CMake to see why this line of code and error are related like this. Is there some alternative piece of code I should include to create the missing variable CMAKE_C_COMPILE_OBJECT?
I assume that when I initially created this project using Eclipse this line was automatically generated and I am unclear as to why it now creates a problem when I had been compiling these files with the same CMakeLists.txt before (without library linking).
This is with clang#8.0.0 on Ubuntu 16.04.
Any help would be much appreciated! Apologies if I have missed something simple!
Is there some alternative piece of code I should include to create the missing variable CMAKE_C_COMPILE_OBJECT?
No, as the CMake error states, this is an "internal CMake variable" which should be initialized by CMake. It is not something you should have to set yourself. It should be set indirectly when you call project(). However, you only tell CMake you are using C++ (with CXX option) in the project() command. If you want CMake to make use of C and C++, you need to add both:
project(${project} LANGUAGES C CXX)
Even better, CMake enables C and C++ by default, so you can simply do:
project(${project})

CMake 3.0 add_library of type INTERFACE breaks get_target_property

I want to add a header only directory to a cmake project which I am using in Windows 7 with Visual Studio 2013 Update 2. I did some research and came up with this Cmakelists.txt file:
add_library(AAA_lib INTERFACE)
target_include_directories(AAA_lib
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
This appears to work however in some of our internal cmake code we call get_target_property:
get_target_property(target_libraries ${target} LINK_LIBRARIES)
This generates a CMake error:
CMake Error at x_common_libs/xml/xsdmap.cmake:41 (get_target_property):
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property "LINK_LIBRARIES" is not allowed.
It seems like an odd error since a get should only return targets with the appropriate property. Is this a bug in CMake? Or is there some other way that this should be implemented?
Why do we need to call get_target_property?
We have a cmake helper function which recursively goes through all of dependencies of a project building up a list of all dependent projects that require some custom post processing. So if project X uses project B and C and C uses D, then we get a list of X, B, C, D and then check to see which directories match a requirement and then call a custom_command.
Thanks,
Jason
Seems that it is CMake bug. There is new target type in CMake 3.0 called INTERFACE_LIBRARY. You are supposed to use only some of properties for this type. However, I don't think it was expected to raise an error in case of reading other properties.
I came out with the following workaround:
get_target_property(_TARGET_TYPE ${target} TYPE)
if(_TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
unset(target_libraries)
else()
get_target_property(target_libraries ${target} LINK_LIBRARIES)
endif()
This is a restriction that was lifted in CMake 3.19.
See https://gitlab.kitware.com/cmake/cmake/-/issues/19145 for details.

cmake if else with option

I have a problem using option together with if-else statement in cmake.
project(test)
option(TESTE "isso é um teste" OFF)
if(TESTE)
message("true")
else()
message("false")
endif()
add_executable(test main.cpp)
It always displays true even if I put OFF in the options, what am I doing wrong?
That's because the value of the option is stored in the cache (CMakeCache.txt).
If you change the default value in the CMakeLists but the actual value is already stored in the cache, it will just load the value from the cache.
So to test the logic in your CMakeLists, delete the cache each time before re-running CMake.
I had a similar problem and was able to solve it using a slightly different approach.
I needed some compilation flags to be added in case cmake was invoked with an option from the command line (i.e cmake -DUSE_MY_LIB=ON).
If the option was missing in the cmake invocation I wanted to go back to default case which was turning the option off.
I ran into the same issues, where the value for this option was being cached between invocations:
cmake -DUSE_MY_LIB=ON .. #invokes cmake and puts USE_MY_LIB=ON in CMake's cache.
cmake .. #invokes cmake with the cached option ON, instead of OFF
The solution I found was clearing the option from within CMakeLists.txt after the option was used:
option(USE_MY_LIB "Use MY_LIB instead of THEIR_LIB" OFF) #OFF by default
if(USE_MY_LIB)
#add some compilation flags
else()
#add some other compilation flags
endif(USE_MY_LIB)
unset(USE_MY_LIB CACHE) # <---- this is the important!!
Note:
The unset option is available since cmake v3.0.2
Try this, it works for me
unset(USE_MY_LIB CACHE)