Make

Go to: Links · Usecase · Response to Make criticism · My C++ Makefile project · Alternatives · CMake · Autotools

Usecase

GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program’s source files.

A Makefile is the input file for programs called make. It’s a logic program that is both declarative and procedural.

But why both? To understand this, we should look into the primary usecase for make: software compilation. Software compilation usually means running a series of instructions depending on what files have changed to produce other files. The goal is to make software compilation efficient during development: we don’t want to recompile parts of the program that is unchanged.

We can use declarative programming to specify what is effected by a file change, and use procedural programming to describe what needs to be done to create certain files.

Sometimes we cannot declare this dependency upfront, because this relation may depend on the content of the file. As an example object files may not only depend on .c files but on header files too. gcc -MMD can help us by generating dependency files (.d) that we can include in the Makefile. This approach can be useful even if don’t have a ready-made tool to generate the dependency files: we can generate this by ourselves too. Example: category pages for my notebook

Build system

make is suitable for your project as a build system: if you don’t need a meta build system.

If you:

But avoid make if:

Task automation

In genaral make is probably suitable for you project as a task automation tool. Give your projects a unified interface, save frequently used commands to execute repetitive tasks quickly.

Good things:

Bad things:

When should I use make?

First we have to define a scope to work in. If the problem requires deep understanding of the assembly code, we need to have deep understanding of the compilers. If all your interaction with the OS can be solved with the help of cmake modules and you don’t care about what happens in the background that is also a valid problem scope.

Make is suitable your task if you want to solve it with multiple tools following the UNIX philosophy.

Response to Make criticism

Make commands aren’t documented

When using Make, the Makefile and other source code is all the documentation that is provided.

Definitely not self-documenting, but we can have something like this:

help:
    @echo "usage: make [OPTIONS] <target>"
    @echo "  Options:"
    @echo "    > VERBOSE Show verbose output for Make rules. Default 1. Disable with 0."
    @echo "    > SANITIZER Compile with GCC sanitizer. Default none. Options: address, thread, etc."
    @echo "Targets:"
    @echo "  debug: Builds all with debug flags"
    @echo "  release: Build with optimiser"
    @echo "  test: Build test executable"

Or autogenerate this from comments

Makes does not come with batteries included

Want to interact with a web API? You need to have cURL installed. Want to parse a text or configuration file? You’ll need awk or sed.

What is the alternative here? How does a tool like invoke solves this? pip install requests?

To check if an executable is installed we can use something like this:

CPPCHECK = cppcheck

define check_exec
    @command -v $(1) >/dev/null || (echo ERROR: $(1) not found in path >&2; exit 1)
endef

cppcheck:
    $(call check_exec, $(CPPCHECK))
    $(CPPCHECK) $(CPPCHECKFLAGS) $(SRC) $(SRC_TESTS) $(INCLUDE)

(??? or use $(error text…))

Make does not support cross platform builds

Want to make the CLI cross platform? You’ll need to handle differences between Windows, Mac and Linux packages and their shell quirks.

That is correct.

Make is hard to debug

With this:

print-%:
    @echo $* = $($*)

We can at least print the variables:

djen at xps in ~/example-cpp-project
make print-CXXFLAGS
CXXFLAGS = -std=c++17 -I/usr/include/png++
djen at xps in ~/example-cpp-project
make SANITIZER=thread print-CXXFLAGS
CXXFLAGS = -std=c++17 -I/usr/include/png++ -fsanitize=thread

Scaling

In Memfault’s codebase, we have around 100 tasks, most of which are namespaced under general top-level modules.

We can organise code in separate files MyModule.include and have them included.

If your project is less complex then the Linux kernel, there is chance that you can handle it.

My C++ Makefile project

Features:

Portable Makefiles?

Notable GnuMake features:

Portable syntaxes:

Alternatives

Notes on CMake

Is CMake really the “cpp standard”? Check out the Rise of Meson.

Introduction to modern CMake

Notes on Autotools

Autotools.info

#sw #build