C++ Makefile, Config File

 

The makefile is starting to get rather large, and so it would be difficult for a user to know all options that are available. At this point, it is time to refactor the options into a separate configuration file.

Ideally, the makefile should be able to be dropped into a project and run immediately. Therefore, whatever configuration file is present should be generated by the makefile. We define a large multi-line variable containing the initial contents of the file.

define DEFAULT_INC_CONTENTS
CC       = gcc
CXX      = g++
AR       = ar
RM       = rm -f

CPPFLAGS =
CXXFLAGS = -g -O3
LDFLAGS  =
LDLIBS   =

# And so on and so forth
endef

Unfortunately, because the determination of many targets depends on the values within the config file, we can’t just add it as a target. Instead, we will make it using a $(shell ...) command, if the default.inc does not exist. We will need to do some substitution to make the newlines play nicely. Otherwise, they are parsed as separate lines.

define newline


endef

ifeq (,$(wildcard default.inc))
    $(shell echo '$(subst $(newline),\n,$(value DEFAULT_INC_CONTENTS))' > default.inc)
endif

We then include the file that we just made. As a precaution, we also evaluate the contents of DEFAULT_INC_CONTENTS. If the makefile has been changed since the generation of default.inc, some of the variables needed by the makefile may not have been defined.

$(eval $(DEFAULT_INC_CONTENTS))
include default.inc

Finally, let’s add a welcome message. This will be shown to the user the first time that make is run. In addition, because we use $(error ...) instead of $(info ...), the stops the parsing of the makefile. This way, if settings need to be changed, they can be changed before attempting to compile the project.

define WELCOME_MESSAGE
default.inc not found, generating now
-----------------------------------------------------
|                                                   |
|             Magic C/C++ Makefile                  |
|                   - Eric Lunderberg               |
|                                                   |
-----------------------------------------------------

# And so on
endef #WELCOME_MESSAGE

ifeq (,$(wildcard default.inc))
    $(error $(WELCOME_MESSAGE))
endif

As before, the full makefile can be found on github.