g ++无法将.o文件链接到可执行文件中

时间:2016-11-25 06:18:41

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

我正在我正在使用的教科书中进行示例练习。我需要做的就是编译,链接和运行以下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作为此程序中的主要实现文件,并尝试使用所有三个声明的&amp;定义的对象。

我采用了两步命令方法来构建使用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

标志也导致了同样的错误。

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

我试图初始化foo,它没有改变任何东西。

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

根据我的理解,错误告诉我,即使my.h包含在两个文件中,也不能使用foo变量(它调用_foo)实际实现任何函数,尽管它是在显式声明的my.h.我的猜测是链接器在引擎盖下使用了错误的名称,这使得无法链接到可执行文件。这是因为错误提到了

__Z9print_foov

在任何文件中都无处存在。

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

2 个答案:

答案 0 :(得分:1)

我建议编译两个命令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;变量。所以你需要在一个单个文件中定义它(但在其他文件中没有!),可能是通过添加(单独my.cpp 例如)

 int foo;

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

  

这是因为错误提到__Z9print_foov无处存在

它是mangled name,在两个目标文件中都被引用(但不是定义)(另请参阅this)。

  

此时几乎看起来像g ++或macOS / Command Line Tools错误

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

BTW,总是首先编译所有警告和调试信息(例如g++ -Wall -g,也许还有-Wextra)。使用gdb调试器。当您确信您的代码没有错误时,您可以通过向编译器询问optimize来对其进行基准测试(因此也可以使用g++ -Wall -O2-g进行编译)。

另请阅读linker wikipage。深入了解C++ textbook(另请参阅this siteC++11标准,例如n3337草案)了解声明之间的区别定义某些变量或函数。您通常在一些公共标题中声明一个全局extern变量(包含在几个翻译单元中),并在其他地方定义一次,但最佳做法是避免拥有大量的全局变量。另请参阅C++17个新inline变量。

答案 1 :(得分:1)

在此声明一个变量:

extern int foo;

并使用变量:

cout << foo << endl;

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

在问题中,您说将extern int foo;更改为int foo;会产生相同的错误。但是,如果您仔细查看错误消息,我认为您会发现它提供了一个不同的定义。