Re: Question about .PATH.o in Makefiles

2011-07-23 Thread Marc Espie
On Fri, Jul 22, 2011 at 09:52:58PM -0700, Philip Guenther wrote:
 On success, A rule *MUST* create the file named by $@.  Telling make
 that you'll create port.o and then creating ${OBJ_DIR}/port.o results
 in *exactly* the behavior you describe: every build regenerates the
 involved file because make doesn't see the file where it's looking.

It's even worse than that.

make has very limited knowledge of the filesystem. Targets such as
./a and a  are distinct, even though they often refer to the same file.

In sequential mode, that's not much of a problem, since make will evaluate
rules one at a time, and most of the time, things will work out just fine.

In parallel mode, this can be a real problem, with exactly the symptoms you
describe, and more...


Actually, that's the main stumbling block I need to fix before make -j is
completely operational, and that's a hard one !

You need to add some kind of fuzzy equivalence relations between targets
that ought to be the same, but are not, and you have to be very careful
about it, since usually, make doesn't like to encounter cycles in its
dependency evaluation.

Retrofitting that into the existing engine is complicated and bug-prone.
From time to time, I think about throwing it away and starting that specific
part from scratch...



Re: Question about .PATH.o in Makefiles

2011-07-22 Thread Philip Guenther
On Thu, Jul 21, 2011 at 12:53 PM, Patsy open...@ethernull.org wrote:
 I'm a little confused by the .PATH.o target in makefiles. For
 the record I'm running on a snapshot from the 29th of June
 (amd64).

 I have the following file structure:

 ./Makefile
 ./port.c
 ./cheese.c
 ./Makefile
 ./objects/
 ./include/
 ./include/port.h

 I have the following makefile:

 =
 .SUFFIXES: .o .c .h
 .INCLUDES: .h

 .PATH.h: include
 .PATH.o: objects

 OBJ_DIR=objects
 CFLAGS=-Iinclude

 happiness:  cheese.o \
port.o
gcc $(CFLAGS) -o happiness \
$(OBJ_DIR)/cheese.o \
$(OBJ_DIR)/port.o

 port.o: port.c  port.h
gcc -c $(CFLAGS) -o $(OBJ_DIR)/port.o port.c

 cheese.o:   cheese.c port.h
gcc -c $(CFLAGS) -o $(OBJ_DIR)/cheese.o cheese.c

 

 If I run make, I get the following output:

 gcc -c -Iinclude -o objects/cheese.o cheese.c
 gcc -c -Iinclude -o objects/port.o port.c
 gcc -Iinclude -o happiness  objects/cheese.o  objects/port.o

 which is fine, dandy and what I expect. If I run make again
 however, I get the same result. running make -d m indicates
 that it isn't finding port.o or cheese.o in the objects
 directory, it is only looking in the current directory.

 Prefixing port.o/cheese.o with $(OBJ_DIR) results in their
 targets not being found. Adding $(OBJ_DIR) as a prefix to all
 .o files seem a little verbose.

 I thought that specifying .PATH.o in the manner above would
 mean that make would interpret port.o as $(.PATH.o)/port.o
 whether it be a dependency or a target. I have read the man
 page (hence I know that .PATH.o exists) but I can't see why
 what I have shouldn't work.

 It seems obvious to me that I'm missing something, but I can't
 see what it is. Could somebody explain it to me, or suggest
 how I could patch the above makefile to make use of .PATH.o?

(Where to start...)

On success, A rule *MUST* create the file named by $@.  Telling make
that you'll create port.o and then creating ${OBJ_DIR}/port.o results
in *exactly* the behavior you describe: every build regenerates the
involved file because make doesn't see the file where it's looking.

In general, 'make' really doesn't like placing objects for suffix
rules in other than the current directory.  The specific exception is
the .OBJDIR logic in BSD make.  Go read the make(1) manpage's
description of the .OBJDIR variable.  You have the choice of using
that logic (and, for example, using the directory named 'obj' instead
of 'objects') or just give up and include full paths in the rules you
write.

If you choose the former, then your Makefile should reduce to
something like this:
-
.INCLUDES: .h
.PATH.h: ${.CURDIR}/include
CPPFLAGS= ${.INCLUDES}
OBJ = cheese.o port.o
TARGET = ${.CURDIR}/happiness

${TARGET}: ${OBJ}
${LINK.c} -o ${TARGET} ${.ALLSRC}

port.o cheese.o: port.h

clean:
rm -f ${OBJ} ${TARGET}


That's assuming you have a hard requirement to place the object file
in the source directory instead of the object directory.  That's
usually the Wrong Thing.  The reasons for moving object files
generally apply to the binaries as well; if you check the OpenBSD
source tree you'll find that output files are *never* placed in the
source directory, for example.  If you drop that perceived
requirement, then simply change the 'TARGET' variable assignment to
'TARGET=happiness'


If you have a hard requirement for naming the subdirectory objects
instead of obj, then you've turned your back on the built-in support
of make for placement of object files, so all their paths will have to
be specified in the makefile, both in targets and prerequisites.  You
can't use suffix rules in that case.  I have written such makefiles in
a large build system using GNU make, which supports the more powerful
[than suffix rules] concept of pattern rules, but I can't generally
recommend it and will not waste my time writing makefiles to do that
in BSD make.


Philip Guenther



Question about .PATH.o in Makefiles

2011-07-21 Thread Patsy

Hello list,

I'm a little confused by the .PATH.o target in makefiles. For
the record I'm running on a snapshot from the 29th of June
(amd64).

I have the following file structure:

./Makefile
./port.c
./cheese.c
./Makefile
./objects/
./include/
./include/port.h

I have the following makefile:

=
.SUFFIXES: .o .c .h
.INCLUDES: .h

.PATH.h: include
.PATH.o: objects

OBJ_DIR=objects
CFLAGS=-Iinclude

happiness:  cheese.o \
port.o
gcc $(CFLAGS) -o happiness \
$(OBJ_DIR)/cheese.o \
$(OBJ_DIR)/port.o

port.o: port.c  port.h
gcc -c $(CFLAGS) -o $(OBJ_DIR)/port.o port.c

cheese.o:   cheese.c port.h
gcc -c $(CFLAGS) -o $(OBJ_DIR)/cheese.o cheese.c



If I run make, I get the following output:

gcc -c -Iinclude -o objects/cheese.o cheese.c
gcc -c -Iinclude -o objects/port.o port.c
gcc -Iinclude -o happiness  objects/cheese.o  objects/port.o

which is fine, dandy and what I expect. If I run make again
however, I get the same result. running make -d m indicates
that it isn't finding port.o or cheese.o in the objects
directory, it is only looking in the current directory.

Prefixing port.o/cheese.o with $(OBJ_DIR) results in their
targets not being found. Adding $(OBJ_DIR) as a prefix to all
.o files seem a little verbose.

I thought that specifying .PATH.o in the manner above would
mean that make would interpret port.o as $(.PATH.o)/port.o
whether it be a dependency or a target. I have read the man
page (hence I know that .PATH.o exists) but I can't see why
what I have shouldn't work.

It seems obvious to me that I'm missing something, but I can't
see what it is. Could somebody explain it to me, or suggest
how I could patch the above makefile to make use of .PATH.o?

Thanks,
Patsy

It appears to be able to find port.h (removing .PATH.h causes
a non-existant error).