Last active
May 12, 2024 21:49
-
-
Save maxtruxa/4b3929e118914ccef057f8a05c614b0f to your computer and use it in GitHub Desktop.
Generic makefile for C/C++ with automatic dependency generation, support for deep source file hierarchies and custom intermediate directories.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# output binary | |
BIN := test | |
# source files | |
SRCS := \ | |
test.cpp | |
# files included in the tarball generated by 'make dist' (e.g. add LICENSE file) | |
DISTFILES := $(BIN) | |
# filename of the tar archive generated by 'make dist' | |
DISTOUTPUT := $(BIN).tar.gz | |
# intermediate directory for generated object files | |
OBJDIR := .o | |
# intermediate directory for generated dependency files | |
DEPDIR := .d | |
# object files, auto generated from source files | |
OBJS := $(patsubst %,$(OBJDIR)/%.o,$(basename $(SRCS))) | |
# dependency files, auto generated from source files | |
DEPS := $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS))) | |
# compilers (at least gcc and clang) don't create the subdirectories automatically | |
$(shell mkdir -p $(dir $(OBJS)) >/dev/null) | |
$(shell mkdir -p $(dir $(DEPS)) >/dev/null) | |
# C compiler | |
CC := clang | |
# C++ compiler | |
CXX := clang++ | |
# linker | |
LD := clang++ | |
# tar | |
TAR := tar | |
# C flags | |
CFLAGS := -std=c11 | |
# C++ flags | |
CXXFLAGS := -std=c++11 | |
# C/C++ flags | |
CPPFLAGS := -g -Wall -Wextra -pedantic | |
# linker flags | |
LDFLAGS := | |
# linker flags: libraries to link (e.g. -lfoo) | |
LDLIBS := | |
# flags required for dependency generation; passed to compilers | |
DEPFLAGS = -MT $@ -MD -MP -MF $(DEPDIR)/$*.Td | |
# compile C source files | |
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(CPPFLAGS) -c -o $@ | |
# compile C++ source files | |
COMPILE.cc = $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ | |
# link object files to binary | |
LINK.o = $(LD) $(LDFLAGS) $(LDLIBS) -o $@ | |
# precompile step | |
PRECOMPILE = | |
# postcompile step | |
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d | |
all: $(BIN) | |
dist: $(DISTFILES) | |
$(TAR) -cvzf $(DISTOUTPUT) $^ | |
.PHONY: clean | |
clean: | |
$(RM) -r $(OBJDIR) $(DEPDIR) | |
.PHONY: distclean | |
distclean: clean | |
$(RM) $(BIN) $(DISTOUTPUT) | |
.PHONY: install | |
install: | |
@echo no install tasks configured | |
.PHONY: uninstall | |
uninstall: | |
@echo no uninstall tasks configured | |
.PHONY: check | |
check: | |
@echo no tests configured | |
.PHONY: help | |
help: | |
@echo available targets: all dist clean distclean install uninstall check | |
$(BIN): $(OBJS) | |
$(LINK.o) $^ | |
$(OBJDIR)/%.o: %.c | |
$(OBJDIR)/%.o: %.c $(DEPDIR)/%.d | |
$(PRECOMPILE) | |
$(COMPILE.c) $< | |
$(POSTCOMPILE) | |
$(OBJDIR)/%.o: %.cpp | |
$(OBJDIR)/%.o: %.cpp $(DEPDIR)/%.d | |
$(PRECOMPILE) | |
$(COMPILE.cc) $< | |
$(POSTCOMPILE) | |
$(OBJDIR)/%.o: %.cc | |
$(OBJDIR)/%.o: %.cc $(DEPDIR)/%.d | |
$(PRECOMPILE) | |
$(COMPILE.cc) $< | |
$(POSTCOMPILE) | |
$(OBJDIR)/%.o: %.cxx | |
$(OBJDIR)/%.o: %.cxx $(DEPDIR)/%.d | |
$(PRECOMPILE) | |
$(COMPILE.cc) $< | |
$(POSTCOMPILE) | |
.PRECIOUS: $(DEPDIR)/%.d | |
$(DEPDIR)/%.d: ; | |
-include $(DEPS) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
int main() { | |
std::cout << "Hello, World!\n"; | |
return 0; | |
} |
@maxsupermanhd I had the same problem and got the makefile to handle repeated builds by treating $(DEPDIR)/%.d
as an order-only dependancy, so that the creation date of the dependancy files doesn't matter.
Note to future readers: Save yourself the trouble and just use CMake.
How do I specify a source directory? Do I have to list out all of the files that need to be compiled and then make
will calculate dependencies? Or can I just tell it to "compile ./src/main.cpp
" and then it will look at all of the files in ./src
?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@johan-boule Yes, thank you for pointing that out. Sadly, I haven't had the time to fix that.