Nicolás Brailovsky


A modern blog

Makefiles

author Posted by: nico on date Aug 18th, 2011 | filed Filed under: Makefiles

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:

  1. # Dependency directoy
  2. df=$(BUILD_DIR)/$(*D)/$(*F)
  3.  
  4. $(OBJECTS): $(BUILD_DIR)/%.o: %.cpp
  5.         @mkdir -p $(BUILD_DIR)/$(*D)
  6.         $(COMPILE.cpp) -MD -o $@ $<
  7.         @cp $(df).d $(df).P; \
  8.         sed -e ‘s/#.*//’ -e ‘s/^[^:]*: *//’ -e ‘s/ *\\$$//’ \
  9.                 -e ‘/^$$/ d’ -e ‘s/$$/ :/’ < $(df).d >> $(df).P; \
  10.         rm -f $(df).d
  11.  
  12. $(MAIN_OBJ): $(MAIN_SRC)
  13.         $(COMPILE.cpp) -MD -o $@ $<
  14.  
  15. # Binary name depends on BIN_DIR/BIN_NAME, so the call to create BIN can
  16. # be forwarded to BIN_DIR/BIN_NAME
  17. $(BINARY): $(BIN_DIR)/$(BINARY)
  18. $(BIN_DIR)/$(BINARY): $(OBJECTS) $(DEPS_OBJECTS) $(MAIN_OBJ)
  19.         @mkdir -p $(BIN_DIR)
  20.         @# Workaround for a linker bug: if the libs are not
  21.         @# at the end it won‘t link (something to do with how the linker
  22.         @# lists the dependencies… too long for a comment, rtfm
  23.         g++ $(CXXFLAGS) $^ -o $(BIN_DIR)/$@ $(LDFLAGS)
  24.         @#$(LINK.cpp) $^ -o $@
  25.  
  26. -include $(DEPENDS)

How is this used? Well, don’t even try to understand the dependency autogeneration, it’ll make your head explode.

  1. $(OBJECTS): $(BUILD_DIR)/%.o: %.cpp

This defines a rule for building .o objects; a variable named OBJECTS should be present when including this file.

  1. $(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).

  1. $(BINARY): $(BIN_DIR)/$(BINARY)
  2. $(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.

tag2 Responses to “Makefiles”

  1. Nicolás Brailovsky » Blog Archive » A Makefile for TDD with C++ Said,

    [...] 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, [...]

     Add A Comment

trackback Trackback URI | rsscomment Comments RSS