PescadorParrudo PescadorParrudo - 10 months ago 69
C Question

Makefile implicit rule not working

I have this makefile and i'm trying to write some test targets

#This a make file of serial communication driver that i'm writing.
#serial_target would be a target to test this driver isolated.
CC = gcc
#mains macros
BUILD_DIR =build
BIN_DIR =bin
SOURCES = $(wildcard $(SOURCE_DIR)/*.c)
OBJECTS =  $(patsubst $(SOURCE_DIR)/%.c, $(BUILD_DIR)/%.o, $(SOURCES))
HEADERS =  $(patsubst $(SOURCE_DIR)/%.c, $(HEADER_DIR)/%.h, $(SOURCES))
TEST_SOURCES = $(wildcard $(TEST_DIR)/*_test.c) \
TEST_OBJECTS = $(filter %.o ,$(patsubst %.c, $(BUILD_DIR)/%.o, $(subst /, , $(TEST_SOURCES))))
serial_test: $(TEST_OBJECTS)
    $(CC) $(CFLAGS) -I$(SOURCE_DIR) -I$(HEADER_DIR) -o $(BIN_DIR)/$@ $^
$(BUILD_DIR)/%.c.o: %.c $(HEADERS)
    $(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@    
    mkdir $(BUILD_DIR)
    mkdir $(BIN_DIR)
    rm -rf $(EXEC) $(OBJECTS)

When running "make serial_test", I'm always getting this:

make: *** No rule to make target `build/serial_test.o', needed by `serial_test'. Stop.

Here's the doubt. Why I'm receiving this error if the rule $(BUILD_DIR)/%.c.o exists?


To make sure that everything else was working I've tried this(this works fine)

serial_test: $(TEST_OBJECTS)
build/serial_test.o: src/test/serial_test.c
$(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@
build/serialCom_xsens.o: src/serialCom_xsens.c
$(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@

To make sure that the variable BUILD_DIR was note empty i did this:

$(BUILD_DIR)/serial_test.o: %.c
$(CC) $(CFLAGS) -I$(HEADER_DIR) -I$(SOURCE_DIR) -c $< -o $@

With this code above, I got another error:

make: *** No rule to make target `%.c', needed by `build/serial_test.o'. Stop.

  • Is there any chance of %.c and %.o rules are broken?

  • If you have any design tips just answer. That would be helpful too.

Answer Source
  • You're mixing pattern and suffix rules, stick with the pattern rule
  • Not entirely sure what you're trying to do with TEST_OBJECTS
  • You're making ever object depend on every header, use dependency generation instead
  • The rule for serial_test is broken, always use $@ as the output of any given rule
  • Make the directories a prerequisite
  • Recycle the built-in recipes (COMPILE.c, LINK.o)
display_string := -Ddisplay_string

source_dir := src
header_dir := src
build_dir  := build
bin_dir    := bin
sources := $(wildcard $(source_dir)/*.c)
objects := $(sources:$(source_dir)/%.c=$(build_dir)/%.o)
test_dir    := src/test
test_target := serial_test
test_sources := $(wildcard $(test_dir)/*_test.c)
test_objects := $(test_sources:$(test_dir)/%.c=$(build_dir)/%.o) $(objects)
deps := $(test_objects:%.o=%.d)

CFLAGS := $(display_string) -I$(header_dir) -MMD -MP
$(bin_dir)/serial_test: $(test_objects) | $(bin_dir)
    $(LINK.o) $^ $(LDLIBS) -o $@
$(build_dir)/%.o: $(source_dir)/%.c | $(build_dir)
$(build_dir) $(bin_dir): ; mkdir $@
clean: $(RM) serial_test $(objects) $(deps)

-include $(deps)