【问题标题】:Makefile dependency file error when including itMakefile依赖文件包含时出错
【发布时间】:2017-04-13 17:57:21
【问题描述】:

当我尝试在我的 Makefile 中包含一个 C 源文件时,我发现了问题。此 C 源文件包含一个由 C++ 代码 (list.cpp) 通过外部 C 链接选项调用的函数。我想知道在 Makefile 中哪个位置可以包含这个 C 源代码,它的函数在 C++ 代码中被调用。如果我尝试将此 C 文件添加到 Makefile 的 SOURCES 变量中以构建它,则 C++ 代码无法正确解析 C 的函数调用,并且我收到 linker error: undefined reference

以下是我的 Makefile 内容:

CFLAGS =-c -g -Wall -std=c++11
SOURCES = list.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXEC = a.out

all: $(SOURCES) $(EXEC)

$(EXEC): $(OBJECTS)
    @$(CXX) $(OBJECTS) -o $@ && $(EXEC)

.cpp.o:
    @$(CXX) $(CFLAGS) $< -o $@

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    假设您在构建中需要的 C 源文件是bar.c, 并且它有一个相关的头文件bar.h 你是 #include-ing in list.cpp,并且您已正确编码 extern C bar.h 中的样板。

    那么下面的makefile就会满足你的需要:

    生成文件

    CXX_SOURCES := list.cpp
    C_SOURCES := bar.c
    OBJECTS = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
    
    CXXFLAGS := -g -Wall -std=c++11
    CFLAGS := -g -Wall
    CPPFLAGS :=
    LDFLAGS :=
    LDLIBS :=
    EXEC := a.out
    
    .PHONY: all clean test
    
    all: $(EXEC)
    
    test: $(EXEC)
        ./$<
    
    $(EXEC): $(OBJECTS)
        $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)
    
    list.o: bar.h
    
    clean:
        rm -f $(EXEC) *.o
    

    这里有很多学习点:

    1. 使用立即评估 (:=) 而不是递归评估 (=) 除非您特别想要递归评估,否则请制作变量。看 6.2 The Two Flavors of Variables

    2. 如果目标只是任务的名称而不是文件名 任务将创建,然后它是phony target 你应该告诉make这是一个虚假的目标,比如:

    .PHONY: all clean test
    

    3. 构建程序的make-recipe运行程序是不正常的 好吧,就像你的:

    @$(CXX) $(OBJECTS) -o $@ && $(EXEC)
    

    您并不总是想运行一个程序,因为您已经构建了它,并且 如果程序是长期运行的或交互式的,那么这种方法 会让构建程序变得不切实际。

    您可能希望运行程序以测试它是否已正确构建。 但是构建是一项任务,测试是另一项任务(可能需要更长的时间和 涉及额外资源);所以你应该提供一个单独的虚假目标 供测试用。我在这个 makefile 中将其称为 test:通常称为 check。 要构建程序而不对其进行测试,只需运行make。为了测试它, 运行make test - 这将(重新)构建程序如果需要(重新)构建

    4. 您无需编写规则即可从name.cpp 生成name.o,或者 从name.c 生成name.o 的规则。 GNU makebuiltin rules 做 这是正确的,只要你正确设置了make-variables make 在这些内置规则中使用:

    • CC:调用 C 编译或链接的命令,例如gcc
    • CXX:调用 C++ 编译或链接的命令,例如g++
    • CFLAGS: C 编译选项
    • CXXFLAGS:C++ 编译选项
    • CPPFLAGS:C/C++ 预处理器的选项

    5.另外两个具有传统含义的重要生成变量是:

    • LDFLAGS:链接选项,不包括库 (-l) 选项
    • LDLIBS:用于链接的库选项 (-l)。

    在上面的简单makefile中,CPPFLAGSLDFLAGSLDLIBS不是 需要并且可以省略。相反,我为它们分配了空值 只是为了说明它们的用途。

    6. 生成文件应该有一个虚假目标clean 可以删除所有文件 makefile 可能已经创建,所以make clean 让你 准备好从头开始构建任何东西。

    7.。如果name.o是从name.cname.cpp编译而来,那么 当然name.o 取决于name.c|name.cpp,但它也取决于 在由 name.c|name.cpp 包含的每个头文件上,以及 makefile 需要表达所有这些依赖关系才能可靠地工作。所以 在这种情况下,您(至少)需要规则:

    list.o: bar.h
    

    因此,如果您更改 bar.h 然后 make 将看到 foo.o 不在 日期并将执行其重新制作foo.o的配方。当你 开始构建复杂的程序,这对您来说将变得不切实际 自己弄清楚所有这些头文件依赖项:那么你需要 了解自动依赖生成

    这里是the GNU Make manual

    【讨论】:

      猜你喜欢
      • 2020-07-28
      • 2016-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 2015-11-26
      • 2011-01-24
      相关资源
      最近更新 更多