makefile

Makefile using subst in the requesite of a pattern to build in different folders


In my makefile, I have the following sources src/commonModule.c src/freeRtos/freeRtosIntegration.c which shall result in objectfiles like this build/commonModule.o build/freeRtos/freeRtosIntegration.o The folders build/ and build/freeRtos/ are created correctly.

Before linking, I am calling build which is supposed to result in the commands

gcc -g -x c -c src/freeRtos/freeRtosIntegration.c -o build/freeRtos/freeRtosIntegration.o
gcc -g -x c -c src/freeRtos/freeRtosIntegration.c -o build/freeRtos/freeRtosIntegration.o
.PHONY: build

SRC_PREFIX =        src
BUILD_PREFIX =      build
SRCDIRS =           ${SRC_PREFIX} ${SRC_PREFIX}/freeRtos
SEARCHC =           $(addsuffix /*.c ,$(SRCDIRS))
SOURCEFILES :=      $(wildcard ${SEARCHC})
OBJECTFILES :=      $(patsubst %.c,%.o,$(SOURCEFILES))
OBJECTFILES :=      $(subst ${SRC_PREFIX},${BUILD_PREFIX},$(OBJECTFILES))
MP_CC =             gcc
CFLAGS =            -g -x c -c

build: ${OBJECTFILES}

${OBJECTFILES}: %.o: $(subst ${BUILD_PREFIX},${SRC_PREFIX},$@)
    ${MP_CC} ${CFLAGS} $< -o $@

This generates the output

gcc -g -x c -c  -o build/commonModule.o
gcc -g -x c -c  -o build/freeRtos/freeRtosIntegration.o

What do I need to change in my subst command to receive the expected result?

Not so great workaround

This works, but it recompiles every time when calling make

.PHONY: build
.PHONY: echoFiles

SRC_PREFIX =        src
BUILD_PREFIX =      buildTest
SRCDIRS =           ${SRC_PREFIX} ${SRC_PREFIX}/freeRtos
SEARCHC =           $(addsuffix /*.c ,$(SRCDIRS))
SOURCEFILES :=      $(wildcard ${SEARCHC})
OBJECTFILES :=      $(patsubst %.c,%.o,$(SOURCEFILES))
MP_CC =             gcc
CFLAGS =            -g -x c -c

echoFiles:
    @echo ${SOURCEFILES}
    @echo ${OBJECTFILES}

build: ${OBJECTFILES}

${OBJECTFILES}: %.o: %.c
    ${MP_CC} ${CFLAGS} $< -o ${BUILD_PREFIX}$(subst ${SRC_PREFIX},,$@)

Solution

  • Your problem comes from the fact that make expands the prerequisites of rules when it parses the Makefile, but at that time the $@ automatic variable expands as the empty string because it has not been assigned yet; it is defined at a later stage.

    Unless you use GNU make's secondary expansion you cannot use automatic variables in prerequisites, only in recipes.

    Your second attempt is also wrong because you are lying to make: you tell it that the recipe builds src/foo.o while it builds build/foo.o. As a consequence make never finds the object files and always decides that they must be rebuilt. Never lie to make.

    Anyway, there is no need for complex text string manipulations or automatic variables in prerequisites, static pattern rules can perfectly handle your case. You can try:

    .PHONY: build
    
    SRC_PREFIX   := src
    BUILD_PREFIX := build
    SOURCEFILES  := $(wildcard $(SRC_PREFIX)/*.c $(SRC_PREFIX)/freeRtos/*.c)
    OBJECTFILES  := $(patsubst $(SRC_PREFIX)/%.c,$(BUILD_PREFIX)/%.o,$(SOURCEFILES))
    CC           := gcc
    CFLAGS       := -g -x c
    
    build: ${OBJECTFILES}
    
    ${OBJECTFILES}: $(BUILD_PREFIX)/%.o: $(SRC_PREFIX)/%.c
        $(CC) $(CFLAGS) -c $< -o $@
    

    Note the use of patsubst to do the whole substitution at once. Your use of subst was also wrong because it substitutes all occurrences, not just the first. If one of your source files is src/foosrcbar.c, your patsubst + subst combination transforms it to build/foobuildbar.o.