C++ .那么,没有正确依赖项的文件为什么可以工作
我无意中遇到了这个问题C++ .那么,没有正确依赖项的文件为什么可以工作,c++,dynamic-linking,undefined-symbol,C++,Dynamic Linking,Undefined Symbol,我无意中遇到了这个问题 // foo.cpp #include <iostream> int i; extern "C" { void pn() { std::cout << "Hello!" << std::endl; } } 然后是bar.cpp // bar.cpp #include <dlfcn.h> #include <stdio.h> #include <iostream>
// foo.cpp
#include <iostream>
int i;
extern "C" {
void pn() {
std::cout << "Hello!" << std::endl;
}
}
然后是bar.cpp
// bar.cpp
#include <dlfcn.h>
#include <stdio.h>
#include <iostream>
using namespace std;
extern "C" {
int decode();
}
int decode() {
void *handle = dlopen("libfoo.so", RTLD_LAZY);
if (!handle) {
printf("%s \n", dlerror());
return 1;
}
void (*pn)() = (void (*)()) dlsym(handle, "pn");
(*pn)();
return 0;
}
// main.cpp
#include <dlfcn.h>
#include <stdio.h>
// Magic sauce
//#include <iostream>
//using namespace std;
int main() {
void *handle = dlopen("libbar.so", RTLD_LAZY);
if (!handle) {
printf("%s \n", dlerror());
return 1;
}
int (*pn)() = (int (*)()) dlsym(handle, "decode");
(*pn)();
return 0;
}
decode
在main.cpp
中调用
// bar.cpp
#include <dlfcn.h>
#include <stdio.h>
#include <iostream>
using namespace std;
extern "C" {
int decode();
}
int decode() {
void *handle = dlopen("libfoo.so", RTLD_LAZY);
if (!handle) {
printf("%s \n", dlerror());
return 1;
}
void (*pn)() = (void (*)()) dlsym(handle, "pn");
(*pn)();
return 0;
}
// main.cpp
#include <dlfcn.h>
#include <stdio.h>
// Magic sauce
//#include <iostream>
//using namespace std;
int main() {
void *handle = dlopen("libbar.so", RTLD_LAZY);
if (!handle) {
printf("%s \n", dlerror());
return 1;
}
int (*pn)() = (int (*)()) dlsym(handle, "decode");
(*pn)();
return 0;
}
我使用ldd检查libfoo
的依赖项
linux-vdso.so.1 => (0x00007ffd5b75e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2d9677a000)
/lib64/ld-linux-x86-64.so.2 (0x0000563d0c838000)
如果我在main.cpp
中使用iostream
,这会导致main依赖于libstdc++.so
。然后这个main
运行没有任何问题。但是如果<代码>主< /代码>不包含C++用法,可执行文件断裂。
./libfoo.so: undefined symbol: _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
我已经挣扎了三天了。谢谢你的帮助
我知道使用
g++
编译foo.cpp
是正确的选择。我只是想了解这里发生了什么。如果不使用iostream
,它就会失败,因为编译器看到的主文件不依赖于libstdc++
,而是依赖于foo.cpp
/foo。所以依赖于libstdc++
你可能想知道为什么仅仅一个#include
就能解决这个问题。这是因为,iostream
实际上只是通过被包含而完成了一些工作。例如,它设置std::cout
。因此,虽然您可能认为程序代码没有更改,但实际上已经更改了-\include
添加了静态初始化,这取决于libstdc++
这类问题(编译器看不到的间接依赖项)的一般解决方案如下:当您不使用iostream
时,它会失败,因为编译器看到的主文件不依赖于libstdc++
,而是foo.cpp
/foo。因此依赖于libstdc++
你可能想知道为什么仅仅一个#include
就能解决这个问题。这是因为,iostream
实际上只是通过被包含而完成了一些工作。例如,它设置std::cout
。因此,虽然您可能认为程序代码没有更改,但实际上已经更改了-\include
添加了静态初始化,这取决于libstdc++
这类问题(编译器看不到的间接依赖)的一般解决方案如下:您应该使用g++而不是gcc来编译libfoo.so。然后libstdc++
将被添加到libfoo.so的依赖项中。您应该使用g++而不是gcc来编译libfoo.so。然后,代码<> LBSTDC++< /COD>将添加到LIbFO中。所以依赖性。 < P>你应该真正坚持一种语言,不要像你那样混合C和C++(只要你不知道你在做什么(没有冒犯、经验))!为什么您的代码中只有C++
部分是使用C
编译器编译的
使用g++而不是gcc编译libfoo:
g++ -fPIC --shared foo.cpp -o libfoo.so
更新
我只是想了解这里发生了什么事
我认为正在发生的事情是多种多样的
首先,gcc和g++不仅仅是编译器程序,还包括编译器、链接器等。它们都会自动决定使用C
编译器或C++
编译器/链接器(选项)。所以你的foo.cpp编译得非常完美
第二个std::cout
定义为extern
(来自我的cygwin安装的代码extern ostream cout;///链接到标准输出
)。这意味着,在链接libfoo.so时,链接器不必链接到libstdc++.so.X,因为它可以是来自另一个链接器单元的依赖项(请参见3.)PLUS使用gcc链接器甚至不会尝试
当您向主应用程序添加iostream时,gcc会识别这一点,并使用其他链接器选项生成二进制文件。您可以使用-v
选项查看gcc和g++之间的差异,您应该看到库路径将有所不同。在COLLECT_GCC_OPTIONS中也使用g++时,会出现-lstdc++选项。如果使用g++编译libfoo,那么这就是依赖性libstdc++.so.6=>/usr/lib/x86\u 64-linux-gnu/libstdc++.so.6
的原因
当您使用dl作为加载选项时,您的共享对象本身或(依赖于操作系统)您的可执行文件应该包含正确的库,而不考虑一些中间人(在您的例子中是libbar)。如果没有,您将看到错误注意:我不建议您依赖可执行文件,因为它依赖于操作系统,可能无法在其他*nix上工作
这是一个你可以玩的例子。尝试将gcc-D MAINDEF-Wall--pedantic--pedantic errors-ldl-lstdc++main.cpp-o main
更改为g++或删除-lstdc++
简而言之:正如前面所说的,使用正确的编译器才是正确的选择!错误不在libbar或main内,因为此单元不应对libfoo的正确库依赖项负责
[…]我无法访问他们的源代码。[…]
告诉那家伙去解决他们的关系你应该坚持一种语言,不要像你那样混合C和C++(只要你不知道你在做什么(没有冒犯,经验))!为什么您的代码中只有C++
部分是使用C
编译器编译的
使用g++而不是gcc编译libfoo:
g++ -fPIC --shared foo.cpp -o libfoo.so
更新
我只是想了解这里发生了什么事
我认为正在发生的事情是多种多样的
首先,gcc和g++不仅仅是编译器程序,还包括编译器、链接器等。它们都会自动决定使用C
编译器或C++
编译器/链接器(选项)。所以你的foo.cpp编译得非常完美
第二个std::cout
定义为extern
(代码来自我的cygwin安装extern ostream cout;///链接到标准