2

For sure this question has been already asked many times, but i can't find the proper answer so I am asking.

I have the following project structure:

/root
 | obj
 | Makefile
 | src/
 | | dir1/
 | |  | 1.cpp
 | | dir2/
 | |  | 2.cpp
 | |  | dir3/
 | |  |  | 3.cpp
 | |  |  | 4.cpp
 | | main.cpp

Can I have a generic makefile that will compile all the cpp files in any subfolder with any depth of the src folder and that will generate the object files into the obj directory ?

Note This project is being developed using Eclipse CDT, and I want now to be able to provide the source code without requiring user to install Eclipse to build it

Manuel Selva
  • 18,554
  • 22
  • 89
  • 134

2 Answers2

3

To achieve 'unlimited' recursion, you can use a wildcard with an extended pattern:

CPPFILES := $(wildcard src/**/*.cpp)

Then you can transform them into a list of .o files:

OBJFILES := $(patsubst src/%.cpp,obj/%.o,$(CPPFILES))

Now we have the build target:

.PHONY: all
all: $(OBJFILES)

Compilation rule:

obj/%.o: src/%.cpp
    mkdir -p "$(@D)"
    $(CC) -c $< -o $@

If the wildcard with an extended pattern doesn't work, then you can use:

CPPFILES := $(shell find src -name '*.cpp')
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • The OP wasn't clear about whether they wanted mirrored directories in `obj` or just a single `obj` directory so this might not be exactly what was called for but nicely done (and easily fixable for the single `obj` dir). – Etan Reisner Jan 26 '16 at 15:35
  • If you happen to have two files with the same name, just in different directories then a single obj directory would break in that case. – Anya Shenanigans Jan 26 '16 at 15:37
  • Also see my answer [here](http://stackoverflow.com/a/26852977/258523) for a make-internal recursive wildcard function (and the source link I found it on). – Etan Reisner Jan 26 '16 at 15:38
  • I agree completely but people seem to routinely ask for it nonetheless. – Etan Reisner Jan 26 '16 at 15:38
  • It works very well except that `mkdir -p` is executed many times. Is it possible to avoid this? – Yves Apr 05 '17 at 19:19
  • You could do: `if [ ! -d "$(@D)" ]; then mkdir-p "$(@D)"; fi` (on phone; may be typoed) – Anya Shenanigans Apr 05 '17 at 20:07
2

Well, I wasn't going to answer this (this answer is not about make per se), however:

  1. The OP stated that he's not targeting make specifically, just the simplest solution.

  2. There are no make-specific answers yet.

So, here's how to do it in cmake and SCons. PLEASE NOTE My purpose is not to belittle make, advocate any of the following two (which, though, I must say - I'm under the impression as being the two mainstream C++ build systems of today), etc.

CMake

In CMake basic tutorial, you would use something like this:

file(GLOB_RECURSE variable [RELATIVE path] 
[FOLLOW_SYMLINKS] [globbing expressions]...)

(See this question for further info.)

Scons

In Scons basic tutorial, you would use something like this:

def getSubdirs(abs_path_dir):  
    lst = [ name for name in os.listdir(abs_path_dir) if os.path.isdir(os.path.join(abs_path_dir, name)) and name[0] != '.' ]    
    lst.sort()
    return lst

(see this question for further info.)

Community
  • 1
  • 1
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • May be worth mentioning, as was mentioned in the linked SO question, CMake caches the found files, so if you add, remove or rename files, then you need to delete and re-generate the cmake files. I haven't used Scons, so I don't know if it has the same behaviour. – eerorika Jan 26 '16 at 15:14