Automatic dependency generation and compilation in non-flat directory src - c++

I'd like to adapt the combined automatic dependency approach to a non-flat directory situation where headers are located under ./include/ and implementation files under ./src/ (while Makefile is in the current directory .). I'd like to hold all intermediate and .d (dependency) files inside a separate directory (potentially separate ./build/ and ./.deps/) . To avoid potential clash for dependency files when more than one file with the same name in different subdirectories of ./include/ and ./src/ can exist, I guess building the same structure as in ./src/ in ./.deps could be a solution.
Apart from adding -I directive to the compile phase in the above linked Makefile, what else should I add?

Related

cmake add_custom_command + Xcode: multi output = multi command invocation

I have custom command that generate several headers at once.
All works fine with make/ninja files generated by cmake.
But if I generate Xcode project via cmake -GXCode,
then instead of once gen.sh was invoked 10 times
and not only that, it also will be invoked every build,
even if timestamps of generated file are younger then gen_in.txt.
How can I fix this?
project(multi_output)
cmake_minimum_required(VERSION 3.17)
set(MANY_HEADERS test0.h test1.h test2.h test3.h test4.h test5.h test6.h test7.h test8.h test9.h)
add_custom_command(
OUTPUT ${MANY_HEADERS}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.sh
DEPENDS gen_in.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_executable(foo main.cpp ${MANY_HEADERS})
where gen.sh is
#!/bin/sh
echo "gen.sh: start"
sleep 1
echo "gen.sh: hard work done"
for i in `seq 0 9`; do
cat gen_in.txt > test$i.h
sed -i bak s/placeholder/$i/g test$i.h
done
In OUTPUT option relative paths are treated as relative to the binary directory.
That is, your add_custom_command actually doesn't produce the files declared as OUTPUT.
This is why it is called more and more: the build tool finds out that an OUTPUT file does not exist, and runs the COMMAND for build that file. (Many build tool don't check whether the OUTPUT file is actually created.)
For files created in the source directory you need to specify their absolute path in OUTPUT option:
set(MANY_HEADERS test0.h test1.h test2.h test3.h test4.h test5.h test6.h test7.h test8.h test9.h)
# This will be a list of _absolute paths_ to the headers
set(MANY_HEADERS_ABS)
foreach(HEADER ${MANY_HEADERS})
list(APPEND MANY_HEADERS_ABS "${CMAKE_CURRENT_SOURCE_DIR}/${HEADER}")
endforeach()
add_custom_command(
OUTPUT ${MANY_HEADERS_ABS}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen.sh
DEPENDS gen_in.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
# In add_executable one could use relative paths too
add_executable(foo main.cpp ${MANY_HEADERS})
Note, that add_executable command may accept relative paths to the file both in source and binary trees.
CMake checks whether a file exists or generated (e.g. with add_custom_command) in the source tree, and if it is, the source path is used. Then similar checks are performed for binary tree. (And if this check fails, CMake will emit an error).
Actually, careful inspecting of the make output may give a hint, whether make rebuilds files in the source tree or in the build tree.
This is what is produced by the original code (remember: make is called from the build directory):
[ 33%] Generating test0.h, test1.h, test2.h, test3.h, test4.h, test5.h, test6.h, test7.h, test8.h, test9.h
And this is what is produced when use absolute paths to the source tree. (Out-of-source build, use build/ subdirectory for build.)
[ 33%] Generating ../test0.h, ../test1.h, ../test2.h, ../test3.h, ../test4.h, ../test5.h, ../test6.h, ../test7.h, ../test8.h, ../test9.h

CMake: How to choose which include directories get passed for each source file

I have a project with many source files, and header files. I could add every single directory that contains a header file to CMake's include directories so they are passed via -I option to the compiling of each source file.
include_directories(I/will/need/tons/of/these);
Is there any way through CMake that I can pass only the relevant include directories to the compiling of each source file?
For example, If i was writing this myself on the command line, I would use a script like this:
g++ -I $(./get_include_dirs.sh foo.cpp) -o foo.o foo.cpp
where $(./get_include_dirs.sh foo.cpp) is a script that gets expanded to only the include dirs of foo.cpp
Can this be done on CMake? I don't know how to tell cmake to use that script for each file
Normally, you should set include directories not globally but on target level:
set(my-target-sources
source1.cpp
...
sourceN.cpp
)
add_library(my-target
${my-target-sources}
)
target_include_directories(my-target
[PUBLIC|PRIVATE|INTERFACE]
directory-relevant-to-my-target
)
This way, the compiler will look for header files in directory-relevant-to-my-target when compiling my-target. I think that there is no reason for setting the include directories on source file granularity.
For executing a script from CMake you can use execute_process and collect your list of directories in the OUTPUT_VARIABLE parameter but I would not propose that since you will lose inherent portability of CMake when doing so.
You can use SET call like following;
set(HEADERS h1.h h2.h h3.h)
set(CPP_SOURCE myfunc.cpp)
add_executable(prog ${HEADERS} ${SOURCE_FILES} )
PS: It is better to review the file hierarchy, because in general you should use just include_directories call.

Cmake configuration for multiple sub-libraries in a "packages" directory

Here is a sample project I am trying to build with a "Packages" directory which includes all the libraries to be used in the main code.
I am trying to keep my root cmake file as clean as possible and avoid relative path such as
include_directory(packages/lib1)
but I am struggling. Is there a way of including sub-directories of a directory for the purposes of header inclusion.
First a few minor remarks:
always name the CMake configuration files CMakeLists.txt (because of)
bookmark the documentation on CMake: https://cmake.org/documentation/
Sometimes it's not that easy to read, but very specific once you adopt your head to the "CMake world" ;-)
make yourself comfortable with the scope of CMake variables
include_directories(DIR1 [DIR2 [...]])
Tells CMake where the compiler should look for header files, i.e. -IDIR1 -IDIR2 ....
add_library(NAME [STATIC|SHARED] SOURCES)
This command creates the required compiler commands to create a static or shared library out of a given list of source files. No need to add in the header files. The make target will be called NAME and the library target is known to CMake as NAME.
add_subdirectory(DIR)
Tells CMake to look into DIR and parse the included CMakeLists.txt with all its content.
target_link_libraries(TARGET LIB1 [LIB2 [...]])
Tells CMake to instruct the linker to link LIB1, LIB2, etc. to the TARGET, i.e. -LLIB1 -LLIB2 .... TARGET is a CMake/make target previously defined/created with a call to add_{library,executable,custom_target}.
CMakeLists.txt:
include_directories(libraries)
# a header file in `libraries/lib1/foo.hpp` can be included
# in the whole CMake project by `#include "lib1/foo.hpp"`.
add_subdirectory(libraries)
add_subdirectory(tests)
libraries/CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
libraries/lib1/CMakeLists.txt:
add_library(lib1 STATIC ${LIB1_SOURCES})
libraries/lib2/CMakeLists.txt:
add_library(lib2 STATIC ${LIB2_SOURCES})
tests/CMakeLists.txt:
add_executable(tests ${TEST_SOURCES})
target_link_libraries(tests lib1 lib2)

How to maintain self-made libraries?

I'm using Qt Creator 2.7.0 on ubuntu 13.04.
I've just recently ran into the idea of using libraries, and they're a whole new thing for me.
I've just figured that I need to have the following in my application's .pro file to use a library of my own:
LIBS += -L<lib's dir> -l<lib's name>
INCLUDEPATH += <headers' dir>
// for example:
LIBS += -L$$PWD/../MyLib/release/ -lMyLib
INCLUDEPATH += $$PWD/../MyLib/src/
As you see, I have all my projects in a folder called Programming (the .. in this case)
Each of my project have .pro and .pro.user files in the root, source files in a sub folder /src and the release in an other sub folder /release.
So, this is what my Programming folder looks like:
Programming
MyLib
MyLib.pro
MyLib.pro.user
src
myclass.h
myclass.cpp
release
libMyLib.a
Makefile
myclass.o
MyApp
MyApp.pro
MyApp.pro.user
src
main.cpp
release
main.o
Makefile
MyApp
However, I figured that I could create a folder Programming/libs/, and add libMyLib.a and myclass.h files inside that libs folder.
I would do the same for all of my libraries, and then I could always include them like this:
LIBS += -L$$PWD/../lib/ -lMyLib
INCLUDEPATH += $$PWD/../lib/
The problem is, I'd get include path for every library stored on my computer and the libs folder would become a mess, especially if there are two headers with same name on different libraries.
I'm really new to using libraries, is there a general solution on how they should be located on your computer, and how to include them into your projects?
You could mimic libraries like Boost and have a directory tree like this:
MyLib
build
Makefile, .pro or .sln file here
lib
MyLib
// your .so / .a here
include
MyLib
// your .h here
src
// your .cpp here
CMake or qmake file here
This way you have an out-of-source build tree (in build/) so that your binary files are not mixed up with your source files.
The lib/ and include/ directories are handy because you can then define an install build target. If you then type
make install
it will copy everything to usr/local/lib and user/local/include so that your App can simply do #include <MyLib/some_header.h> and you can link directly against your library binaries (because you copied everything to a location in your system wide path). There is also no danger of name clashes because you wrapped it inside your own MyLib subdirectory.

Cmake and coding style for common config code

following the structure of my project:
/myproject
CMakeLists.txt (containing "add_subdirectory" and "include_directories" ..)
/src
/lib1
CMakeLists.txt (containing "add_library(lib1 .. )" )
..
/lib2
idem as lib1 ..
/mains
/common
=>config.cpp<=
=>gui.cpp<=
/main1
CMakeLists.txt
main1.cpp
/main2
CMakeLists.txt
main2.cpp
/data
/images_and_different_stuff
/conf
params.cfg
/bin
(output executables)
/release
(cmake build_files)
My question is about the linking of the configuration classes I placed in /common. These classes read the CLI or the configuration file params.cfg and initialize mains objects that are present in both main1.cpp and main2.cpp and main3.cpp ... (one config file for all exes)
For now I have in my /main1's CMakeLists.txt: set(main1_source main1.cpp ../common/config.cpp ..). So the common code is recompile for each exe. What is the best way to do this ? Make a static lib from common files ?
What is the best way to do this ? Make a static lib from common files ?
Exactly. Or use a shared library if you want to cut down your total install size.