3
\$\begingroup\$

I'm trying to create a generic Makefile that will work with the following directory structure:

  • Project Directory
    • Makefile
    • main.c source file
    • source directory
      • Source files
    • include directory
      • Header files for each source file
    • depend directory
      • GCC generated depend (.d) files for each source/header pair
    • object directory
      • all compiled object (.o) files

It should automatically generate depend files and include them to build the executable. Currently this works for my basic C projects that are all from source but I'm planning on also using this (or some slightly modified version of this) for an OpenGL project using glfw and GLAD. I would like this Makefile to remain cross-platform between MSYS2 on Windows and Linux. Any thoughts?

TARGET      = hashtest # executable name
SOURCE_DIR  = source
OBJECT_DIR  = objects
DEPENDS_DIR = depends
MAIN        = main.c

NAMES   := $(shell find $(SOURCE_DIR) -name "*.c" -printf "%f\n")
SOURCES := $(addprefix $(SOURCE_DIR)/, $(NAMES))
OBJECTS := $(addprefix $(OBJECT_DIR)/, $(NAMES:.c=.o))
DEPS    := $(addprefix $(DEPENDS_DIR)/, $(NAMES:.c=.d))

DEPS += $(DEPENDS_DIR)/$(TARGET).d

INCL_DIRS := $(shell find . -type d -name "include*")
INCL_FLAG := $(addprefix -I , $(INCL_DIRS))

CC            = gcc
OBJ_CFLAGS    = -g -Wall $(INCL_FLAG) -MMD -MP -MF $(DEPENDS_DIR)/$*.Td -c
TARGET_CFLAGS = -g -Wall $(INCL_FLAG) -MMD -MP -MF $(DEPENDS_DIR)/$@.Td
#Add -mwindows to disable console window opening on launch (stdout can only be piped afterwards)

$(TARGET): $(OBJECTS) | $(DEPENDS_DIR)
    $(CC) $(TARGET_CFLAGS) -o $@ $(OBJECTS) $(MAIN)
    @mv -f $(DEPENDS_DIR)/$@.Td $(DEPENDS_DIR)/$@.d && touch $@
    @echo "Build successful."

$(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c $(DEPDIR)/%.d | $(OBJECT_DIR) $(DEPENDS_DIR)
    $(CC) $(OBJ_CFLAGS) -o $@ $<
    @mv -f $(DEPENDS_DIR)/$*.Td $(DEPENDS_DIR)/$*.d && touch $@

$(OBJECT_DIR):
    mkdir -p $(OBJECT_DIR)

$(DEPENDS_DIR):
    mkdir -p $(DEPENDS_DIR)

.PHONY: clean

$(DEPDIR)/%.d: ;

.PRECIOUS: $(DEPDIR)/%.d

clean:
    rm -f $(OBJECT_DIR)/*.o
    rm -f $(DEPENDS_DIR)/*.d
    rm -f $(TARGET)
    @echo "Clean successful."

-include $(DEPS)
```
\$\endgroup\$
  • 1
    \$\begingroup\$ My first thought is: did you try CMake? It probably provides all the features you need. \$\endgroup\$ – Roland Illig Mar 22 at 18:28
  • \$\begingroup\$ What does CMake provide that isn't already in this makefile? \$\endgroup\$ – dylanweber Mar 22 at 18:29
  • \$\begingroup\$ I'm with @RolandIllig and you can find an explanation here on the differences. \$\endgroup\$ – Bo R Mar 23 at 18:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.