MacOS, CMake and OpenMP - cmake

I am using the newest CMake (3.9.3) from Homebrew along with LLVM 5.0.0 also from Brew, because Clang here has OpenMP support.
This worked in CMake 3.8.2 with LLVM 5.
In my CMakeLists.txt I have
find_package( OpenMP )
and later I want to do
if( OpenMP_CXX_FOUND )
However CMake doesn't seem to pick up on the find_package directive.
I run CMake with
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DUSE_WERROR=ON
where I have checked that clang and clang++ points correctly to /usr/local/opt/llvm/bin/clang and /usr/local/opt/llvm/bin/clang++
All I get is these two lines:
-- Could NOT find OpenMP_C (missing: OpenMP_C_FLAGS OpenMP_C_LIB_NAMES) (found version "1.0")
-- Could NOT find OpenMP_CXX (missing: OpenMP_CXX_FLAGS OpenMP_CXX_LIB_NAMES) (found version "1.0")
If I set OpenMP_C_FLAGS myself (with -DOpenMP_C_FLAGS=-fopenmp=libomp) it changes the error to
-- Could NOT find OpenMP_C (missing: OpenMP_C_LIB_NAMES) (found version "3.1")
Notice that it changes the version number, so it must be finding something, right?
What am I missing for this to work properly?
Okay, it seem that inside the FindOpenMP.cmake supplied by CMake we do a try_compile, which fails silently (because we do it a lot of times and most of them will fail, this makes sense). However, with Clang a -Werror flag is supplied, which fails because of an unused command line argument. I can thus add:
if(APPLE)
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(OpenMP_C_FLAG "-fopenmp=libomp -Wno-unused-command-line-argument")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(OpenMP_CXX_FLAG "-fopenmp=libomp -Wno-unused-command-line-argument")
endif()
endif()
to my project because I know that -fopenmp=libomp will work for this Clang.
Is this the right way of doing it?

The message basically tells you that you have to provide the path to the libraries and the names of the libraries. The following example should fix your problem (see also find_package(OpenMP)). Note that I use the brew installation using the command "brew install llvm". The first four lines are just for completeness.
set(CMAKE_C_COMPILER "/usr/local/Cellar/llvm/5.0.1/bin/clang")
set(CMAKE_CXX_COMPILER "/usr/local/Cellar/llvm/5.0.1/bin/clang++")
set(OPENMP_LIBRARIES "/usr/local/Cellar/llvm/5.0.1/lib")
set(OPENMP_INCLUDES "/usr/local/Cellar/llvm/5.0.1/include")
OPTION (USE_OpenMP "Use OpenMP to enamble <omp.h>" ON)
# Find OpenMP
if(APPLE AND USE_OpenMP)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(OpenMP_C "${CMAKE_C_COMPILER}")
set(OpenMP_C_FLAGS "-fopenmp=libomp -Wno-unused-command-line-argument")
set(OpenMP_C_LIB_NAMES "libomp" "libgomp" "libiomp5")
set(OpenMP_libomp_LIBRARY ${OpenMP_C_LIB_NAMES})
set(OpenMP_libgomp_LIBRARY ${OpenMP_C_LIB_NAMES})
set(OpenMP_libiomp5_LIBRARY ${OpenMP_C_LIB_NAMES})
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(OpenMP_CXX "${CMAKE_CXX_COMPILER}")
set(OpenMP_CXX_FLAGS "-fopenmp=libomp -Wno-unused-command-line-argument")
set(OpenMP_CXX_LIB_NAMES "libomp" "libgomp" "libiomp5")
set(OpenMP_libomp_LIBRARY ${OpenMP_CXX_LIB_NAMES})
set(OpenMP_libgomp_LIBRARY ${OpenMP_CXX_LIB_NAMES})
set(OpenMP_libiomp5_LIBRARY ${OpenMP_CXX_LIB_NAMES})
endif()
endif()
if(USE_OpenMP)
find_package(OpenMP REQUIRED)
endif(USE_OpenMP)
if (OPENMP_FOUND)
include_directories("${OPENMP_INCLUDES}")
link_directories("${OPENMP_LIBRARIES}")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
# set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif(OPENMP_FOUND)
You might want to set e.g. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lpthread") such that the linker automatically detects the appropriate pthread library (see pthread and wiki).

Apparently, case is important. For an unrelated project I can make it work with
find_package ( OPENMP REQUIRED )
This didn't work:
find_package ( OpenMP REQUIRED )
With that directive, no need for setting all the other flags by hand.
cmake 3.13.2, clang-1000.11.45.5 (High Sierra)

Maybe it's a CMake version thing, I come up with a slightly different solution with Franzi's.
I also use brew install libomp on my machine. It seems like OpenMP_CXX_FLAGS is used for compiling project source code instead of compiling the omp (the flag is stored in the omp target and will be populated by command target_link_libraries).
Besides that, OpenMP_CXX_LIB_NAMES shouldn't have prefix lib because it will cause an error like -llibomp not found, where -lomp should be used instead.
I also noticed that CMAKE_C_COMPILER_ID is AppleClang instead of Clang if I put project(playground) after cmake_minimum_required. In reverse, it's Clang, quite annoying and I don't know why.
Xpreprocessor used here is because apple clang doesn't ship with OpenMP and this flag tells the compiler to look for pragma (preprocessor expansion) elsewhere. In our case, it's the header files in the include path where the libomp is installed.
cmake_minimum_required(VERSION 3.12)
project(playground)
if(APPLE)
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
if(CMAKE_C_COMPILER_ID MATCHES "Clang\$")
set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp")
set(OpenMP_C_LIB_NAMES "omp")
set(OpenMP_omp_LIBRARY omp)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang\$")
set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp")
set(OpenMP_CXX_LIB_NAMES "omp")
set(OpenMP_omp_LIBRARY omp)
endif()
endif()
find_package(OpenMP REQUIRED)
add_executable(helloworld helloworld.cxx)
target_link_libraries(helloworld PRIVATE OpenMP::OpenMP_CXX)
Here's my helloworld
#include <cstdio>
#include <thread>
#include <sstream>
int main(void)
{
#pragma omp parallel
{
std::stringstream ss;
ss << std::this_thread::get_id();
printf("%s, Hello, world.\n", ss.str().c_str());
}
return 0;
}
output is,
0x700002dc8000, Hello, world.
0x10a17d5c0, Hello, world.
0x7000045d1000, Hello, world.
0x7000055d7000, Hello, world.
0x700005dda000, Hello, world.
0x7000035cb000, Hello, world.
0x7000065dd000, Hello, world.
0x700003dce000, Hello, world.
0x700007de6000, Hello, world.
0x700004dd4000, Hello, world.
0x7000075e3000, Hello, world.
0x700006de0000, Hello, world.

With recent versions of CMake (3.18, didn't work with 3.14) and a fresh installation of MacOS (with developer CL tools installed, of course), brew install libomp was the only action needed to make things work.

MacOS Ventura
cmake: /usr/local/Cellar/cmake/3.25.1
OpenMP: /usr/local/Cellar/libomp/15.0.7
llvm: /usr/local/Cellar/llvm/15.0.7_1
above solution worked after setting compiler directories and libomp directories to the correct values
with the change:
set(OpenMP_C_FLAGS "-fopenmp=libomp")
for both the clang and clangxx sections

Related

change "Requesting program interpreter: /lib64/ld-linux-x86-64.so.2" to a customized one through cmake [duplicate]

I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).
This is for an Android device, and I only want to use CMake, not ndk-build.
For example - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
It works with no problem...
The problem ... I am trying to compile the file with a CMake file.
I want to add the -fexceptions as a flag. I tried with
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
and
set ( CMAKE_C_FLAGS "fexceptions")
It still displays an error.
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
Suppose you want to add those flags (better to declare them in a constant):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
There are several ways to add them:
The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
Appending to corresponding CMake variables:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
Using target properties, cf. doc CMake compile flag target property and need to know the target name.
get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
if(TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # Set to empty string
else()
SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
endif()
# Append our values
SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
Right now I use method 2.
In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):
target_compile_options(first-test PRIVATE -fexceptions)
The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.
As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.
Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:
set (CMAKE_CXX_FLAGS "-fexceptions")
The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.
Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.
The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:
instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.
Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.
Steps to add a toolchain:
Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
(You can find an example Linux cross-compiling toolchain file here.)
When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:
mkdir android-arm-build && cd android-arm-build
cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
(Note: you cannot use a relative path.)
Build as normal:
cmake --build .
Toolchain files make cross-compilation easier, but they have other uses:
Hardened diagnostics for your unit tests.
set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
Tricky-to-configure development tools.
# toolchain file for use with gcov
set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
Enhanced safety checks.
# toolchain file for use with gdb
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
You can also add linker flags to a specific target using the LINK_FLAGS property:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
If you want to propagate this change to other targets, you can create a dummy target to link to.
This worked for me when I needed a precompile definition named "NO_DEBUG":
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
Then from code
#ifdef NO_DEBUG
.....
With CMake 3.4+, APPEND can be used with the string command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")

cmake - building target with custom compile options [duplicate]

I am using the arm-linux-androideabi-g++ compiler. When I try to compile a simple "Hello, World!" program it compiles fine. When I test it by adding a simple exception handling in that code it works too (after adding -fexceptions .. I guess it is disabled by default).
This is for an Android device, and I only want to use CMake, not ndk-build.
For example - first.cpp
#include <iostream>
using namespace std;
int main()
{
try
{
}
catch (...)
{
}
return 0;
}
./arm-linux-androideadi-g++ -o first-test first.cpp -fexceptions
It works with no problem...
The problem ... I am trying to compile the file with a CMake file.
I want to add the -fexceptions as a flag. I tried with
set (CMAKE_EXE_LINKER_FLAGS -fexceptions ) or set (CMAKE_EXE_LINKER_FLAGS "fexceptions" )
and
set ( CMAKE_C_FLAGS "fexceptions")
It still displays an error.
Note: Given CMake evolution since this was answer was written in 2012, most of the suggestions here are now outdated/deprecated and have better alternatives.
Suppose you want to add those flags (better to declare them in a constant):
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov")
There are several ways to add them:
The easiest one (not clean, but easy and convenient, and works only for compile flags, C & C++ at once):
add_definitions(${GCC_COVERAGE_COMPILE_FLAGS})
Appending to corresponding CMake variables:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
Using target properties, cf. doc CMake compile flag target property and need to know the target name.
get_target_property(TEMP ${THE_TARGET} COMPILE_FLAGS)
if(TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # Set to empty string
else()
SET(TEMP "${TEMP} ") # A space to cleanly separate from existing content
endif()
# Append our values
SET(TEMP "${TEMP}${GCC_COVERAGE_COMPILE_FLAGS}" )
set_target_properties(${THE_TARGET} PROPERTIES COMPILE_FLAGS ${TEMP} )
Right now I use method 2.
In newer versions of CMake you can set compiler and linker flags for a single target with target_compile_options and target_link_libraries respectively (yes, the latter sets linker options too):
target_compile_options(first-test PRIVATE -fexceptions)
The advantage of this method is that you can control propagation of options to other targets that depend on this one via PUBLIC and PRIVATE.
As of CMake 3.13 you can also use target_link_options to add linker options which makes the intent more clear.
Try setting the variable CMAKE_CXX_FLAGS instead of CMAKE_C_FLAGS:
set (CMAKE_CXX_FLAGS "-fexceptions")
The variable CMAKE_C_FLAGS only affects the C compiler, but you are compiling C++ code.
Adding the flag to CMAKE_EXE_LINKER_FLAGS is redundant.
The preferred way to specify toolchain-specific options is using CMake's toolchain facility. This ensures that there is a clean division between:
instructions on how to organise source files into targets -- expressed in CMakeLists.txt files, entirely toolchain-agnostic; and
details of how certain toolchains should be configured -- separated into CMake script files, extensible by future users of your project, scalable.
Ideally, there should be no compiler/linker flags in your CMakeLists.txt files -- even within if/endif blocks. And your program should build for the native platform with the default toolchain (e.g. GCC on GNU/Linux or MSVC on Windows) without any additional flags.
Steps to add a toolchain:
Create a file, e.g. arm-linux-androideadi-gcc.cmake with global toolchain settings:
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_CXX_FLAGS_INIT "-fexceptions")
(You can find an example Linux cross-compiling toolchain file here.)
When you want to generate a build system with this toolchain, specify the CMAKE_TOOLCHAIN_FILE parameter on the command line:
mkdir android-arm-build && cd android-arm-build
cmake -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../arm-linux-androideadi-gcc.cmake ..
(Note: you cannot use a relative path.)
Build as normal:
cmake --build .
Toolchain files make cross-compilation easier, but they have other uses:
Hardened diagnostics for your unit tests.
set(CMAKE_CXX_FLAGS_INIT "-Werror -Wall -Wextra -Wpedantic")
Tricky-to-configure development tools.
# toolchain file for use with gcov
set(CMAKE_CXX_FLAGS_INIT "--coverage -fno-exceptions -g")
Enhanced safety checks.
# toolchain file for use with gdb
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-fsanitize=address,undefined -fsanitize-undefined-trap-on-error")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-fsanitize=address,undefined -static-libasan")
You can also add linker flags to a specific target using the LINK_FLAGS property:
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
If you want to propagate this change to other targets, you can create a dummy target to link to.
This worked for me when I needed a precompile definition named "NO_DEBUG":
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -DNO_DEBUG")
Then from code
#ifdef NO_DEBUG
.....
With CMake 3.4+, APPEND can be used with the string command to add flags.
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fexceptions")

How can I add a minimum compiler version requisite?

I want to create a project in C++11 and I use CMake as my build system.
How can I add a minimum compiler version requisite in the CMake config files?
AFAIK, there is no built-in support for something like this, but you could certainly write it yourself:
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "your.required.gcc.version")
message(FATAL_ERROR "Insufficient gcc version")
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "your.required.msvc.version")
message(FATAL_ERROR "Insufficient msvc version")
endif()
elseif(...)
# etc.
endif()
However, I suggest you actually consider a feature-detection approach instead. That is, use try_compile() to verify that the compiler supports the features you need, and FATAL_ERROR if it doesn't. It's more idiomatic in CMake, and has the added benefit you don't have to discover the appropriate minimal version for all compilers out there.
Starting with CMake 2.8.10 the CMAKE_<LANG>_COMPILER_VERSION variables can be accessed by users to get the compiler version. In previous versions those were only reserved for internal purposes and should not be read by user code. They are also not guaranteed to be set for all languages but C and CXX should definitely be available.
CMake also contains operators for version comparison (VERSION_LESS, VERSION_EQUAL, VERSION_GREATER) that you can use to write your version validation code.
Remember that you will need to find out which compiler you have first and then check for the correct version.
Here is a short sample from one of my projects:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# require at least gcc 4.8
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
message(FATAL_ERROR "GCC version must be at least 4.8!")
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# require at least clang 3.2
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.2)
message(FATAL_ERROR "Clang version must be at least 3.2!")
endif()
else()
message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang and GCC.")
endif()
You can check the specific gcc version as follows:
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
message(FATAL_ERROR "Require at least gcc-5.1")
endif()
There is built-in support nowadays. From the Documentation:
target_compile_features(mylib PUBLIC cxx_std_11)
"In this example, CMake will ensure the compiler is invoked in a mode of at-least C++ 11 (or C++ 14, C++ 17, ...), adding flags such as -std=gnu++11 if necessary. This applies to sources within mylib as well as any dependents (that may include headers from mylib)."

How to set warning level in CMake?

How to set the warning level for a project (not the whole solution) using CMake? Should work on Visual Studio and GCC.
I found various options but most seem either not to work or are not consistent with the documentation.
In modern CMake, the following works well:
if(MSVC)
target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX)
else()
target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror)
endif()
My colleague suggested an alternative version:
target_compile_options(${TARGET_NAME} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>
)
Replace ${TARGET_NAME} with the actual target name. -Werror is optional, it turns all warnings into errors.
Or use add_compile_options(...) if you want to apply it to all targets as suggested by #aldo in the comments.
Also, be sure to understand the difference between PRIVATE and PUBLIC (public options will be inherited by targets that depend on the given target).
As #davidfong notes in the comments, since CMake v3.24, there is the CMAKE_COMPILE_WARNING_AS_ERROR variable that switches on treating compile warings as errors. In case it is set inside CMakeLists.txt, the user can still turn it off with the --compile-no-warning-as-error cmake flag. In case you want to add warning-as-error manually, add /WX in Windows and -Werror elsewhere to target_compile_options.
UPDATE: This answer predates the Modern CMake era. Every sane CMake user should refrain from fiddling with CMAKE_CXX_FLAGS directly and call the target_compile_options command instead. Check the mrts' answer which presents the recommended best practice.
You can do something similar to this:
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
# Update if necessary
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
endif()
Some CMake modules I've written include experimental cross-platfrom warning suppression:
sugar_generate_warning_flags(
target_compile_options
target_properties
ENABLE conversion
TREAT_AS_ERRORS ALL
)
set_target_properties(
foo
PROPERTIES
${target_properties}
COMPILE_OPTIONS
"${target_compile_options}"
)
Result for Xcode:
Set CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION Xcode attribute
(aka build settings -> warnings -> suspicious implicit conversions -> YES)
Add compiler flag: -Werror
Makefile gcc and clang:
Add compiler flags: -Wconversion, -Werror
Visual studio:
Add compiler flags: /WX, /w14244
Links
List of available warnings
Usage and more options
As per Cmake 3.24.2 documentation:
if (MSVC)
# warning level 4 and all warnings as errors
add_compile_options(/W4 /WX)
else()
# lots of warnings and all warnings as errors
add_compile_options(-Wall -Wextra -pedantic -Werror)
endif()
GCC and Clang share these flags, so this should cover all 3.
Here is the best solution I found so far (including a compiler check):
if(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
add_definitions(/W2)
endif()
The GCC equivalent is -Wall (untested).
if(MSVC)
string(REGEX REPLACE "/W[1-3]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()
If you use target_compile_options - cmake will try to use double /W* flag, which will give warning by compiler.
How to set the warning level for a project (not the whole solution) using CMake?
(I assume this to mean a CMake target, and not a CMake project.)
I found various options but most seem either not to work or are not consistent with the documentation.
Kitware's APIs may be trying to deter you from making your build system brittle and error-prone. The special-casing encouraged by other answers to this question violate at least two important principles of modern CMake build systems...
Firstly, prefer not to specify toolchain-specific details in CMakeLists.txt files. It makes the build system brittle. For example, if a new warning appears in a future version of the toolchain, the compiler will emit an error and your user may need to hack your project in order to build the target.
Instead, write toolchain-agnostic CMakeLists.txt files and preserve the user's ability to customise as they see fit. Ideally, your project should build everywhere with vanilla toolchain configuration - even if that doesn't enable your preferred warnings by default.
Secondly, if you intend to link binaries together, flags should be consistent. This reduces the risk of incompatibility which could result in an ill-formed program. However, warning flags are unlikely to affect code generation, so it may be safe to vary these between the targets you link together.
So... if you wish to specify flags per toolchain and if you absolutely must have different flags for different targets, use custom variables:
# CMakeLists.txt
project(my_project)
add_executable(my_target source_file.cpp)
target_compile_options(my_target PRIVATE "${MY_PROJECT_ELEVATED_WARNING_FLAGS}")
There are many ways to set these variables, such as CMakeCache.txt, a toolchain file, and via CMAKE_PROJECT_INCLUDE_BEFORE. But the simplest way is on the command line during configuration, for GCC
cmake -DMY_PROJECT_ELEVATED_WARNING_FLAGS:STRING="-Wall;-Wextra;-Wpedantic;-Werror" <path-to-project>
for MSVC
cmake -DMY_PROJECT_ELEVATED_WARNING_FLAGS:STRING="/W4;/WX" <path-to-project>

CMake adding libraries for Windows/Linux

Visual Studio C++ 2008 / GCC 4.4.2
I have written a program to run on Linux and now I have to port my code to run on Windows. I have decided to use CMake as I want to keep the same build system for both platforms.
However, I need to link with some libraries for both platforms. In my CMakeLists.txt I have the following:
# Compile with gcc c89 standard
IF(CMAKE_COMPILER_IS_GNUCXX)
MESSAGE(STATUS "GCC detected - Adding compiler flags")
SET(CMAKE_C_FLAGS "-pthread -ggdb -Wextra -Wall -pedantic -std=c89")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(WIN32)
SET(CMAKE_C_FLAGS "ws2_32.lib")
ENDIF(WIN32)
However, when I compile on Visual Studio I get the following error:
fatal error C1083: Cannot open source file: 'ws2_32.lib': No such file or directory
What can I do to resolve this problem?
========= Edit
In the top level directory
# Project Client Server
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
# Name of project
PROJECT(CLIENT_SERVER)
# Compile with gcc c89 standard
IF(CMAKE_COMPILER_IS_GNUCXX)
MESSAGE(STATUS "GCC detected - Adding compiler flags")
SET(CMAKE_C_FLAGS "-pthread -ggdb -Wextra -Wall -pedantic -std=c89")
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(WIN32)
SET(CMAKE_C_FLAGS "ws2_32")
ENDIF(WIN32)
# Includes
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/cltsvr_ults)
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/server)
INCLUDE_DIRECTORIES(${CLIENT_SERVER_SOURCE_DIR}/client)
# libraries
LINK_DIRECTORIES($CLIENT_SERVER/cltsvr_ults)
# Add subdirectories
ADD_SUBDIRECTORY(client)
ADD_SUBDIRECTORY(server)
ADD_SUBDIRECTORY(cltsvr_ults)
ADD_SUBDIRECTORY(test_client)
ADD_SUBDIRECTORY(test_server)
In the subdirectory of client I have this CMakeLists.txt
# libray called client from client.c
ADD_LIBRARY(client client)
And in the subdirectory of test_clt where I create and link my executable.
# Test client add executable
INCLUDE_DIRECTORIES($CLIENT_SERVER_SOURCE_DIR/client)
INCLUDE_DIRECTORIES($CLIENT_SERVER_SOURCE_DIR/cltsvr_ults)
# Link the library
LINK_DIRECTORIES($CLIENT_SERVER/client)
# Add the executable
ADD_EXECUTABLE(clt test_clt)
# Link the executable to the client library
IF(WIN32)
TARGET_LINK_LIBRARIES(clt client ws2_32)
ENDIF(WIN32)
Disclaimer: My answer is of philosophical nature which should encourage you to avoid touching CMAKE_C_FLAGS directly. For the direct answer that just solves your problem look what Bill ( the lead architect of the CMake btw. ) wrote.
The thing about CMake is, that it lets you describe what you want to do without referring to a specific compiler or platform. What CMake does is building the compiler and linker flags from your usage of
include_directories
add_definitions
add_library
add_executable
target_link_libraries
If there are no external dependencies, other than the compiler itself, this is all you need. For external dependencies use
find_package
It defines a set of variables, like
find_package(SDL)
defines
SDL_INCLUDE_DIR
SDL_LIBRARY
for usage with respectively include_directories and target_link_libraries. CMake ships with a bunch of so called module files, like FindSDL.cmake and many others can be googled.
The next lower level is to use
find_path
find_library
which are used in the Find???.cmake modules itself.
The CMAKE_C_FLAGS variable is composed by CMake from these commands. Modifying it means you bypass CMake. There are cases, like for special optimization flags, you want to do this, but at this point all power and thus responsibility transfered from CMake to you.
By adding ws2_32.lib to the C_FLAGS, you are using it at compile time, and not link time. If you look at the error message, you can see it it treating the file as if it were a c++ source file: Cannot open source file: 'ws2_32.lib'. target_link_libraries(target ws2_32) should work.
You need to use the Target Link Libraries command. The target would be the executable you're building.
EDIT: You shouldn't specify the libs you're linking against in C_FLAGS. You can do something like TARGET_LINK_LIBRARIES(execName, ws_32, ...). I'm not 100% sure if you need the .lib. Been a while since I used CMake.