Solved How to use Make's OBJDIR feature?

Hi,

I am using make(1) to build a simple project; and I would like to put the object files into a dedicated directory, say ./x86/. From reading the man page on make(1), I figure that .OBJDIR should be the way to go.

Here is my attempt (general review about this Makefile is appreciated!)
Code:
.SUFFIXES: .o .c

.c.o:
        ${CC} -g ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}

SRCS=parser.c string_list.c items.c item_hooks.c rooms.c \
    room_hooks.c game_state.c messages.c command_proc.c \
    test_parser.c main.c

OBJS=${SRCS:S/.c/.o/g}

# This should put the .o files into a "x86" directory.
.OBJDIR: x86

all: depend myprogram

myprogram: ${OBJS}
        $(CC) -o ${.TARGET} ${OBJS}

depend: ${SRCS} main.c
        mkdep ${CFLAGS} ${SRCS}

When I create the directory x86 and run make, I get the following:
Code:
mkdep -O2 -pipe parser.c string_list.c items.c item_hooks.c rooms.c  room_hooks.c game_state.c messages.c command_proc.c test_parser.c main.c
cc: error: no such file or directory: 'parser.c'
cc: error: no such file or directory: 'string_list.c'
cc: error: no such file or directory: 'items.c'
cc: error: no such file or directory: 'item_hooks.c'
cc: error: no such file or directory: 'rooms.c'
cc: error: no such file or directory: 'room_hooks.c'
cc: error: no such file or directory: 'game_state.c'
cc: error: no such file or directory: 'messages.c'
cc: error: no such file or directory: 'command_proc.c'
cc: error: no such file or directory: 'test_parser.c'
cc: error: no such file or directory: 'main.c'
cc: error: no input files
mkdep: compile failed
*** Error code 1

I interpret the error messages as follows: Make chdir's into x86/, but cannot find the source files anymore.

What am I missing?

Best,
Holger
 
Activating debugging make(1) with (for example -dA) for more info perhaps?

Based on bmake*, however:
.OBJDIR
[...]
In the simplest case, if the directory obj exists in the directory bmake was invoked in, then bmake will chdir into it before doing anything else. This helps keep src and object files separate.
So what happens when you have a ./obj directory and leave out the OBJDIR directive?
Based on the algorithm for finding an object dir at the above bmake reference and make(1), instead of .OBJDIR: x86, shouldn't it be:
.OBJDIR: ${.CURDIR}/x86 ?

___
* pmake, fmake, bmake all are part of FreeBSD's history of its current implementation of make(1); more info & REFS: here
 
Admittedly, even with all the time I have spent with bmake over the years, I have never been able to work this one out.

As you mentioned, having an obj (or other OBJDIR) directory is handled in a special way of bmake first chdir into that directory and then executing the rules.

... which obviously breaks because the relative paths to the .c files are no longer correct along with everything else.

Will be eagerly lurking on this thread to see if an answer pops up! :D
 
So what happens when you have a ./obj directory and leave out the OBJDIR directive?
Then make ignores the obj-directory and puts all the object files into the current directory.

Edit: My object directory is called “x86”, not ”obj”. When the object directory has a non-standard name (“x86” in my case), it is ignored by make.

Based on the algorithm for finding an object dir at the above bmake reference and make(1), instead of .OBJDIR: x86, shouldn't it be:
.OBJDIR: ${.CURDIR}/x86 ?
I tried it (thank you!) but it makes no difference.
 
This worked.

Code:
.SUFFIXES: .o .c

.c.o:
        ${CC} -g ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}

SRCS=   getlogin.c

OBJS=   ${SRCS:S/.c/.o/g}

.OBJDIR: x86

all: depend prog

prog: ${OBJS}
        ${CC} -o ${.TARGET} ${OBJS}

depend:  ${SRCS}
        mkdep ${CFLAGS} ${SRCS:C/^(.*)/..\/\1/g}
 
OK, so it seems that we would need to use ${.IMPSRC}, ${.TARGET} rather than $<, $@ respectively. These variables have the location adjusted paths?

mkdep ${CFLAGS} ${SRCS:C/(.*\.c)/..\/\1/g}

Seems to be a bit of a hack. I guess the mkdep stuff doesn't fully support the changing of directory.

I will have a play. Hopefully this is useful for OP too.
 
Still, not clear to me:
How does the process of determining the objdir work? From make(1):
Code:
       .OBJDIR
	       A path to the directory where the targets are built.  Its value
	       is  determined  by trying to chdir(2) to	the following directo-
	       ries in order and using the first match:

	       1.   ${MAKEOBJDIRPREFIX}${.CURDIR}

		    (Only if `MAKEOBJDIRPREFIX'	is set in the  environment  or
		    on the command line.)

	       2.   ${MAKEOBJDIR}

		    (Only  if `MAKEOBJDIR' is set in the environment or	on the
		    command line.)

	       3.   ${.CURDIR}/obj.${MACHINE}

	       4.   ${.CURDIR}/obj

	       5.   /usr/obj/${.CURDIR}

	       6.   ${.CURDIR}
and
So what happens when you have a ./obj directory and leave out the OBJDIR directive?
Then make ignores the obj-directory and puts all the object files into the current directory.
Are MAKEOBJDIRPREFIX and/or MAKEOBJDIR initialised, somehow? If they are not, how does this process of determining the object directory (i.e. "A path to the directory where the targets are built") work because the "first match" (with an existing obj directory) should be:
Code:
4.   ${.CURDIR}/obj
just as:
[...]
Based on bmake*, however:
.OBJDIR
[...]
In the simplest case, if the directory obj exists in the directory bmake was invoked in, then bmake will chdir into it before doing anything else. This helps keep src and object files separate.



It looks like using environment variables MAKEOBJDIRPREFIX and/or MAKEOBJDIR (see for example this and that) works more "automatically" (must be set before calling make), but there could be more to that under the hood. However, according to FreeBSD building with bmake (from FreeBSD bmake and meta mode), the more prudent way to go is modifying MAKEOBJDIR:
Separating sources and objects
• default ${.CURDIR}/obj/ or ${.CURDIR}/obj.${MACHINE}/ insufficient
• cannot do read-only src tree
• cannot simply rm -rf ${OBJTOP}
• MAKEOBJDIRPREFIX easy - but ugly
• bmake allows applying modifiers to MAKEOBJDIR
$ export MAKEOBJDIR='${.CURDIR:S,${SRCTOP},${OBJTOP},}'
 
making ./obj directory and removing .OBJDIR: x86 line from my sample works as Erichans expected. So, the problem is how to pass the path of source files relative to .OBJDIR to mkdep.
Thanks for checking that, and indeed:
[...]
should be
Code:
mkdep ${CFLAGS} ${SRCS:C/(.*\.c)/..\/\1/g}
Given possible other source type files like *.h header files, generalising .c to something like ${SRCSUFFIXES} looks like an option.
 
Maybe, using /usr/share/mk/bsd.prog.mk is easier.
I wrote this makefile:

Code:
SRCS=   getlogin.c
PROG=   getlogin
CFLAGS= -g -O2
MK_MAN= no
.MAKE.MODE: verbose

.include <bsd.prog.mk>

and the output was:
Code:
% make
Warning: Using /usr/home/hiroo/work/sandbox/maketest/obj as object directory instead of canonical /usr/obj/usr/home/hiroo/work/sandbox/maketest
cc  -g -O2   -fPIE -g -gz=zlib -MD  -MF.depend.getlogin.o -MTgetlogin.o -std=gnu99 -Wno-format-zero-length -nobuiltininc -idirafter /usr/lib/clang/17/include -fstack-protector-strong    -Qunused-arguments    -c /usr/home/hiroo/work/sandbox/maketest/getlogin.c -o getlogin.o
cc -g -O2 -fPIE -g -gz=zlib -std=gnu99 -Wno-format-zero-length -nobuiltininc -idirafter /usr/lib/clang/17/include -fstack-protector-strong -Qunused-arguments  -Wl,-zrelro -pie   -o getlogin.full getlogin.o  
objcopy --only-keep-debug getlogin.full getlogin.debug
objcopy --strip-debug --add-gnu-debuglink=getlogin.debug  getlogin.full getlogin

The program getlogin was made in the ./obj directory.
 
Back
Top