Search code examples
gnu-make

GNUMake: How to use patterns with subdirectories?


My original Makefile build rules were:

SRCS := $(shell find . -name '*.c')
HEADERS := $(shell find . -name '*.h')
OBJS := $(SRCS:.c=.o)

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

executable : $(OBJS) $(HEADERS)
  $(CC) $(CFLAGS) $(OBJS) -o executable

I'd like to move .c and .h files into a src/ directory, and have the .o files generated into a obj/ directory, but I'm struggling a bit:

SRCS := $(shell find src/ -name '*.c')
HEADERS := $(shell find src/ -name '*.h')
OBJS := $(SRCS:.c=.o)  <- what do I replace this line with??

obj/ :
  mkdir -p obj

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

bin/ :
  mkdir -p bin

bin/executable : $(OBJS) $(HEADERS) bin/
  $(CC) $(CFLAGS) $(OBJS) -o bin/executable

Is there an easy way to generate the obj/%.o filepaths from the src/%.c filepaths? I tried searching through the docs, but didn't know what keywords to look for.


Solution

  • Better than shell is to use wildcard, unless you have subdirectories:

    SRCS := $(wildcard src/*.c)
    HEADERS := $(shell find src/ -name '*.h')
    

    You can use the simplified form:

    OBJS := $(SRCS:src/%.c=obj/%.o)
    

    or use the patsubst function:

    OBJS := $(patsubst src/%.c,obj/%.o,$(SRCS))