Alexander Shukaev
Alexander Shukaev

Reputation: 17019

C++ Project: Artifact-Name dependant "include" directory population using CMake (build-time)

I've devised a good structure for a new project which I currently successfully use.

NOTE: This structure is beneficial for the project which is developed by multiple programmers.

<Project Directory>
    + include
        + Haroogan
            + Utility
                - util.h
            + More
                - more.h
                + Whatever
                    - whatever.h

    + src
        + Haroogan.More             <--- Artifact
            - more.h
            - more.cpp
            - CMakeLists.txt
        + Haroogan.More.Whatever    <--- Artifact
            - whatever.h
            - whatever.cpp
            - CMakeLists.txt
        + Haroogan.Utility          <--- Artifact
            - util.h
            - util.cpp
            - CMakeLists.txt
        + Haroogan.Application      <--- Artifact
            - app.h
            - app.cpp
            - CMakeLists.txt
        - CMakeLists.txt            <--- "Root" CMakeLists.txt

Artifact - is library, executable, etc. - you got the point.

Artifact-Name (as in the subject) - is simply the name of the artifact which is deduced by CMake from the name of the directory dedicated to the artifact. Actually terms Artifact and Artifact-Name are essentially the same. For example: artifact residing in directory "Haroogan.More.Whatever" has name "Haroogan.More.Whatever".

This has several consequences:

What we need here is simply a public header repository - the "include" directory. Therefore, to address the last issue - I decided to do the following:

I believe it's a nice and robust approach since now if I want to use "whatever" and "more" classes from "Haroogan.More.Whatever" and "Haroogan.More" artifacts in other components - I simply write:

#include <Haroogan/More/Whatever/whatever.h>
#include <Haroogan/More/more.h>

using Haroogan::More::Whatever::whatever;
using Haroogan::More::more;

The system works like a charm (I can provide CMake scripts if anybody wants). However, I'm not satisfied with the fact that headers are copied. It would be much better if, for example, instead of copying "whatever.h" CMake would create new file "whatever.h" in "Haroogan/More/Whatever/" and inject #include "../../../../src/Haroogan.More.Whatever/whatever.h" in it.

My system right now it fully automated. In other words, path "Haroogan/More/Whatever" is automatically deduced from Artifact-Name "Haroogan.More.Whatever". Therefore, it would be great if injection of #include "../../../../src/Haroogan.More.Whatever/whatever.h" with all those nasty ../../ would be also automated.

Unfortunately, I'm new to CMake and don't know how to achieve this functionality, but I think it is possible and might be already done by someone. Thank you.

EDIT:

A temporary solution for this problem could be the following:

Instead of creating "whatever.h" inside "Haroogan/More/Whatever/" which immediately leads to dealing with ../../ mess, I could simply create "Haroogan.More.Whatever.whatever.h" (by prefixing "whatever.h" with "Haroogan.More.Whatever") right in the "include" directory and use it as:

#include <Haroogan.More.Whatever.whatever.h>

using Haroogan::More::Whatever::whatever;

This solution is acceptable, but I don't like it as much as the one I'm interested in.

Upvotes: 1

Views: 762

Answers (1)

arrowd
arrowd

Reputation: 34411

How about this:

macro(add_public_headers)
  foreach(header ${ARGN})
    get_filename_component(abspath ${header} ABSOLUTE)
    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${header} "#include ${abspath}"
  endforeach()
endmacro()

This maro can be used now in such way:

In src/Haroogan.More.Whatever/CMakeLists.txt you do

add_public_headers(whatever.h)

and this will generate header with single #include line in your build dir.

The only thing is that path would be absolute, but it shouldn't be problem for you.

Upvotes: 1

Related Questions