Bug 217613 - FreeBSD make -- local variable $(.PREFIX) does not strip preceding directory components
Summary: FreeBSD make -- local variable $(.PREFIX) does not strip preceding directory ...
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 11.0-RELEASE
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-bugs (Nobody)
Depends on:
Reported: 2017-03-07 15:33 UTC by Erik Nordstrøm
Modified: 2017-03-10 15:55 UTC (History)
1 user (show)

See Also:

BSDmakefile (241 bytes, text/plain)
2017-03-07 15:33 UTC, Erik Nordstrøm
no flags Details
BSDmakefile with typo fixed (255 bytes, text/plain)
2017-03-07 15:48 UTC, Erik Nordstrøm
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Erik Nordstrøm 2017-03-07 15:33:16 UTC
Created attachment 180603 [details]

From the make(1) man page:

  Local variables are all built in and their values vary magically from
  target to target.  It is not currently possible to define new local
  variables.  The seven local variables are as follows:


        .PREFIX   The file prefix of the target, containing only the file
                  portion, no suffix or preceding directory components;
                  also known as ‘*’.  The suffix must be one of the known
                  suffixes declared with .SUFFIXES or it will not be

However, it seems that preceding directory components are not actually stripped.

$ mkdir -p ~/tmp/hello
$ cd ~/tmp/hello/

Place the attached BSDmakefile in this directory and after you've done that, create the hello world program in src/main.c.

$ mkdir src
$ cat > src/hello.c <<EOF
#include <stdio.h>
int main()
   printf("Hello, World!");

$ make
make: don't know how to make src/build/hello.c. Stop

make: stopped in /usr/home/erikn/tmp/hello

As you can see from the output above when I attempt to run make, the prefix was not stripped of preceding directory components.
Comment 1 Erik Nordstrøm 2017-03-07 15:37:35 UTC
Furthermore, even if making the paths absolute by replacing

BINDIR = bin
OBJDIR = build

in the BSDmakefile with

BINDIR = $(PWD)/bin
OBJDIR = $(PWD)/build

the prefix is still not stripped of the preceding directory.

$ make
make: don't know how to make src//usr/home/erikn/tmp/hello/build/hello.c. Stop

make: stopped in /usr/home/erikn/tmp/hello
Comment 2 Erik Nordstrøm 2017-03-07 15:48:06 UTC
In the original message I meant to say "create the hello world program in src/hello.c", not "create the hello world program in src/main.c", and also, the line in the BSDmakefile that reads

	$(CC) $(.ALLSRC) -O $(.TARGET)

was supposed to say

	$(CC) $(.ALLSRC) -o $(.TARGET)

Attaching a new version of the BSDmakefile with the typo fixed.

Aside from these couple of mistakes, the problem itself is as described.
Comment 3 Erik Nordstrøm 2017-03-07 15:48:43 UTC
Created attachment 180605 [details]
BSDmakefile with typo fixed
Comment 4 Erik Nordstrøm 2017-03-08 05:53:25 UTC
Mark, you added the keyword "patch", but I have not made any patches. The "BSDmakefile with typo fixed" is only an updated version of the attachment that shows the problem in question. Apologies for any confusion caused.
Comment 5 Mark Linimon freebsd_committer freebsd_triage 2017-03-08 16:55:26 UTC
The "patch" was merely an example.  Mea culpa for reading it too quickly.
Comment 6 Simon J. Gerraty freebsd_committer 2017-03-10 06:31:04 UTC
The handling of .PREFIX et al, is rather contorted.
Despite what the man page says, the trimming of dirs etc does not apply to those explicitly specified.

For example :

% cat tmf
.SUFFIXES: .ext .c

.PATH: /tmp

target.ext: $*.c
        @echo '@=$@ *=$* >=$>'
        @echo '.TARGET=${.TARGET} .PREFIX=${.PREFIX} .ALLSRC=${.ALLSRC}'

all: target.ext
% mkdir obj
% touch target.ext
% touch target.c
% bmake -r -f tmf
@=/tmp/target.ext *=target >=/tmp/target.c
.TARGET=/tmp/target.ext .PREFIX=target .ALLSRC=/tmp/target.c

both target.c and target.ext were found via .PATH
and we can see that .PREFIX (*) was set to the basename without extension as documented.  But if you make that an explicit /tmp/target.ext:
It does not.
Comment 7 Simon J. Gerraty freebsd_committer 2017-03-10 06:46:59 UTC
Sorry I should have been more explicit, I was refering to the dependency.
If we tweak that makefile so it is consumable by both bmake and gmake

% cat tmf

.SUFFIXES: .ext .c

VPATH = /tmp

/tmp/target.ext: target.c
        @echo '@=$@ *=$* >=$> ^=$^'

all: target.ext

we cannot have $*.c as source - gmake doesn't like it,
bmake behaves as documented:

% bmake -r   -f tmf
@=/tmp/target.ext *=target >=/tmp/target.c ^=

gmake just trims suffix:

% make -r -f tmf 
@=/tmp/target.ext *=/tmp/target >= ^=target.c

which I think is expected, we can better see what bmake is doing if we put the $*.c back as a dependency, but qualify it.

cat tmf

.SUFFIXES: .ext .c

VPATH = /tmp

/tmp/target.ext: ${.CURDIR}/$*.c
        @echo '@=$@ *=$* >=$> ^=$^'

all: target.ext
% bmake -r   -f tmf 
bmake: don't know how to make /tmp//tmp/target.c. Stop

but if we lose the ${.CURDIR}/ qualification it works:

% bmake -r   -f tmf 
@=/tmp/target.ext *=target >=/tmp/target.c ^=

on the rhs of the dependency only the suffix is trimed, once we are into the target context the directory is also.

Bug? hard to say, it has behaved this way for 20+ years
Comment 8 Erik Nordstrøm 2017-03-10 15:55:23 UTC
(In reply to Simon J. Gerraty from comment #7)

Thanks Simon, your examples are very helpful :)

With the understanding gained from your comments I suggest regarding the original issue as a documentation bug that needs to be fixed (as opposed to a software bug as I first believed that this was) so that the manpage is not misunderstood in the way that I did.