【问题标题】:Compile multiple **changed** source files at once in GNU make在 GNU make 中一次编译多个**更改的**源文件
【发布时间】:2011-08-28 04:10:54
【问题描述】:

我知道有几个标题相似的问题,但似乎没有一个能提供我需要的答案(如果我错了,请纠正我)。

考虑这个makefile:

SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog

all: $(SOURCES) $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
    $(CXX) -o $@ $(OBJECTS)

file1.o: file1.cpp file1.h
file2.o: file2.cpp file2.h file1.h
file3.o: file3.cpp

.cpp.o:
    $(CXX) $(CXXFLAGS) -c -o $@ $<

如果我更改 file1.h,则运行以下内容:

g++ -c -o file1.o file1.cpp
g++ -c -o file2.o file2.cpp
g++ -o myprog file1.o file2.o file3.o 

我想要的是:

g++ -c file1.cpp file2.cpp
g++ -o myprog file1.o file2.o file3.o 

(我知道我无法使用 GCC 指定对象输出目录,但我可以接受;应该可以使用一些 cd 命令解决。)

在 nmake 中,这是通过双冒号推理规则(所谓的“batch-mode rule"”)完成的。基本上,它将多个目标的推理规则(例如“.obj.cpp:”)分组并调用所有依赖项的编译器,而不是每个文件一次。$&lt; 变量获取依赖项列表,而不仅仅是第一个。

现在我们正在使用并行构建 (make -j),但它有自己的问题,而且 VC++ 编译器在一次调用模式下工作得更好,所以我更喜欢使用它。

【问题讨论】:

  • 为什么你的all 目标依赖于你的$(SOURCES)?不需要,因为您的 $(OBJECTS) 已经一一依赖它们。
  • 这只是我找到的一个例子。在我们的makefile(它们非常复杂)中,我们确实只依赖于最终的可执行文件。无论哪种方式,这都不是问题所在。
  • gcc 包装器将多次调用 cc1、gas 等。您将保存的唯一程序调用是 gcc 包装器本身。
  • 你为什么想要那个?
  • 您是否测试了使用和不使用“批处理模式”的编译速度?你看到有多大的不同?如果您没有测试并看到显着差异,您为什么认为这会有所帮助?

标签: c gcc makefile nmake


【解决方案1】:

我不明白你为什么想要这种效果,但这里是如何获得它(在 GNUMake 中):

SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog

all: $(EXECUTABLE)

$(EXECUTABLE): $(SOURCES)
    $(CXX) $(CXXFLAGS) -c $?
    $(CXX) -o $@ $(OBJECTS)

编辑:
我很惊讶该解决方案有效 - 我对 Make 所做的事情的想法有问题 - 但我认为它不会在你的情况下工作,具有标题依赖关系,没有以下内容。 (如果不成功,还有一两种其他方法可能有效。)

SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog

all: $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
    $(CXX) -o $@ $(OBJECTS)

file1.cpp: file1.h
file2.cpp: file2.h file1.h

$(SOURCES):
    @touch $@

$(OBJECTS): $(SOURCES)
    $(CXX) $(CXXFLAGS) -c $?
    @touch $(OBJECTS)

【讨论】:

  • 谢谢,这是可能的。但是,有了这个,我将不得不在同一规则中进行编译和链接。我可以以某种方式将链接和编译分开吗?
  • 这个解决方案的一个问题是它不跟踪单个文件的依赖关系(我们已经声明过)。所以例如更改标头不会触发重新编译。我找到了一个几乎可以工作的解决方案here,但它需要将我们所有的依赖项从 .obj 更改为 .cpp。嗯……
【解决方案2】:

您可以通过在构建规则中收集要重新构建的文件然后在链接时实际构建它们来使 GNUmake 做您想做的事情:

SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog

all: $(EXECUTABLE)

.PHONY: build_list

build_list:
        -rm -f build_list

$(OBJECTS): %.o: %.cpp | build_list
        echo $< >> build_list

$(EXECUTABLE): build_list $(OBJECTS)
        if [ -r build_list ]; then $(CXX) $(CXXFLAGS) -c `cat build_list`; fi
        $(CXX) -o $@ $(OBJECTS)

file1.o: file1.h
file2.o: file2.h file1.h

【讨论】:

  • 这看起来很有趣,我们会看看它是否有效。虽然我想知道您是否可以使用 make 变量而不是列表文件。
猜你喜欢
  • 2017-10-16
  • 2017-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
相关资源
最近更新 更多