Skip to content

Instantly share code, notes, and snippets.

@eddieh
Created December 29, 2021 01:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eddieh/67ac677db19264ecbeb578543b4bf65f to your computer and use it in GitHub Desktop.
Save eddieh/67ac677db19264ecbeb578543b4bf65f to your computer and use it in GitHub Desktop.
GNU Make Oddness (with -rR)

GNU Make Oddness

Since version 4.0 of GNU Make a feature was added that almost every makefile should use. The 4.0 release notes describes the feature as “setting the -r and -R options in MAKEFLAGS inside a makefile now works as expected, removing all builtin rules and variables, respectively.”

Unfortunately, despite the claim it does not work as expected. Maybe there’s some justification for the behavior, but it certainly isn’t expected.

Why set the make flags -r and -R? The Linux makefile explains it perfectly “Do not use make’s builtin rules and variables (this increases performance and avoids hard-to-debug behavior).”

For me personally, setting those flags makes the ever useful output of -p and -d less verbose and easier to read.

For this explainer I created two makefiles. Makefile.builtins and Makefile.nobuiltins:

Makefile.builtins

$(foreach v, $(.VARIABLES), $(info $(v)))

Makefile.nobuiltins

MAKEFLAGS += -rR
$(foreach v, $(.VARIABLES), $(info $(v)))

Each makefile will print a list of defined variables names. We can easily count how many variables each makefile has defined by piping to wc.

$ make -f Makefile.builtins | wc -l
make: *** No targets.  Stop.
   107

This invocation is showing 107 defined variables. This number includes variables inherited from the environment, which is around 10 variables in the chroot environment I’m using. So make has around 97 builtin variables. So how many variables does the second makefile have defined?

make -f Makefile.nobuiltins | wc -l
make: *** No targets.  Stop.
     107

I told you the behavior isn’t as expected.

To prove the behavior of -rR on the command line isn’t the same as setting MAKEFLAGS consider the next invocation:

make -f Makefile.builtins -rR | wc -l
make: *** No targets.  Stop.
      44

Why isn’t it 0 (or 10 counting the inherited variable from the environment)? That’s because make needs a few variables to be around no matter what.

Those variables as far as I can tell are:

.DEFAULT_GOAL
.FEATURES
.LOADED
.RECIPEPREFIX
.SHELLFLAGS
.VARIABLES
CURDIR
GNUMAKEFLAGS
MAKE
MAKEFILES
MAKEFILE_LIST
MAKEFLAGS
MAKELEVEL
MAKE_COMMAND
MAKE_HOST
MAKE_TERMERR
MAKE_VERSION
MFLAGS
SHELL
SUFFIXES

and the cryptic variables %D %F *D *F +D +F <D <F ?D ?F @D @F ^D ^F

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment