1

我有一个目录,我在其中不断添加不同的 C++ 源文件和通用 Makefile 来编译它们。这是 Makefile 的内容:

.PHONY: all clean

CXXFLAGS = -pipe -Wall -Wextra -Weffc++ -pedantic -ggdb

SRCS = $(wildcard *.cxx)
OBJS = $(patsubst %.cxx,%.out,$(SRCS))

all: $(OBJS)

clean:
    rm -fv $(OBJS)

%.out: %.cxx
    $(CXX) $(CXXFLAGS) $^ -o $@

注意:从上面很明显,我将 *.out 用于可执行文件扩展名(而不是用于目标文件)。

此外,还有一些文件是一起编译的:

g++ file_main.cxx file.cxx -o file_main.out

为了编译这样的文件,到目前为止我一直在 Makefile 中添加明确的规则:

file_main.out: file_main.cxx file.cxx

file.out: file_main.out
    @echo "Skipping $@"

但是现在我的 Makefile 有很多显式规则,我想用更简单的隐式规则替换它们。

知道怎么做吗?

4

2 回答 2

4

首先,这种将多个源文件直接编译成可执行文件的方法并不是一个非常好的主意。比较常见的先编译后链接方式会省去很多不必要的编译。

也就是说,用更简单的规则替换许多显式规则的方法取决于显式规则的共同点。您已经有一个模式规则:

%.out: %.cxx
    $(CXX) $(CXXFLAGS) $^ -o $@

如果您只想将另一个源文件添加到特定目标,则不必这样做:

g++ file_main.cxx file.cxx -o file_main.out

您只需添加一个先决条件(单独一行)即可获得效果:

file_main.out: file.cxx

如果您有多个具有该模式的目标,则可以使用模式规则:

file_main.out another_main.out a_third_main.out: %_main.out : %.cxx

如果你有很多这样的目标,你可以使用一个变量:

MAIN_THINGS = file another a_third a_fourth and_yet_another
MAIN_TARGETS = $(addsuffix _main.out, $(MAIN_THINGS))
$(MAIN_TARGETS): %_main.out : %.cxx

您可以为其他目标集添加其他模式,甚至是重叠集。这是否涵盖了您的情况?

于 2010-06-16T21:10:52.833 回答
1

您似乎将多个不同程序的源代码放在同一个文件夹中,这确实是您问题的根源。如果您将库和程序的源代码分隔到单独的文件夹(或者更好的是,单独的项目)中,那么您可以通过依赖给定文件夹中的所有源文件来绕过这个问题。当您将所有内容混合在一起时,有必要明确。

也就是说,如果您的依赖项具有一致的、可预测的名称,那么可以通过使用eval 函数来消除这种冗余。例如,基于上面的例子:

#
# I'm going to use standard file extensions here,
# slightly deviating from your conventions. I am also
# assuming that there is a variable named PROGNAMES,
# which gives a list of all the programs to be built.
#
define ADD_EXECUTABLE
     $(1): $(1).o $(1)_main.o
         $(LINK.cc) $(1).o $(1)_main.o -o $(1)
endef

$(foreach progname,$(PROGNAMES),$(eval $(call ADD_EXECUTABLE,$(progname)))) 

另外,只是一些建议...您应该附加到 CXXFLAGS 而不是覆盖它,并且最好使用标准文件扩展名(“.cpp”用于 C++ 源文件,“.o”用于目标文件,不用于可执行文件的扩展名)。请参阅我的Makefile 教程,了解使用 Make 使事情变得更容易的技巧(没有双关语)。

于 2010-06-15T11:20:08.343 回答