Have you ever wanted a simple, easy to configure, flexible Makefile for everyday development? Don’t want to have to invoke automake/autoconf or construct new Makefiles for every little test program? This may be what you’re looking for:
edam’s general-purpose Makefile!
Features:
- Easy configuration (documented below)
- Support for C, C++, assembly (nasm only) and D (gdc only) source files
- Build modes (normal, debug and profile mode)
- Subdirectories (for automatic recursion when building and cleaning)
- A sophisticated dependency file generation system
Download: Makefile (version 2.3, 5KB)
Configuration
Target Settings
The TARGET variable specifies the name of the target.
If uncommented, MKSTATICLIB and MKSHAREDLIB cause a static library or a shared library to be built instead of a binary executable.
For example, to build your libtim.so, you might have:
MKSHAREDLIB := 1
TARGET := libtim.so
Specifying Build Input
Specify all source files you want to build, libraries you want to link against and subdirectories that you want to build first in the variable SOURCES, LIBRARIES and SUBDIRS respectively. All three variables takes a space-separated list.
For example:
LIBRARIES := gl glu
SUBDIRS := subdir1 subdir2
How a file is compiled depends on it’s extension. The following extension types are recognised:
- C source files: .c
- C++ source files: .cc, .C, .cpp
- assembly source files: .s, .S, .asm
- D source files: .d
Please note that while you can happily mix different source file types in the SOURCES variable, you can not have two files named the same thing, but with a different extension (such as “foo.cc” and “foo.c”). For one thing, when compiled, they’d produce object files with the same name.
Build Flags
If you need more control over build flags, use the following variables:
- CPPFLAGS are passed to the C, C++ and D compiler
- CFLAGS is only passed to the C compiler
- CXXFLAGS is only passed to the C++ compiler
- DFLAGS is only passed to the D compiler
- ASFLAGS is only passed to the assembler
- LDFLAGS is passed to the linker before the list of object files
- LDPOSTFLAGS is passed to the linker after the list of object files
For example:
CFLAGS :=
CXXFLAGS :=
DFLAGS :=
ASFLAGS :=
LDFLAGS :=
LDPOSTFLAGS := `pkg-config --libs gtkmm-2.4`
Build Modes
When running make, there are three build modes:
- release — this is the default. Output is optimised and symbol information stripped
- debug — for use in everyday development with gdb.
- profile — for profilling with gprof
Specifying the Build Mode
With no overriding options, the Makefile will build in release mode. There are several ways to initiate a build other than the default. You can:
- Create the environment variables DEBUGMODE and PROFILEMODE and set them to the value “1″. Like this:
$ export DEBUGMODE=1
Alternatively, they should be unset (a value of “0″ will not unset them!), like this:
$ unset DEBUGMODE - Specify a build mode on the make command line, like this:
$ make DEBUGMODE=1
or like this:
$ make DEBUGMODE=This overrides any environment variables set as above.
- Uncomment the build-mode variables at the top of the Makefile to hard-code the build mode (although this is probably a less preferable method!)
This allows for some fairly flexible configurations. What I would recommend for development purposes is to add the line
to your ~/.bashrc so that you are always building in debug-mode by default. Then, when you want to build in release-mode, run make like this:
or to build in profile-mode, like this:
Build Mode Specific Files
Obviously, when compiling, the Makefile will generate .obj files. The release-, debug- and profile-mode versions of these files must be kept separate, as must the resulting executable or library.
To differentiate between build modes, debug-mode files have “_d” appended to them and profile-mode files have “_p” appended to them. So, for example, “test.cc” will compile into “test_d.o” in debug-mode. This in turn may compile into the executable “test_d”. Similarly, in profile-mode, “test.cc” would compile in to “test_p.o”, which in turn would become part of the executable “test_p”.
Dependency Files
In addition to the .obj files, .dep files are generated to track the build dependencies between files. Unlike the .obj files, these are not generated separately for each build-mode. In fact, they are only built in debug-mode.
In a nutshell, dependency files are built as a by-product of compilation (rather than separately), do not include system headers, and include dummy targets to prevent make complaining when depended-upon files are deleted or renamed.
For more information about the dependency file generation system, see this excellent article on advanced auto-dependency generation. The full system outlined in the article is implemented with the slight improvement that dummy targets are created at compile-time, not in post-processing by an unsightly sed command. The unsightly sed command is still used, however, for other, less-able compilers/assemblers.
On a final note, dependency files are not generated for D.
Make Goals
The full list of goals for the general-purpose Makefile are:
- all — the default; builds any subdirectories and then any target
- subdirs — builds the subdirectories (but not any target)
- target — builds the target (but not any subdirectories)
- run — builds the target (but not any subdirectories) and, on success, executes it
- clean — removes intermediate build files for the target only
- clean_all — removes intermediate build files for the target and any subdirectories
- <subdir> — you can specify a specific subdirectory to build (so long as it is defined in SUBDIRS)
- <file> — you can also specify any object files, or the target, as with most Makefiles
Finally
There have been many revisions of this Makefile. If you find any errors, or have any suggestions for its improvement, please email me. I would love to hear about them.