Makefiles With Source Files in Different Directories

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.

Makefile builds source files from different directories into the same object directory

After having read the answer of Felix Palmen, especially the last sentence

If you really want the objects directly in your objects directory, you need two pattern rules, one matching the sources in src1 and one matching the sources in src2.

I modified the Makefile accordingly (out of curiosity):

src1 = src1/
src2 = src2/
obj = objects/
src1_files = a.c b.c
src2_files = c.c d.c
source_files = $(addprefix $(src1), $(src1_files)) $(addprefix $(src2), $(src2_files))
objects := $(addprefix $(obj), $(src1_files:.c=.o)) $(addprefix $(obj), $(src2_files:.c=.o))

$(obj)%.o: src1/%.c
$(CC) $(CFLAGS) -c $< -o $@

$(obj)%.o: src2/%.c
$(CC) $(CFLAGS) -c $< -o $@

all: $(objects)

I tested in bash on cygwin:

$ mkdir src1 src2 objects

$ touch src1/a.c src1/b.c src2/c.c src2/d.c

$ make
cc -c src1/a.c -o objects/a.o
cc -c src1/b.c -o objects/b.o
cc -c src2/c.c -o objects/c.o
cc -c src2/d.c -o objects/d.o

$

...and it worked.

(I left out the detail about building the objects directory – just created it manually).

Single Makefile for sources in multiple sub directories

OBJ=$(patsubst %,$(OBJ_DIR)/%,$(_OBJ)) prepends obj/ to the words of _OBJ. You want to replace the src by obj something which you can do with

OBJ=$(patsubst $(SRC_ROOT)/%,$(OBJ_DIR)/%,$(_OBJ))

Note that the directory structure you get expect subdirectories Application and Tasks to obj you either have to create them manually before calling make or updating the Makefile to create them.

Here is something which behaves as I expect when the directory structure is pre-created.

APPNAME=MyBinary
SRC_ROOT=src
OBJ_DIR=obj

DEPS=$(SRC_ROOT)/Application/Application.h \
$(SRC_ROOT)/Tasks/BackgroundWorker.h

_OBJ=$(SRC_ROOT)/Application/Application.o \
$(SRC_ROOT)/Tasks/BackgroundWorker.o\
$(SRC_ROOT)/main.o

OBJ=$(patsubst $(SRC_ROOT)/%,$(OBJ_DIR)/%,$(_OBJ))

$(OBJ_DIR)/%.o: $(SRC_ROOT)/%.cpp $(DEPS)
echo Making $@ from $<
touch $@

$(APPNAME): $(OBJ)
echo Making $@ from $^
touch $@

Note that in practice you have to be finer with the dependencies and probably have them to be generated by the compiler (see -MM and similar options for g++), here you recompile everything when you change an header.

How to compile sources in different directories into object files all in a single directory (Makefile)?

You can make a shred library from object files, even if they're in different directories. So that's not really a reason to put them elsewhere.

However, a better reason is just to keep the source directories tidy and make it simple to clean up (just remove the obj directory).

Putting object files from source files in different directories into a single directory is problematic: if you have two source files with the same name they'll overwrite each other. One common way to work around this is to keep the directory structure for source files but put it below a new top-level directory; GNU make supports that easily:

# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))

# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(addprefix obj/,$(SRC:.cpp=.o))

obj/%.o : %.cpp
@mkdir -p $(@D)
$(COMPILE.cpp) -o $@ $<

If you really, really want to have all the object files in the same directory you'll have to get fancier, because make uses simple string matching for targets so you have to write a new rule for every relationship where the target and prerequisite names are different: basically that means a new rule for every separate source directory.

You can avoid this by using the VPATH feature of GNU make, like this:

# grab all cpp files with their path that are in some DIRS list
SRC = $(wildcard *.cpp) $(foreach DIR,$(DIRS),$(wildcard $(DIR)/*.cpp))

# remove the path
SRC_WITHOUT_PATH = $(notdir $(SRC))

# stick the .obj/ directory before the .cpp file and change the extension
OBJ = $(SRC_WITHOUT_PATH:%.cpp=obj/%.o)

# Give all the source directories to make
VPATH = $(sort $(dir $(SRC))

obj/%.o : %.cpp
$(COMPILE.cpp) -o $@ $<

Writing makefile for source files across different directories

The problem is, that

program_C_SRCS := $(wildcard *.cc)

only adds source files in the same directory. So when linking you don't have the object files of your second folder. You probably can solve the problem by simply adding the source files of the other folder to your program_C_SRCS:

program_C_SRCS += $(wildcard ../FOLDER2/*.cc)

Include directorys

I guess you are using the gcc/g++, in this case http://gcc.gnu.org/onlinedocs/cpp/Search-Path.html says, that header paths are searched from left to right, meaning the first path given is searched first. Therefore you only have to add -I INCLUDE2 before -I INCLUDE1 option to achive what you want.
Your starting makefile already has some transformation for more then one include path build in:

   CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))

So you only have to rewrite your include paths:

program_INCLUDE_DIRS := ../INCLUDE2
program_INCLUDE_DIRS += ../INCLUDE1

Makefiles with source / object files in different directories

(This question looks very familiar-- I'd almost swear that one essentially the same has been asked and answered.)

Let's take this in stages. We could write the rules one at a time:

$(doc)/tests/test1.rst: $(tests)/test1/test1.e
...

but that's tedious. It's the kind of situation that cries out for a wildcard solution, such as a pattern rule, but one of Make's serious shortcomings is its crude handling of wildcards. A pattern rule in which the wildcard is repeated:

$(doc)/tests/%.rst: $(tests)/%/%.e
...

is not allowed. But we could write the rules using eval:

define template
$(doc)/tests/$(1).rst: $(tests)/$(1)/$(1).e
use some tool to build $$@ from $$<
endef

$(eval $(call template,test1))
$(eval $(call template,test2))
...

Then instead of writing all of those eval statements, we can delegate that job to foreach:

TESTS := test1 test2 ...

$(foreach TEST,$(TESTS),$(eval $(call template,$(TEST)))

Then instead of writing that list of tests, we can delegate that to wildcard, and use the same list to construct a list of target files:

TESTS := $(notdir $(wildcard $(tests)/*))
TARGETS := $(patsubst %,$(doc)/tests/%.rst,$(TESTS))

all: $(TARGETS)

Putting all of these together is straightforward, but this answer is getting long.



Related Topics



Leave a reply



Submit