英文:
Makefile pattern with replacement doesn't capture non-local sources
问题
我有一个项目,其中的源代码分布在本地子目录和SDK中,而SDK位于不同的位置。
所有目标文件都需要在项目的构建目录树中生成,而来自SDK的源文件需要放在 $(OUTPUT_DIR)/sdk
目录中。我需要一种通用的方法来处理GNU-Make中的所有源代码。
我有以下函数将源路径匹配到目标路径:
source_to_object_path = $(OUTPUT_DIR)/$(subst $(SDK_PATH),sdk,$1)
这成功地将本地的 app.c
匹配到 $(OUTPUT_DIR)/app.o
,也将 $(SDK_PATH)/timer/timer.c
匹配到 $(OUTPUT_DIR)/sdk/timer/timer.o
。
但是,我无法编写一个能够捕获所有 .c 源文件到 .o 目标文件的模式。
无论是这个(1):
$(call source_to_object_path,%).o : %.c
还是这个(2):
$(call source_to_object_path,$(<D))%.o: %.c
只能捕获本地源文件,但是对于SDK中的源文件却显示 "Nothing to be done"。尽管对SDK中的源文件应用 source_to_object_path
可以得到正确的目标路径,并且目标列表也构建正确。所有源文件路径也都在VPATH中。
因此,我需要另一种成功工作的模式(3)来处理SDK中的源文件:
$(call source_to_object_path,$(SDK_PATH))/%.o: $(SDK_PATH)/%.c
为什么没有指定 SDK_PATH
的模式不能处理这些源文件?难道 source_to_object_path
不应该处理这个吗?有没有可能在这里只使用一个模式而不是两个?
英文:
I've got a project that has sources in the local subdirectories and also sources in the SDK, which is in the different location.
All object files need to be built in the project's build directory tree, and the sources from the SDK need to be placed in the $(OUTPUT_DIR)/sdk
. And I need a generic way to deal with all the sources with GNU-Make.
I have this function to match a source path to an object path:
source_to_object_path = $(OUTPUT_DIR)/$(subst $(SDK_PATH),sdk,$1)
So this successfully matches, for example, local app.c
to $(OUTPUT_DIR)/app.o
, and also $(SDK_PATH)/timer/timer.c
to $(OUTPUT_DIR)/sdk/timer/timer.o
.
But I'm struggling to write a pattern that would capture all .c sources to .o targets.
Either this (1):
$(call source_to_object_path,%).o : %.c
or this (2):
$(call source_to_object_path,$(<D))%.o: %.c
only capture the local sources, but there's "Nothing to be done" for the sources in the SDK. Even though source_to_object_path
applied to the sources in the SDK gives the correct path to the objects, and the objects list is built correctly. All sources paths are also in VPATH.
Therefore I need another pattern (3) for the sources in the SDK which works successfully:
$(call source_to_object_path,$(SDK_PATH))/%.o: $(SDK_PATH)/%.c
Why doesn't the pattern without specifying SDK_PATH
work for these? Shouldn't source_to_object_path
care of this, and how is it possible to use one pattern instead of two here?
答案1
得分: 1
答案非常简单:在解析makefile时,目标和先决条件的变量扩展发生_立即_。这并不是在后来,而是在make搜索隐式规则时发生。因此,当make看到以下行:
$(call source_to_object_path,%).o : %.c
您正在使用文字字符串%
调用您的函数。由于它不以$(SDK_PATH)
开头,因此这是一个无操作并且结果只是%.o
。
您可以在GNU Make手册中了解更多关于何时扩展变量的信息:https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html
在那里,您将看到这个:
$(call source_to_object_path,$(<D))%.o: %.c
甚至更不方便,因为自动变量如$(<D)
等仅在配方中扩展。因此,当它扩展时,此变量为空字符串。
如果您想将输出放在两个不同的目录中,您需要两个模式规则。首先,用于sdk目标的规则:
$(OUTPUT_DIR)/sdk/%.o : $(SDK_PATH)/%.c
...
其次,用于其余目标的规则:
$(OUTPUT_DIR)/%.o : %.c
...
英文:
The answer is very simple: variable expansion of targets and prerequisites happens immediately when the makefile is being parsed. It doesn't happen later, when make is searching for implicit rules. So when make sees the line:
$(call source_to_object_path,%).o : %.c
you're calling your function with the literal string %
. Since that doesn't start with $(SDK_PATH)
, this is a no-op and results in just %.o
.
You can read more about when variables are expanded in the GNU Make manual: https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html
There you will see that this:
$(call source_to_object_path,$(<D))%.o: %.c
is even less helpful because automatic variables like $(<D)
etc. are expanded only within the recipe. So this variable is the empty string when it is expanded.
If you want to put the outputs in two different directories you need two pattern rules. First, the one for the sdk targets:
$(OUTPUT_DIR)/sdk/%.o : $(SDK_PATH)/%.c
...
Second, one for the rest of the targets:
$(OUTPUT_DIR)/%.o : %.c
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论