Cmake - select different c++ standard for different sources - c++

As the title suggest, I'd like to use cmake to build a project, and depending on the source file, enforcing a different c++ standard.
The reason is : I am working on a library and would like to make it c++03 compliant for compatibility, but would like to use Google test suite which requires c++11.
So the unit tests would be compiled with c++11, but I'd like my library to fail at compilation if there is reference to a c++11 only feature.

So just do that - ompile your library with one standard, and your tests with the other. Nowadays, https://stackoverflow.com/a/61281312/9072753 method should be preferred.
add_library(mylib lib1.cpp)
set_target_properties(mylib
PROPERTIES
CXX_STANDARD 03
CXX_EXTENSIONS off
)
add_executable(mytest main.cpp)
set_target_properties(mytest
PROPERTIES
CXX_STANDARD 11
CXX_EXTENSIONS off
)
target_link_libraries(mytest PRIVATE mylib)
add_test(NAME mytest COMMAND mytest)

You can do that, if they are used by different targets, using add_targrt_compile_options , as follows.
Assuming you want to use c++03 with the lib and c++11 with the exec, you may use something like what follows
add_executable(exec1 main.cpp)
add_library(lib1 STATIC lib1.cpp)
target_compile_options(lib1 PRIVATE -std=c++03)
target_compile_options(exec1 PRIVATE -std=c++11)

Related

Cmake Top level project has two dependent projects, one child is also dependent on the other child

I have Project A at the top.
Project A requires library B and library C.
Library B also requires library C by itself.
So, in short. How can I link libraries B and C up to A by just linking B?
I have it working now by individually linking all the libraries, but I feel like there is redundancy I could get rid of.
This is part of the CMAKE for Project A at the top:
find_package(libB REQUIRED)
include_directories(${libB_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libB_LIBRARY})
find_package(libC REQUIRED)
include_directories(${libC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libC_LIBRARY})
But also within libB I have this in its CMAKE:
find_package(libC REQUIRED)
include_directories(${libC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libC_LIBRARY})
I feel like there is a better way to do this, please let me know. Thank you for any help.
You can use target_include_directories (documentation) to specify include directories for your target instead of specifying them for all targets of the current directory using include_directories. Among other things, this gives the ability to provide visibility specifiers to your includes dirs, which control whether your include dirs will affect only current target (PRIVATE), only those targets which link to your target (INTERFACE) or both (PUBLIC). The same specifiers are used similarly for target_link_libraries.
So, you can use PUBLIC to avoid duplicating your lib C includes and libraries, and since it is the default specifier, you can omit it. Then, parts of your CMakeLists may look like this:
In project A CMakeLists.txt:
find_package(libB REQUIRED)
target_include_directories(${PROJECT_NAME} ${libB_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libB_LIBRARY})
In lib B CMakeLists.txt:
find_package(libC REQUIRED)
target_include_directories(${PROJECT_NAME} ${libC_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${libC_LIBRARY})
If you, e.g., want only lib B to link to lib C, but leave public 'inheritance' of include directories, you could change the last line of lib B CMakeLists.txt excerpt:
target_link_libraries(${PROJECT_NAME} PRIVATE ${libC_LIBRARY})

CSTDDEF file not found in GTest macOS

I'm trying to create a project in C using Gtest for unit tests.
For this, I have installed Xcode developer tools (because I'm in macOS big sur environment). and after this, I am cloning gtest and adding to submodules.
But, when I am trying to run test, the error appear :
googletest/googletest/include/gtest/gtest.h:52:10: fatal error: 'cstddef' file not found
After trying to reinstall Xcode tools, download the header to set it in my env, I have no more idea.
Do you have any idea to fix this or anybody had the same ?
Thank
PS : this is my CMakeLists
cmake_minimum_required(VERSION 3.0)
project(MasterDSA)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -o3")
add_library(Addition src/addition.c include/addition.h)
add_executable(Main src/main.c)
target_link_libraries(Main Addition)
set_target_properties(Main
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/bin")
set (gtest_force_shared_crt ON CACHE BOOL "MSVC defaults to shared CRT" FORCE)
add_subdirectory(googletest/googletest)
target_compile_definitions(gtest
PUBLIC
GTEST_LANG_CXX20
GTEST_HAS_TR1_TUPLE=0
)
add_executable(tests)
target_sources(tests
PRIVATE
test/addition_test.c
)
set_target_properties(tests PROPERTIES COMPILE_FLAGS "${cxx_strict}")
target_link_libraries(tests gtest gtest_main Core)
You are attempting to compile C++ code (in gtest.h) with a C compiler. (CMake chooses a C compiler for source files whose names end with .c.) C and C++ are different languages, not, generally speaking, source compatible in either direction. You must compile C with a C compiler, and C++ with a C++ compiler.
If considerable care is exercised then it is possible to write code in the shared subset of the two languages or that use the preprocessor to adapt to the chosen language, but this is uncommon, except sometimes for headers that declare functions and external objects having (from the C++ perspective) C linkage. That evidently is not how your gtest.h is written.
Your main options are:
convert your project to a C++ project. This has significant implications, so do not do it lightly.
write C++ tests for your C code. This may or may not be viable.
choose a C test framework instead of C++-specific GTest.

Add interface library as SYSTEM in modern CMake

I'm currently transforming my C++ project from simply using a Makefile to using CMake. As I'm unfamiliar with CMake, I try and avoid learning "old" CMake and stick to "modern CMake" best practices, e.g. described here.
However, I could not figure out how to include a simple, header-only, third party library without getting bothered with warnings about that library.
Say I have a project structure like this:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
third-party-lib/
foo/
foo.h
Say main.cpp uses foo: #include <foo.h>
The problem is, I use a bunch of warning flags and foo.h introduces some warnings that I don't care about, as I'm not the author and it's nothing serious.
In a classic Makefile I would just have written -isystem third-party-lib/foo somewhere appropriate and be done.
In CMake, I achieved this by a include_directories(SYSTEM PRIVATE third-party-lib/foo) in the top-level CMakeLists.txt.
Now, according to the link above, I should keep my hands off include_directories() to avoid hidden dependencies and I think that this is a good idea. I'd rather specify for each target that actually needs foo to include that library and treat it as 'don't warn me here'. As I understand it, the approach would be:
find foo target in top-level CMakeLists.txt
target_link_libraries(main PRIVATE foo) or so in src/CMakeLists.txt
How would I achieve that, i.e. what is the command for finding, and where to specify the SYSTEM property? Or any other suggestions for how to approach this?
To add a header-only library in modern CMake, you can use target_include_directories with SYSTEM INTERFACE. You can place this in your top-level CMake file, before processing the src/CMakeLists.txt file:
add_library(foo INTERFACE)
target_include_directories(foo SYSTEM INTERFACE
${CMAKE_SOURCE_DIR}/third-party-lib/foo
)
Your friend is target_include_directories. It works like include_directories but on a per-target basis.
add_executable(foo foo.c)
target_include_directories(foo SYSTEM
PRIVATE sys_inc
)

cmake add_library with minimum cpp standard

library needs atleast cpp14 but if cpp17 is available, it unlocks more features. I tried the below.
cmake_minimum_required(VERSION 3.10)
project(dummy)
add_library(awesomelib STATIC awesomelib.cpp awesomelib.h)
target_compile_features(awesomelib INTERFACE cxx_std_14)
add_executable(dummy14 main.cpp)
target_link_libraries(dummy14 awesomelib)
target_compile_features(dummy14 PRIVATE cxx_std_14)
add_executable(dummy17 main.cpp)
target_link_libraries(dummy17 awesomelib)
target_compile_features(dummy17 PRIVATE cxx_std_17)
What I want is:
dummy14 to compile using the C++14 standard
dummy17 and awesomelib to compile using the C++17 standard
But what happens is that awesomelib is compiled (only once) according to the c++14 std.
Update
I have shown the executables in the same file for simplicity. In real setup, the library would be in a separate project/repository and the users will be in a different project. I am looking for how the library can advertise its minimum requirements. i.e it needs at least c++14 standard and depending on the user, it has to be compiled with whatever latest version the user has.
I added a few changes to your CMkaeLists.txt file and it seems to work now
cmake_minimum_required(VERSION 3.10)
project(dummy)
set (CMAKE_CXX_STANDARD 17)
add_library(awesomelib STATIC awesomelib.cpp awesomelib.h)
target_compile_features(awesomelib INTERFACE)
add_executable(dummy17 main.cpp)
target_link_libraries(dummy17 awesomelib)
target_compile_features(dummy17 PRIVATE cxx_std_17)
set (CMAKE_CXX_STANDARD 14)
add_executable(dummy14 main.cpp)
target_link_libraries(dummy14 awesomelib)
target_compile_features(dummy14 PRIVATE cxx_std_14)

CMake's equivalent to Visual Studio's Property Sheets (.vsprops)

I'm trying to migrate from Visual Studio towards Jetbrains' (awesome) CLion IDE which uses CMake to organize the projects.
Until now, the transition has been smooth: creating CMake projects and importing them into CLion is easy, and I can begin coding on one plateform then continue on another one without problems.
However, one aspect of Visual Studio that I couldn't find an equivalent to in CMake is property sheets: I use them mainly for holding the include directories' paths and the linking libs for libraries (i.e. one .vsprops file for each library, e.g. OpenCV.vsprops, Boost.vsprops, etc.).
This way, in VS, I could share a library's .vsprops file between different projects without having to configure the paths/libs each time.
Does CMake have a similar mechanism to Visual Studio's property sheets ? How is it possible to store a library's includes/libs in a CMake-parsable file then "import" it in CMakeLists.txt in order to link against the library ?
Basically, what I want to do is:
Create a "cmake property sheet" (for lack of a better name) for a given library.
Then, in CMakeLists.txt, write something like link_target_to_libs(myTarget "path/to/propertySheet1" "path/to/propertySheet2" ...) .
In CMake, libraries can export a package with IMPORTED targets which other buildsystems import using find_package:
http://www.cmake.org/cmake/help/v3.1/manual/cmake-packages.7.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#imported-targets
Instead of 'linking to property sheets', you link to the IMPORTED targets.
target_link_libraries(myTarget Dep1::Dep1 Dep2::Dep2)
Not all libraries create IMPORTED targets, and not all provide cmake config-file packages. In those cases (including OpenCV and Boost), CMake provides find modules:
http://www.cmake.org/cmake/help/v3.0/manual/cmake-developer.7.html#find-modules
which you use with find_package and link to the contents of variables.
Since I really want to make the libraries' inclusion/linking into a one-line command, and as far as my (basic) knowledge of CMake goes, I think that some compromise should be made -- mainly sharing the target name's variable between CMakeLists.txt and the "property sheets". So this is my solution... until someone proposes a simpler/cleaner one:
A CMake property sheet is a .cmake text file,
A well-known variable name --TARGET-- designates the target (i.e. the first argument of add_executable()),
Aside from library-specific commands, a .cmake file contains a call to target_include_directories(${TARGET} PRIVATE ${PATH_TO_INCLUDE_DIR}) and target_link_libraries(${TARGET} ${LIST_OF_LIBS}),
In order to use/link against a library, call include("path/to/.cmake") in CMakeLists.txt.
I have successfully built and executed a simple program that uses X11 and OpenCV with the following files:
x11.cmake
target_include_directories(${TARGET} PRIVATE "/usr/include/X11")
target_link_libraries(${TARGET} "/usr/lib/x86_64-linux-gnu/libX11.so")
opencv.cmake
# OpenCV-specific stuff
set(OpenCV_DIR "/PATH/TO/OPENCV/INSTALL/DIR/share/OpenCV") # path to OpenCVConfig.cmake
find_package(OpenCV REQUIRED)
# include path
target_include_directories(${TARGET} PRIVATE ${OpenCV_INCLUDE_DIRS})
# linking libs
target_link_libraries(${TARGET} opencv_world opencv_ts)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.4)
project(hello_clion)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
## hello-clion ##############################
# make a new target name
set(TARGET hello-clion)
# find sources
file(GLOB_RECURSE SOURCE_FILES "src/*.cpp" "src/*.hpp")
# declare a target
add_executable(${TARGET} ${SOURCE_FILES})
# link the libraries (to the last-declared ${TARGET}, which should be the last-added executable)
include("x11.cmake")
include("opencv.cmake")
#############################################
main.cpp
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <thread>
#include <opencv2/opencv.hpp>
#include <Xlib.h>
int main_x11()
{
// adapted from: http://rosettacode.org/wiki/Window_creation/X11#Xlib
}
int main_ocv()
{
// adapted from: http://docs.opencv.org/doc/tutorials/introduction/display_image/display_image.html#source-code
}
int main()
{
using namespace std;
thread tocv(main_ocv);
thread tx11(main_x11);
tocv.join();
tx11.join();
return 0;
}
Now, each time I want to use OpenCV in a project/program, I just have to put include("opencv.cmake") in the corresponding CMakeLists.txt.
This seems to work great, but there could certainly be problems I haven't discovered. (I was worried multiple macros adding the same target_link_libraries would cause "already defined" linking errors , but at least g++ 5.1.0 handles being given the same library name multiple times without error.)
In root CMakeLists.txt, BEFORE add_subdirectory() calls or globs, include:
macro(USES_WX)
include_directories(SYSTEM /usr/local/include/wx-3.0)
include_directories(SYSTEM /usr/local/lib/wx/include/gtk3-unicode-3.0)
link_directories(/usr/local/lib)
add_definitions(-D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXGTK__ -pthread)
target_link_libraries(${TARGET} pthread wx_gtk3u_xrc-3.0 wx_gtk3u_html-3.0 wx_gtk3u_qa-3.0 wx_gtk3u_adv-3.0 wx_gtk3u_core-3.0 wx_baseu_xml-3.0 wx_baseu_net-3.0 wx_baseu-3.0)
endmacro()
(You can make the macro more fancy, like checking for if CMAKE_BUILD_TYPE is "Debug" or "Release" to link to the appropriate libraries, vary preprocessor definitions, etc. See http://www.cmake.org/cmake/help/v3.0/command/if.html)
And have your project's CMakeLists.txt be like this:
set(TARGET myProgramName)
add_executable(${TARGET} myProgramName.cpp)
USES_WX()
^^ The macro call MUST be after add_executable()
And, if you want multiple target support, modify the line in the root CMakeLists.txt section shown above to:
...
target_link_libraries(${ARGV0} pthread wx_gtk3u_xrc-3.0 ...)
...
And have your project's CMakeLists.txt be like this (less lines, but more chance for error):
add_executable(myProgramName myProgramName.cpp)
USES_WX(myProgramName)