Pretend headers are in a certain subdirectory? - c++

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)

Related

CMake/make apply -D flags on header files

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.

How to namespace C++ header files?

I use a code with different libraries, which use names like defines.h. This does not only cause conflicts for identical filenames, but also creates confusion. From which library is the defines.h include?
Including as #include <library/defines.h> would be a clean solution, but then the include path would need to be the parent directory of the library, which is rather unclean again.
Is there some way to alias the include path, so that -I/path/to/library makes the headers available under library/headername.h?
Is there some way to alias the include path, so that -I/path/to/library makes the headers available under library/headername.h?
There seems to be no need to in this case. You can simply use -I/path/to which makes /path/to/library/headername.h available under library/headername.h.
That said, while there is no such compilation option (that I know of), you can create such "aliases" to file paths in most file systems. These aliases are called symbolic links. In this case, you could make a link /path/to/library/mylibrary that points to . which would make /path/to/library/headername.h available under mylibrary/headername.h assuming you've used -I/path/to/library.
At least on unixy systems, when you compile and install a library, headers are installed for example to
/usr/lib/libraryname/*.h
Or maybe something like
/opt/libraryname-1.2/include/libraryname/*.h
And then if necesssry (not installing to compiler's default include search path), right dir is added with compiler option, for gcc for example option
-I/opt/libraryname-1.2/include
Then just always do this in source code, trusting build system to have included the right search paths:
#include <libraryname/includefile.h>

How can I include directories with project relative paths in CMake?

I am developing a product with a team using CMake. We have several Visual Studio projects (libraries and executables) inside of our CMake project which reference other project headers (via target_include_directories()). In a source file these header includes look like:
#include "some_header.h" // from project_x
#include "another_header.h" // from project_y
I'd like to be able to include these headers with paths that reference the project they are pulled from, e.g.:
#include "project_x/some_header.h"
#include "project_y/another_header.h"
What is the most acceptable way to do this? I have thought of a couple solutions:
Add the directory which contains the project as an include path. This has the undesirable side-effect of including everything and seems like a bad solution.
Include a subfolder of the project called 'include' which contains a folder named with the same as the project, which creates a slightly redundant path: /<project_name>/include/<project_name>/<...>
There is a third solution, to use a shared include directory with a subfolder for each project, but it will not work for our project because we group our build projects by category in the file system and Visual Studio solution and it will cause the folder structure inside of /include/ to diverge from the rest of source tree which is undesirable.
Are there any better (or more canonical/idiomatic) ways to accomplish this?
If you have a project structure like this:
project_x/some_header.h
project_y/another_header.h
and you want to keep all of your CMakeLists the same, then I would introduce another folder in each project:
project_x/project_x/some_header.h
project_y/project_y/another_header.h
Of course, this requires changing the includes in each project to reflect this new structure, including the project where the header is defined proper.
There's some precedence to this, as this is how curl and googletest do it.
Edit: I understand this is very similar to the second approach you outlined. If your directory structure already employs include directories, then my suggestion is exactly the same as your second one. At the very least, this should confirm your intuition that this isn't an entirely absurd thing to do, even if it creates some redundancy.

MACRO depending on its folder location

In the following files:
app/main.cpp
app/config.hpp
app/show.hpp
app/file.hpp
lib/append.hpp
lib/clear.hpp
lib/reopen.hpp
lib/crypt.hpp
I have a problem. Imagine a few of my files use lib/crypt.hpp. For example in app/file.hpp I should write:
#include "../lib/crypt.hpp"
If I take this file to lib folder it does not work anymore. So I need a something like:
#include "LIB/crypt.hpp"
So, this LIB/ has meaning of (empty) in lib directory while it has meaning of "../lib/" in app directory.
Then I will have no worry about moving file.hpp from app to lib. I just need to fix the callers of it. But not what it calls.
Similar to concept of web programming frameworks. Is it possible in C/C++?
According to what you wrote you're searching for a way to move your sources around without worrying for hard-coded paths to your headers.
You didn't specify the compiler you're using so I'm not focusing on a specific one, anyway most C++ compilers have an option to specify one or more header search paths (on gcc you would just use something like -Ilib_parent_dir).
Once you've included your lib's parent path to the search list, you can move your sources around (as long as you don't move lib's headers) and have them include the right headers with something like #include <lib/crypt.hpp> (and keep include paths priority in mind)
This should be a cleaner and simpler way to achieve what you asked rather than using a macro.

Header files dependencies between C++ modules

In my place we have a big C++ code base and I think there's a problem how header files are used.
There're many Visual Studio project, but the problem is in concept and is not related to VS. Each project is a module, performing particular functionality. Each project/module is compiled to library or binary. Each project has a directory containing all source files - *.cpp and *.h. Some header files are API of the module (I mean the to the subset of header files declaring API of the created library), some are internal to it.
Now to the problem - when module A needs to work with module B, than A adds B's source directory to include search path. Therefore all B's module internal headers are seen by A at compilation time.
As a side effect, developer is not forced to concentrate what is the exact API of each module, which I consider a bad habit anyway.
I consider an options how it should be on the first place. I thought about creating in
each project a dedicated directory containing interface header files only. A client module wishing to use the module is permitted to include the interface directory only.
Is this approach ok? How the problem is solved in your place?
UPD On my previous place, the development was done on Linux with g++/gmake and we indeed used to install API header files to a common directory is some of answers propose. Now we have Windows (Visual Studio)/Linux (g++) project using cmake to generate project files. How I force the prebuild install of API header files in Visual Studio?
Thanks
Dmitry
It sounds like your on the right track. Many third party libraries do this same sort of thing. For example:
3rdParty/myLib/src/ -contains the headers and source files needed to compile the library
3rdParty/myLib/include/myLib/ - contains the headers needed for external applications to include
Some people/projects just put the headers to be included by external apps in /3rdParty/myLib/include, but adding the additional myLib directory can help to avoid name collisions.
Assuming your using the structure: 3rdParty/myLib/include/myLib/
In Makefile of external app:
---------------
INCLUDE =-I$(3RD_PARTY_PATH)/myLib/include
INCLUDE+=-I$(3RD_PARTY_PATH)/myLib2/include
...
...
In Source/Headers of the external app
#include "myLib/base.h"
#include "myLib/object.h"
#include "myLib2/base.h"
Wouldn't it be more intuitive to put the interface headers in the root of the project, and make a subfolder (call it 'internal' or 'helper' or something like that) for the non-API headers?
Where I work we have a delivery folder structure created at build time. Header files that define libraries are copied out to a include folder. We use custom build scripts that let the developer denote which header files should be exported.
Our build is then rooted at a substed drive this allows us to use absolute paths for include directories.
We also have a network based reference build that allows us to use a mapped drive for include and lib references.
UPDATE: Our reference build is a network share on our build server. We use a reference build script that sets up the build environment and maps(using net use) the named share on the build server(i.e. \BLD_SRV\REFERENCE_BUILD_SHARE). Then during a weekly build(or manually) we set the share(using net share) to point to the new build.
Our projects then a list of absolute paths for include and lib references.
For example:
subst'ed local build drive j:\
mapped drive to reference build: p:\
path to headers: root:\build\headers
path to libs: root:\build\release\lib
include path in project settings j:\build\headers; p:\build\headers
lib path in project settings j:\build\release\lib;p:\build\release\lib
This will take you local changes first, then if you have not made any local changes(or at least you haven't built them) it will use the headers and libs from you last build on the build server.
I've seen problems like this addressed by having a set of headers in module B that get copied over to the release directory along with the lib as part of the build process. Module A then only sees those headers and never has access to the internals of B. Usually I've only seen this in a large project that was released publicly.
For internal projects it just doesn't happen. What usually happens is that when they are small it doesn't matter. And when they grow up it's so messy to separate it out no one wants to do it.
Typically I just see an include directory that all the interface headers get piled into. It certainly makes it easy to include headers. People still have to think about which modules they're taking dependencies on when they specify the modules for the linker.
That said, I kinda like your approach better. You could even avoid adding these directories to the include path, so that people can tell what modules a source file depends on just by the relative paths in the #includes at the top.
Depending on how your project is laid out, this can be problematic when including them from headers, though, since the relative path to a header is from the .cpp file, not from the .h file, so the .h file doesn't necessarily know where its .cpp files are.
If your projects have a flat hierarchy, however, this will work. Say you have
base\foo\foo.cpp
base\bar\bar.cpp
base\baz\baz.cpp
base\baz\inc\baz.h
Now any header file can include
#include "..\baz\inc\baz.h
and it will work since all the cpp files are one level deeper than base.
In a group I had been working, everything public was kept in a module-specific folder, while private stuff (private header, cpp file etc.) were kept in an _imp folder within this:
base\foo\foo.h
base\foo\_imp\foo_private.h
base\foo\_imp\foo.cpp
This way you could just grab around within your projects folder structure and get the header you want. You could grep for #include directives containing _imp and have a good look at them. You could also grab the whole folder, copy it somewhere, and delete all _imp sub folders, knowing you'd have everything ready to release an API.
Within projects headers where usually included as
#include "foo/foo.h"
However, if the project had to use some API, then API headers would be copied/installed by the API's build wherever they were supposed to go on that platform by the build system and then be installed as system headers:
#include <foo/foo.h>