如何为GNU Make的不同文件名编写不同的隐式规则

时间:2010-06-15 11:00:40

标签: makefile gnu-make

我有一个目录,我不断添加不同的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有很多明确的规则,我想用更简单的隐式规则替换它们。

知道该怎么做吗?

2 个答案:

答案 0 :(得分:4)

首先,这种将几个源文件直接编译成可执行文件的方法并不是一个非常好的主意。更常见的compile-then-link方法将节省大量不必要的编译。

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

%.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

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

答案 1 :(得分:1)

您似乎将多个不同程序的源代码放在同一个文件夹中,这确实是您遇到问题的根源。如果将库和程序的源代码分离到单独的文件夹(或者更好的是单独的项目),那么您可以根据给定文件夹中的所有源文件来解决此问题。当你把所有东西混合在一起时,就必须明确。

也就是说,如果您的依赖项具有一致的,可预测的名称,那么可以使用eval function来消除此冗余。例如,基于上面的示例:

#
# 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 tutorial,了解使用Make(无双关语)让事情变得更轻松的提示。