Makefiles with source files in different directories

The traditional way is to have a Makefile in each of the subdirectories (part1, part2, etc.) allowing you to build them independently. Further, have a Makefile in the root directory of the project which builds everything. The "root" Makefile would look something like the following:

all:
    +$(MAKE) -C part1
    +$(MAKE) -C part2
    +$(MAKE) -C part3

Since each line in a make target is run in its own shell, there is no need to worry about traversing back up the directory tree or to other directories.

I suggest taking a look at the GNU make manual section 5.7; it is very helpful.


You can add rules to your root Makefile in order to compile the necessary cpp files in other directories. The Makefile example below should be a good start in getting you to where you want to be.

CC=g++
TARGET=cppTest
OTHERDIR=../../someotherpath/in/project/src

SOURCE = cppTest.cpp
SOURCE = $(OTHERDIR)/file.cpp

## End sources definition
INCLUDE = -I./ $(AN_INCLUDE_DIR)  
INCLUDE = -I.$(OTHERDIR)/../inc
## end more includes

VPATH=$(OTHERDIR)
OBJ=$(join $(addsuffix ../obj/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.o))) 

## Fix dependency destination to be ../.dep relative to the src dir
DEPENDS=$(join $(addsuffix ../.dep/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.d)))

## Default rule executed
all: $(TARGET)
        @true

## Clean Rule
clean:
        @-rm -f $(TARGET) $(OBJ) $(DEPENDS)


## Rule for making the actual target
$(TARGET): $(OBJ)
        @echo "============="
        @echo "Linking the target $@"
        @echo "============="
        @$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
        @echo -- Link finished --

## Generic compilation rule
%.o : %.cpp
        @mkdir -p $(dir $@)
        @echo "============="
        @echo "Compiling $<"
        @$(CC) $(CFLAGS) -c $< -o $@


## Rules for object files from cpp files
## Object file for each file is put in obj directory
## one level up from the actual source directory.
../obj/%.o : %.cpp
        @mkdir -p $(dir $@)
        @echo "============="
        @echo "Compiling $<"
        @$(CC) $(CFLAGS) -c $< -o $@

# Rule for "other directory"  You will need one per "other" dir
$(OTHERDIR)/../obj/%.o : %.cpp
        @mkdir -p $(dir $@)
        @echo "============="
        @echo "Compiling $<"
        @$(CC) $(CFLAGS) -c $< -o $@

## Make dependancy rules
../.dep/%.d: %.cpp
        @mkdir -p $(dir $@)
        @echo "============="
        @echo Building dependencies file for $*.o
        @$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^../obj/$*.o^" > $@'

## Dependency rule for "other" directory
$(OTHERDIR)/../.dep/%.d: %.cpp
        @mkdir -p $(dir $@)
        @echo "============="
        @echo Building dependencies file for $*.o
        @$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^$(OTHERDIR)/../obj/$*.o^" > $@'

## Include the dependency files
-include $(DEPENDS)


The VPATH option might come in handy, which tells make what directories to look in for source code. You'd still need a -I option for each include path, though. An example:

CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
VPATH=part1/src:part2/src:part3/src

OutputExecutable: part1api.o part2api.o part3api.o

This will automatically find the matching partXapi.cpp files in any of the VPATH specified directories and compile them. However, this is more useful when your src directory is broken into subdirectories. For what you describe, as others have said, you are probably better off with a makefile for each part, especially if each part can stand alone.


If you have code in one subdirectory dependent on code in another subdirectory, you are probably better off with a single makefile at top-level.

See Recursive Make Considered Harmful for the full rationale, but basically you want make to have the full information it needs to decide whether or not a file needs to be rebuilt, and it won't have that if you only tell it about a third of your project.

The link above seems to be not reachable. The same document is reachable here:

  • aegis.sourceforge.net (archived)
  • lcgapp.cern.ch

Tags:

Linux

Makefile