73

I want to disable builtin rules and variables as per passing the -r and -R options to GNU make, from inside the make file. Other solutions that allow me to do this implicitly and transparently are also welcome.

I've found several references to using MAKEFLAGS, and had similar problems.

Martin Thomson
  • 3,433
  • 2
  • 16
  • 13
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • 3
    You're not making a cthulhoid build system, are you Joiner? – Jack Kelly Nov 08 '10 at 23:33
  • One among many, this time it generates make files for free parallelism. Converting to C++ has increased my build times tenfold which is unacceptable. – Matt Joiner Nov 09 '10 at 06:56
  • 4
    "Converting to C++ ... is unacceptable." – Matt Joiner. ;-) – Jack Kelly Nov 09 '10 at 23:57
  • 2
    Do you have control over what's invoking the `Makefile`, then? If so, just read `$(MAKEFLAGS)` and fail if it's not called with the correct options. – Jack Kelly Nov 09 '10 at 23:58
  • 1
    I also want to know a good trick for this. Twice on separate occasions I have lost work because stupid make did this `mv y.tab.c foo.c`, and `lex -t foo.l > foo.c`. Some of the built in rules have C sources as their target. If you have a `foo.y` yacc file or `foo.l` lex file, make will happily clobber your `foo.c` file that is not intended to be made from either of these. POSIX demands this, evidently. – Kaz Oct 06 '13 at 02:05
  • @Kaz: If that's the case consider upvoting the question :P – Matt Joiner Oct 06 '13 at 04:28

8 Answers8

48

Disabling the built-in rules is done by writing an empty rule for .SUFFIXES:

.SUFFIXES:

Having erased the built-in rules, I'm not sure that erasing the built-in variables helps you much more than just remembering to set them yourself or not use them, but you could use something like

$(foreach V,
    $(shell make -p -f/dev/null 2>/dev/null | sed -n '/^[^:#= ]* *=/s/ .*//p'),
    $(if $(findstring default,$(origin $V)),$(eval $V=)))

...which is admittedly fairly crazy. If there is a way to get a list of the defined variables from within make (instead of shelling out to another make), it would be viable. As it is, it's not really much better than

CC=
CXX=
# etc, for each likely built-in variable
John Marshall
  • 6,815
  • 1
  • 28
  • 38
  • This is nice, but a bit too hacky. – Matt Joiner Mar 19 '11 at 01:56
  • 4
    I don't think this handles the built-in [match anything rules](http://www.gnu.org/software/make/manual/make.html#Match_002dAnything-Rules) – Brandon Bloom Jan 12 '12 at 00:31
  • 1
    [It seems](https://savannah.gnu.org/bugs/?20501) that in some versions of GNU Make, clearing `.SUFFIXES` disables built-in _suffix rules_ but not _pattern rules_ (see Brandon's answer). In my version of GNU Make (3.81) `.SUFFIXES` appears sufficient, though. – Søren Løvborg Jul 11 '14 at 15:18
  • 2
    On make 3.82, this still doesn't disable automatic rules like `cp Sample Sample.out` – rjh Aug 09 '18 at 06:31
  • Using the same link you have mentioned, >SUFFIXES would be empty if no-builtin-rules is active: >The ‘-r’ or ‘--no-builtin-rules’ flag causes the default list of suffixes to be empty – PMN Mar 09 '21 at 09:49
  • 1
    @PMN: The question in this case is: “I know about the -r etc options, but is there a way to do this from _inside_ the makefile”. – John Marshall Mar 09 '21 at 11:32
38

@hseldon has the right idea because .SUFFIXES doesn't cover the match-everything built-in implicit rules. However, I don't think his syntax is exactly right.

MAKEFLAGS += --no-builtin-rules

.SUFFIXES:
.SUFFIXES: .you .own .here

See http://www.gnu.org/software/make/manual/make.html#Match_002dAnything-Rules and http://www.gnu.org/software/make/manual/make.html#index-g_t_002eSUFFIXES-998

Brandon Bloom
  • 1,301
  • 10
  • 26
  • That doesn't do it for me. I have a rule. % : foo.o bar.o and on execution make does "rm foo.o bar.o". That does not go away with your proposed flag setting. – Victor Eijkhout Sep 10 '13 at 16:30
  • 6
    @VictorEijkhout: That's not caused by built-in rules, but by [chaining of rules](https://www.gnu.org/software/make/manual/html_node/Chained-Rules.html). Use `.SECONDARY` to prevent automatic removal. – Søren Løvborg Jul 11 '14 at 15:23
  • 1
    Note to readers: `.SUFFIXES:` is not needed if you just want to do away with the built-in rules. `MAKEFLAGS` is all you need. – André Chalella Oct 02 '19 at 18:36
  • @AndréChalella: not true in my case. Using both statements I get the fewest lines when doing "make -d xxx". – Axel Bregnsbo Nov 06 '19 at 14:30
  • @AxelBregnsbo strange, check the manual on the `--no-builtin-rules` section. – André Chalella Nov 07 '19 at 15:17
  • The ‘-r’ or ‘--no-builtin-rules’ flag causes the default list of suffixes to be empty, from : http://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html – PMN Mar 09 '21 at 09:50
  • Yes, the variable `$(SUFFIXES)` is empty when `--no-builtin-rules` is passed on the command line. On the contrary, it isn't empty when `--no-builtin-rules` is added to `MAKEFLAGS` inside the Makefile, but **it doesn't mean that known suffixes aren't ignored**. For example known suffixes can also be ignored by adding the rule `.SUFFIXES:` but it does **not** alter the variable `$(SUFFIXES)` either. Therefore I also believe that `.SUFFIXES:` is not needed when `--no-builtin-rules` is used (whether inside the Makefile or not) – DaveC Mar 18 '21 at 22:24
16

https://www.gnu.org/software/make/manual/make.html#Canceling-Rules

# Disable built-in rules and variables
MAKEFLAGS += --no-builtin-rules
MAKEFLAGS += --no-builtin-variables

# Makefile begins
main: main.c
    cc main.c -o main
Jaakko
  • 4,674
  • 2
  • 26
  • 20
  • 1
    For some reason, I can't make this work, although the following works: `make --no-builtin-rules` – Jesper Matthiesen Jan 15 '20 at 21:50
  • I remember this was a pain when I last did it. – Jaakko Jan 16 '20 at 12:34
  • 1
    This is the best answer, simple and complete, you can check it with `make -p`, look for `# No implicit rules.` and `# No pattern-specific variable values.`. Remove the `MAKEFLAGS` lines and you can see hell more output. – PMN Mar 09 '21 at 09:56
  • This worked for me for `GNU Make 4.4.1`. Same behavior as PMN. – 425nesp Mar 10 '23 at 18:15
10

Disabling of built-in rules by writing an empty rule for .SUFFIXES does not work if one then writes another .SUFFIXES rule to add previously known suffixes - the built-in rules are re-enabled. Example: One wants to define rules for .c.i and .i.o, and to disable the built-in rule .c.o. Writing

.SUFFIXES:
.SUFFIXES: .o .i .c

does not work - it does not prevent the built-in rule .c.o from being applied.

The solution is the one employed by Marc Eaddy and documented in the GNU make manual, 10.5.6 Canceling Implicit Rules:

You can override a built-in implicit rule (or one you have defined yourself) by defining a new pattern rule with the same target and prerequisites, but a different recipe. When the new rule is defined, the built-in one is replaced. The new rule’s position in the sequence of implicit rules is determined by where you write the new rule.

You can cancel a built-in implicit rule by defining a pattern rule with the same target and prerequisites, but no recipe. For example, the following would cancel the rule that runs the assembler:

    %.o : %.s
Armali
  • 18,255
  • 14
  • 57
  • 171
7

This works for me:

# Disable implicit rules to speedup build
.SUFFIXES:
SUFFIXES :=
%.out:
%.a:
%.ln:
%.o:
%: %.o
%.c:
%: %.c
%.ln: %.c
%.o: %.c
%.cc:
%: %.cc
%.o: %.cc
%.C:
%: %.C
%.o: %.C
%.cpp:
%: %.cpp
%.o: %.cpp
%.p:
%: %.p
%.o: %.p
%.f:
%: %.f
%.o: %.f
%.F:
%: %.F
%.o: %.F
%.f: %.F
%.r:
%: %.r
%.o: %.r
%.f: %.r
%.y:
%.ln: %.y
%.c: %.y
%.l:
%.ln: %.l
%.c: %.l
%.r: %.l
%.s:
%: %.s
%.o: %.s
%.S:
%: %.S
%.o: %.S
%.s: %.S
%.mod:
%: %.mod
%.o: %.mod
%.sym:
%.def:
%.sym: %.def
%.h:
%.info:
%.dvi:
%.tex:
%.dvi: %.tex
%.texinfo:
%.info: %.texinfo
%.dvi: %.texinfo
%.texi:
%.info: %.texi
%.dvi: %.texi
%.txinfo:
%.info: %.txinfo
%.dvi: %.txinfo
%.w:
%.c: %.w
%.tex: %.w
%.ch:
%.web:
%.p: %.web
%.tex: %.web
%.sh:
%: %.sh
%.elc:
%.el:
(%): %
%.out: %
%.c: %.w %.ch
%.tex: %.w %.ch
%: %,v
%: RCS/%,v
%: RCS/%
%: s.%
%: SCCS/s.%
.web.p:
.l.r:
.dvi:
.F.o:
.l:
.y.ln:
.o:
.y:
.def.sym:
.p.o:
.p:
.txinfo.dvi:
.a:
.l.ln:
.w.c:
.texi.dvi:
.sh:
.cc:
.cc.o:
.def:
.c.o:
.r.o:
.r:
.info:
.elc:
.l.c:
.out:
.C:
.r.f:
.S:
.texinfo.info:
.c:
.w.tex:
.c.ln:
.s.o:
.s:
.texinfo.dvi:
.el:
.texinfo:
.y.c:
.web.tex:
.texi.info:
.DEFAULT:
.h:
.tex.dvi:
.cpp.o:
.cpp:
.C.o:
.ln:
.texi:
.txinfo:
.tex:
.txinfo.info:
.ch:
.S.s:
.mod:
.mod.o:
.F.f:
.w:
.S.o:
.F:
.web:
.sym:
.f:
.f.o:

Put this in a file named disable_implicit_rules.mk and include it in every makefile.

Marc Eaddy
  • 1,762
  • 3
  • 16
  • 23
3

You could start the Makefile with a #! and call it something different so people don't try to use make directly:

#!/usr/bin/make -rRf
# ...

This will cause horrific problems if GNU make is not the system make. Maybe a wrapper script?

You can also read $(MAKEFLAGS) and make sure the required flags are present.

Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
  • 3
    I think you want `#!/usr/bin/env make -rRf`?. Oh I see what you mean now. – Matt Joiner Nov 09 '10 at 06:57
  • `/usr/bin/env` is probably better. – Jack Kelly Nov 09 '10 at 11:33
  • 3
    This won't work and yield `/usr/bin/env: ‘make -rRf’: No such file or directory` on many systems (such as e.g. Linux) as only a single optional argument is supported on the shebang line and no command splitting is done. See [here](https://en.wikipedia.org/wiki/Shebang_(Unix)#Portability). – Sebastian Schrader Sep 05 '16 at 06:50
1

Do this:

MAKEFLAGS += rR
$(foreach x,$(filter-out .% MAKE% SHELL CURDIR,$(.VARIABLES)) MAKEINFO,$(if $(filter default,$(origin $x)),$(eval override undefine $x)))

Here, rR is equivalent to --no-builtin-rules --no-builtin-variables.

--no-builtin-rules seems to work properly, but --no-builtin-variables is wonky.

--no-builtin-variables prevents the recipes from seeing the variables, but if you try to access them outside of a recipe, they are still there.

That's what the second line is for. It manually undefines all built-in variables. (Same idea as in @JohnMarshall's answer, but without shell invocations.)

It removes all variables for which $(origin ) reports default, except that it ignores SHELL,CURDIR, and variables starting with . and MAKE (except MAKEINFO), since those look useful.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
1
################################################################
# DISABLE BUILT-IN RULES
#
.SUFFIXES:
    MAKEFLAGS += -r
hseldon
  • 35
  • 1