CMake/make apply -D flags on header files - c++

I'm (cross-)compiling a shared C library with support for many different platforms which is handled by an hierarchy of CMakeLists files. In those files, several platform specific compiler flags are conditionally produced (with add_definitions()). I can successfully compile and link the source code leading to an appropriate .so file.
But to use the library in any project, I need to provide the right header files, too. The following install command of CMake selects the right header files to copy but does not apply the replacement of preprocessor defines/includes:
install(FILES ${headers} DESTINATION include/mylibrary)
So how can I generate/install the "post-compiled" header files?
What I thought of so far:
As add_definitions() should stack my -D's in the COMPILE_DEFINITIONS variable, maybe running a foreach loop on the copied raw headers and replace the define/include placeholders?
Using add_custom_command() to apply some logic before copying?
Edit: As pointed out by Tsyvarev, there is an answer quite near to my needs here, but unfortunately not quite it. In summary, the answer gives 2 options:
Include a special 'config' header in all of the library's headers and leverage the cmakedefine command to call configure_file() on this header. I can't use this approach because I don't want to alter the library headers.
Create a target-specific .cmake file which helps external projects in including the right headers together with all necessary -D defines. I can't use this approach either, because my external projects do not use cmake for building. Plus, I wish to create a library that is as easy to include as possible.
Any other thoughts?
Edit 2: I may have to elaborate on my statement, that the install command of CMake is not replacing defines. Take the following example:
//sampleheader.hpp
#ifndef SAMPLEHEADER_HPP_
#define SAMPLEHEADER_HPP_
#include OS_SPECIFIC_HEADER
//...
Now I have a CMakeLists.txt file that does something like this:
# ...
if (${OS} MATCHES "arm-emblinux")
add_definitions(-DOS_SPECIFIC_HEADER="emblinuxHeader.hpp")
elseif (${OS} MATCHES "linux")
add_definitions(-DOS_SPECIFIC_HEADER="linuxHeader.hpp")
endif()
# ...
Everything compiles fine, but when the install command above gets called, I have a header file in my ../include/ directory still with OS_SPECIFIC_HEADER placeholder in it. And of course, this cannot be properly included in any development project.

Related

Pretend headers are in a certain subdirectory?

Note: I'm currently tinkering with more modern CMake styles, not trying to accomodate an existing project. I'd consider alternative approaches to what I am doing as perfectly acceptable as long as they are scalable (i.e., downstream target shouldn't need to know about the internals of the upstream target).
Let's say I have two targets in the same CMake build, down and up, where down depends on up:
target_link_libraries(down PUBLIC up)
Let's say the headers of up are inside up/src/:
+---up
+---CMakeLists.txt
+---src
+---header.hpp
+---<other headers/sources>
Now let's say that inside down I want to include the headers of up like so:
// down/foo.cpp
#include "up/header.hpp"
If down is an external dependency (i.e. in a separate CMake build), that's easy: I just have to install all the headers of up in some kind of include/up/ directory and then use that:
target_include_directories(up
INTERFACE
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/up>")
But what if down is part of the same CMake build as up? I want to uniformize the code; I don't want down's sources to have to do any of...
#include "up/src/header.hpp"
#include "src/header.hpp"
#include "header.hpp"
The headers of up wouldn't be installed inside include/up until after all the targets, including down, would be built, since down is inside the same CMake build.
Is that sort of thing even possible without using horrible manual file copies? Should I just put all up's sources inside a up/src/up/ directory then?
My motivation is: up might be depended on by libraries both inside and outside the CMake build, so I want to uniformize the code accross internal and external targets.
If you want #include "up/header.hpp" to work, then the file header.hpp should be physically located in the directory up. This is how all major compilers work, so CMake simply cannot "emulate" location of a header file.
However, it is quite easy to copy headers into desired directory. E.g. by using file(COPY) command. List of files to copy can be obtained using file(GLOB), like in that answer:
file(GLOB UP_HEADERS /path/to/up/src/*.h)
file(COPY ${UP_HEADERS} DESTINATION /path/to/some/dir/include/up)

CMake how to include headers without sources?

This is probably a dummy question but I have literally looked at the two first pages of google without success.
I'm writing a header only library and I'm unable to set up correctly the CMake configuration in order that when I build my solution a given main.cpp finds the proper includes.
How can this be accomplished?
EDIT
So I probably should give a little more detailed explanation.
Lets say I have a ./src folder with: ./src/core and ./src/wrappers. Inside each folder I have .h files that needs to be included in a main.cpp file:
#include <src/core/reader.h>
Still when I put in CMakeList.txt something like:
include_directories(src/core)
add_executable(main main.cpp)
I receive a message like: src/core/reader.h no such file or directory.
To be able to use that path, you should refer to the parent directory of src.
Assuming the top level CMakeLists.txt is at the same level of src, you can use this instead:
include_directories(${CMAKE_SOURCE_DIR})
As from the documentation of CMAKE_SOURCE_DIR:
The path to the top level of the source tree.
If src is directly in the top level directory, this should let you use something like:
#include <src/whatever/you/want.h>
That said, a couple of suggestions:
I would rather add this:
include_directories(${CMAKE_SOURCE_DIR}/src)
And use this:
#include <whatever/you/want.h>
No longer src in your paths and restricted search area.
I would probably use target_include_directories instead of include_directories and specify the target to be used for that rules:
target_include_directories(main ${CMAKE_SOURCE_DIR}/src)
This must be put after the add_executable, otherwise the target is not visible.
Another option which might make sense in some situations would be to create a dedicated target for the header-only library:
add_library(headerlib INTERFACE)
target_include_directories(headerlib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
And then to use it:
target_link_libraries(mytarget headerlib)
This has the advantage that if you want to use it in multiple targets, it's easy to do so.
Just add a include_directories() directive in order to find where your header only library can be found by the target project.
According to your edit. To find
#include <src/core/reader.h>
You need to add
include_directories(/full_parent_path_of_src)
If I understand your question correctly then in your CMakeLists.txt you need to add include_directories(<DIRECTORY>) for every directory of your header library.

Correct installation of config.h for shared library using autotools

I am converting a C++ program which uses the autotools build system to use a shared library, introducing the use of libtool. Most of the program functionality is being placed in the shared library, which is loaded by the main program, so that the common code can be accessed by other programs in future.
Throughout the program and library sources the autoheader generated config.h is used with the usual macro:
#if HAVE_CONFIG_H
# include <config.h>
#endif
In configure.ac I use the macro to generate it:
AC_CONFIG_HEADERS([config.h])
My question is, do I need to install config.h for others to be able to use my library, and if so, what is the appropriate way to do it, and should it be renamed to avoid conflicts etc?
The most information I have found on this is here:
http://www.openismus.com/documents/linux/building_libraries/building_libraries#installingheaders
But this is hardly an official source.
Never ever install autoheader's config.h.
The last thing the users of your library need is interference from the macros leaking out of your config.h. Your library may have HAVE_FOOBAR, but my software might be compiled in a way that foobar is disabled, so that HAVE_FOOBAR will break my compilation.
The AX_PREFIX_CONFIG macro from the archive is a workaround, where everything gets prefixed.
A better approach is to create a template file (e.g. blargconfig.h.in) with lines like:
typedef #BLARG_TYPE# blarg_int_t;
#BLARG_RANDOM_INCLUDE#
And then AC_SUBST() those variables in configure.ac:
AC_SUBST(BLARG_TYPE, ["unsigned short"])
AC_SUBST(BLARG_RANDOM_INCLUDE, ["#include <somerandomheader.h>"])
Then list it as an output file:
AC_CONFIG_FILES([Makefile
src/Makefile
...
include/blargconfig.h])
The .h file should be listed with nodist_include_HEADERS; the .h.in file will be automatically distributed because it's listed in AC_CONFIG_FILES.
Destination for such files is commonly $libdir/packagename/include. See GLib for example, although they generate glibconfig.h without a template (by writing the whole creation code inline in configure.ac, as the autobook suggests). I find this approach less maintainable than using AC_SUBST, but it's more flexible.
Of course, to help the compiler find the platform-dependent header you'll probably also want to write a pkgconfig script, like GLib does.
You will need to install config.h if it affects the interface. In practical terms, if the #define's are required by the header(s), not just the .cc implementation / compilation units.
If config.h is a problem, you can specify another name in the AC_CONFIG_HEADERS macro. e.g., AC_CONFIG_HEADERS([foo_config.h]).
The easiest way to install the header, assuming automake, is with:
nodist_include_HEADERS = foo_config.h
in the top-level Makefile.am. the nodist prefix tells automake that foo_config.h is generated rather than distributed with the package.
If not using automake, install foo_config.h in $includedir. $exec_prefix/include is arguably a more correct location for a generated header, but in practice the former location is fine.
I avoid using config.h, by passing relevant definitions in CPPFLAGS or foo_CPPFLAGS along with AC_SUBST to Makefile.am for source builds, or AC_SUBST to foo.h.in to generate headers at configure-time. A lot of config.h is test-generated noise. It requires more infrastructure, but it's what I prefer. I wouldn't recommend this approach unless you're comfortable with the autotools.

Using cmake's automoc on external header files without knowing their filenames

In essence I want to be able to moc header files that are not part of any target in cmake with the additional difficulty that I don't know the filenames of those headers.
The actual project is quite complex and part of an automated build system. The following is an easy example.
Consider a project structured like this:
CMakeLists.txt
src/lib/source.cpp
src/lib/CMakeLists.txt
src/include/some_header.hpp # which is included in source.cpp
Content of main CMakeLists.txt:
cmake_mimimum_required(VERSION 2.8.6)
project("automoctest")
add_subdirectory(src/lib)
Content of src/lib/CMakeLists.txt:
include_directories(${CMAKE_HOME_DIRECTORY}/src/include)
find_package(Qt4 4.8 REQUIRED QtCore)
include(UseQt4)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(foo SHARED source.cpp)
target_link_libraries(foo ${QT_LIBRARIES})
set_target_properties(foo PROPERTIES AUTOMOC true)
Inside source.cpp the file some_header.hpp is included like this:
#include "some_header.hpp"
The Problem:
The file some_header.hpp includes a Q_OBJECT and has some signals, so moc needs to work its magic. But as the header is not inside the actual project the header will not get mocked. I don't even know the filename of some_header.hpp so I can't add it specifically to be mocked. Obviously AUTOMOC does not check the include_directories for mockable files even when a source file includes one of them.
What I tried (unsuccessfully):
use #include moc_some_header.cpp in source.cpp as it is described in the cmake documentation. This leads to an error in which cmake complains that it could not find some_header{.h,.hpp,.hxx,.H}
setting CMAKE_AUTOMOC_RELAXED_MODE to true. Even though it's not clear from the doc what this actually does. Made no difference anyway.
setting AUTOMOC_MOC_OPTIONS to -Isrc/include or -I/path/to/project/src/include or -I${CMAKE_HOME_DIRECTORY}/src/include Doesn't do anything that I could see.
The great thing about AUTOMOC is that I don't need to know which files actually need to be mocked. In this case however I would need to know all the headers that might have a Q_OBJECT inside, that are included by my source files.
Is there a way to tell AUTOMOC where exactly to look for mockable files?
Did you truly set AUTOMOC_MOC_OPTIONS to -Isrc/include, or to -I/path/to/myproject/src/include? The former probably doesn't exist.
I have always used the MOC macros; it looks like AUTOMOC is something new that is built into CMake.
I usually include all headers when creating a library or executable - i.e.
add_library(foo SHARED source.cpp ../include/some_header.hpp )
I assume that this will allow AUTOMOC to work. It will have the added benefit of causing make to work as expected - rebuilding your library when the header changes.
If you are truly unable to add the file to the add_library command ahead of time, then I think you'll have to write a cmake function to search for #include statements within source.cpp, locate those files, and search them for Q_OBJECT. If they match, add them to a variable - perhaps EXTRA_MOCS. Then, the add_library line becomes
add_library(foo SHARED source.cpp ${EXTRA_MOCS} )

CMake: ordering of include directories (How to mix system- and user-based include paths?)

I've got a CMake project that includes and links against two libraries, say A and B (actually it's more than two and one of them is boost stuff, but that doesn't really matter here). Both are located via FindSomething.cmake scripts that (correctly) populate the standard CMake variables such that include directories are added via
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${B_INCLUDE_DIRS})
and linking is later done via
TARGET_LINK_LIBRARIES(mytarget ${A_LIBRARIES} ${B_LIBRARIES})
Now, the problem is that both libraries can either reside in a user based location or in the system directories (I'm on linux by the way, CMake 2.8.2) - or in both. Let's say A is only in $HOME/usr/include and $HOME/usr/lib while B (boost in my case) resides in both the system paths (/usr/include and /usr/lib) AND in the user based paths - in different versions. The find scripts can be made to find either the system or the user-based library B, this works.
The trouble starts when I want to link against B from the system paths.${B_INCLUDE_DIRS} and ${B_LIBRARIES} correctly point to the system-wide locations of the headers and libraries. But there is still ${A_INCLUDE_DIRS} that points to a non-system include directory and ultimately also the headers for library B are taken from this location, while the linking for B uses the version from the system paths (via ${B_LIBRARIES}) which leads to conflicts, i.e. linking errors.
Changing the order of the INCLUDE_DIRECTORIES statements does not seem to change anything. I checked the origin of the symbols that cause the linking errors via nm --line-numbers on the object files.
What can I do? Is there a trick to
force the ordering of the include directories (even if this would mean to give precedence to a system path although there is also a user-based location specified)?
tell CMake to use ${A_INCLUDE_DIRS} for all headers from A and ${B_INCLUDE_DIRS} for all headers from B?
Here's what CMake says about include_directories():
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
You can specify that you want to have include directories searched before or after the system include directories at the time that you tell it about those directories.
You may also be specific to a target:
target_include_directories(target [SYSTEM] [BEFORE] [items1...] [ [items2...] ...])
If A and B are different libraries containing different header files and paths, there should be no problem doing what you are doing right now.
That being said, if A and B are similar libraries containing header files of the same name at the same location, that is problematic. In that case, the order of the include_directory() call is important. I ran a little test where I had three copies of a header file. The first copy is located in my system path (say /usr/include). The other copies are located in two user-defined locations (say /tmp/include1 and /tmp/include2). The file in /tmp/include1 is found and used first if I put the include_directory() call in the following order:
include_directory("/tmp/include1")
include_directory("/tmp/include2")
The file in /tmp/include2 is found and used first if I put the include_directory() call in the following order:
include_directory("/tmp/include2")
include_directory("/tmp/include1")
If I put no include_directory() statement, then the header in the system path is found and used.
You may want to re-check how your FindSomething.cmake are written. The search order of the find_*() CMake commands can be found in the CMake documentation,
As far as I can remember, there is now way of telling CMake to use ${A_INCLUDE_DIRS} for all headers from A and ${B_INCLUDE_DIRS} for all headers from B if the header file can be found in both location. It all depends in what order the include_directory() call are made. If the FindSomething.cmake are written properly, if the CMAKE_MODULE_PATH (this is the location where CMake will look for the Find*.cmake files) is set properly and all the paths are good, then you should be good to go. If not, I will need more information on your current CMake/library setup.
When using third party libraries, I would always do this
Library A + B header files:
third_party/include/libA_name/ <-- put header files in there
third_party/include/libB_name/ <-- put header files in there
In source files you would always use it like this
#include "libA_name/file.h" <-- no ambiguity possible
#include "libB_name/file.h" <-- no ambiguity possible
Then you can still use -I "third_party/include" as the include folder and no ambiguity in ordering will happen in source files.
This also disambiguates custom header files from system header files which could clash from time to time from 3rd party libs.
For me this worked fine:
INCLUDE_DIRECTORIES(BEFORE ${A_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${B_INCLUDE_DIRS})