【问题标题】:g++ fails to link .o files into an executableg++ 无法将 .o 文件链接到可执行文件中
【发布时间】:2016-11-25 06:18:40
【问题描述】:

我正在我用来学习的教科书中做一个示例练习。我需要做的就是编译、链接和运行以下 3 个文件:

//file my.h
extern int foo;
void print_foo();
void print(int);

my.h 是一个简单的头文件,它声明了两个函数和一个“全局”int foo,没有初始值。

//file my.cpp
#include "my.h"
#include "std_lib_facilities.h" //not included but not source of error

void print_foo()
{
    cout << foo << endl;
}

void print(int i)
{
    cout << i << endl;
}

my.cpp 包含 my.h 中包含的函数的实现。 std_lib_facilities.h 是教科书中的文件,不是错误的来源(根据 g++)。如果需要,我可以将其编辑到问题的正文中。

//file use.cpp
#include "my.h"
#include <iostream>

int main() {
    foo = 7;
    print_foo();
    print(99)

    char cc; cin >> cc;
    return 0;
}

use.cpp 作为该程序的主要实现文件,并尝试使用所有三个已声明和定义的对象。

我采用了两步命令方法来使用 g++ 构建。首先,我编译了两个 .cpp 文件:

g++ -c my.cpp use.cpp

它创建了两个目标文件,my.o 和 use.o。我使用以下命令链接它们:

g++ -o myprog my.o use.o

给我这个错误:

Undefined symbols for architecture x86_64:
  "_foo", referenced from:
      print_foo() in my.o
      _main in use.o
     (maybe you meant: __Z9print_foov)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我试过放

int foo;

进入 my.h 而不是

extern int foo;

这给了我同样的错误。

我尝试过使用

-std=c++11

flag 也导致了同样的错误。

我正在使用装有最新 macOS(实际上只是更新)的 MacBook Pro,如果这有助于解释错误消息。

我尝试初始化 foo,但并没有改变任何东西。

另外,我试过更新命令行工具,同样的错误。

据我了解,错误告诉我,即使 my.h 包含在两个文件中,也无法使用 foo 变量(它称为 _foo)实际实现任何函数,尽管它在我的。我的猜测是链接器在后台使用了错误的名称,这使得无法链接到可执行文件。这是因为错误提到了一个

__Z9print_foov

在任何文件中都不存在。

在这一点上,它几乎看起来像是一个 g++ 或 macOS/命令行工具错误。我不想每次都添加声明,因为无论如何都会产生重复的符号错误。将 my.cpp 和 use.cpp 放入一个文件可能会正确链接,但我需要确保我实际上可以链接多个 cpp 文件,因为我最终(希望)将处理需要链接的多个 cpp 文件。任何帮助表示赞赏!

【问题讨论】:

    标签: c++ linker g++ clang linker-errors


    【解决方案1】:

    在这里声明一个变量:

    extern int foo;
    

    你使用变量:

    cout << foo << endl;
    

    但是您没有在任何地方定义变量。链接器错误表示链接器找不到变量的定义。要解决此问题,请将int foo; 放在.cpp 文件之一的文件范围内。

    在问题中,您说将 extern int foo; 更改为 int foo; 会产生相同的错误。但是,如果您更仔细地查看错误消息,我想您会发现它给出了不同的错误消息,关于多个定义。

    【讨论】:

      【解决方案2】:

      我建议编译两个命令g++ -Wall -c my.cpp(给出my.o)和g++ -Wall -c use.cpp(给出use.o),然后用g++ my.o use.o -o myprog链接一个程序。实际上,您应该写一个Makefile(请参阅this 以获得灵感)并简单地运行make

      您的翻译单元my.cppuse.cpp声明一些extern int foo; 变量从未定义。因此,您需要在 one 单个文件中定义它(而不是在其他文件中!),可能通过添加(例如 my.cpp alone )

       int foo;
      

      (没有extern)甚至有一些明确的初始值,例如int foo = 34;

      这是因为错误提到了一个不存在的__Z9print_foov

      它是一个mangled name,在两个目标文件中都被引用(但未定义)(另见this)。

      在这一点上,它几乎看起来像是一个 g++ 或 macOS/命令行工具错误

      您不太可能在编译器工具中发现错误(GCCClang/LLVM 都经过非常好的测试;因为它们是数百万行的免费软件,它们确实有残留的错误,但你有更多的机会赢得彩票而不是受到编译器错误的影响)。我从 1974 年开始编码,这在我的一生中只发生过一次。更现实的态度是更加谦虚,在怀疑编译器或构建链之前质疑你自己的代码(和知识) p>

      顺便说一句,总是先编译所有警告和调试信息(例如g++ -Wall -g 可能还有-Wextra)。使用gdb 调试器。当您确信您的代码没有错误时,您可以通过要求编译器对optimize 进行基准测试(因此使用g++ -Wall -O2 可能也与-g 一起编译)。

      另请阅读linker 维基页面。深入了解您的C++ textbook(另请参阅this siteC++11 标准,例如n3337 草案)以了解声明定义之间的区别一些变量或函数。您通常在一些公共头文件中声明一个全局 extern 变量(包含在几个翻译单元中),并在其他地方定义它一次,但好的做法是避免使用很多全局变量。另请参阅 C++17 新的 inline 变量。

      【讨论】:

      • 声明 int foo;在我的.cpp中;有效!谢谢您的帮助。但是,我不明白为什么链接器会出现问题,如果变量是在标头中声明的,因此是在包含它的 .cpp 文件中声明的(除非我遗漏了一些东西)。如果我必须在 .cpp 文件中再次声明它,那么在标题中声明 extern int foo 有什么意义?为了公约?我不认为 extern 有什么特别之处,但仍然很好奇,所以我不会再遇到这个问题了。
      • 阅读您的 C++ 书籍,了解声明变量和定义变量之间的区别。
      • 很公平。错误评论更多是出于挫败感,并不打算破坏 gcc 的努力,哈哈。肯定会尝试变得更加谦虚。感谢您花时间给我建议,而不仅仅是回答问题!我阅读了一些文档并意识到普通 int foo,即使没有任何初始化值,也算作声明和定义,而标头中的 extern int foo 声明没有定义,因此未定义,导致我的错误。
      • 但是好的做法是把extern int foo;放在标题中(它包含在几个翻译单元中),并有一个 .cpp文件声明 foo。另请参阅C++17内联变量
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多