Alex44
Alex44

Reputation: 3855

Makefile for multiple source dirs and one target dir

I try to write a single makefile, which search for lib-directories in the current directory, compile the sources of every directory and put the object-file into a separate object-directory. I don't want to have more than one makefile.

This makefile will do this:

SRCDIR  := $(shell ls -d lib_*/)

CC      := gcc
DB      := gdb
OBJDIR  := obj
CFLAGS  := -Wall -Werror -Wextra -pedantic -O3
LDFLAGS := #

# Rules
all:
    @ # create object directory
    @mkdir -p  $(OBJDIR)/ ;
    @ # go through all source dirs
    @for dir in $(SRCDIR); do \
        echo $$dir && \
        cd $$dir && \
        for n in $$(ls *.c); do \
            m=$${n%%.c}; \
            $(CC) -c \
               $(CFLAGS) \
               $(LDFLAGS) \
               -o ../$(OBJDIR)/$$m.o $$n;\
        done; \
        cd ..; \
    done

But: The makefile compiles every run all sources. Also the the sources without any changes. If it possible that the makefile recognizes if there are changes or not and compiles only the changed sources?


Here the strcture of the dirs:

lib
 |-lib_one
 |  |-lib_one.c
 |  |-lib_one.h
 |
 |-lib_two
 |  |-lib_two.c
 |  |-lib_two.h
 |
 |-lib_n
 |  |-lib_n.c
 |  |-lib_n.h
 |
 |-obj
 |  |-lib_one.o
 |  |-lib_two.o
 |  |-
 |  |-lib_n.o
 |
 |-makefile

Upvotes: 0

Views: 571

Answers (2)

Beta
Beta

Reputation: 99084

If you don't care about header files, you can do this:

SRCS := $(wildcard */*.c)

OBJDIR := obj

OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(SRCS)))

all: $(OBJS)
    @:

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

vpath %.c $(wildcard *)

If you care about the obvious header files (e.g. lib_one.c includes lib_one.h), then you can make a simple adjustment:

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

vpath %.c $(wildcard *)
vpath %.h $(wildcard *)

If you have other dependencies (e.g. lib_n.c includes lib_one.h), you could add them by hand:

lib_n.o: lib_one.h

or you could use Advanced Auto-Dependency Generation, but that's an advanced technique I'd advise you to leave for another day.

Upvotes: 1

dinox0r
dinox0r

Reputation: 16039

You can use the following:

SRCDIR  := $(shell ls -d lib_*/)

CC      := gcc
DB      := gdb
OBJDIR  := obj
CFLAGS  := -Wall -Werror -Wextra -pedantic -O3
LDFLAGS := #

# Rules
all:
    @ # create object directory
    @mkdir -p  $(OBJDIR)/ ;
    @ # go through all source dirs
    @for dir in $(SRCDIR); do \
        echo $$dir && \
        cd $$dir && \
        for n in $$(ls *.c); do \
            m=$${n%%.c}; \
            if [ ! -e ../$(OBJDIR)/$$m.o ] || \
                [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$n` ] || \
                ([ -e $$m.h ] && [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$m.h` ]); then \
                echo "Change detected, compiling $$n..."; \
                $(CC) -c \
                    $(CFLAGS) \
                    $(LDFLAGS) \
                    -o ../$(OBJDIR)/$$m.o $$n;\
            fi; \
        done; \
        cd ..; \
    done

The following line adds a check over the object files to see if they exists, if that then it compare source modification time against object modification time (kind of repeating the make work inside make).

 if [ ! -e ../$(OBJDIR)/$$m.o ] || [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$n` ] || ([ -e $$m.h ] && [ `stat -c %Y ../$(OBJDIR)/$$m.o` -lt `stat -c %Y $$m.h` ]); then 

Upvotes: 0

Related Questions