0

Here is my Makefile. All the %.o depend on %.c and main.h, except the ones under main, event, cmd folder, which depend on $(MAIN_HEADERS).

How do I combine the below and make them simpler, as their recipes are all the same?

$(BUILD_OBJ_DIR)/%.o: %.c main.h
    @mkdir -p $(dir $@)
    @$(CC)  $(CFLAGS) -c $< -o $@
    @echo "CC  $(patsubst $(PWD)/%,%,$<)"

$(BUILD_OBJ_DIR)/main/%.o: main/%.c $(MAIN_HEADERS)
    @mkdir -p $(dir $@)
    @$(CC)  $(CFLAGS) -c $< -o $@
    @echo "CC  $(patsubst $(PWD)/%,%,$<)"

$(BUILD_OBJ_DIR)/event/%.o: event/%.c $(MAIN_HEADERS)
    @mkdir -p $(dir $@)
    @$(CC)  $(CFLAGS) -c $< -o $@
    @echo "CC  $(patsubst $(PWD)/%,%,$<)"

$(BUILD_OBJ_DIR)/cmd/%.o: cmd/%.c $(MAIN_HEADERS)
    @mkdir -p $(dir $@)
    @$(CC)  $(CFLAGS) -c $< -o $@
    @echo "CC  $(patsubst $(PWD)/%,%,$<)"
2
  • 2
    Pattern rules shouldn't have non-pattern dependencies; add a separate non-pattern "rule" to just add the dependency (but no commands) Commented Oct 17 at 3:07
  • @o11c could you please explain or give the source of why shouldn't Pattern rules have non-pattern dependencie? My Makefile work actually, just tedious. Commented Oct 17 at 6:50

2 Answers 2

2

How do I combine below and make it simpler, as their recipy are all the same.

Given that the only differences among the rules are the prerequisite headers, a fairly good way to handle the situation would be to generate those prerequisites automatically. This does suppose a compiler that is capable of doing so, but there are several popular compilers that can do, with GCC heading the list.

Doing so does require you to have a list, in a variable, of all the sources (or all the objects), but it would allow you to reduce the four redundant rules expressed explicitly in your makefile to two non-redundant ones (plus multiple automatically generated makefile fragments). Something along these lines, for example:

# ...

$(BUILD_OBJ_DIR)/%.o: %.c
    @mkdir -p $(dir $@)
    @$(CC)  $(CFLAGS) -c $< -o $@
    @echo "CC  $(patsubst $(PWD)/%,%,$<)"

%.d: %.c
        @set -e; rm -f $@; \
         $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
         sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
         rm -f $@.$$$$

include $(sources:.c=.d)

(Based on the above-linked chapter of the GNU make manual.)

Sign up to request clarification or add additional context in comments.

1 Comment

Hi John, thanks for your answer. This looks promising. However it is also misleading for things like: the CPPFLAGS shold be replaced by CFLAGS, the output ".o" file location is not inside $(BUILD_OBJ_DIR), the "sources" is actually a variable for all the source file (mine is CSRCS) ... etc I will definitely look up the automatically generated prerequisites, thanks
2

You can add rules without recipe to add dependencies:

SRC := $(wildcard main/*.c event/*.c cmd/*.c)
OBJ := $(patsubst %.c,$(BUILD_OBJ_DIR)/%.o,$(SRC))

$(OBJ): $(MAIN_HEADERS)

$(BUILD_OBJ_DIR)/%.o: %.c main.h
    @mkdir -p $(dir $@)
    @$(CC)  $(CFLAGS) -c $< -o $@
    @echo "CC  $(patsubst $(PWD)/%,%,$<)"

3 Comments

This solution is the exactly what chatgpt sugggest and doesn't work in my environment with GNU Make 4.3. Does it work in your environment?
Sorry, my bad, you cannot do this with pattern rules without recipes. Please see my updated answer to do it with non-pattern rules.
Wait; A human knows more than ChatGPT? In fact, the updated answer and @John Bollingers are similar. The other answer uses a gcc mechanic to automatically create the dependencies from parsing the source. Still an interesting fact that pattern match doesn't allow dependency lists.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.