【问题标题】:Makefile executed unexpected behaviorMakefile 执行了意外的行为
【发布时间】:2018-11-13 04:18:02
【问题描述】:

我使用以下 Makefile 编译 C++ 文件,但发生了一些意外行为。环境是 MacOS X Mojave。 Makefile 如下:

CC=gcc
CXX=g++
CXXFLAGS=-std=c++11
RM=rm -f

all: clean sort_test ds_test

sort_test: data_structure sort .sort_test.o .sort_test

.sort_test: sort_test.o sort.o ds.o
        $(CXX) $(CXXFLAGS) -o sort_test sort_test.o sort.o ds.o

.sort_test.o: sort_test.cpp ../include/io.hpp
        $(CXX) $(CXXFLAGS) -c -o sort_test.o sort_test.cpp

sort: ../include/sort.hpp ../include/data_structure.hpp ../src/sort.cpp
        $(CXX) $(CXXFLAGS) -c -o sort.o ../src/sort.cpp

data_structure: ../include/data_structure.hpp ../src/data_structure.cpp ../include/io.hpp
        $(CXX) $(CXXFLAGS) -c -o ds.o ../src/data_structure.cpp

ds_test: data_structure .ds_test.o .ds_test

.ds_test: ds.o ds_test.o
        $(CXX) $(CXXFLAGS) -o ds_test ds.o ds_test.o

.ds_test.o: ds_test.cpp ../include/io.hpp ../include/data_structure.hpp
        $(CXX) $(CXXFLAGS) -c -o ds_test.o ds_test.cpp

clean:
        $(RM) *.o sort_test ds_test

当我在同一目录中运行“make ds_test”时,发生了一些奇怪的事情:

g++ -std=c++11   -c -o ds_test.o ds_test.cpp
g++ -std=c++11 -c -o ds.o ../src/data_structure.cpp
g++ -std=c++11 -c -o ds_test.o ds_test.cpp
g++ -std=c++11 -o ds_test ds.o ds_test.o
gcc   ds_test.o data_structure .ds_test.o .ds_test   -o ds_test
clang: error: no such file or directory: 'data_structure'
clang: error: no such file or directory: '.ds_test.o'
clang: error: no such file or directory: '.ds_test'
make: *** [ds_test] Error 1

此输出中的第一行和第五行永远不会用于命令“make ds_test”,因为它应该只调用“data_structure”、“.ds_test.o”和“.ds_test”。 任何人,请解释为什么会发生这些额外的意外行为以及如何避免它?谢谢!

【问题讨论】:

    标签: makefile g++ gnu-make


    【解决方案1】:

    你的 Makefile 有点奇怪。基本的制作规则如下:

    file-to-build: files-it-depends-on
        command-to-build
    

    虽然你写了这样的东西:

    .ds_test: ds.o ds_test.o
            $(CXX) $(CXXFLAGS) -o ds_test ds.o ds_test.o
    

    其中目标不是配方生成的文件。此外,您在没有适当的扩展名的情况下重命名事物(data_structureds.o)。最后,您对同一事物使用不同的名称(同样是 data_structureds.o)。如果你是从 C++ 和 make 开始的,你应该避免所有这些花哨的东西。

    您的 Makefile 失败的主要原因是因为 make 试图构建一个名为 ds_test 的文件(这是您在键入 make ds_test 时所要求的)。并且 make 知道很多构建文件的方法。在这种特定情况下,它使用其默认规则,即使用$(CC)ds_test.o 和所有其他文件ds_test 依赖在一起,即data_structure.ds_test.o.ds_test 链接在一起。

    如果您是新手,我建议您首先坚持其最基本的原则。比如:

    CC       := gcc
    CXX      := g++
    CXXFLAGS := -std=c++11
    RM       := rm -f
    
    .PHONY: all clean
    
    all: clean sort_test ds_test
    
    sort_test: sort_test.o sort.o data_structure.o
        $(CXX) $(CXXFLAGS) -o $@ $^
    
    sort_test.o: sort_test.cpp ../include/io.hpp
        $(CXX) $(CXXFLAGS) -c -o $@ $<
    
    sort.o: ../src/sort.cpp ../include/sort.hpp ../include/data_structure.hpp
        $(CXX) $(CXXFLAGS) -c -o $@ $<
    
    data_structure.o: ../src/data_structure.cpp ../include/data_structure.hpp ../include/io.hpp
        $(CXX) $(CXXFLAGS) -c -o $@ $<
    
    ds_test: data_structure.o ds_test.o
        $(CXX) $(CXXFLAGS) -o $@ $^
    
    ds_test.o: ds_test.cpp ../include/io.hpp ../include/data_structure.hpp
        $(CXX) $(CXXFLAGS) -c -o $@ $<
    
    clean:
        $(RM) *.o sort_test ds_test
    

    解释:

    • $@$&lt;$^make automatic variables,分别作为目标、第一个先决条件和所有先决条件的列表展开。它们不仅方便,而且比在目标、先决条件和配方中重新输入相同的文件名更不容易出错。
    • .PHONY 是一个 special target,您可以通过它发出信号以使哪些目标不是真实文件。

    编辑:添加LDLIBS 以使用gcc 和备用链接规则链接C++ 目标文件。

    注意:由于 make 非常聪明,并且默认知道如何编译和链接 C++ 文件,因此您可以简化这一切。特别是如果您还使用VPATH make variable:

    CC       := gcc
    CXX      := g++
    CXXFLAGS := -std=c++11
    LDLIBS   := -lstdc++
    RM       := rm -f
    EXEC     := sort_test ds_test
    
    .PHONY: all clean
    
    all: clean sort_test ds_test
    
    VPATH    := ../src:../include
    
    sort_test.o: io.hpp
    sort.o: sort.hpp data_structure.hpp
    data_structure.o: data_structure.hpp io.hpp
    ds_test.o: io.hpp data_structure.hpp
    
    sort_test: sort_test.o sort.o data_structure.o
    ds_test: data_structure.o ds_test.o
    
    clean:
        $(RM) *.o $(EXEC)
    

    注意:由于 make 将使用 gcc 链接,我们必须将 -lstdc++ 添加到链接器标志 (LDLIBS)。另一种选择是指定链接规则,而不是让 make 使用默认值:

    $(EXEC):
        $(CXX) $(CXXFLAGS) -o $@ $^
    

    请注意,在最后一种情况下,指定先决条件的规则和指定配方的规则是不同的。

    【讨论】:

    • 嗨 Renaud,这个答案对我帮助很大,非常感谢!顺便说一句,对于“sort_test”和“ds_test”,我必须手动添加命令才能使用$(CXX),否则他们会默认使用gcc来链接* .o文件,这会导致一些链接问题。跨度>
    • 你是对的。我编辑了我的答案并添加了两种可能性来解决这个问题。
    猜你喜欢
    • 2016-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 2018-01-09
    相关资源
    最近更新 更多