(c)make - resursive compile - c++

Let's assume I have directories like:
dir1
main.cpp
dir2
abc.cpp
dir3
def.cpp
dir4
ghi.cpp
jkl.cpp
And let's assume that main.cpp includes dir2/abc.cpp and dir3/def.cpp, def.cpp includes dir4/ghi.cpp and dir4/jkl.cpp.
My question is, how can I have one Makefile/CMakeLists.txt in dir1/ which goes in each directory recursively and compiles *.cpp, and then "joins" them?
Sorry for my english, hope that I explained my question well!
Thanks!

For makefile, dir1/Makefile should:
declare that main.o dependends on dir2/abc.o and dir3/def.o
declare how to create dir2/abc.o and dir3/def.o
As for cmake it detects such dependencies "automatically" (binary depended on dir2/abc.o and dir3/def.o), so virually you don't need care about it.

One CMakeLists.txt file:
file(GLOB_RECURSE MAIN_SOURCES "dir1/*.cpp")
add_executable(MainExecutable ${MAIN_SOURCES})
# or
add_library(MyLibrary ${MAIN_SOURCES})
I am unsure what you mean by "joining" the sources. I am assuming here that you are combining them into either a library or an executable.

There is an open argument whether recursive make is a good thing. Please see this blog entry for a survey of relatively up-to-date pro and con papers.

Related

Including directories in Clion

Whenever I wanted to include a directory that was located outside of my project with Clion I would use the -I somedir flag. This time however, what I want to do is to have a hierarchy like this:
/project
CMakeLists.txt
/src
/Graph
Graph.h
Graph.cpp
/Dijkstra
Dijkstra.h
Dijstra.cpp
I want my code in a /src directory. And not only that, but also, for example, inside the file Dijkstra.h I want to include the Graph.h like this: #include "Graph/Graph.h and not like this: #include "../Graph/Graph.h.
If I only add an -I src flag, then if I am inside the Dijkstra.h file and I wanted to include Graph.h, I would have to write #include "../Graph/Graph.h, which is not what I want.
So I tried to also add INCLUDE_DIRECTORIES(src). That fixed the problem above, however when tried to compiled, I got a linker error undefined reference to....
So I tried adding the files one by one like this:
set(SOURCE_FILES
src/Dijkstra/Dijkstra.h
src/Dijkstra/Dijkstra.cpp
src/Graph/Graph.h
src/Graph/Graph.cpp)
add_executable(someprojectname ${SOURCE_FILES})
and that brought back the previous problem, where I had to include the files like this: #include "../Graph/Graph.h".
How can I do this properly to get the behavior I want ?
Command INCLUDE_DIRECTORIES doesn't add any source file for compile!
Instead, this command defines directories for search header files.
You need to list all source files in add_executable() call in any case:
include_directories(src)
set(SOURCE_FILES
src/Dijkstra/Dijkstra.cpp
src/Graph/Graph.cpp)
add_executable(someprojectname ${SOURCE_FILES})
UPDATE: #Tsyvarev's answer is correct. I've edited this answer to remove the incorrect part and keep the comments relating to target_include_directories(), but it should be viewed as additional to Tsyvarev's answer.
INCLUDE_DIRECTORIES(src) will make the src directory get added as a search path to all targets defined from that point on. It does not add sources to any targets. The search path will be relative to the current source directory and CMake will adjust it as appropriate when descending into subdirectories via add_subdirectory(). While this is fine if that's what you want, as the project gets bigger and more complicated, you may find you would prefer to apply the include path settings to just some targets. For that, use target_include_directories() instead:
target_include_directories(someprojectname "${CMAKE_CURRENT_SOURCE_DIR}/src")
This will have the same effect, but it restricts the use of the added include path to just the someprojectname target. If you later define some other target which doesn't need the include path, it won't be added. This can help prevent situations like unexpected files being picked up if you have deep directory hierarchies and you re-use directory names in different places, for example).
The target_include_directories() command has additional benefits when applied to library targets because CMake has the ability to carry the include path through to anything you link against that library too. Doesn't sound like much, but for large projects which define and link many libraries, it can be a huge help. There are other target-specific commands which have similar benefits too. This article may give you a bit of a feel for what is possible (disclaimer: I wrote the article). It is more focused on target_sources(), but the discussion around carrying dependencies through to other targets may be useful.

Right way to do non-recursive make?

There seem to be only a handful of resources on creating a non-recursive make system, and in none of the ones I've found can I figure out how to handle my use case. My hierarchy looks like this:
project/
project/libA/...
project/libB/...
...
project/appA/...
project/appB/...
So maybe project/appA/makefile depends on libA and libB and project/appB/makefile depends on libA, libC, and libF or something. I want to be able to make in every directory and have that work. I have a recursive solution for this already.
All the resources always define a root project/makefile that includes all the directories above it. But I need that backwards. Are there any examples in the wild for this? I think ideally I want a given library makefile to look like:
include ../../rules.mk
SRC := $(wildcard src/*.cpp)
INCDIR := ./include
$(add_build_target)
... where the base rules.mk would define add_build_target to append the correct rules for the given SRC and INCDIR to build. Is this the correct approach? And how do I actually write add_build_target to add the correct targets (.o's for all the .cxx's) - everything I've tried gives me "no rule to make target whatever.o" issues, despite me thinking that I've defined them....
I have implemented and extended ideas from the paper
http://evbergen.home.xs4all.nl/nonrecursive-make.html
on multiple occasions in corporate environments, and they work very well, in small or large scale environments. Basically, there is implemented a "directory stack" there and recursive inclusion. Like I said, works well for me. Read this paper, I recommend it.
Have a look at my non-recursive build system implementation called prorab:
https://github.com/cppfw/prorab
It allows to achieve exactly what you want. So, you will have independent makefile in each directory appA, appB, libA, libB,... and if you cd to that directory you'll be able to build the project by just typing make. In that makefile you'll be able to include a makefile from another directory and add a dependency for your app binary on library binary. So, that way if you do some changes to the library code and build the app, it will detect that and rebuild the library.
Then it is also possible to have a top-level makefile which includes all makefiles from those sub-directories, for building everything.
Let me know if you need help with using prorab.

Non recursive (non-recursive) Automake

I am trying to convert a project to use non-recursive automake. Based on a search on SO I could see that the topic has been covered to some extend. But there are not really any questions on how to convert a recursive automake project to a non recursive one. I have already read Karel Zak's blog and of course the autotools-mythbuster. There is a question with experiences regarding non-recursive automake but it does not explain how to convert a project. The only question that explains a bit seems to be regarding the subdir-objects option. But I could not get my project converted with these resources. Hence this question.
Lets start with a simple project setup:
project/
\-- configure.ac
|-- Makefile.am
\-- src/
\-- Makefile.am
|-- foo.c
|-- foo.h
\-- main.c
In configure.ac I just add the subdir-objects option:
AM_INIT_AUTOMAKE([subdir-objects])
In Makefile.am I removed the src directory from the root Makefiles.am's SUBDIRS variable. Then I removed the src/Makefile entry from the AC_CONFIG_FILES macro in `configure.ac.
Karel Zak's blog suggests to name the included Makefiles of the subdirectories Makemodule.am but Makefile.am seem to work too, if the sub folder is removed for the SUBDIRS variable and if the Makefile entry is removed from the AC_CONFIG_FILES config files macro.
Next I defined a global variable for the programs in the root Makefile.am and included the src/Makefile.am
bin_PROGRAMS=
include src/Makefile.am
In src/Makefile.am I changed:
bin_PROGRAMS=foo
to:
bin_PROGRAMS+=src/foo
and I also changed all occurences of foo_XXX to src_foo_XXX. And I added the prefix src/ to all .c and .h file names in src_foo_SOURCES.
But the program was not building and gave errors about include files not being found, for example:
fatal error: debug.h: No such file or directory
#include <debug.h>
Originally my src directories Makefile.am only hat the content variables src_foo_SOURCES, src_foo_CFLAGS, src_foo_LDFLAGS and src_foo_LDADD. My solution to this problem was to add src_foo_CPPFLAGS like this:
src_foo_CPPFLAGS = \
$(AM_CPPFLAGS) \
-I$(top_builddir)/src \
-DDATADIR='"$(datadir)"' \
-DMODULEDIR='"$(moduledir)"' \
-DLIBEXECDIR='"$(libexecdir)"'
But I dont' really understand why this was necessary and why it built fine when I was using recursive automake?
I have another question regarding the answer of Brett Hale in this question. He writes:
You could use "$(srcdir)/sourceA.cpp", but this directory is implicit anyway. All you need is:
libadapter_la_SOURCES = sourceA.cpp sourceB.cpp
But I could not get it to work without prefixing the path, so that seems wrong to me, can someone confirm my experience?
Update: I am also having problems with the po/ subdir, how can I make that non-recursive? There is no Makefile.am in po/ just a Makevars file. There is a post on autotools-mythbuster, that indicates non-recursive make with gettext is not supported, but that post is from 2011. I'm not sure if anything might have changed in the mean time.
I'll start from the bottom up: nothing changed with respect to gettext since 2011, and po/ directories should still be handled recursively, unfortunately. The same is true for gtk-doc. The reason is that they build somewhat-automake-compatible Makefile.in files, but they are not really automake-based.
As for the header file not found, the reason why it now fails is because you're using the wrong #include statement format: you should use #include "debug.h" and then it would work without having to add the -Isrc to the command line. The preprocessor will look for "" enclosed headers in the same directory as the source file, and for <> enclosed header in the include path; automake by default adds the current directory to the include path with -I. and that meant that it was satisfied when using recursive Makefile.am, but now the "current directory" no longer matches your source file's directory.
I would also suggest both against re-using the name Makefile.am if you're using Karel's suggested approach (automake, or at least some versions of it, will then generate a Makefile.in file for the subdirectory that will not work properly), and to consider not using Karel's approach at all if your software is self-contained enough, for instance if it only has one binary target. Karel's use case was linux-utils which is a fairly sparse project with a few dozen targets each with its own set of source files.
I'll try to comment on the Brett Hale answer you noted, as I think there's a misunderstanding there altogether.

The right way to structure my c++ project with cmake?

I have been struggling with this for quite a while, and my adventures with cmake have only resulted in hackish solutions that I am pretty sure are not correct.
I created a library that consists of several files, as follows:
-libfolder
-codepart1folder
-CMakeLists.txt
-codepart1.cpp
-codepart1.hpp
-codepart2folder
-codepart3folder
-lib.cpp
-lib.hpp
-CMakeLists.txt
I wrote a CMakeLists file to compile the library (after some experimentation), and I can generate a lib.a file. Now I would like to include this code as a library in other projects, and access it through the interface in lib.hpp. What is the best way to do this, in terms of directory structure, and what I need to put into CMakeLists.txt in my root project?
My current attempt has been to add -libfolder as a subfolder to my current project, and add the commands:
include_directories(${PROJECT_SOURCE_DIR}/libfolder)
link_directories(${PROJECT_BINARY_DIR}/libfolder)
add_subdirectory(libfolder)
target_link_libraries(project lib)
When I run make, the library compiles fine, but when project.cpp compiles, it complains that it cannot find codepart1.hpp (which is included in lib.hpp, included from project.cpp).
I suspect that this is the wrong way about doing this, but I cannot wade through the CMake documentation and find a good tutorial on setting up projects like this. Please help, CMake gurus!
The clean way to import one CMake project into another is via the find_package command. The package declaration is done by using the export command. An advantage of using find_package is that it eliminates the need to hard-code paths to the package's files.
Regarding the missing hpp file, you didn't include codepart1folder, so it's not on the include path.
Ok, so after consulting a coworker of mine who is a CMake guru, it seems CMake does not have support for what I am trying to do, leaving one with 3 options:
Add all of the dependencies to the parent projects CMakeLists.txt - not very clean, but it will get the thing to work. You'll have to do this for every project you add the code to, and go back and fix things if your library changes.
clean up your library headers. This is done through some compiler hackery. The idea is to forward-declare every class, and use only pointers or boost::shared_ptr, and then include the dependencies only in the cpp file. That way you can build the cpp file using all the findpackage stuff, and you get the bonus of being able to use the lib by only including the header and linking to the library.
Look into build systems. Having portable code and fast code compilation with complex dependencies is not a solved problem! From my investigations it turned out to be quite complicated. I ended up adopting my coworkers build system which he created himself in cmake, using things he picked up from Google.
Looking at your post you don't seem to add 'codepart1folder' to the includes anywhere. How are you including codepart1.hpp as:
#include <codepart1.hpp>
#include "codepart1folder/codepart1.hpp"
I don't think there is a standard accepted way to structure cmake projects. I've looked at a bunch of cmake repos and they tend to have differences. Personally I do the following:
-project
CMakeLists.txt
-build
-cmake
OptionalCmakeModule.cmake
-src
-Main
Main.cpp
Main.hpp
-DataStructs
SomeTree.hpp
SomeObject.hpp
-Debug
Debug.hpp
-UI
Window.hpp
Window.cpp
Basically that dumps all the source code into 1 directory, then you perform an out of source build with: 'mkdir build && cd build && cmake .. && make' in the projects root folder.
If you have separate libs as part of your project, then you might want a separate libs directory with another subfolder for your specific lib.
I have some of my repos on: https://github.com/dcbishop/ if you want to look at the CMakeLists.txt files.
The main problems with my project structure are that I use the FILE_GLOB which is apparently the 'wrong' way to do things (if you add files after running 'cmake ..' then they won't be picked up hen you do a 'make'). I haven't figured out what the 'right' way to do it is (from what I can see it involves keeping a separate list of files) I also only use 1 CMakeLists.txt file.
Some projects also choose to separate their cpp and hpp files into separate directories. So you would have an include and src folders (at least for the hpp files that are intended to be used externally). I think that would mainly be for projects that are mainly large libraries. Would also make installing header files much easier.
You are probably missing
include_directories(${PROJECT_SOURCE_DIR}/libfolder/codepart1folder)
In such a case you might want to set( CMAKE_INCLUDE_CURRENT_DIR on) to add all folders to the include directory path variable.
Check cmake's output on the command line whether the correct include folders are set or not. Additionally you can always use message() as "print debugging" for cmake variables.
In case of include directories however you need to read the directory property to see what is actually in the include directories.
get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
message("inc_dirs = ${inc_dirs}")
I hope this helps you figuring out what is missing.
Edit
I just saw your comment about added codepart1folder in the libfolder. It is only available in the libfolder's include_directory path and not propagated to the root folder.
Since the include codepart1.hpp is present in the lib.hpp however you need to have it also available in the project path otherwise you will get missing declaration errors when you build your project.

makefile which build the library (lib.a)from the list of object files (*.o)

I have a problem because i have never written any makefile. So if any could help me I become happy. I have a lot of different .o files, which stored in the different folders. For example:
folder1: obj1.o
folder2: obj2.o
folder3: obj3.o
I need makefile, which will build the library from files which I send to makefile like param. Param should be makefile too and include info about folders where stored necessary files.
For example I would like to build lib from objects stored at folder1 and folder2 without folder3. So makefile which I send as param to the main makefile must include routes to folder1 and folder2:
local_libs := ../folder1
local_libs += ../folder2
main makefile should parse that info and call libtool utilite for creating lib from files at this folders. Could anybody help?
I suppose it is easy for realization, example will be great!
You need a rule that inputs the .o files, outputs the .a file and calls the ar command to do the work. Something like:
lib.a: $(OBJECTS)
${AR} -cr ${#} ${^}
GNU make does not support passing parameters "to the makefile" on the command line.
You have two basic mechanism for setting parameters to be used by make while executing a makefile (I'm assuming that you are using GNU make, and not all of his advice will apply to other makes):
Write to submakefiles, possibly using a script. If you makefile has a line like
include file.mk
gmake will include the contents of file.mk. Change the contents of file.mk and you change the behavior of your makefile.
Make can take variable values from environment variables when set. This provides a powerful mechanism for letting the user customize the behavior of your makefile.