11
votes

I have some C++ classes, every one into his own folder with a makefile, test.cpp for testing purpose, etc.

Main folder
 |-> Class1 folder
 |-> Class2 folder
      |-> Class2.1 folder
 |-> Class2 folder

I have a main project, that must include these classes. I am trying to include all sub-makefiles into the main makefile.

I have tried with "INCLUDE POO/makefile", but this solution has 2 problems:

  • The path of the sub-makefiles is incorrect, so files are not found ("There is not rule to build the target 'Vector3D.cpp'").
  • The "test.cpp" file is overrided, probably because of the path problem.("warning: overriding recipe for target ...")

I would like all makefile independent, so I can copy/paste the class folder into a new project and it still working, or I may exec the makefile alone without changes on it.

So the question is: How to include (correctly) a makefile into another makefile?

Example, just for test purpose.

Main makefile (simplified)

include Vector3D/makefile
include Color/makefile

CPP      = g++
CXXFLAGS = $(CXXINCS) -Wall -O0

all: main

main: main.o Vector3D.o Color.o
    $(CPP) main.o Vector3D.o Color.o -o main

main.o: main.cpp
    $(CPP) -c main.cpp -o main.o $(CXXFLAGS)

Sub-makefile example (simplified)

#Vector3D
CPP      = g++
CXXFLAGS = $(CXXINCS) -Wall -O0


all: test

test: Vector3D.o test.o
    $(CPP) Vector3D.o test.o -o test

Vector3D/test.o: test.cpp
    $(CPP) -c test.cpp -o test.o $(CXXFLAGS)

Vector3D.o: Vector3D.cpp Vector3D.hpp
    $(CPP) -c Vector3D.cpp -o Vector3D.o $(CXXFLAGS)

Similar for Color/makefile than Vector3D.

2

2 Answers

7
votes

I would like all makefile independent, so I may copy/past the class folder into a new project and it still working, or I may exec the makefile alone without changes on it.

I'm pretty sure that's not possible. Your makefiles either need to be standalone, in which case you can make the top-level files invoke make in lower level directories recursively (so do not include them) or you can have a single non-recursive makefile formed by including other makefiles. I don't think it's possible to do both.

How to include (correctly) a makefile into an other makefile?

The only valid answer is "using the include directive" (other than the usual "it depends".) Any other advice depends on the structure of the makefiles. Makefiles designed to be included will obviously be easier to include. Just including some random makefile and hoping it will work ... won't work. Check out Implementing non-recursive make and Boilermake for how to make non-recursive makefiles work.

Note that there's no need to include them at the top of the file and doing so may be a bad idea, as the default target becomes the first one in the included file.

3
votes

Thanks to @Jonathan-wakely to provide the initial concepts for this solution.

There are probably many things that may be improved, but it works.

Requirements summary:

  • Makefiles should work standalone
  • The main makefile will includes sub-makefiles
  • No conflicts or path problem should appear.

A simple solution is to call recursively makefiles:

  • Create a "normal" script for leaf makefiles
  • Using an empty target allow to execute always make calls for example "sub-make:" without any requirement after ":"
  • Use the "-C" parameter to set the root directory for the make call.
  • Create the final linking with binaries created by sub-makefiles.

Example for the main makefile:

#all make recursive calls
sub-make:
    make -C Vector3D
    make -C Color

#final linking
CPP      = g++
FLAGS = $(CXXINCS) -Wall -O0

all: main

main: main.o Vector3D/Vector3D.o Color/Color.o
    $(CPP) main.o Vector3D/Vector3D.o Color/Color.o -o main

main.o: main.cpp
    $(CPP) -c main.cpp -o main.o $(FLAGS)

There is probably a better way to provide *.o binaries to the linker without writing all full path, but that is another problem.

Creating the clean target. For leaf makefiles, there are no special considerations to take, but for the main makefile, it must call sub-clean rules.

clean:
    make -C Vector3D clean
    make -C Color clean
    rm -f *.o main

EDITING:

Here is the makefile structure I have done, for if it may be useful to anyone.

To work, All classes must be in it own folder with:

  • .hpp header
  • .cpp code
  • main.cpp for testing
  • Required classes (LIBS) directory are specified with "$(LIBSPATH)LibName" in relation to this makefile.

Makefile

#Following configuration may be set with a parameter:
#   e.g: make FLAGS="-Wall -O0"
FLAGS = $(CXXINCS) -Wall -O0

#Configurable variables
EXEC     = main
CLASS    = World
LIBS     = Color Vector3D Triangle
LIBSPATH = ../

#Static content
CPP      = g++
OBJS     = $(foreach dir, $(LIBS), $(LIBSPATH)$(dir)/$(dir))

all: $(EXEC)

clean: 
    rm -f *.o $(EXEC)
    $(foreach dir,$(LIBS),make clean --no-print-directory -C $(LIBSPATH)$(dir);)

$(EXEC): $(CLASS).o $(EXEC).o $(OBJS:=.o)
    $(CPP) $(CLASS).o $(OBJS:=.o) $(EXEC).o -o $(EXEC)

$(EXEC).o: $(EXEC).cpp
    $(CPP) -c $(EXEC).cpp -o $(EXEC).o $(CXXFLAGS)

$(CLASS).o: $(CLASS).cpp $(CLASS).hpp
    $(CPP) -c $(CLASS).cpp -o $(CLASS).o $(CXXFLAGS)

$(OBJS:=.o): $(OBJS:=.cpp) $(OBJS:=.hpp)
    make --no-print-directory -C $(LIBSPATH)$(strip $(foreach dir,$(LIBS),$(if $(findstring $(dir),$@),$(dir))))