Reputation: 966
I have a rule in my project to generate libraries from sourcecode. I already have the function to compile %.c
to %.o
, but I split my library code in multiple source files that begin with the same prefix. I have two separate library code in the same directory, but their source files have different prefixes, that's why I am trying to build a single rule for both (or maybe more) libraries. But I can't pass the prefix of the codebase to the dependencies to filter the object files needed.
The rule I have is this in my Makefile:
# ...
BINDIR = bin
LIBDIR = lib
# ...
# These are all the libraries source files.
LIB_SOURCES = $(wildcard $(LIBDIR)/*.c)
# These are all the libraries "main" source files.
LIB_SRCS = $(filter-out $(wildcard $(LIBDIR)/*_*.c), $(LIB_SOURCES))
# These are all the source files to which I have exported some code from the "main" library source file.
LIB_CODE = $(filter-out $(LIB_SRCS), $(LIB_SOURCES))
# These are all the objects produced by compiling the c source files.
LIB_OBJS = $(patsubst %.c, %.o, $(LIB_CODE))
# ...
# These are all the libraries produced.
LIBS = $(patsubst $(LIBDIR)/%.c,$(BINDIR)/lib%.so,$(LIB_SRCS))
# ...
.PHONY: libs
# ...
%/:
mkdir -p $@
libs: $(BINDIR)/ $(LIBS)
.SECONDEXPANSION:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
@echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $@ $^
$(LIBDIR)/%.o: $(LIBDIR)/%.c $(LIBDIR)/%.h
@echo $(CC) $(CFLAGS) -o $@ -c $<
For the moment I just print the (incomplete) command, but it still doesn't get the correct output with all the objects needed.
In the directory lib
I have the following files:
$ tree lib
lib
├── app.c
├── app_db.c
├── app_db.h
├── app.h
├── app_logic.c
├── app_logic.h
├── app_net.c
├── app_net.h
├── server.c
├── server.h
├── server_queue.c
└── server_queue.h
But it never builds the dependencies correctly.
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o
I have read the following question How to use pattern-dependent variables in dependencies in make pattern rules, which had a tip I thought it would help me, but it didn't.
Any idea how can I achive this?
EDIT 1:
I want the output of the last command to be:
$ make libs
gcc -Wpedantic -O3 -o lib/app.o -c lib/app.c
gcc -Wpedantic -O3 -o lib/app_db.o -c lib/app_db.c
gcc -Wpedantic -O3 -o lib/app_logic.o -c lib/app_logic.c
gcc -Wpedantic -O3 -o lib/app_net.o -c lib/app_net.c
gcc -Wpedantic -O3 -o bin/libapp.so lib/app.o lib/app_db.o lib/app_logic.o lib/app_net.o
gcc -Wpedantic -O3 -o lib/server.o -c lib/server.c
gcc -Wpedantic -O3 -o lib/server_queue.o -c lib/server_queue.c
gcc -Wpedantic -O3 -o bin/libserver.so lib/server.o lib/server_queue.o
Thanks for your attention.
Upvotes: 0
Views: 353
Reputation: 101051
You added .SECONDEXPANSION
, but you didn't escape anything in the prerequisites list so it doesn't actually do anything:
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
None of these variables/functions are escaped, so everything here is expanded during the initial read-in, so there's nothing for secondary expansion to do.
The secondary expansion feature consists of two parts: first, you enable it with the special target. Second, you escape the variables and/or functions you want to delay expansion of. So this could be:
getobjs = $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))
$(BINDIR)/lib%.so: $(LIBDIR)/%.o $$(getobjs)
@echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $@ $^
Note how we escape the $(getobjs)
as $$(getobjs)
so that this variable is not expanded until the second pass.
Upvotes: 1
Reputation: 99164
Make isn't very deft with wildcards, and your approach requires it to handle two different wildcards in one line. If that's possible at all, it will be a terrible thing to see. I suggest a different approach.
First, your variables are wrong. It's not clear what your intention was, but here are the ones that fit your desired results:
LIB_SOURCES := $(wildcard $(LIBDIR)/*.c)
LIB_OBJS := $(patsubst %.c,%.o,$(LIB_SOURCES))
Now, you want your makefile to act as if it had these two rules:
$(BINDIR)/libapp.so: $(filter $(LIBDIR)/app%,$(NEW_LIB_OBJS))
@echo build $@ somehow from $^
$(BINDIR)/libserver.so: $(filter $(LIBDIR)/server%,$(NEW_LIB_OBJS))
@echo build $@ somehow from $^
But rather than spelling them out in the makefile, you want Make to build them at run time. So we'll use a "canned recipe":
define librule
$(BINDIR)/lib$(1).so: $(filter $(LIBDIR)/$(1)%,$(LIB_OBJS))
@echo building $$@ somehow from $$^
endef
$(eval $(call librule,app))
$(eval $(call librule,server))
Then rather than writing those last two lines in the makefile, specifying app
and server
, we can have Make extract them from LIBS
:
LIB_NAMES := $(patsubst $(BINDIR)/lib%.so,%,$(LIBS))
$(foreach libname,$(LIB_NAMES),$(eval $(call librule,$(libname))))
Upvotes: 0