简体   繁体   English

是否可以使用 Makefile“定义”来定义目标及其配方?

[英]Is it possible to use Makefile "define" to define a target plus its recipes?

I have a C/C++ project that contains different directories, each containing a set of objects executables to build from C/C++ source code.我有一个包含不同目录的 C/C++ 项目,每个目录都包含一组从 C/C++ 源代码构建的对象可执行文件。

To enable automatic dependency tracking (generating .d dependency files whenever my #include header files change), I have defined the following variables in a common Makefile:为了启用自动依赖项跟踪(每当我的#include头文件更改时生成 .d 依赖项文件),我在通用 Makefile 中定义了以下变量:

# automatic prerequisite generation
# source: http://web.archive.org/web/20210820223028/http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
DEPFLAGS = -MT "$@" -MMD -MP -MF "$(@:.o=.d)"
CC_WRITE_DEP = $(CC) $(CFLAGS) -c "$<" -o "$@" $(DEPFLAGS)
CXX_WRITE_DEP = $(CXX) $(CXXFLAGS) -c "$<" -o "$@" $(DEPFLAGS)

So that when I write directory-specific Makefiles I can write:因此,当我编写特定于目录的 Makefile 时,我可以编写:

# common compile options
common := common/Makefile
-include $(common)

# automatic dependency tracking
deps = $(objs:.o=.d)
-include $(deps)

# compile all .cpp source code files into .o object files
%.o: %.cpp
    $(CXX_WRITE_DEP)

# compile all .c source code files into .o object files
%.o: %.c
    $(CC_WRITE_DEP)

Where objs refers to the object files needed to build each executable.其中objs是指构建每个可执行文件所需的目标文件。

But I found that the block of lines I have presented above must be repeated for every Makefile that I use to build executables in each directory, which could be a hassle if there are many of them.但是我发现对于我用来在每个目录中构建可执行文件的每个 Makefile 都必须重复我上面介绍的行块,如果它们中有很多,这可能会很麻烦。

I then have tried to write this in the common Makefile:然后我尝试在通用的 Makefile 中写这个:

define CC_OBJ_COMPILE =
%.o: %.c
    $(CC_WRITE_DEP)
endef

define CXX_OBJ_COMPILE =
%.o: %.cpp
    $(CXX_WRITE_DEP)
endef

and to include them in building executables:并将它们包含在构建可执行文件中:

common := common/Makefile
-include $(common)

$(CC_OBJ_COMPILE)
$(CXX_OBJ_COMPILE)

But this does not work.但这不起作用。 When I ran make -p --dry-run in one directory for executables to see how those variables expanded, I saw these lines:当我在一个可执行文件的目录中运行make -p --dry-run以查看这些变量如何扩展时,我看到了以下make -p --dry-run行:

# ...
# makefile (from 'common/Makefile', line 16)
define CC_OBJ_COMPILE
%.o: %.c
    $(CC_WRITE_DEP)
endef
# ...
# makefile (from 'common/Makefile', line 21)
define CXX_OBJ_COMPILE
%.o: %.cpp
    $(CXX_WRITE_DEP)
endef
# ...

This means that the text variables are properly included into my executable-specific Makefiles.这意味着文本变量已正确包含在我的可执行文件特定的 Makefile 中。

However the implicit rules are expanded as:然而,隐式规则被扩展为:

# Implicit Rules

%.o: %.c
 cc -Wall -Werror -c "" -o "" -MT "" -MMD -MP -MF ""

%.o: %.cpp
 g++ -Wall -Werror -c "" -o "" -MT "" -MMD -MP -MF ""

Which means that they fail to include the automatic $< and $@ variables for targets .这意味着它们无法包含 target 的自动$<$@变量

So is it possible to create reusable rules that can be define d as variables and -include d in other Makefiles using variable references?那么是否有可能创建可重用的规则,这些规则可以使用变量引用define d define为变量并在其他 Makefile 中-include d? Did I miss something here?我在这里错过了什么吗?

Make is an old grandpa - it is 45 years old. Make是一位老爷爷——今年45岁。 Consider moving to something newer - CMake, Scons, Meson, etc. Such tools will take care of dependencies automatically, will be portable, will come with a lot more features and will save you from endless (and pointless) hours of reinventing the wheel.考虑转向更新的东西 - CMake、Scons、Meson 等。这些工具将自动处理依赖项,将是可移植的,将提供更多功能,并将使您免于重新发明轮子的无休止(和无意义)时间。

Is it possible to use Makefile "define" to define a target plus its recipes?是否可以使用 Makefile“定义”来定义目标及其配方?

You have to eval the call.您必须评估通话。

define CXX_OBJ_COMPILE =
%.o: %.cpp
    $(CXX_WRITE_DEP)
endef

$(eval $(CXX_OBJ_COMPILE))

Which means that they fail to include the automatic $< and $@ variables for targets.这意味着它们无法包含目标的自动 $< 和 $@ 变量。

Sure it does - $@ is like "expanded first", they need to be left for expansion.当然可以 - $@就像“先扩展”一样,需要留下它们进行扩展。

CC_WRITE_DEP = $(CC) $(CFLAGS) -c "$$<" -o "$$@" $(DEPFLAGS)

As I see it you have three options.在我看来,您有三个选择。

You could use the correct syntax for using "canned" code, as @KamilCuk directs.正如@KamilCuk 所指示的,您可以使用正确的语法来使用“罐头”代码。

Or you could put the rules in the common file rather than assigning them to variables, as @thebusybee suggested.或者您可以将规则放在公共文件中,而不是像@thebusybee 建议的那样将它们分配给变量。

Or you could omit the rules entirely and let Make use the default rule with your extra flags:或者你可以完全省略规则,让 Make 使用带有额外标志的默认规则:

CPPFLAGS += $(DEPFLAGS)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM