For open source projects, makefiles are a must. All C++ projects need them, even though cmake is strong nowadays, and even though Java has its own version (actually, several of them, but that's not important now) a makefile could be used.
Even if it is an ubiquitous build system, it is pretty much outdated nowadays, and although using its basic features is easy, mastering it is a complex task. Worst still, mastering makefiles means you'll probably produce write-only-code, and as makefiles are code themselves, and must therefore be maintained, this can be a nuisance to a newcomer to your project.
There's an upside to makefiles being code: they can be reused. Once you find a configuration that suits your development process, you don't need to write it again. I'll post here some of the main targets I ussually include in a common.mk. As I mentioned, it's mostly write-only-code, yet you may find it useful:
# Dependency directoy
df=$(BUILD_DIR)/$(*D)/$(*F)
$(OBJECTS): $(BUILD_DIR)/%.o: %.cpp
@mkdir -p $(BUILD_DIR)/$(*D)
$(COMPILE.cpp) -MD -o $@ $<
@cp $(df).d $(df).P;
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\$$//'
-e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P;
rm -f $(df).d
$(MAIN_OBJ): $(MAIN_SRC)
$(COMPILE.cpp) -MD -o $@ $<
# Binary name depends on BIN_DIR/BIN_NAME, so the call to create BIN can
# be forwarded to BIN_DIR/BIN_NAME
$(BINARY): $(BIN_DIR)/$(BINARY)
$(BIN_DIR)/$(BINARY): $(OBJECTS) $(DEPS_OBJECTS) $(MAIN_OBJ)
@mkdir -p $(BIN_DIR)
@# Workaround for a linker bug: if the libs are not
@# at the end it won't link (something to do with how the linker
@# lists the dependencies... too long for a comment, rtfm
g++ $(CXXFLAGS) $^ -o $(BIN_DIR)/$@ $(LDFLAGS)
@#$(LINK.cpp) $^ -o $@
-include $(DEPENDS)
How is this used? Well, don't even try to understand the dependency autogeneration, it'll make your head explode.
$(OBJECTS): $(BUILD_DIR)/%.o: %.cpp
This defines a rule for building .o objects; a variable named OBJECTS should be present when including this file.
$(MAIN_OBJ): $(MAIN_SRC)
A special rule is defined for a main object (actually this is needed to compile the tests, which we'll do next time, since you may have a different main function).
$(BINARY): $(BIN_DIR)/$(BINARY)
$(BIN_DIR)/$(BINARY): $(OBJECTS) $(DEPS_OBJECTS) $(MAIN_OBJ)
And finally, a rule for to create the real binary. Next time I'll add some cool features for TDD to this makefile.
[...] Makefiles [...]
ReplyDelete[...] after reading my post about makefiles you decided that you like them but would like to add some TDD to be buzzword compliant? No problem, [...]
ReplyDelete