Configure cmake to choose compiler based on environment - c++

My current project directory looks like
myproject
/-build
/-include
/-somefile.h
/-somefile2.h
/-myproject.cpp
/-CMakeLists.txt
and current CMakeLists.txt looks like :
cmake_minimum_required (VERSION 3.1)
project (myproject)
add_executable(myproject myproject.cpp)
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
include_directories("${PROJECT_INCLUDE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}")
I want to build this project in both x64Windows and x64Linux environment while keeping single cmake file. Currently I have Visual Studio 13 CE in Win and gcc in Linux. Is it possible that Cmake could intelligently choose the correct compiler depending on OS? And what changes should I make to CMakeLists for that?
I'm using normal stuff like STL and vanilla C++ ( no os dependent libraries) if that matters. Thanks

You want to add conditional code for each compiler:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Set the C++ and linker flags to GCC specifics here.
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# Set the C++ and linker flags to VC++ specifics here.
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# Set the C++ and linker flags to Clang specifics here.
elseif()
The right compiler is set automatically at least on linux. On windows I don't know. However you could always overwrite the selected compiler by the environment variables CC and CXX. This changes the cmake configuration. The changes will only affect new build configurations. So don't forget to delete your old one before selecting a new compiler.
Edit: The compiler must be of course in your PATH variable. Otherwise CMake will not find it correctly.

Related

AUTOMOC set to true makes fail cmake build

I'm at the very first day of Qt + Cmake and Conan, trying to make things work. I'm not using qmake because I'll integrate everything into a bigger project using cmake.
By following QT's tutorial, I figured out that I need to compile QT macros, and for that there's a useful AUTOMOC CMake property, as suggested here.
The point is that it's making me fail cmake builds.
My conanfile.txt:
[requires]
qt/5.15.2
[generators]
cmake
My CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(qttest)
set(CMAKE_CXX_STANDARD 20)
set_target_properties(${PROJECT_NAME} PROPERTIES AUTOMOC TRUE)
set (PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
with the following output:
CMake Warning (dev) in CMakeLists.txt:
AUTOGEN: No valid Qt version found for target qttest. AUTOMOC disabled.
Consider adding:
find_package(Qt<QTVERSION> COMPONENTS Core)
to your CMakeLists.txt file.
This warning is for project developers. Use -Wno-dev to suppress it.
ouch, but adding the find doesn't make things better:
CMake Warning at CMakeLists.txt:6 (find_package):
By not providing "FindQt5.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "Qt5", but
CMake did not find one.
Could not find a package configuration file provided by "Qt5" with any of
the following names:
Qt5Config.cmake
qt5-config.cmake
Actually the project compiles, Qt is there in its conan dir:
matteo#MacBook-Pro-de-matteo 96a68a791abfc7a246f2bc28aa2f6fc210be0f9f % cd ~/.conan/data/qt
matteo#MacBook-Pro-de-matteo qt % ls
5.15.2 6.2.2
matteo#MacBook-Pro-de-matteo qt %
how could I enable it, or make things easier to compile it along with cmake?
You need to tell CMake, where to find Qt.
So, as CMake suggests by itself:
find_package(Qt5 COMPONENTS Core)
for the most basic stuff, you might want to add some of the other components later.
Depending on the system you are working on and your Qt installation, you need to tell CMake where to search for the package configuration files (second error message). CMake has some default directories, where it looks for these files, but obviously, there is none. On Linux, this can be solved by installing Qt with a package manager (this will install the CMake config files to one of the Qt default locations). If you are on Windows or if you installed Qt to a different location, this can be solved by providing the path with the PREFIX_PATH-variable.
cmake -B $BUILD_DIR -S $SOURCE_DIR -DCMAKE_PREFIX_PATH=$QT_INSTALL_PATH/5.15.2/$ARCHITECTURE $OTHER_OPTIONS
(You can have different versions installed in the same installation path, that's why Qt adds an other folder with the version number. And you can have different compilers/architectures. On Windows for example, you might have a mingw73_32 and a msvc2017 folder to choose.)
As already mentioned in the comments, a project is no CMake target. CMake targets are either libraries (add_library), executables (add_executable) or custom targets (add_custom_target); the project is not. If you want to set the AUTOMOC property target wise, that's ok and even suggested by CMake, but you can also set it globally by using:
set(CMAKE_AUTOMOC ON)

CMake skips standard precompiled headers

I'm new to C++, really trying to get familiar with CMake, but there's always something wrong.
I'm using CLion with Cygwin and G++11 package installed
My CMakeLists.txt file:
cmake_minimum_required(VERSION 3.20)
project(testing)
set(CMAKE_CXX_STANDARD 20)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif ()
set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
add_executable(testing main.cpp)
Clion says me that execution header is not found, but I could locate it in lib/ folder:
Could somebody tell me what I'm doing wrong?
Here are a few things I have tried when debugging similar problems:
If in doubt, delete and re-create your build directories. CMake caches certain variables and can sometimes get into a weird state. A fresh directory will remove any uncertainty.
CMake should print out what compiler it is using - Check that and make sure it's correct. For example, it could be finding an older version that does not have that header.
In this case, the fix may be to put your desired compiler at the front of your PATH, or to force CMake to find the correct one via CMAKE_CXX_COMPILER.
Build in verbose mode - you should be able to see what include paths are being used (-I, -isystem). Make sure that directory is in there.
Alternatively, you can dump a compile_commands.json file that should contain the same information by setting CMAKE_EXPORT_COMPILE_COMMANDS=true
Try using one of these build commands to build a single object in your Cygwin shell. If it works, it may indicate a problem with how your CLion is configured.

link qt5 libraries automatically pass extra fPIC flag to nvcc compiler by cmake cause error

I have a project based on cuda10.1, qt5. And I use cmake to manage the compilation. However the same cmake script work fine in Windows, but in Linux, I got error "Unknown option 'fPIC'" when compiling .cu files. I look into makefile, then find there is a extra error flag "-fPIC" passed to nvcc compiler. Spending hours of testing, I find linking qt5 libraries will automatically pass extra fPIC flag which causes this error. I don't know this is bug or feature of cmake?
cmake_minimum_required(VERSION 3.10)
project(PyPhysLeo LANGUAGES CXX CUDA)
find_package(Qt5 COMPONENTS Core Widgets)
if(Qt5_FOUND)
message("Find QT5")
link_libraries(Qt5::Widgets Qt5::Core Qt5::Gui)
endif()
set(CMAKE_CXX_STANDARD 14 CACHE STRING "CXX STANDARD VERSION 11,14,17")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CUDA_SEPARABLE_COMPILATION ON CACHE BOOL "DEFAULT SET SEPERABLE COMPILATION MODE")
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -arch=sm_60")
include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE})
add_executable(test test.cu)
if you try above cmake script with any sample cuda code, you will get "nvcc fatal" error because it doesn't recognize fPIC flag.
It is a problem with qt5.cmake. Thanks to Robert Crovella for commenting (see above) about the related information gitlab.kitware.com/cmake/cmake/issues/16915. There is no perfect solution so far. But...
One solution, if you can separate your project into a library and an executable sub-projects, then you can cleanly avoid the issue altogether. Try to put all the .cu files in a library sub-project and only link qt5 in an executable sub-project. This is one way to avoid this problem.
Otherwise, you can try to modify the variable defined by qt5.cmake, for that solution please refer to cmake issue 16915.

Setup CMake with SFML in VS2017

Just like in CLion I want to use SFML with Visual Studio 2017, but I'm still learning cmake and I don't know the commands or the logic of how cmake works at all. I've just seen some posts and got this litle script.
Note: I downloaded the latest version of sfml in the link provided, I just taked the extrated directory and put alongside CMakeLists.txt in my folder
#sets up the minimum version of cmake
cmake_minimum_required(VERSION 3.9)
#how the project will be called
project (space_impact)
#set c++11 standard
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" -std=c++11)
#set source files
set (SOURCE_FILES main.cpp)
#we add the executable of the program
add_executable (space_impact ${SOURCE_FILES})
#taked from a mac-clion tutorial, doesn't work
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/SFML/cmake-modules/")
find_package (SFML REQUIRED system window graphics network audio)
if (SFML_FOUND)
include_directories(${SFML_INCLUDE_DIR})
target_link_libraries(space_impact ${SFML_LIBRARIES})
endif()
that thing gave me errors:
Error CMake Error at SFML/cmake-modules/FindSFML.cmake:355 (message):
Could NOT find SFML (missing: SFML_SYSTEM_LIBRARY SFML_WINDOW_LIBRARY
SFML_GRAPHICS_LIBRARY SFML_NETWORK_LIBRARY SFML_AUDIO_LIBRARY) SFML/cmake-modules/FindSFML.cmake
I want everything to be dynamic, but I don't know how can I do that..
So my question is what should I do for setting up correctly SFML with Cmake in Visual Studio.
I don't want the old-fashioned method from the official website
UPDATE
Here's my location....
The thing is.. the FindSFML.cmake script it's not working...
What files should I move for make it working?
Your script is perfectly fine, except three things I'd change:
Move the whole module detection before defining targets. I'm pretty sure you also have to define your include directories before.
Your if(SFML_FOUND) bracket is pretty pointless right now, because you've set SFML to be required, which means it will never get past find_package() unless it's found.
-std=c++11 is a GCC only flag (MSVC will always use the latest standard, unless specified). As such you'll have to check the compiler here or use CMAKE_CXX_STANDARD.
So the "cleaned" CMakeLists.txt could look like this:
#sets up the minimum version of cmake
cmake_minimum_required(VERSION 3.9) # personally I'd set this version as low as required; you don't have to require the cutting edge version
#how the project will be called
project (space_impact)
#set the C++ standard to be used
set (CMAKE_CXX_STANDARD 11)
#set source files
set (SOURCE_FILES main.cpp)
#look for SFML and add it
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/SFML/cmake-modules/")
find_package (SFML REQUIRED system window graphics network audio)
include_directories(${SFML_INCLUDE_DIR})
#we add the executable of the program
add_executable (space_impact ${SOURCE_FILES})
target_link_libraries(space_impact ${SFML_LIBRARIES} ${SFML_DEPENDENCIES})
Note that adding SFML_DEPENDENCIES to the library list is optional, unless you're using a static version of SFML.
But what about your SFML issue? Since you don't have the SFML files installed in any directory looked into by default, you'll have to tell CMake where it's found using the CMake variable SFML_ROOT or the environment variable of the same name.
So the first time you're invoking CMake, it could look like this:
cmake -G "Visual Studio 15 2017" -DSFML_ROOT=path/to/sfml path/to/source
This is all you need to compile sfml in your cmake project.
find_package(SFML 2.5.1 COMPONENTS system graphics audio network REQUIRED)
add_executable (AwesomeProject "AwesomeProject.cpp" "AwesomeProject.h")
target_link_libraries(AwesomeProject PRIVATE sfml-audio sfml-graphics sfml-network sfml-system)
Also set SFML_DIR var to your sfml folder.

Cmake: Specifiy config specific settings for multi-config cmake project

Cmake novice here, I am currently trying to convert a cmake project that was developed with only single configuration in mind to a multi-config project which can generate visual studio files.
My problem that I can not solve is that in the cmake project there exist logic depending on the variable CMAKE_BUILD_TYPE such as:
set(ENABLE_DEBUG TRUE)
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
set(ENABLE_DEBUG FALSE)
)
Since for multi-config cmake the CMAKE_BUILD_TYPE is empty this way of doing it does not work. The variable ENABLE_DEBUG is then in the cmake project used for stuff such as:
Case 1: Adding libraries to only debug config
if(ENABLE_DEBUG)
list(APPEND LIB_SRC src/lib_debug.cpp)
endif()
add_library(LIB OBJECT LIB_SRC)
Case 2: Adding preprocessor flags to only debug config
if(ENABLE_DEBUG)
add_definitions(...)
endif()
So what I wonder is if anyone has a workaround for one or both of the cases above that would work for multi-config cmake projects, i.e so that I can specify library additions and preprocessor flags without depending on the CMAKE_BUILD_TYPE variable. Or even better if there a config specific way of setting the ENABLE_DEBUG without depending on the CMAKE_BUILD_TYPE variable?
In CMake common way for config-specific settings for multi-config build tools is using generator expressions.
Command add_library allows to use generator expressions for source files. E.g. this:
add_library(mylib common.c $<$<CONFIG:DEBUG>:debug.c>)
creates a library consisted from common.c in all configuration plus additional debug.c in Debug configuration.
Documentation for add_definitions doesn't note usage of generator expressions, but documentation for target_compile_definitions does:
target_compile_definitions(mylib PUBLIC $<$<CONFIG:DEBUG>:-DDEBUG_VAR>)