Is there a cmake compile feature for c++17's charconv? - c++

I have written some code that make use c++17's charconv, that I can compile just fine with g++ 9. Even though I have set the std to c++17 in my CMakeLists.txt, cmake insists on using c++ 7.5, which does not support charconv.
How do I tell cmake that I need a compiler that supports charconv ?
I see no switch in CMAKE_CXX_KNOWN_FEATURES.
Here is my CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
file(GLOB CLIENT_SRC "srcs/*.cpp")
include_directories("includes")
add_executable(client ${CLIENT_SRC})
set_target_properties(client PROPERTIES OUTPUT_NAME "distff-client")
target_compile_features(client PUBLIC cxx_std_17 )

Not a cmake guy... and I don't really understand cmake's approach to compile features here. But in C++ in general, we now use feature-test macros to detect the presence of features. You're looking specifically for __cpp_lib_to_chars.
I think you want to require compilation of this program:
#if __has_include(<version>)
# include <version>
#elif __has_include(<charconv>)
# include <charconv>
#else
# error "neither <version> nor <charconv> available to test"
#endif
#ifndef __cpp_lib_to_chars
# error "tochars not implemented"
#endif
Which can probably be generalized to something you can configure_file() for an arbitrary library feature (just pull out the header name and the macro name, and probably also check for the macro having the minimum required value).
Either way, if you try_compile() the resultant source file, you could probably get the behavior you want?

Not a CMAKE expert, but the easiest would be to set the CXX environment variable. Like so:
export CXX="/usr/bin/x86_64-linux-gnu-g++-9"
see more at How to specify a compiler in CMake?

Related

CMake doesn't link the actual object to the resulting dll [duplicate]

How do I define a preprocessor variable through CMake?
The equivalent code would be #define foo.
For a long time, CMake had the add_definitions command for this purpose. However, recently the command has been superseded by a more fine grained approach (separate commands for compile definitions, include directories, and compiler options).
An example using the new add_compile_definitions:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
add_compile_definitions(WITH_OPENCV2)
Or:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)
The good part about this is that it circumvents the shabby trickery CMake has in place for add_definitions. CMake is such a shabby system, but they are finally finding some sanity.
Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html
Likewise, you can do this per-target as explained in Jim Hunziker's answer.
To do this for a specific target, you can do the following:
target_compile_definitions(my_target PRIVATE FOO=1 BAR=1)
You should do this if you have more than one target that you're building and you don't want them all to use the same flags. Also see the official documentation on target_compile_definitions.
The other solutions proposed on this page are useful for some versions of Cmake > 3.3.2. Here the solution for the version I am using (i.e., 3.3.2). Check the version of your Cmake by using $ cmake --version and pick the solution that fits your needs. The cmake documentation can be found on the official page.
With CMake version 3.3.2, in order to create
#define foo
I needed to use:
add_definitions(-Dfoo) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
and, in order to have a preprocessor macro definition like this other one:
#define foo=5
the line is so modified:
add_definitions(-Dfoo=5) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
PLEASE NOTE (as #squareskittles suggests in one of the comment): "if you are using CMake 3.3.2, you have to use add_definitions() or target_compile_definitions(). The more modern command, add_compile_definitions(), was not added until CMake 3.12."
1.) target_compile_definitions
If you are using CMake 3.X your first choice for adding a preprocessor macro should be target_compile_definitions.
The reason you should prefer this approach over any other approach is because it granularity is target based. IE the macro will only be added to your exe/library.
Here is a common example:
if (WIN32)
target_compile_definitions(my_lib PRIVATE
# Prevents Windows.h from adding unnecessary includes
WIN32_LEAN_AND_MEAN
# Prevents Windows.h from defining min/max as macros
NOMINMAX
)
endif()
2.) add_compile_definitions
New in version 3.12.
Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html
add_compile_definitions applies macros to any targets that are defined after the call.
Here is the same logic as above with add_compile_definitions.
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX)
add_library(my_lib)
If you use this approach be careful if you are the top level project.
Otherwise if users consume your library using add_subdirectory they may have issues.
3.) The other less recommended ways
These approaches really aren't recommended anymore. Due to not being modular, not scaling well, not supporting generator expressions, etc.
add_definitions
CMAKE_LANG_FLAGS
Why is target_compile_definitions better/preferred?
It's much more clear to readers of your CMake code how it works.
Allows usage of PRIVATE/PUBLIC/INTERFACE if needed. Which can make life easier for consumers of your library.
It's much more modular.
Applying pre-processor flags (Or any compiler flag) globally can create hidden dependencies in your build.
Essentially think of add_compile_definitions as globals in C/C++. Sometimes you need them, but be careful.
i'd like to recommend use target_*** operations instead of add_*** operations when your solution include many projects.
here is an example where you can pass values from CMAKE to C++ code. Say, you want to pass:
flag, here: BOOST ("true" or "false")
software version string (e.g.: "1.0.0")
I recommend to pass them as strings.
So, when you build software with CMAKE, you can pass parameters like for example if it was built using boost library, software version pulled from CMAKE variable (so that you change that number only in one place)
See below.
In CMakeLists.txt:
add_compile_definitions(
BOOST="${BOOST}"
Software_VERSION="${PROJECT_VERSION}"
)
In your .cpp code:
std::cout << "Software version is: " << Software_VERSION << " BOOST: " << BOOST << "\n";
Hope this helps. Regards.

How to suppress Clang warnings in third-party library header file in CMakeLists.txt file?

I'm currently trying to setup a project that will make use of multiple compilers (including Clang, MSVC, and GCC) using Visual Studio 2019's new CMake functionalities (notably using Clang and Ninja in conjunction with CMake and VS2019).
I'm using CMake to configure the project to be "compiler-agnostic", so that I don't need to edit the code itself to handle different compilers via pre-processor instructions or #pragma instructions.
This project needs to be configured to have a high warning level (/W4 for MSVC, -Wall, -Wextra, and -Wpedantic for Clang), and must treat warnings as errors.
I don't have any issues when it comes to configuring the MSVC portion of the project. A lot of these settings have "sane" defaults that "just work" as I'd expect them to. When it comes to Clang, however, I've encountered a problem:
I can't seem to disable warnings for third-party library header files. I'm currently using the Dear Imgui and SFML libraries. Since Dear Imgui isn't pre-compiled, I simply do the following in my CMakeLists.txt file to include it:
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui
)
I use the statically linked version of SFML, so I do the following to include it:
# Find SFML and link statically to it.
# Note: We need to set the SFML_DIR variable manually.
set(SFML_STATIC_LIBRARIES TRUE)
set(SFML_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs/SFML-2.5.1/lib/cmake/SFML")
find_package(SFML 2.5.1 COMPONENTS system audio window graphics REQUIRED)
target_link_libraries(${PROJECT_NAME}
PRIVATE
sfml-system
sfml-audio
sfml-window
sfml-graphics
)
Sadly, SFML doesn't currently follow the current CMake standard way of adding libraries, so it's kind of weird to work with or configure it via CMake.
Now, the above works just fine when it comes to including the libraries in my project (but it might be something I need to change, so I've included it in the post). The problems come when I try to impose the warnings and warnings-as-errors configurations to them when using Clang.
Here are the parts of my CMakeLists.txt file which handle Clang and my C++ configurations:
# Set project to use C++ 17 standard.
set_target_properties(
${PROJECT_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
target_compile_options(${PROJECT_NAME} PRIVATE
# All warnings, warnings as errors, be pedantic.
-Wall
-Wextra
-Werror
-Wpedantic
# Disable warnings about C++98 incompatibility. We're using C++17 features...
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
)
Using the above configuration results in hundreds of warnings/errors in Dear Imgui's source files (due to the usage of "old-school" C++/C-style code), as well as a whole bunch of them in SFML's own source files and header files.
I've been looking for ways to get around this for nearly a week, before settling on the following solution (which doesn't entirely work, more on that later):
set(LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/libs")
set(IMGUI_FOLDER "${LIBS_FOLDER}/imgui")
set(SFML_FOLDER "${LIBS_FOLDER}/SFML-2.5.1/include/SFML")
file(GLOB LIBRARY_FILES
# Dear-imgui
"${IMGUI_FOLDER}/*.cpp"
"${IMGUI_FOLDER}/misc/freetype/*.cpp"
"${IMGUI_FOLDER}/misc/fonts/*.cpp"
"${IMGUI_FOLDER}/misc/cpp/*.cpp"
# SFML
"${SFML_FOLDER}/Audio/*.cpp"
"${SFML_FOLDER}/Graphics/*.cpp"
"${SFML_FOLDER}/Network/*.cpp"
"${SFML_FOLDER}/System/*.cpp"
"${SFML_FOLDER}/Window/*.cpp"
)
set_source_files_properties(
${LIBRARY_FILES}
PROPERTIES
COMPILE_FLAGS
"-Wno-everything"
)
I begin by GLOB-ing my library source files (NOTE: I know GLOB is usually looked down upon, but I felt like using it with third-party library files was fine since they're not supposed to change anyway). I then pass them to the set_source_files_properties function to apply the -Wno-everything flag, which seems to properly suppress all errors and warnings from those files.
Everything seems to work just fine, except for one warning which I can't seem to disable without using a #pragma instruction in my code (which I want to avoid). When compiling an empty main function that includes SFML headers, I get warnings about their .hpp files (which can't be passed to the set_source_files_properties function).
This:
#include <SFML/Graphics.hpp>
int main()
{
}
Results in the following warnings/errors:
zero as null pointer constant [-Werror,-Wzero-as-null-pointer-constant]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
In these respective SFML files:
ThreadLocal.hpp (57)
Keyboard.hpp (161)
Event.hpp (105)
PrimitiveType.hpp (52)
Other things I've tried that didn't work:
Putting the .h/.hpp files in the set_source_files_properties CMake function (alongside the .cpp files). Works for Dear Imgui, but all its errors were in .cpp files, not its headers. Doesn't work for SFML's headers.
(Not for SFML, but for Dear Imgui) Including the directories as SYSTEM includes to suppress the warnings. Doesn't appear to work on Windows. Can't really do this with SFML, since I'm using CMake's find_package function instead of doing everything manually.
Using #pragma instructions. While this worked, every SFML file has dozens of different errors, and I want to avoid using #pragmas everywhere (or wrapping SFML's headers in my own headers that just wrap the #include instruction in #pragmas).
Is it even possible to suppress these warnings for my library headers without #pragmas? I've never really used Clang before, so apologies if this seems like a simple question, but searching online hasn't really given me anything that would work:
Outside of a commandline (I'm using Visual Studio with CMake).
On Windows (the system flag doesn't seem to work with this setup).
That would work with CMake specifically.
You can mark the include paths as SYSTEM. Most compilers will not report warnings in system headers. In your case that might look something like this:
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui)
set_target_properties(sfml-system PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-system,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-audio PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-audio,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-window PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-window,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-graphics PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-graphics,INTERFACE_INCLUDE_DIRECTORIES>)
For example, this dummy project:
project(example)
cmake_minimum_required(VERSION 3.18)
add_library(dep INTERFACE)
target_include_directories(dep INTERFACE include)
file(WRITE include/header.h "static int a;")
add_library(lib STATIC lib.c)
target_link_libraries(lib PRIVATE dep)
target_compile_options(lib PRIVATE -Wunused -Werror)
file(WRITE lib.c "#include <header.h>")
Fails with:
$ cmake . && make
include/header.h:1:12: error: ‘a’ defined but not used [-Werror=unused-variable]
But after adding this line:
set_target_properties(dep PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:dep,INTERFACE_INCLUDE_DIRECTORIES>)
It builds with no errors.
There is a way to suppress warnings from third party headers in a CMake way.
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
The system keyword is most likely what you want.
If SYSTEM is specified, the compiler will be told
the directories are meant as system include directories on some platforms
The SYSTEM keyword adds -isystem for GCC/Clang. Instead of treating the directory like a normal include directory.
# GCC docs
Warnings from system headers are normally suppressed.
On the assumption that they usually do not indicate real problems
and would only make the compiler output harder to read.
For a while there was no solution for MSVC until recently in CMake 3.22, because the MSVC compiler finally added support for this.
Here is the MSVC blog post where they talk about the new compiler functionality.
The “Ninja” and “NMake Makefiles” generators now use
the MSVC “-external:I” flag for system includes.
This became available as of VS 16.10
(toolchain version 14.29.30037).

CMake: Set different name for #cmakedefine variable

I know you can use CMake's configure_file to make CMake variables available to your program. For example, I can use
#define ${CMAKE_BUILD_TYPE}
resulting in
#define Release
However, to keep my code more readible, I would prefer to define
#define BUILD_TYPE_RELEASE
Is there a simple way to achieve this?
Here is a fairly simple way to solve it:
In CMakesLists.txt:
if (NOT CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Release)
endif (NOT CMAKE_BUILD_TYPE)
string (TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE_NAME)
configure_file (config.h.in config.h)
And in config.h.in:
#define BUILD_TYPE_${BUILD_TYPE_NAME}
I am, however, still curious if there is a more elegant solution.
This is more a question of your preferred programming style (configuration files vs. compiler definitions).
In your case I would use add_definitions() or directly modify/append COMPILE_DEFINITIONS directory property (using generator expressions also supports multi-configuration environments):
set_property(
DIRECTORY
APPEND
PROPERTY
COMPILE_DEFINITIONS "BUILD_TYPE_$<UPPER_CASE:$<CONFIG>>"
)
Most simplified Debug/Release Check
You can also check what compiler definitions CMake does pre-define. Without having to modify/add something to your CMakeLists.txt files you could simply check for NDEBUG definition (set for Release builds across platforms) in you C/C++ code:
#ifdef NDEBUG
...
#endif
References
CMake: How to pass preprocessor macros
How to check if a CMake build directory build type is Debug or Release?
What predefined macro can be used to detect debug build with clang?

C++ Macro defined from outside .cpp or .hpp

I want to do something like an application that is build in debug or release mode.
Is it possible to define a macro outside the .cpp or .hpp?
I am using CMake. I have seen that add_definitions(...) is doing something like this. Shall I create two executables proj and proj_debug and for debug define a macro with add_definitions(...)? Is this a good approach? If not, how would you suggest me to do?
Use something like this:
target_compile_definitions(myproj PRIVATE $<$<CONFIG:Debug>:MY_DEBUG_MACRO>)
http://www.cmake.org/cmake/help/v3.0/manual/cmake-generator-expressions.7.html
http://www.cmake.org/cmake/help/v3.0/command/target_compile_definitions.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
This works with all generators and is the documented, right, supported way of doing it (and implemented by me :) ).
Man g++ http://linux.die.net/man/1/g++
Look for the -D option for defining macros
and you can configure your makefiles to set that option http://www.cmake.org/Wiki/CMake_Useful_Variables
set(CMAKE_CXX_FLAGS "-g -Wall -Dxxxx")
To define Macro in the different file can be done by following ways:
1) You can define Macro in any other .h file.
and include the file in .cpp file.
This can help you to define Macro in different file
To check the Macro for Debug and Release version use _Debug or _Release Macro.
2) Another way to do this is By using the way told by #Soren.
using set(CMAKE_CXX_FLAGS "-g -Wall -Dxxxx")
like this. Shall I create two executables proj and proj_debug and for debug
No need.
With cmake you can change the CMAKE_BUILD_TYPE variable when configuring your project. Then in your CMakeLists.txt you can do something like:
if(NOT CMAKE_BUILD_TYPE STREQUAL "Release")
add_definitions(-DMY_DEBUG_MACRO)
endif()
Then you can easily configure your project twice (in two directories): once with CMAKE_BUILD_TYPE set to Debug and once CMAKE_BUILD_TYPE set to Release.

Check CMake's option in C++ source

I have the following option defined in CMake:
option(OURAPP-DEV-USE_EXTREME_DEBUGGING "Use extreme debugging features" OFF)
and I would like to check in a C++ file that this option was checked (in the CMake-GUI) or not.
I.e. writing C++ code like:
#if OURAPP-DEV-USE_EXTREME_DEBUGGING
print_extra_debugging();
#endif
Please note, that our project setup requires that there is a - between the options regarding the components (such as OURAPP and DEV and the rest ...)
Any idea how to make it happen?
Transfer the CMake option to the C++ world using a preprocessor define.
IF(OURAPP-DEV-USE_EXTREME_DEBUGGING)
ADD_DEFINITIONS(-DUSE_EXTREME_DEBUGGING)
ENDIF()
Under the hood, this adds the define to the compiler command line, and is then available to the preprocessor:
#ifdef USE_EXTREME_DEBUGGING
print_extra_debugging();
#endif
Note that a hyphen is not a valid character in a C preprocessor token, so you'll have to change the name in the define.
You can also use cmake CONFIGURE_FILE, cf. http://www.cmake.org/cmake/help/cmake2.6docs.html#command%3Aconfigure_file