Renato Tavares
Renato Tavares

Reputation: 203

Using Makefile with subfolders

I have the following directory structure.

Project/
    ├── bin/
    ├── src/
    │    ├── main.c
    │    ├── util/
    │         ├── util.c
    │         ├── util.h
    ├── obj/
    ├── .depend/

All my source code are in the src folder. In the src root is my main.c file; which includes other files that are on the same level that he (or within a same level folder). I have a Makefile below that works well for all files in the same level of main.c but does not work on files in a subfolder within src

How change my Makefile to allow subfolder within the src folder?

CC := gcc
CFLAGS := -Wall -Wextra
BINDIR := bin
OBJDIR := obj
SRCDIR := src
DEPDIR := .depend
SOURCES := $(wildcard $(SRCDIR)/*.c)
OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SRCDIR)/%.c, $(DEPDIR)/%.d, $(SOURCES))

$(BINDIR)/app: $(OBJECTS) | $(BINDIR)
    @$(CC) -o $@ $^

-include $(DEPENDS)

$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
    @$(CC) $(CFLAGS) -c -o $@ $<

$(DEPDIR)/%.d: $(SRCDIR)/%.c | $(DEPDIR)
    @$(CC) -MM -MG $< | sed 's!^\(.\+\).o:!$(DEPDIR)/\1.d $(OBJDIR)/\1.o:!' > $@

$(DEPDIR) $(BINDIR) $(OBJDIR):
    @mkdir $@

clean:
    @rm -rf $(BINDIR)/*
    @rm -rf $(OBJDIR)/*

.PHONY: clean

EDIT: the .o and .d files do not need to respect the original design of the structure. And I'm using Windows (MinGW)

Upvotes: 1

Views: 2363

Answers (2)

Andrea Biondo
Andrea Biondo

Reputation: 1686

First, you'll have to change your SOURCES to recursively find the sources. This can be done in pure make:

subdirs = $(filter-out $1,$(sort $(dir $(wildcard $1*/))))
rfind = $(wildcard $1$2) $(foreach d,$(call subdirs,$1),$(call rfind,$d,$2))

SOURCES := $(call rfind,$(SRCDIR)/,*.c)

Everything else will work, except for directory creation. First, change your prerequisites to use $(@D) with secondary expansion:

.SECONDEXPANSION:

$(OBJDIR)/%.o: $(SRCDIR)/%.c | $$(@D)
    ...
$(DEPDIR)/%.d: $(SRCDIR)/%.c | $$(@D)
    ...

Then, change your directory creation rule to include all the directories:

$(BINDIR) $(patsubst %/,%,$(sort $(dir $(OBJECTS) $(DEPENDS)))):
    @mkdir -p $@

Like the recursive find, it uses sort to deduplicate the directories (otherwise make will warn) and strips the trailing slash (because $(@D) won't have a trailing slash). Note that -p is needed to avoid issues with order and with directories only containing other directories and no sources.

Upvotes: 3

igagis
igagis

Reputation: 2079

try to set your sources like this:

SOURCES := $(shell find $(SRCDIR) -type f -name "*.c")

if it does not work right a way, try to debug it by just running in your command line

find src -type f -name "*.c"

and see if it outputs the correct list of files and with correct relative path, adjust accordingly.

Note, that this approach works only in unix-like environment, if you are using MinGW from MSYS or Cygwin environment it should work.

Upvotes: 0

Related Questions