Needed clarity on CMAKE_NO_SYSTEM_FROM_IMPORTED property - cmake

Many of the open source projects include a set of directories with CMake's SYSTEM attribute. With this, these header files are provided to gcc with -isystem option:
include_directories(SYSTEM ${pybind11_INCLUDE_DIRS})
The inclusion of C++ headers using -isystem has issues on AIX as gcc on AIX by default adds implicit extern "C" for headers included with -isystem option. This causes templates in extern "C" errors on AIX. (More details can be found at here)
So, was trying to see if we can use any CMake feature to have -I option used for these C++ headers, though these are included with SYSTEM option on AIX. Otherwise, we need to change a whole lot of include_directories() invocations in these projects for AIX alone.
I came across CMAKE_NO_SYSTEM_FROM_IMPORTED attribute which sets the default value of NO_SYSTEM_FROM_IMPORTED for targets. But, setting it didn't override the SYSTEM attribute set in include_directories().
Please let me know whether we are using CMAKE_NO_SYSTEM_FROM_IMPORTED rightly and if there is any other CMake option to achieve the above.

Related

How would I include asio library using CMake?

I am trying to work on a project for a class and I want to use CMake to build the project. My current project looks like
|-bin
|-CMakeLists.txt
|-include
|-asio-1.12.2
|-chat_message.hpp
|-chat_message.cpp
|-CMakeLists.txt
|-src
|-Server.cpp
although my Server.cpp needs asio.hpp that is in /include/asio-1.12.2/include.
The professor has a makefile that compiles it with the flags
-DASIO_STANDALONE -Wall -O0 -g -std=c++11 -I./include -I./include/asio-1.12.2/include. My CMakeLists files look like this:
./CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.12)
PROJECT(Server VERSION 0.0.1)
SET(CPP_STANDARD 11)
SET(CPP_STANDARD_REQUIRED True)
ADD_SUBDIRECTORY(include)
ADD_EXECUTABLE(Server src/Server.cpp)
TARGET_LINK_LIBRARIES(
Server PRIVATE
chat_message
asio
)
./include/CMakeLists.txt
ADD_LIBRARY(
chat_message
chat_message.cpp
chat_message.hpp
)
ADD_LIBRARY(
asio
asio-1.12.2/include/asio.cpp
asio-1.12.2/include/asio.hpp
)
TARGET_INCLUDE_DIRECTORIES(
chat_message PUBLIC "${CMAKE_SOURCE_DIR}/include"
asio PUBLIC "${CMAKE_SOURCE_DIR}/include/asio-1.12.2/include"
)
How would I link the asio header file to the Server.cpp file WITH the flags needed?
First of all, as Tzyvarev pointed out in the comments, you must split the target_include_directories() command into two separate commands. This will then propagate asio and chat_message's include directories to your Server target, which will turn add the correct include flags to the compiler flags.
Note: I'd recommend switching from CMAKE_SOURCE_DIR to CMAKE_CURRENT_SOURCE_DIR and altering your paths accordingly to make your life slightly easier if in future you decide to change your project structure, as you will usually keep a CMakeLists.txt file in the same directory as the sources for a target it creates.
The -DASIO_STANDALONE option can be added with a target_compile_definitions() call:
target_compile_definitions(asio PUBLIC ASIO_STANDALONE)
Note you do not need the -D - CMake will generate the correct compiler flag for you. Also, since this is a requirement for the asio target and all its consumers will need it, it should be added to that, rather than its consumers - it will then propagate to dependencies as needed.
In your CMakeLists.txt you have set the CPP_STANDARD and CPP_STANDARD_REQUIRED variables. The one's you're after are CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED respectively.
This will set the flag for all targets throughout your project.
There are different ways to add the error, optimization and debug symbols flags and which one you use depends on your use case. The following is not an exhaustive list.
If you want everyone who builds the library to have these, irrespectively of build configuration (debug/release/etc), you set the CMAKE_CXX_FLAGS variable in your CMakeLists.txt
If you want everyone to have the flags, but only in certain build types, set the CMAKE_CXX_FLAGS_<CONFIG> variable, where <CONFIG> is the build type selected (DEBUG/RELEASE/MINSIZEREL/RELWITHDEBINFO are available by default)
If you don't want to force the flags upon everyone, before invoking CMake you can set the CXXFLAGS environment variable. But note that according to documentation this will be ineffective if CMAKE_CXX_FLAGS is set in your CMake scripts.
If you want to add flags to a single target, you can call target_compile_options on it, and set the appropriate visibility option to enable/disable propagation to consumers.
However in general you do need to think about portability when using these. For example GCC may support a certain flag which in Clang could be different.
Edit to address this comment
Since the header-only ASIO library does not like being compiled with the compiler definition mentioned above, there are two ways to address it:
Remove the ASIO_STANDALONE compiler flag
This will be the easiest thing to do from your point of view, but as a knock-on effect it will require you to have Boost installed on your system, as not having the flag above will cause the pre-processor to go through some Boost includes. There may be other effects, but this is the first one I encountered before moving on to the solution below.
Keep the flag, and use a CMake interface library
add_library() can allow you to add a target that does not actually produce any compiled objects/libraries/executables, but simply a logical CMake target that can posses properties just like any other ones - include directories, link libraries, etc. So as a minimum you could do this:
add_library(asio INTERFACE)
target_compile_options(asio INTERFACE ASIO_STANDALONE)
target_include_directories(asio INTERFACE <dir where asio.hpp lives>)
target_link_libraries(asio INTERFACE <threads>) # Using ASIO requires you link your final executable/library with your system's threading library (e.g. pthread on linux)
Then when you link another target with it like
target_link_libraries(any_lib PRIVATE asio)
any_lib will inherit all properties required to build with ASIO.
The solution you choose will be dictated by your use case, but if you have to do it the same way as your professor, then go the INTERFACE library route.

clang-tidy cmake exclude file from check

I have a dependency as source in my project that I have no control over.
I'm using cmake's clang-tidy integration to analyze my code, and this dependency is firing A LOT of warnings. Is there a way to tell cmake not to run clang-tidy on specific files ?
I tried to add the files to the -line-filter option of clang-tidy, but this doesn't work:
set_target_properties(target PROPERTIES
CXX_CLANG_TIDY "${clang_tidy_loc};\
${TIDY_CONFIG} \
-line-filter=\"[\
{\"name\":\"path/to/file.cpp\"},\
{\"name\":\"path/to/file.h\"}\
]\"")
If the solution could work with other static analyzers like cppcheck it would be really nice.
Thanks.
If some property - like CXX_CLANG_TIDY - is only available on target level, you have to move the files you want to have different settings for into a separate new target itself.
This can be done by using OBJECT libraries.
In your case something like:
add_library(
target_no_static_code_analysis
OBJECT
path/to/file.cpp
path/to/file.h
)
# NOTE: Resetting only needed if you have a global CMAKE_CXX_CLANG_TIDY
set_target_properties(
target_no_static_code_analysis
PROPERTIES
CXX_CLANG_TIDY ""
)
...
add_library(target ${other_srcs} $<TARGET_OBJECTS:target_no_static_code_analysis>)
References
CMake/Tutorials/Object Library
In case you have a header only library I use SYSTEM (should also be possible for OBJECT libraries)
add_library(
header_only_library_no_static_code_analysis
INTERFACE
)
target_include_directories(
header_only_library_no_static_code_analysis
SYSTEM # Adds -isystem instead of -I and this tells clang-tidy not to analyze these includes
INTERFACE
path/to
)
I couldn't use this approach for a long time due to following bug
https://bugs.launchpad.net/gcc-arm-embedded/+bug/1698539
But with GNU Arm Embedded Toolchain Version 9-2020-q2-update it seems resolved :)

Recompile with -fPIC Gentoo

I'm new to Gentoo and trying to install a 3D modelling program called TexGen (http://texgen.sourceforge.net/index.php/Main_Page) using CMake, and I keep getting the error:
relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
This occurs during the step:
[ 80%] Linking CXX shared module ../_Renderer.so
I've looked all over and tried setting the -fPIC flag in the cmake options file, but there's no change in the result. As I said I'm quite new (in the order of a few weeks) to Linux and Gentoo and any help would be greatly appreciated.
Actually Gentoo has a eclass(es) to build CMake based projects (see /usr/portage/cmake*.eclass). And AFAIK, it replace package options with yours (to be precise, it adds a new configuration type), configured in /etc/portage/make.conf (or /etc/paludis/bashrc if you use paludis). So, I not wondered that "hacking" CMakeLists.txt in the package ebuild do not help.
So, easiest way is to add that option to your Gentoo settings instead. Personaly I use this way to build boost library in my system (yep, I need boost's static libraries to be linked into dynamic one in some of my projects). And yes, I'm using paludis, but emerge probably has similar feature (a way to set per package compiler options).
The other way, instead of "hacking" compiler options directly (via CMAKE_<LANG>_FLAGS), take a look to CMAKE_POSITION_INDEPENDENT_CODE -- it'll add a proper compiler option for you, and probably eclass' manipulations with cache wouldn't affect this setting.
I got it to work (for installing ffmpeg) by simply reinstalling the whole thing from the beginning with all instances of $ ./configure replaced by $ ./configure --enable-shared (first make sure to delete all the folders and files including the .so files from the previous attempt).
Apparently this works because https://stackoverflow.com/a/13812368/10593190.

Building SDL2_image as a CMake external project

I've been trying to create a CMake-based build-system for a project that is supposed to use SDL2_image library. I do not want to force user to install any libraries to the system to be able to build the project, so I took advantage of the CMake's ability to download and build dependencies (freetype, SDL2 and SDL2_image) from source code as External Projects.
Everything is fine with freetype and SDL2 (which both include CMakeLists.txt files out of the box), but I've ran out of ideas how to make it work for SDL2_image. CMake's external projects support custom configuration and building settings which I used in different variants with no success.
The CMake file itself can be found here, but the problematic part is this:
# SDL_image library
ExternalProject_Add(sdl2_image_project
URL https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.0.tar.gz
DEPENDS sdl2_project
PREFIX ${LIBS_DIR}/SDL2_image
CONFIGURE_COMMAND LDFLAGS=-L${SDL2_BIN} CFLAGS=-I${SDL2_SRC}/include SDL2_CONFIG=${SDL2_BIN}/sdl2-config <SOURCE_DIR>/configure --prefix=<INSTALL_DIR> --enable-shared=no
BUILD_COMMAND make
INSTALL_COMMAND ""
)
An error occurs while building sdl2_image_project. Some trivial research discovered that the error is generated by the undefined references to parts of libdl. Here is a tiny part of the hole error:
libtool: link: gcc -I/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project/include -I/usr/local/include/SDL2 -D_REENTRANT -o showimage showimage.o -Wl,-rpath -Wl,/usr/local/lib -pthread -L/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project-build ./.libs/libSDL2_image.a -L/usr/local/lib -lSDL2 -pthread
/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project-build/libSDL2.a(SDL_dynapi.c.o): In function `get_sdlapi_entry':
/home/snikitin/_src/img_glypher/libs/SDL2/src/sdl2_project/src/dynapi/SDL_dynapi.c:227: undefined reference to `dlopen'
I think the problem takes place due to the fact that linker tries to create a shared version of SDL2_image library while linking it to a static libSDL2.a. The thing is - if this is right - SDL2 building step creates both static and shared versions of itself so one would assume that linker would use libSDL2-2.0.so instead (I do not actually need a shared library - just the static one, but I do not know how to prevent the build system from trying to create it apart from passing --enable-shared=no to SDL2_image configure script, which does not help in this case).
After a lot of googling I've discovered that the possible source of the problem is that sdl2-config (which is called to get some flags for compiler during SDL_image building) may be called with wrong arguments and produces wrong cflags which confuse everything else. But I'm not sure that is the case and also I do not know how to influence sdl2_config call from CMake (configure --help does not seem to unveil any useful options for this situation).
I am running Ubuntu 14.04 x64 if it matters in any way. Would appreciate any advice!
Looks like you need to link some libraries like m and dl. It can be fixed by providing
custom sdl2-config file. Copy sdl2-config from extracted archive and substitute --libs result:
--libs)
echo -L${exec_prefix}/lib -Wl,-rpath,${libdir} -pthread -lSDL2 -lm -ldl
;;
Note that order is important (that's why just modifying LIBS not works for me).
Now this file can be used in your ExternalProject_Add command instead of SDL2_CONFIG=${SDL2_BIN}/sdl2-config:
...
... CFLAGS=-I${SDL2_SRC}/include SDL2_CONFIG=${CMAKE_CURRENT_LIST_DIR}/sdl2-config <SOURCE_DIR>/configure
...

OSX Deprecation Warnings CMake

I'm building some code using CMake that should be compiled against the ScriptingBridge.
I'm seeing many tens of thousands of log lines such as:
In file included from /Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmapple.h:30,
from /Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/Security.h:25,
from /Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURLCredential.h:9,
from /Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:70,
from /Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/AppKit.framework/Headers/AppKit.h:10,
from /Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/include/apple/itunes.h:5,
from /Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/src/osx/itunes_scripting_bridge.m:1:
/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmtype.h:142: warning: ‘CSSM_GUID’ is deprecated
/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmtype.h:143: warning: ‘CSSM_VERSION’ is deprecated
/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmtype.h:156: warning: ‘CSSM_GUID’ is deprecated
/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmtype.h:197: warning: ‘CSSM_DATA’ is deprecated
/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmtype.h:217: warning: ‘CSSM_DATA_PTR’ is deprecated
/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework/Headers/cssmtype.h:220: warning: ‘CSSM_DATA’ is deprecated
(Full extensive output here)
The files are being compiled with:
/usr/bin/c++ -I/Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/include -I/Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/../libwatchedit/include -x objective-c -o CMakeFiles/whatsplaying.dir/src/osx/itunes_scripting_bridge.m.o -c /Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/src/osx/itunes_scripting_bridge.m
/usr/bin/gcc -I/Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/include -I/Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/../libwatchedit/include -F/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks -x objective-c -o CMakeFiles/whatsplaying.dir/src/osx/itunes_scripting_bridge.m.o -c /Users/codebeaker/Projects/watchedit-client-code/src/libwhatsplaying/src/osx/itunes_scripting_bridge.m
Having reviewed the man page for (Clang) gcc on my Mac, there's this which sounds interesting:
-Fdir
Add the framework directory dir to the head of the list of directories to be searched for header files. These directories are interleaved with those
specified by -I options and are scanned in a left-to-right order.
A framework directory is a directory with frameworks in it. A framework is a directory with a "Headers" and/or "PrivateHeaders" directory contained
directly in it that ends in ".framework". The name of a framework is the name of this directory excluding the ".framework". Headers associated with
the framework are found in one of those two directories, with "Headers" being searched first. A subframework is a framework directory that is in a
framework's "Frameworks" directory. Includes of subframework headers can only appear in a header of a framework that contains the subframework, or in
a sibling subframework header. Two subframeworks are siblings if they occur in the same framework. A subframework should not have the same name as a
framework, a warning will be issued if this is violated. Currently a subframework cannot have subframeworks, in the future, the mechanism may be
extended to support this. The standard frameworks can be found in "/System/Library/Frameworks" and "/Library/Frameworks". An example include looks
like "#include ", where Framework denotes the name of the framework and header.h is found in the "PrivateHeaders" or "Headers"
directory.
-iframeworkdir
Like -F except the directory is a treated as a system directory. The main effect is to not warn about constructs contained within header files found
via dir.
Maybe I ought to be looking for -iframework. When building with -iframework on the terminal, manually this completes without any deprecation warnings.
However CMake doesn't support an option to use -framework. From their find_library() documentation:
CMake will use a -framework A, and a -F to link the framework to the target.
I'm looking for any way to have a quiet build. I also have (4x) smaller warnings from OpenSSL'x EVA interface, those I can handle... thanks in advance.
The answer was to use -iframework, probably as this is intended to ignore system level deprecation warnings when you can't resolve them.
Instead I was able to use -Wno-deprecated-declarations, a flag to GCC which is documented and available everywhere. It's reliable, and I include it in my CMake declaration as such:
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
find_and_add_framework(Foundation watchedit)
find_and_add_framework(Cocoa watchedit)
find_and_add_framework(AppKit watchedit)
find_and_add_framework(ScriptingBridge watchedit)
set_source_files_properties(${sources} PROPERTIES COMPILE_FLAGS
"-xobjective-c -Wno-deprecated-declarations")
set_source_files_properties(${sources} PROPERTIES LANGUAGE C)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
For anyone who would benefit, here's the implementation of find_and_add_framework. I'm not sure where I cribbed it from, but it's not my own work:
macro(FIND_AND_ADD_FRAMEWORK fwname appname)
find_library(FRAMEWORK_${fwname}
NAMES ${fwname}
PATHS ${CMAKE_OSX_SYSROOT}/System/Library
PATH_SUFFIXES Frameworks
NO_DEFAULT_PATH)
if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
MESSAGE(ERROR ": Framework ${fwname} not found")
else()
TARGET_LINK_LIBRARIES(${appname} ${FRAMEWORK_${fwname}})
# MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
endif()
endmacro(FIND_AND_ADD_FRAMEWORK)