rmyorston / pdpmake

Public domain POSIX make
https://frippery.org/make
Other
106 stars 11 forks source link

Empty recipes and PHONY targets #56

Open ale5000-git opened 1 month ago

ale5000-git commented 1 month ago

If there is a file named ./my_file.sh then using make my_file will do this:

cp my_file.sh my_file
chmod a+x my_file

On GNU make it can be prevented with my_file: ; inside the Makefile but it doesn't seems to work with pdpmake.

On GNU make for an empty recipe it always say: make: 'my_file' is up to date.

More info: https://www.gnu.org/software/make/manual/html_node/Empty-Recipes.html

rmyorston commented 1 month ago

Empty commands are allowed in GNU, BSD, Schily and Unix Version 7 make.

Only BSD make and pdpmake didn't support them.

Now pdpmake does, both here and in busybox-w32.

ale5000-git commented 1 month ago

Thanks, I have tested it with this Makefile:

.PHONY: dummy9 dummy10

dummya:

dummyb:
    echo 'Random text'

dummyc: dummya

dummy1:;
dummy2: ;
dummy3: dummya;
dummy4: dummya ;
dummy5: dummyb
dummy6: dummyb ;
dummy7: ;dummyb
dummy8: ; dummyb
dummy9:

and I have created a corresponding file with the name of the target plus .sh and the result with pdpmake is:

$ make dummya
cp dummya.sh dummya
chmod a+x dummya
$ make dummyb
echo 'Random text'
Random text
$ make dummyc
cp dummyc.sh dummyc
chmod a+x dummyc
$ make dummy1
$ make dummy2
$ make dummy3
$ make dummy4
$ make dummy5
echo 'Random text'
Random text
cp dummy5.sh dummy5
chmod a+x dummy5
$ make dummy6
echo 'Random text'
Random text
$ make dummy7; echo $?
dummyb
sh: dummyb: not found
make: (makefile:16): failed to build 'dummy7' exit 127
2
$ make dummy8; echo $?
dummyb
sh: dummyb: not found
make: (makefile:17): failed to build 'dummy8' exit 127
2
$ make dummy9
cp dummy9.sh dummy9
chmod a+x dummy9
$ make dummy10
cp dummy10.sh dummy10
chmod a+x dummy10

While with GNU make I get:

$ make dummya
cat dummya.sh >dummya
chmod a+x dummya
$ make dummyb
echo 'Random text'
Random text
$ make dummyc
cat dummyc.sh >dummyc
chmod a+x dummyc
$ make dummy1
make: 'dummy1' is up to date.
$ make dummy2
make: 'dummy2' is up to date.
$ make dummy3
make: 'dummy3' is up to date.
$ make dummy4
make: 'dummy4' is up to date.
$ make dummy5
echo 'Random text'
Random text
cat dummy5.sh >dummy5
chmod a+x dummy5
$ make dummy6
echo 'Random text'
Random text
$ make dummy7; echo $?
dummyb
make: dummyb: No such file or directory
make: *** [Makefile:16: dummy7] Error 127
2
$ make dummy8; echo $?
dummyb
make: dummyb: No such file or directory
make: *** [Makefile:17: dummy8] Error 127
2
$ make dummy9
make: Nothing to be done for 'dummy9'.
$ make dummy10
make: Nothing to be done for 'dummy10'.

So it is improved a lot but there are still differences.

ale5000-git commented 1 month ago

@rmyorston I have created a repo with almost all combinations for testing: https://github.com/ale5000-git/make-test

rmyorston commented 1 month ago

I don't see make dummy6 succeeding with pdpmake.

There are differences in the messages issued but those aren't significant.

The only significant difference is that pdpmake creates the phony target dummy5. (So does Schily make, though it doesn't have an inference rule for .sh, so one has to be provided for the purposes of this test.)

The issue with phony targets is unrelated to empty commands. The GNU make documentation says:

The implicit rule search (see Using Implicit Rules) is skipped for .PHONY targets.

This is not the case in pdpmake.

Phony targets are new in POSIX 2024. I can't immediately find anything in the standard that requires inference rules to be skipped for phony targets. I may need to read it more closely.

ale5000-git commented 1 month ago

I don't see make dummy6 succeeding with pdpmake.

Right, probably I have mistyped something somewhere. Now I have updated the test results.

1) I noticed there is also the difference of cp vs cat, is it not specified in POSIX?

2) PHONY: https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html

A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request.

If the PHONY target is one that is not really the name of a file, then the inference rules that presume that it is a real file (since it use cp/cat on a real file) it make sense to skip them. Probably it is implied even if not directly specified (just my guess).

rmyorston commented 1 month ago

the difference of cp vs cat, is it not specified in POSIX?

It is. The default .sh rule in POSIX uses cp, so that's what pdpmake uses.

It certainly makes sense to skip inference rules for phony targets. Though it is possible to write an inference rule that doesn't create a file, just as it is with a target rule.

It needs more consideration.

ale5000-git commented 1 month ago

Is it possible to just skip the ones that access files? Since it cite improve performance, it should include also test -e filename.sh, not just file creation but any type of disk access.

rmyorston commented 1 month ago

Is it possible to just skip the ones that access files?

I don't think it's feasible to try that. The commands associated with a rule can be of arbitrary complexity.

The most relevant thing in POSIX is probably:

If a phony target's commands are executed, that phony target shall then be considered up-to-date until the execution of make completes.

This might be taken to imply that the commands are to come from a target rule, but it doesn't exclude the possibility that they're obtained from an inference rule. The latter would still be "a phony target's commands". In the absence of an explicit exclusion of inference rules it's safest to suppose they are allowed (even if only accidentally).

GNU make doesn't allow the use of implicit rules for phony targets. This includes both inference rules and the .DEFAULT target.

The man page for BSD make says:

Suffix-transformation rules are not applied to .PHONY targets.

There's no mention of the .DEFAULT target, but by experiment I find that it can be used for a phony target.

My plan is to disallow the use of inference rules and the .DEFAULT target for phony targets as a non-POSIX extension. This matches what GNU make does.

When the POSIX 2024 standard is being enforced it will allow the use of inference rules and the .DEFAULT target for phony targets.

POSIX 2017 doesn't support phony targets so there can be no special treatment for them.

ale5000-git commented 1 month ago

I just started and I still don't understand everything about make but wouldn't it make sense to skip just the default inference rules (the one from make itself) and leave enabled the ones specified in the Makefile?

rmyorston commented 1 month ago

The problem isn't where the inference rules come from, it's what they do.

I'm sure Makefile authors are just as capable of writing problematic inference rules as POSIX.

ale5000-git commented 1 month ago

What I mean is (trying to predict what a generic Makefile author want): If Makefile authors write inference rules specifically in the Makefile maybe they want them applied but instead the default ones that they didn't write maybe they want to avoid them with PHONY.

But it is just my guess.

rmyorston commented 1 month ago

I've implemented my plan, so inference rules and the .DEFAULT target aren't used for phony targets as a non-POSIX extension.

The make in busybox-w32 has been updated to match.