仅使用 g++ 有效,但不能使用 "g++ -c" 和 ld

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6704780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 20:34:00  来源:igfitidea点击:

Using only g++ works, but not "g++ -c" and ld

c++linkerg++

提问by Valentin Lorentz

I have the following source code in main.cpp:

我在 main.cpp 中有以下源代码:

#include <iostream>
#include <iomanip>

int main() {
    std::cout << "Hi" << std::endl;
    return 0;
}

Using this command works, and creates the executable file:

使用此命令有效,并创建可执行文件:

g++ -o main main.cpp

But this commands don't work:

但是这个命令不起作用:

g++ -c main.cpp
ld -o main main.o

The second one errors with:

第二个错误:

ld: warning: cannot find entry symbol _start; defaulting to 00000000004000e8
main.o: In function `main':
main.cpp:(.text+0xa): undefined reference to `std::cout'
main.cpp:(.text+0xf): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
main.cpp:(.text+0x14): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
main.cpp:(.text+0x1c): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
main.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cpp:(.text+0x4a): undefined reference to `std::ios_base::Init::Init()'
main.cpp:(.text+0x4f): undefined reference to `std::ios_base::Init::~Init()'
main.cpp:(.text+0x54): undefined reference to `__dso_handle'
main.cpp:(.text+0x61): undefined reference to `__cxa_atexit'

回答by Sodved

I think if you use lddirectly it does not include the C++ libraries by default. You can use g++to do the linking as well, it will call ldwith the correct settings.

我认为如果你ld直接使用它默认不包含 C++ 库。您也可以使用g++来进行链接,它将ld使用正确的设置进行调用。

g++ -c main.cpp
g++ -o main main.o

回答by Johannes Schaub - litb

GCC internally links against a few additional libraries and object files. To see what those are, execute -###, which will print the tool commands it would execute, including the linker. The linker command used by my GCC is (I made the actual .ofile I invoked g++on bold, so you can spot it easily).

GCC 内部链接到一些额外的库和目标文件。要查看它们是什么,请执行-###,它将打印它将执行的工具命令,包括链接器。我的 GCC 使用的链接器命令是(我制作了在bold 上.o调用的实际文件,因此您可以轻松找到它)。g++

/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/collect2 --build-id --eh-frame-hdr -m elf_i386 "--hash-style=both" -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/4.6.0 -L/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../.. main1.o"-lstdc++" -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crtn.o

/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/collect2 --build-id --eh-frame-hdr -m elf_i386 "--hash-style=both" -dynamic-linker /lib /ld-linux.so.2 /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crt1.o /usr/lib/gcc/i686-pc- linux-gnu/4.6.0/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/crtbegin.o -L/usr/lib/gcc /i686-pc-linux-gnu/4.6.0 -L/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../.. main1.o"-lstdc++" -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0 /../../../crtn.o

You can substitute the collect2path by ld(if I remember correctly, collect2is only needed as a proxy for the real ldby GCC backends that don't support modern binary formats, to collectconstructor and destructor functions according to their mangled name. The ELF format has native sections support for that).

您可以将collect2路径替换为ld(如果我没记错的话,collect2只需要作为ld不支持现代二进制格式的 GCC 后端的真实代理,根据它们的损坏名称收集构造函数和析构函数。ELF 格式具有本机部分支持)。

Executing that command, with ldsubstituted literally, successfully links the executable.

执行该命令,按ld字面替换,成功链接可执行文件。

回答by Nawaz

When you use g++, it also links the libstd++library which linker uses to resolve the names. But using g++ -cand then lddo not link the library automatically. You've to link the library manually now.

当您使用 时g++,它还链接链接libstd++器用来解析名称的库。但是使用g++ -c然后ld不自动链接库。您现在必须手动链接库。

Try (untested):

尝试(未经测试):

ld -o main main.o -llibstd++

Or you can look into the correct syntax by reading this manual:

或者您可以通过阅读本手册来查看正确的语法:

回答by Lightness Races in Orbit

Well, you didn't link in the standard library. g++does this for you automatically; that's why we use it: it wraps calls to ccplus1and ldwith all the extras taken care of.

好吧,您没有在标准库中链接。g++自动为您执行此操作;这就是为什么我们使用它:它包装调用ccplus1,并ld与所有的照顾群众演员。

BTW, strictly speaking, the equivalent of g++ main.cpp -o mainis:

顺便说一句,严格来说,相当于g++ main.cpp -o main

cc1plus main.cpp -o main.o
ld -o main main.o

(cc1plusmay well not be on your path; I found mine in /usr/libexec/gcc/i386-redhat-linux/4.1.1/)

(很cc1plus可能不在你的路上;我在 中找到了我的/usr/libexec/gcc/i386-redhat-linux/4.1.1/

g++ -c main.cppdoes traditionally perform that first step. g++ main.cpp -o mainwraps both.

g++ -c main.cpp传统上确实会执行第一步。g++ main.cpp -o main包裹两者。

g++is a wrapperto the individual compilation and linkage tools, tuned for C++. As such, it provides arguments to cc1plusand ldas it sees fit, including the argument to link in the C++ Standard Library:

g++是单个编译和链接工具的包装器,针对 C++ 进行了调整。因此,它提供了参数cc1plusld其认为合适,包括参数C ++标准库中的链接:

ld -o main main.o -llibstd++

It'll also link in the runtime and possibly some other stuff.

它还会在运行时链接,可能还有其他一些东西。

In general, there is no need to try to do these things yourself: let g++take care of it.

一般来说,没有必要尝试自己做这些事情:让我们g++照顾它。