CMAKE: switch between clang / g++ and libc++ /libstdc++
Asked Answered
S

1

9

This is my first cmake file. I have a linux system with both clang and g++. Also libc++ is installed. I develop on Mac (xcode) but deploy to linux. I am writing a cmake file in which I can pick either clang or g++ and libc++ or libstdc++. So 4 possible combinations.

I figured out how to select the compiler and force c++11 on it, but I can't figure out how to specify the standard library. Any suggestions?

This is what I have so far:

## cmake ###
cmake_minimum_required (VERSION 3.5)

#set project directories
set(ProjectDirectory ${CMAKE_SOURCE_DIR}) #.../Project/
set(BuildDirectory ${ProjectDirectory}/Build)
set(ProductDirectory ${ProjectDirectory}/Products)
set(sourceDirectory ${ProjectDirectory}/Source)

#print project directories
message(${ProjectDirectory})
message(${BuildDirectory})
message(${ProductDirectory})

#configure cmake
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ProductDirectory})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${ProductDirectory})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${ProductDirectory})

set(CMAKE_VERBOSE_MAKEFILE on)

#compiler and standard library settings
set(CMAKE_CXX_COMPILER "clang++")
set(CMAKE_CXX_STANDARD 11)
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -v -stdlib=libc++")
        #libstdc++ #linux
        #libc++    #OS X

#compiler flags
SET( CompilerFlags  " ")
#SET( CompilerFlags  "${CompilerFlags} -stdlib=libc++" )
SET( CompilerFlags  "${CompilerFlags} -Wno-unknown-pragmas" )
SET( CompilerFlags  "${CompilerFlags} -Wall" )
SET( CompilerFlags  "${CompilerFlags} -Wextra" )

set (CMAKE_CXX_FLAGS ${CompilerFlags})

#linker flags
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")

#message(${CMAKE_CXX_FLAGS})

##################
### Libraries ###
################
### common library ###
project(common)

#message(STATUS ${CMAKE_CXX_FLAGS})

#source files
#set (commonSource ${sourceDirectory}/Object/object.cpp) #specify specific files
file(GLOB_RECURSE commonSource ${sourceDirectory}/Object/*.cpp) # recursive

#targets
add_library (common STATIC ${commonSource})

#target_compile_options (common PUBLIC ${CompilerFlags})


#####################
### Applications ###
###################
### Hello project ###
project (hello)

#source files
#set (helloSource ${sourceDirectory}/main.cpp)

#targets
#add_executable (hello ${helloSource})

#linking
#target_link_libraries (hello common)


#install(TARGETS common DESTINATION ${ProductDirectory})

I run this command on a console

../Project/Build$ rm -r *; rm -r ../Products/*; cmake ..; make VERBOSE=1;

My folder structure is:

Project
    Source
    Build
    Products
    CMakeLists.txt

I have also noticed that the compiler flags are sometimes ignored and only used when I run cmake and make a second time.

Also, I use a lot of #warning todo in my code How can I disable these warnings during compilation?

Sabah answered 27/4, 2017 at 16:4 Comment(7)
Have you checked that question: #7031626? Among other things its answer explains proper setting of compiler flags. Your last question about disabling warnings is unrelated to the other parts of your question post. It is better to create new question post for it.Garganey
If I understand correctly, that is about changing the compiler for the entire linux system. I just want to specify the compiler and standard library for a specific project.Sabah
Selection of compiler is usually outside of project's CMakeLists.txt. And related question describes how to do that. As for libc++ library, its selection also can be viewed as separate compiler environment, so it is natural to move this selection outside of the project's CMakeLists.txt too.Garganey
Ok, it's unusual. But I don't care that it's unusual. I just want it to work the way I want it to work. So, if it's possible, how can it be done?Sabah
If you are about setting variable CMAKE_CXX_FLAGS, before project() call it should be set as CMAKE_CXX_FLAGS_INIT.Garganey
There are better ways to specify to use C++11 and also to let CMake choose the appropriate C++ library to link with. In short, the target properties CXX_STANDARD, CXX_STANDARD_REQUIRED and CXX_EXTENSIONS are what you want (and/or their CMake variable counterparts). An article explaining it all in depth can be found here. Compiler selection should really be left up to the developer unless you really need one and not the other for some reason.Sheepcote
My code compiles and runs just fine on OS X. But it's a nightmare to compile on linux. I have been told the linux c++ libraries do not yet fully implement the c++11 standard. So I want to try clang and libc++ instead of gcc and libstdc++. Frankly I don't care about compilers as long as it runs.Sabah
F
7

It's a little tricky because I don't believe CMake has a built in way to select a standard library. What I do is pass it into the linker flags. e.g.

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")

CMake does, however, support setting the compiler:

set(CMAKE_CXX_COMPILER "clang++")
Footfall answered 29/4, 2017 at 3:2 Comment(6)
Better to use the full path. On linux I get the following error: CMake Error at tests/CMakeLists.txt:6 (project): The CMAKE_CXX_COMPILER: clang++ is not a full path and was not found in the PATH. Tell CMake where to find the compiler by setting either the environment variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path to the compiler, or to the compiler name if it is in the PATH. -- Configuring incomplete, errors occurred!Lapoint
Anyway it didn't work for me: the creation of makefiles locks in an eternal loopLapoint
I disagree, adding the compiler to your PATH is the more accepted and better way of doing things. It makes code reuse easier and doesn't hardcode the development environment setup into source code. If you need to specify a full path, it's better just to set it using -D when you run CMake. cmake -D CMAKE_CXX_COMPILER "/path/to/your/cpp/compiler/executable" /path/to/directory/containing/CMakeLists.txt The generation recursion you mention wouldn't have anything to do with the compiler variable. Look for issues elsewhere.Footfall
The compiler is in my path. Nonetheless, I got the error message. I might be a bug with my tool's versions.Lapoint
Setting the linker flags for your project can work (although target_link_options() is a better way to do this). Unfortunately, this approach falls apart as soon as you try to use a package manager like VCPKG, because VCPKG builds packages before your project is ever configured and will therefore use the system default standard library, and you'll get tons of linker errors as soon as you try to link to any of the 3rd-party libs that VCPKG built using libstdc++.Nonlinearity
target_link_options() and vcpkg were not available when this answer was written almost seven years ago.Footfall

© 2022 - 2024 — McMap. All rights reserved.