Skip to content
Jason Travis edited this page Dec 7, 2013 · 9 revisions

How to set up Rules.mk - with examples

You already know that Rules.mk is nearly all what users need to know :). Let me explain how it looks like. First rule is that there should be header.mk/footer.mk included at the beginning/end of Rules.mk. These two files are needed since header cleans the variables that you can use in Rules.mk and footer is where everything you've typed in Rules.mk is translated into a proper makefile rules.

Simple case - "automatic" targets

Since it is after all makefile system we need to provide some targets that should be built in given directory. In simple cases - e.g. when you just want to compile sources into object files you can just use SRCS variable (or OBJS - to be specific if OBJS is not defined then SRCS is used - with extension of all files in it changed into .o).

Here's an example from first example provided saying that in directory Dir_2/Dir_2a you need to compile three files

#-8<---Dir_2/Dir_2a/Rules.mk---
SRCS := dir_2a_file1.c dir_2a_file2.c dir_2a_file3.c
#-8<---Dir_2/Dir_2a/Rules.mk---

Normally wildcards in variable assignments are not expanded in make but this make system detects wildcards in SRCS and expands them (both in directory of the Rules.mk and its SRCS_VPATH subdirectories - see below what SRCS_VPATH is used for). Thus you can simply say in Rules.mk:

SRCS := *.c

If you have directory with large number of files where simple glob is what you want to use in SRCS but there are some files that you'd like to exclude just list them in SRCS_EXCLUDES :) - this is a list of makefile patterns e.g.

SRCS_EXCLUDES := extra% test%

like it is shown in Rules.mk in Dir_1/Dir_1a directory. Of course you can use the built in make wildcards but you should do that as follows:

SRCS := $(notdir $(wildcard $(d)/*.c))

Keep in mind that the directory where make is invoked is usually different from where given Rules.mk is located (d is the directory of given Rules.mk). In a more general case, for any target that is automatically handled (its pattern is mentioned in AUTO_TGTS and which has corresponding entry in skeleton macro - see def_rules.mk - or it has its own build rules, possibly built in make itself) you don't have to provide DEPS/LIBS/CMD vars - which are discussed below.

Targets with explicit dependencies/libs/commands

In a more complicated situation you use following variables (taken from the Rules.top of the first example in the repository):

#-8<---Rules.top---------------
1:  TARGETS := app.exe cli.exe
2:  SUBDIRS := Dir_1 Dir_2 Dir_3
3:
4:  app.exe_DEPS = top_a.o top_b.o main.o $(SUBDIRS_TGTS)
5:  app.exe_LIBS = -lm
6:  # Let's use DEFAULT_MAKECMD for app.exe
7:
8: cli.exe_DEPS = cli.o cli_dep.o
9: cli.exe_CMD = $(LINK.c) $(^R) $(LDLIBS) -o $@
#-8<---Rules.top---------------
  • Line 1 - this directory has two targets that should be built.
  • Line 2 - this directory has three subdirectories that should be scanned
  • Line 4 - app.exe depends on ... (SUBDIRS_TGTS is a convenience variable that contains all the targets from the subdirectories mentioned at line 2)
  • Line 5 - app.exe should be linked with math library (it will be added to LDLIBS for this target)
  • Line 6 - app.exe will be built with default "rule"
  • Line 8 - cli.exe depends on ... and
  • Line 9 - use the following command to build it (notice $(^R) instead of simple $^ - see description of OBJDIR on List Of Features)

So every target can have its DEPS, LIBS and CMD.

DEPS

This variable tells what are the target dependencies. When supplying its value you can refer to objects from the same directory with no directory prefix. To be specific all dependencies that are not absolute paths will be treated as ones from the $(OBJDIR) subdirectory of current directory (see List Of Features for explanation of OBJDIR and OBJPATH). You can use SUBDIRS_TGTS variable which will list all targets in subdirectories. You can also name them explicitly like $(TARGETS_$(d)/subdir) and so on - see e.g. the Rules.mk in Dir_2 directory where Dir_ex is mentioned as a subdirectory but is excluded from the DEPS (this allows you to create folders that "inherit" all the setting from the project build system - and thus have simple structure of Rules.mk - but are not meant to be a part of the project itself, like examples :)).

If you would like to have all targets from a subtree listed (not just subdirectories) you can use subtree_tgts macro just like it is shown in second example Rules.top:

#-8<---Rules.top---------------
TARGETS := app.exe
SUBDIRS := a b

app.exe_DEPS = app.o $(call subtree_tgts,$(d)/a) $(TARGETS_$(d)/b)
#-8<---Rules.top---------------

Here you have two subtrees starting at a and b. First one has only objects generated and all these object are made dependencies of app and second one gathers all objects from its subtree into one archive like that:

#-8<---Rules.mk---------------
TARGETS := b.a
SUBDIRS := 1 2

# You can't use simple $(call subtree_tgts,$(d)) since it includes
# target of this directory also and this would be a circular dependency
b.a_DEPS = b.o $(foreach sd,$(SUBDIRS_$(d)),$(call subtree_tgts,$(sd)))
#-8<---Rules.mk---------------

and in top level rules we can just add this archive as a dependency.

One last thing about the TARGETS/OBJS. By default source files for the objects are searched in the directory where Rules.mk is, but if you want to have source files in a subdirectory (say src) you can do that via SRCS_VPATH variable (see List Of Features for explanation).

LIBS

Not much to say here :). LIBS specified here are eventually expanded in LDLIBS variable when updating the target. This variable is used by several make built in rules (and also default update command that this make system uses - see below) and you can use it if you create your own rule or MAKECMD.*.

CMD

Again not much to say :). You can provide command line that should be invoked to build the target but when CMD is not present then either MAKECMD.suff (where .suff is the suffix of the target) or DEFAULT_MAKECMD is used - take a look into skel.mk, and see how MAKECMD.a defines what should be run to build an archive. You should remember though what has been said in Variables section of Basic Concepts - in particular that you should avoid using d in CMD variables.

Warning

Starting with 070f681 you can have in your project two LIBS, LDFLAGS or CMD variables (that is those that are used during second phase of make execution) that have the same names (previously that was not supported). For example in one part of your tree you're generating target abc which has it's abc_CMD and in the other part another target that has the same name and also it's own command. However there is a catch here! Since these variables are not mandatory (you don't have to provide them for each target) in order to differentiate between case where abc_CMD was actually given for this instance of abc target from the situation where abc_CMD is still visible from previous instance of abc target those abc_(LIBS|LDFLAGS|CMD) variables are cleared once their value is used/remembered (see save_vars macro in skel.mk). That means referring to these variables outside Rules.mk where they were assigned will not work (and even in the same Rules.mk they will work only in case of simply expanded variables - not recursive). If you have such need I'd advice to introduce your own variable and use this variable in all places, e.g.:

MATH_LIBS := -lgsl -lgslcblas -lm
...
TARGETS := abc

abc_DEPS = ...
abc_LIBS = $(MATH_LIBS)
...