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