Search code examples
gnu-make

Simple Makefile to do out of source build into a single build dir from multiple source trees


I have following simple Makefile that almost does what I want.

This compiles .c files from directories listed in SRC_DIRS into a single executable.

The source files are in ./src and ../pmlin/master and the intermediate files are supposed to be in directory ./build

The problem is that this compiles files from ./src to ./build correctly, but files from ./pmlin/master end up in ./pmlin/master and not ./build/pmlin/master.

I've tried various things like removing the ../ from the paths in OBJS with pathsubst but at the end of the day after hours of googling and experimenting I've not been able to make this work.

TARGET_EXEC = aslac-calibrator

BUILD_DIR = ./build
SRC_DIRS = ./src ../pmlin/src/master
SRCS := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)

INC_DIRS := $(shell find $(SRC_DIRS) -type d) ../pmlin/src ../pmlin/src/devices
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

CPPFLAGS ?= $(INC_FLAGS) -MMD -MP

$(TARGET_EXEC): $(OBJS)
    $(CC) $(OBJS) -o $@ $(LDFLAGS)

$(BUILD_DIR)/%.c.o: %.c
    $(MKDIR_P) $(dir $@)
    $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@

.PHONY: clean

clean:
    $(RM) -r $(BUILD_DIR)

-include $(DEPS)

MKDIR_P ?= mkdir -p

Solution

  • I actually ended up with this solution where I turn the relative path to the other source trees into absolute paths with $(abspath). In this way everything is compiled into the build directory and there no chance of a name conflict.

    TARGET_EXEC = pmlin-demo
    
    BUILD_DIR = ./build
    PMLIN_DIR = $(abspath ../pmlin)
    SRC_DIRS = ./src $(PMLIN_DIR)/src/master $(PMLIN_DIR)/src/slave
    SRCS := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
    OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
    DEPS := $(OBJS:.o=.d)
    
    INC_DIRS := $(shell find $(SRC_DIRS) -type d) ../pmlin/src ../pmlin/src/devices
    INC_FLAGS := $(addprefix -I,$(INC_DIRS))
    
    CFLAGS += -target macos-x86_64
    CPPFLAGS ?= $(INC_FLAGS) -MMD -MP 
    LDFLAGS += -target macos-x86_64
    
    $(TARGET_EXEC): $(OBJS)
        $(CC) $(OBJS) -o $@ $(LDFLAGS)
    
    $(BUILD_DIR)/%.c.o: %.c
        $(MKDIR_P) $(dir $@)
        $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
    
    .PHONY: clean
    
    clean:
        $(RM) -r $(BUILD_DIR)
    
    -include $(DEPS)
    
    MKDIR_P ?= mkdir -p
    
    all: pmlin-demo