Reputation: 17019
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:
#include "../Haroogan.More/more.h"
not only looks messy, but also breaks the basic idea that artifacts actually represent stand-alone components which have to be decoupled even in terms of file-system. Moreover, the concept of private headers is also broken, because this way I can access any headers inside other artifacts.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
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