如何通过makefile中的规则模式传递依赖性?

发布于 2025-01-21 08:08:23 字数 2649 浏览 2 评论 0原文

我的项目中有一条规则,可以从sourcecode生成库。我已经有可以编译%的功能。C to %。o,但是我将我的库代码拆分为以同一前缀开头的多个源文件。我在同一目录中有两个单独的库代码,但是它们的源文件具有不同的前缀,这就是为什么我试图为这两个库构建单个规则。但是我无法将代码库的前缀传递给依赖项来过滤所需的对象文件。

我拥有的规则是在我的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 $<

目前我只打印(不完整)命令,但它仍然无法获得所需的所有对象的正确输出。

在目录lib中,我有以下文件:

$ 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

但是它永远不会正确构建依赖项。

$ 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

我已经阅读了以下问题如何在制作模式规则中使用模式依赖的变量,我认为它会帮助我,但事实并非如此。

知道我该如何实现这一目标?

编辑1:

我希望最后一个命令的输出是:

$ 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

感谢您的关注。

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 
lt;

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

若水微香 2025-01-28 08:08:23

您添加了.secondexpansion,但是您没有在先决条件列表中逃脱任何内容,因此它实际上没有做任何事情:

$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))

这些变量/函数都没有逃脱,因此在初始读取过程中,此处的所有内容都扩展了 - 在,因此没有什么可做的。

次要扩展功能包括两个部分:首先,您可以使用特殊目标启用它。其次,您逃脱要延迟扩展的变量和/或函数。因此,这可能是:

getobjs = $(filter $(LIBDIR)/$*_%.o, $(LIB_OBJS))

$(BINDIR)/lib%.so: $(LIBDIR)/%.o $(getobjs)
        @echo $(CC) $(CFLAGS) $(CLNKERFLAGS) -o $@ $^

请注意我们如何逃脱$(getObjs)作为$$(getObjs),以便在第二次通过之前不扩展此变量。

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.

热血少△年 2025-01-28 08:08:23

通配符不是很聪明,您的方法要求它在一行中处理两种不同的通配符。如果有可能,那将是一件可怕的事情。我建议一种不同的方法。

首先,您的变量是错误的。目前尚不清楚您的意图是什么,但以下是适合您所需的结果的意图:

LIB_SOURCES := $(wildcard $(LIBDIR)/*.c)
LIB_OBJS := $(patsubst %.c,%.o,$(LIB_SOURCES))

现在,您希望您的Makefile像有这两个规则一样行事:

$(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 $^

但是,您不想在Makefile中拼写它们,而是想建立构建他们在运行时间。因此,我们将使用“ nofollow noreferrer”>“罐头食谱”

define librule
$(BINDIR)/lib$(1).so: $(filter $(LIBDIR)/$(1)%,$(LIB_OBJS))
    @echo building $@ somehow from $^
endef

$(eval $(call librule,app))
$(eval $(call librule,server))

然后,我们可以从libs

LIB_NAMES := $(patsubst $(BINDIR)/lib%.so,%,$(LIBS))
$(foreach libname,$(LIB_NAMES),$(eval $(call librule,$(libname))))

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))))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文