HardcoreHenry
HardcoreHenry

Reputation: 6387

Makefile rule with no target

I'm debugging a makefile, and in a macro expansion it creates a rule with no target (as so:)

: | directoryA
    @echo running $@
    ...

I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.

With my current version of make (gnu Make 4.2.1), it's not killing me, but I'm just wondering whether this is considered undefined behavior or whether this is supported, and if so, what it should do.

Upvotes: 1

Views: 1944

Answers (2)

John Bollinger
John Bollinger

Reputation: 181459

I've looked it up online, and the makefile documentation seems to hint (but not explicitly state) that there should be at least one target.

Different makes may behave differently. They may even exhibit variant handling of specific makefile syntax matters depending on the content of the makefile -- for example, a makefile may be interpreted differently if it starts with a rule for the .POSIX: special target than an otherwise identical makefile without that rule is interpreted.

Overall, however, if you want some sort of general idea of what should be considered correct then the POSIX standard's defintion of make is a reasonably good baseline. It says:

Target rules are formatted as follows:

target [target...]: [prerequisite...][;command]
[<tab>command<tab>command...]

line that does not begin with <tab>

Target entries are specified by a <blank>-separated, non-null list of targets, then a <colon>, [...]

(emphasis added). It furthermore goes on to say that

Applications shall select target names from the set of characters consisting solely of periods, underscores, digits, and alphabetics from the portable character set

, from which we can infer that the syntax description is talking about the rule text after macro expansion, since macro references can appear in the target lists of rules (or literally anywhere in a makefile, per the spec), but the characters $, (, ), {, and } appearing in macro references are not among those that can appear in targets.

That specification of makefiles' expected contents does explicitly state that target lists are non-empty, and it is reasonable to treat it as authoritative where your specific make's documentation does not override it.

I'm just wondering whether [an empty target list] is considered undefined behavior or whether this is supported

Your combination of makefile and runtime macro values does not conform to the requirements of POSIX make. The spec does not define what should happen in this case, so in that sense the behavior is undefined, but "undefined behavior" isn't as strong a concept in this area as it is in, say, the C and C++ language specifications.

In view of that, I would account it a makefile flaw for any rule's target list to be empty (after macro expansion). Although the make you are presently using may accept it without complaint, other makes, including future versions of your present make, may reject it or worse.

Upvotes: 1

Ondrej K.
Ondrej K.

Reputation: 9679

Rule does expect one or more targets, there really are no two ways about it in the docs. For instance GNU make docs notation:

targets : prerequisites
        recipe

Or 1p section manpage:

target [target...]: [prerequisite...][;command]

Illumos:

target [:|::] [dependency] ... [; command] ...
               [command]
               ...

After all how would you refer to a target that had no name? I would assume no target rule should be an error...

However, I've tried different flavors of make (BSD, Illumos, GNU) and with varying degree of leniency (GNU make for instance seemed to also not care about syntax of prerequisites any more) or lack thereof they all seemed to have processed the line and possibly following tab indented block as a rule (with a recipe)... which then was ignored (also for the purpose of determining the default target).

I guess a rationale for this actually being consider valid Makefile... you could end up in this situation also with:

$(VAR):
        @echo foobar

other:
        @echo barbaz

In case VAR is undefined or empty, you'd end up with a such empty target as well.

Upvotes: 1

Related Questions