Other [make] Substitute dirnames and suffixes in paths

Hi folks!

I have the following Makefile:
Code:
SRCDIR=	src
INCDIR=	include
OBJDIR=	obj
BINDIR=	bin

SRCS!=	ls $(SRCDIR)/*.c
OBJS=	$(SRCS:c=o)
OBJS=	$(SRCS:src=obj)

all: $(SRCDIR)/*.c
	echo SRCDIR: $(SRCDIR)
	echo INCDIR: $(INCDIR)
	echo OBJDIR: $(OBJDIR)
	echo BINDIR: $(BINDIR)
	echo SRCS: $(SRCS)
	echo OBJS: $(OBJS)

This prints out (as expected) wrong OBJS:
Code:
SRCDIR: src
INCDIR: include
OBJDIR: obj
BINDIR: bin
SRCS: src/mod1.c src/mod2.c
OBJS: src/mod1.c src/mod2.c

What I'd need is "obj/mod1.o obj/mod2.o". How can I do that?

Greetings,
/dev
 
If you want to use FreeBSD's make, read make(1). To replace strings in a variable, there's the :S modifier, and yes, this is very different from GNU make. Alternatively, use GNU make syntax and require GNU make for building.

If you want to be portable, don't rely on such features at all, but that means writing lots of rules manually. You'd typically rather use some tools (GNU autotools, cmake, ...) to generate such a portable Makefile.

In any case, executing a shell command to expand a variable isn't the best practice (will hit each make run and has potential portability issues). You *should* define manually which modules are part of your project somewhere....
 
Wow, thank you for answering that fast! :)

I'm using this but now, OBJS is even empty!
Code:
OBJS=	${SRCS:S/.c/.o/}
OBJS=	${OBJS:S/src/obj/}

Portability is not an issue for me, actually, I'm choosing (b)make specifically...
 
I'm using this but now, OBJS is even empty!
Make variables are expanded lazily. Only when you use ${OBJS}, make will expand its content. So I guess you see what's the problem ;) (your second assignment overrides your first one, OBJS becomes self-referential and empty...)

Either use another "temporary" variable, or do both replacements in the same expansion.

Example for single expansion:
Code:
SRCS= src/foo.c src/bar.c
OBJS= ${SRCS:S/src\//obj\//:S/.c/.o/}

all:
    @echo OBJS: ${OBJS}

.PHONY: all

edit: You could also force immediate expansion by using the := assignment instead of plain =.
 
Ok, got the substitutions to work! But now, the Makefile is somehow executing in the obj subdirectory! How come?
Code:
deever@freesbie:~/modulexamples % cat Makefile 
SRCDIR=	src
INCDIR=	include
OBJDIR=	obj
BINDIR=	bin

E!=	pwd
SRCS!=	ls ../$(SRCDIR)/*.c
OBJS=	${SRCS:S/src\//obj\//:S/.c/.o/}

all: $(SRCDIR)/*.c
	echo E: $(E)
	echo SRCDIR: $(SRCDIR)
	echo INCDIR: $(INCDIR)
	echo OBJDIR: $(OBJDIR)
	echo BINDIR: $(BINDIR)
	echo SRCS: $(SRCS)
	echo OBJS: $(OBJS)
.SILENT:
deever@freesbie:~/modulexamples % ll -R
total 7
-rw-r--r--  1 fips  fips  305 Jan 21 10:22 Makefile
drwxr-xr-x  2 fips  fips    2 Jan 21 10:23 bin
drwxr-xr-x  2 fips  fips    2 Jan 21 10:23 include
drwxr-xr-x  2 fips  fips    2 Jan 21 10:23 obj
drwxr-xr-x  2 fips  fips    4 Jan 21 10:23 src

./bin:
total 0

./include:
total 0

./obj:
total 0

./src:
total 1
-rw-r--r--  1 fips  fips  0 Jan 21 10:23 mod1.c
-rw-r--r--  1 fips  fips  0 Jan 21 10:23 mod2.c
deever@freesbie:~/modulexamples % make
E: /home/deever/modulexamples/obj
SRCDIR: src
INCDIR: include
OBJDIR: obj
BINDIR: bin
SRCS: ../src/mod1.c ../src/mod2.c
OBJS: ../obj/mod1.o ../obj/mod2.o
 
Again, see make(1), handling of the special variable .OBJDIR. There's some builtin "magic", e.g. a writable dir ./obj will be used automatically.

If you don't want that, add the special rule
.OBJDIR: ${.CURDIR}
 
Ah, thank you so much! Maybe I'll keep the manual page open and search it by default now before asking questions! :)
 
Just as an additional hint: If portability is not an issue and you're specifically targeting FreeBSD, you might want to make use of its "make libraries" in /usr/share/mk.

Instead of writing everything yourself, you might e.g. want to just define some variables and add .include <bsd.prog.mk>.
 
FreeBSD's manpages are typically high quality, so this is a good idea. Don't try the same with e.g. GNU make ;)
If you have to be use gmake: there is an O'Reilly book about gmake (it has a cute monkey on the cover). It is way better than the documentation the gmake developers wrote (which is awful).
 
BSD make doesn't have that feature (called pattern rules in GNU make), it only supports suffix rules which don't help here.

You could for example create something similar using a .for loop.
 
Back
Top