Hi David, Ingo, For others starting to read this thread now, it started here: <https://lists.gnu.org/archive/html/bug-make/2022-08/msg00059.html>
On 8/22/22 16:46, David A. Wheeler wrote:
On Aug 22, 2022, at 12:02 AM, Alejandro Colomar <alx.manpa...@gmail.com> wrote: Hi David, On 8/22/22 04:45, David A. Wheeler wrote:On Aug 20, 2022, at 11:35 AM, Alejandro Colomar <alx.manpa...@gmail.com> wrote: I'd say there is: make(1) treats file names as text strings, not really file names, for most of its operations. As an example, foo/ and foo/. are different targets. I don't see why ./bar and bar should be the same. Consistency is essential; otherwise, what to expect? Why does make(1) need to special-case a leading ./ ?Because treating "./foo" and "foo" as different files is likely to lead to endless footguns. Consistency is nice, but making something easy to use *correctly* is more important. I have no problem with special-casing "./XXX" as a synonym for "XXX"; anything else would be *unexpected* (if for no other reason than backwards compatibility). As far as "foo/" vs. "foo/.", it's *much* less common to have directories as prerequisites or targets, so not handling them with special conveniences seems quite reasonable.Is it so *much* less common? I never really knew that make(1) treats ./foo and foo as the same thing until this bug report. make(1) is (almost) very consistent in that it handles text, and not really file names. But _all_ non-phony targets should declare a dependency like '|$$(@D)/', unless you can guarantee that it already exists by the time you'll try to create the file (e.g., when the file depends on another file in the same dir).My Makefiles are plagued with that dependency, but a correctly-written Makefile shouldn't even notice that ./ is trimmed.I also try to do that, but I think it'd backwards-incompatible if GNU make changed its current behavior. I suspect a lot of makefiles would quietly work incorrectly if that change was made.
Yeah, I guess the bug is resolving ./, and also that we will live forever with that bug.
Do other make(1) implementations trim this leading ./?
I tried on OpenBSD, and it seems to do that and more; it seems to be resolving symlinks and .. (physically, although I'm not yet sure of what it does to .. after segments of the path that don't exist). It doesn't seem to be documented, and also doesn't seem to be obvious in the source code (I can't find any realpath(3) calls, nor '..').
I wrote a program that behaves similar to how I think BSD make(1) behaves, after testing it a little bit:
$ cat canonicalizepath.c #include <bsd/string.h> #include <err.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> char *canonicalizepath(const char *path); int main(int argc, char *argv[]) { int ret; char *p; if (argc < 2) errx(EXIT_FAILURE, "missing operand"); ret = EXIT_SUCCESS; for (ptrdiff_t i = 1; i < argc; i++) { p = canonicalizepath(argv[i]); if (!p) { ret = EXIT_FAILURE; warn("%s", argv[1]); } else { puts(p); free(p); } } exit(ret); } char * canonicalizepath(const char *path) { char *cpy, *end, *sep, *p, *ret; size_t len; cpy = strdup(path); if (!cpy) return NULL; end = cpy + strlen(cpy); sep = end; do { *sep = '\0'; p = realpath(cpy, NULL); if (p) goto found; sep = strrchr(cpy, '/'); } while (sep); sep = cpy; found: len = end - sep + 1; if (p) len += strlen(p); ret = malloc(len); if (!ret) goto fail; ret[0] = '\0'; if (p) strlcat(ret, p, len); for (char *q = sep; q < end; q++) { if (*q == '\0') *q = '/'; } strlcat(ret, sep, len); fail: free(cpy); return ret; } alx@asus5775:~/tmp$ ./canonicalizepath . /home/alx/tmp alx@asus5775:~/tmp$ ./canonicalizepath ./foo/../asd /home/alx/tmp/foo/../asd alx@asus5775:~/tmp$ ./canonicalizepath ./asd /home/alx/tmp/asd alx@asus5775:~/tmp$ ./canonicalizepath asd asd alx@asus5775:~/tmp$ ./canonicalizepath canonicalizepath /home/alx/tmp/canonicalizepath alx@asus5775:~/tmp$ ./canonicalizepath /home/../tmp/../../etc/ /etc I don't think me want GNU make(1) to behave like that.Ingo, do you know how your make(1) behaves with respect to '..', '//', '.', and symlinks? Is that documented anywhere?
No idea. However, I took a quick look at the POSIX make specification: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html The POSIX specification for make is notoriously underpowered. It doesn't say anything about whether or not ./FOO is the same as FOO. It refers to files by PRECEDING them with "./", e.g. "By default, the following files shall be tried in sequence: ./makefile and ./Makefile. If neither ./makefile or ./Makefile are found, other implementation-defined files may also be tried. [XSI] On XSI-conformant systems, the additional files ./s.makefile, SCCS/s.makefile, ./s.Makefile, and SCCS/s.Makefile shall also be tried." I interpret that as an expectation that adding "./" is expected to have the same result if the filename starts with an alphabetic character, but that's just my reading and not directly supported.
That refers to the input file, and not to targets within the DAG, AFAICS. Cheers, Alex -- Alejandro Colomar <http://www.alejandro-colomar.es/>
OpenPGP_signature
Description: OpenPGP digital signature