g++ 无法将 link .o 文件转换为可执行文件
g++ fails to link .o files into an executable
我正在对我用来学习的教科书进行示例练习。我需要做的就是编译 link 和 运行 以下 3 个文件:
//file my.h
extern int foo;
void print_foo();
void print(int);
my.h 是一个简单的头文件,它声明了两个函数和一个 'global' 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。我使用以下命令 link 他们:
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)实际实现任何函数,尽管它在 my.h 中明确声明。我的猜测是 linker 在幕后使用了错误的名称,这使得 link 无法进入可执行文件。这是因为错误提到了 a
__Z9print_foov
在任何文件中都不存在。
在这一点上,它几乎像是一个 g++ 或 macOS/Command 线工具错误。我不想每次都添加声明,因为无论如何都会产生重复的符号错误。将 my.cpp 和 use.cpp 放入一个文件中可能会 link 正确,但我需要确保我实际上可以 link 多个 cpp 文件,因为我最终(希望)正在处理需要 linked 的多个 cpp 文件。任何帮助表示赞赏!
我建议在 两个 命令中编译 g++ -Wall -c my.cpp
(给出 my.o
)和 g++ -Wall -c use.cpp
(给出 use.o
),然后 link 一个带有 g++ my.o use.o -o myprog
的程序。实际上你应该写一个 Makefile (see this 作为灵感)并且简单地 运行 make
你的翻译单元my.cpp
和use.cpp
都声明一些extern int foo;
变量从不[=62] =] 定义。所以你需要在一个单个文件中定义它(但不是在其他文件中!),可能通过添加(到my.cpp
单独 例如)
int foo;
(没有 extern
)或者甚至有一些明确的初始值,例如int foo = 34;
This comes from the fact that the error mentioned a __Z9print_foov
which exists nowhere
这是一个mangled name, which is referenced (but not defined) in both object files (see also this).
It almost seems like a g++ or macOS/Command Line Tools bug at this point
您不太可能在编译器工具中发现错误(GCC & Clang/LLVM 都非常好 测试;因为它们是数百万行的免费软件,它们确实有残留 个错误,但您中奖的机会比受编译器错误影响的机会多)。我从 1974 年开始编码,这在我的一生中只发生过一次。更现实的态度是谦逊一些,质疑自己的代码(和知识)在怀疑编译器 或构建链。
顺便说一句,始终首先编译所有警告和调试信息(例如 g++ -Wall -g
,也许还有 -Wextra
)。使用 gdb
调试器。当您确信您的代码没有错误时,您可以通过要求编译器 optimize 来对其进行基准测试(因此使用 g++ -Wall -O2
也可能与 -g
一起编译)。
另请阅读 linker wikipage. Dive into your C++ textbook (see also this site and the C++11 standard, e.g. n3337 draft) to understand the difference between declaring and defining some variable or function. You generally declare a global extern
variable in some common header (included in several translation units), and define it once somewhere else, but the good practice is to avoid having lots of global variables. See also C++17 new inline 变量。
在这里声明一个变量:
extern int foo;
并且您使用变量:
cout << foo << endl;
但是你没有在任何地方定义变量。链接器错误表示链接器找不到变量的定义。要解决此问题,请将 int foo;
放在 .cpp
文件之一的文件范围内。
在问题中,您说将 extern int foo;
更改为 int foo;
会产生相同的错误。但是,如果您更仔细地查看错误消息,我想您会发现它给出了不同的错误消息,关于多个定义。
我正在对我用来学习的教科书进行示例练习。我需要做的就是编译 link 和 运行 以下 3 个文件:
//file my.h
extern int foo;
void print_foo();
void print(int);
my.h 是一个简单的头文件,它声明了两个函数和一个 'global' 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。我使用以下命令 link 他们:
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)实际实现任何函数,尽管它在 my.h 中明确声明。我的猜测是 linker 在幕后使用了错误的名称,这使得 link 无法进入可执行文件。这是因为错误提到了 a
__Z9print_foov
在任何文件中都不存在。
在这一点上,它几乎像是一个 g++ 或 macOS/Command 线工具错误。我不想每次都添加声明,因为无论如何都会产生重复的符号错误。将 my.cpp 和 use.cpp 放入一个文件中可能会 link 正确,但我需要确保我实际上可以 link 多个 cpp 文件,因为我最终(希望)正在处理需要 linked 的多个 cpp 文件。任何帮助表示赞赏!
我建议在 两个 命令中编译 g++ -Wall -c my.cpp
(给出 my.o
)和 g++ -Wall -c use.cpp
(给出 use.o
),然后 link 一个带有 g++ my.o use.o -o myprog
的程序。实际上你应该写一个 Makefile (see this 作为灵感)并且简单地 运行 make
你的翻译单元my.cpp
和use.cpp
都声明一些extern int foo;
变量从不[=62] =] 定义。所以你需要在一个单个文件中定义它(但不是在其他文件中!),可能通过添加(到my.cpp
单独 例如)
int foo;
(没有 extern
)或者甚至有一些明确的初始值,例如int foo = 34;
This comes from the fact that the error mentioned a
__Z9print_foov
which exists nowhere
这是一个mangled name, which is referenced (but not defined) in both object files (see also this).
It almost seems like a g++ or macOS/Command Line Tools bug at this point
您不太可能在编译器工具中发现错误(GCC & Clang/LLVM 都非常好 测试;因为它们是数百万行的免费软件,它们确实有残留 个错误,但您中奖的机会比受编译器错误影响的机会多)。我从 1974 年开始编码,这在我的一生中只发生过一次。更现实的态度是谦逊一些,质疑自己的代码(和知识)在怀疑编译器 或构建链。
顺便说一句,始终首先编译所有警告和调试信息(例如 g++ -Wall -g
,也许还有 -Wextra
)。使用 gdb
调试器。当您确信您的代码没有错误时,您可以通过要求编译器 optimize 来对其进行基准测试(因此使用 g++ -Wall -O2
也可能与 -g
一起编译)。
另请阅读 linker wikipage. Dive into your C++ textbook (see also this site and the C++11 standard, e.g. n3337 draft) to understand the difference between declaring and defining some variable or function. You generally declare a global extern
variable in some common header (included in several translation units), and define it once somewhere else, but the good practice is to avoid having lots of global variables. See also C++17 new inline 变量。
在这里声明一个变量:
extern int foo;
并且您使用变量:
cout << foo << endl;
但是你没有在任何地方定义变量。链接器错误表示链接器找不到变量的定义。要解决此问题,请将 int foo;
放在 .cpp
文件之一的文件范围内。
在问题中,您说将 extern int foo;
更改为 int foo;
会产生相同的错误。但是,如果您更仔细地查看错误消息,我想您会发现它给出了不同的错误消息,关于多个定义。