GNU Make: disable all built-in rules, except desired ones - gnu-make

Twice in the past, GNU make has destroyed my work because some of its built-in rules have .c files as a target.
If you have a file called foo.c, and also a foo.l Lex scanner or foo.y Yacc parser, watch out! GNU make assumes that the .c file is a target made from these (it's evidently a POSIX requirement!), and it will will do something like mv y.tab.c foo.c or lex -t foo.l > foo.c.
What is the way to disable all such hidden, dangerous rules (whether known or unknown) while keeping the useful ones?
Specifically, how can we give this request to GNU Make: "please retain all your rules related to (for example) .c and .o files, and disable all rules which involve any other file type"?

From the manual:
Many of the predefined implicit rules are implemented in make as
suffix rules, so which ones will be defined depends on the suffix list...
If you modify the suffix list, the only predefined suffix rules in
effect will be those named by one or two of the suffixes that are on
the list you specify; rules whose suffixes fail to be on the list are
disabled...
If you wish to eliminate the default known suffixes instead of just
adding to them, write a rule for .SUFFIXES with no prerequisites. By
special dispensation, this eliminates all existing prerequisites of
.SUFFIXES. You can then write another rule to add the suffixes you
want.
.SUFFIXES: # Delete the default suffixes
.SUFFIXES: .c .o # Define a new suffix list

Related

Why does gnu make delete this file?

Consider this Makefile:
.PHONY: all
all: main.txt
main.txt: build/main.txt
cp build/main.txt .
%/main.txt: %/data.txt
cp $*/data.txt $*/main.txt
%/data.txt:
touch $*/data.txt
After running make, build/data.txt is removed automatically. Why is this the case?
I tried adding .PRECIOUS: build/% to the file, but it it not help, the file was still removed. How can I prevent this?
According to the GNU Make documentation
You can also list the target pattern of an implicit rule (such as ‘%.o’) as a prerequisite file of the special target .PRECIOUS to preserve intermediate files created by rules whose target patterns match that file’s name.
the prerequisite for.PRECIOUS needs to be the (exact) target pattern of an existing implicit rule.
In your case this would be %/data.txt instead.
The documentation hints at this, but is not particularly clear about it.
As a side note: As far as I can tell build/main.txt is not automatically deleted since it is explicitly named as a prerequisite for the main.txt target and build/data.txt is automatically deleted since it is never explicitly named.

Gnu make, multiple sets of grouped targets

I have a makefile that includes two rules each of which defines a (completely different) grouped target. The intention in each case is (of course) to generate all of the targets by executing the associated recipe once.
If both rules are present, each using the target separator "&:", I get "warning: overriding recipe for target '&'", with the first lines of each of the two recipes cited.
If I change either rule to use the standard target separator ":", the warning goes away.
I can provide extracts from the makefile but believe the above description is as concise as it will get.
Grouped targets were introduced in GNU make version 4.3.
Your version of GNU make is too old and doesn't recognize this syntax (it thinks that & is a target name).

Should the longer synonyms for local variables be used in a Makefile?

In make (I am using OpenBSD’s implementation, but I suppose the question is relevant for GNU make as well), we have the following so called local variables
# The name of the target
% The name of the archive member (for library rules)
! The name of the archive file (for library rules)
? The list of prerequisites for this target that were deemed out of date
< The name of the prerequisite from which this target is to be built (for inference rules)
* The file prefix of the file, containing only the file portion, no suffix or preceding directory components
(roughly from make(1) on OpenBSD)
These local variables have synonyms: for exampe, .IMPSRC for < or .TARGET for #. The manual in FreeBSD says these longer versions are preferred. OpenBSD’s man page mentions no such thing, but says these longer names are an extension.
Is it better to use to longer names? Which is better for compatibility? Are both POSIX?
Those variables are called automatic variables in GNU make and internal variables in the POSIX standard.
The long names for these are purely BSD make inventions, they do not exist in any other version of make (such as GNU make) and they are not mentioned in the POSIX standard for make.
It's up to you whether you want to use them, but they are completely non-portable. Of course you could always define them yourself if you wanted to implement a compatibility layer.

How do /** and /* differ in terms of directory navigation in Grunt?

This is quite an easy one for you guys, but I can't find a definitive/formal answer to this question.
Suppose we are in directory A. Then,
"A/* " probably means: Every file and folder directly inside A.
"A/** " then may mean: Every file and folder inside A, and every file and folder directly inside every child that is directly inside A. (Basically, an extension of /* operator that traverses one level deeper of the root folder? aka "/** " = "/* /* " )
My "directly inside" terminology might be wrong. May be its better to say "direct child" or something, but you get the idea.
Then, what does "A/**/* " mean? Is it equal to "A/* /* /* " ?
Although this seems basic, its quite confusing when I don't have a formal definition of the operators.
I'm currently using Javascript and trying to modify a Gruntfile. But I guess these operators may come up in any context.
This behavior is not intrinsic to JavaScript and is not related to any operators: as far as JavaScript is concerned, it is just a string.
The handling of such glob expansion is determined by the specific library/consumer. For gruntjs it is covered in Grunt Globbing Patterns:
It is often impractical to specify all source filepaths individually, so Grunt supports filename expansion (also know as globbing) via the built-in node-glob and minimatch libraries ..
* matches any number of characters, but not /
** matches any number of characters, including /, as long as it's the only thing in a path part
All most people need to know is that foo/*.js will match all files ending with .js in the foo/ subdirectory, but foo/**/*.js will match all files ending with .js in the foo/ subdirectory and all of its subdirectories.
As such (but refer to the specific documentation!), /**/ generally means "match any depth of directories" and /*/ or /* means "match a single directory or file part".
The gruntjs documentation is a bit vague on the specific mechanics of ** in the standard "/**/*.x" pattern, but referring to node-glob says:
If a "globstar" (**) is alone in a path portion, then it matches zero or more directories and subdirectories searching for matches. It does not crawl symlinked directories.
[.. The double-star character] is supported in the manner of bsdglob and bash 4.3, where ** only has special significance if it is the only thing in a path part. That is, a/**/b will match a/x/y/b, but a/**b will not.
Using this knowledge we get the equivalency (when used as a path component), of A/**/f with A/f, A/*/f, A/*/*/f, etc for every number of intermediate directories.
If you see A/**/* that means to recursively search all the way down the tree of every folder under folder A. For more information look up basic linux style file commands.

make does not realize that a relative path name dependency is the same as an absolute pathname target

The following is a simplified makefile for a problem I'm having:
all: /tmp/makey/../filey
#echo All done
/tmp/filey:
#echo Filey
When I run make it says:
make-3.79.1-p7: * No rule to make target /tmp/makey/../filey', needed byall'. Stop.
Clearly it does not realize that /tmp/makey/../filey is the same as /tmp/filey. Any ideas how I can make this work?
Thanks
Ciao
-- Murali
Newer versions of GNU make have $(abspath ...) and $(realpath ...) functions you can apply to your prerequisites and targets to resolve the paths to the same string. If you've constructed these names yourself (for example, $(PREFIX)/../filey) then you can use $(dir $(PREFIX))filey instead.
Other than that, there's no way to solve this problem. Make uses string matching on targets and if the strings are not identical, they don't match (there's a special case to ignore the simple prefix ./) Even if make understood this distinction (by applying abspath itself to each target name, maybe) it would still not help in the face of symbolic links for example.
The only "real" answer would be for make to understand something about the underlying file system (device IDs and inodes for example) that let you talk about files without referring to their pathname. However, in a portable program like make doing this is problematic.

Resources