Reputation: 742
Say, there's a source directory with non-defined internal structure, and we want to grab all the files and declare the files they are supposed to be compiled into as targets.
Something like that:
SOURCES := $(shell find src -name \*.c)
OBJS := $(addprefix /tmp,$(addsuffix .o,$(basename $(notdir $(SOURCES)))))
$(OBJS): $(SOURCES)
cc $(CFLAGS) -o $@ $^
However, it starts with the second line not working (it's just being empty). So, I ended up replacing it:
OBJS := $(shell find src -name \*.c -exec sh -c "basename {} | sed 's/^/\/tmp\/g' | sed 's/\.c/\./o/g'" \;)
I don't like this approach much, but otherwise it doesn't seem to be working anyway. Okay, now it's expected to be working. However, the targets don't work as expected, say, as if I declared them explicitly:
TARGETS := /tmp/foo.o /tmp/bar.o
$(TARGETS): $(SOURCES)
...
Instead, I just get an error No rule to make target /tmp/foo.o
.
So, guess, I have two questions:
$(OBJS)
empty?Upvotes: 2
Views: 7935
Reputation: 5685
$ uname -a
Linux - 3.2.0-4-686-pae #1 SMP Debian 3.2.54-2 i686 GNU/Linux
$ make -v
GNU Make 3.81
$ cat makefile
SOURCES := $(shell find ./ -name \*.c)
OBJS := $(addprefix /tmp,$(addsuffix .o,$(basename $(notdir $(SOURCES)))))
$(info $(OBJS))
$ mkdir test; touch test/1.c; touch test/2.c; make -f makefile
Output:
/tmp1.o /tmp2.o
The test shows that the first snippet is ok, except for the missing slash after /tmp
.
Questions:
OBJS
?SOURCES
is not empty?make
with $(info $(SOURCES))
in makefile
?*.c
files in the src
directory?$ sed --version
GNU sed 4.2.1
$ cat makefile
SOURCES := $(shell find ./ -name \*.c)
OBJS := $(shell find ./ -name \*.c -exec sh -c \
"basename {} | sed 's/^/\/tmp\/g' | sed 's/\.c/\./o/g'" \;)
$(info $(OBJS))
$ make -f makefile
Output:
sed: -e expression #1, symbol 10: unknown modifier for s'
sed: -e expression #1, символ 12: incomplete command s'
sed: -e expression #1, символ 12: incomplete command s'
sed: -e expression #1, символ 10: unknown modifier for s'
With that version of the second snippet, OBJS
is not empty.
Note the removed '\'
in the first sed
command and the removed '/'
in the second command:
OBJS := $(shell find ./ -name \*.c -exec sh -c \
"basename {} | sed 's/^/\/tmp\//g' | sed 's/\.c/\.o/g'" \;)
Yep. It's easy, if you can store .o files in the source directories.
The next snippet does the trick:
sources := $(shell find ./ -name \*.c)
objects := $(sources:.c=.o)
$(objects): %.o: %.c
$(cc) -c $<
But perhaps it's not what you want.
With using VPATH
and a couple of additional strings, you can do better.
target := ./a.out
obj_dir := ./tmp/
sources := $(shell find ./ -name \*.c)
objects := $(addprefix $(obj_dir), $(notdir $(sources:.c=.o)))
dirs := $(dir $(sources))
VPATH := $(dirs)
$(target): $(objects)
$(cc) -o $@ $^
$(objects): $(obj_dir)%.o: %.c
$(cc) -o $@ -c $<
Upvotes: 4