我在处理最近开始从事的 C++ 项目时遇到了一个问题。该项目的组织如下(我无法更改):
liba.so
是通过编译包含两个函数 a.cpp
和 void foo()
的单个文件 void bar()
创建的。main.cpp
和其他源代码创建的,这些源代码也实现了核心库中已存在的一些功能。为了便于讨论,我们假设有一个文件 b.cpp
包含 void bar()
。
可以使用以下代码重现此行为:
啊啊
#ifndef a_h_g
#define a_h_g
void foo();
void bar();
#endif
a.cpp
#include <iostream>
#include "a.h"
void foo(){
std::cout<<"I am foo in a.cpp"<<std::endl;
bar();
}
void bar(){
std::cout<<"I am bar in a.cpp"<<std::endl;
}
b.cpp
#include "a.h"
#include <iostream>
void bar(){
std::cout<<"I AM bar in b.cpp"<<std::endl;
}
主.cpp
#include "a.h"
#include <iostream>
int main(){
std::cout<<"I AM MAIN"<<std::endl;
foo();
return 0;
}
并编译为:
g++ -fPIC -shared -o liba.so a.cpp
g++ -c b.cpp
g++ -c main.cpp
g++ -o main main.o b.o -L. -la
在使用 g++ 版本 11.2.0 的 Centos7 机器上尝试此代码时,结果就是该项目的目标:
I AM MAIN
I am foo in a.cpp
I AM bar in b.cpp
相反,在 clang 版本 14.0.0 的 MAC 上,结果是:
I AM MAIN
I am foo in a.cpp
I am bar in a.cpp
有没有办法用 clang 重现 Centos7 结果?
在 MacOS 上,共享库更喜欢
在同一共享库中定义的符号而不是全局定义的符号(类似于 Windows DLL 的工作方式)。
在 Linux 上,共享库更喜欢全局符号,除非该库与 -Bsymbolic
-Bsymbilic-functions
链接。
来自 MacOS 链接器文档:您应该能够通过将
-Wl,-flat_namespace
添加到 liba.so
链接线来获得类似 Linux 的行为。有没有办法用 clang 重现 Centos7 结果?
添加到当然:只需将
-Wl,-Bsymbolic
liba.so
链接线即可。来自 Linux
man ld
:
-Bsymbolic
When creating a shared library, bind references to global symbols
to the definition within the shared library, if any. Normally, it is
possible for a program linked against a shared library to override the
definition within the shared library. This option is only meaningful
on ELF platforms which support shared libraries.
重复您的命令:g++ -fPIC -shared -o liba.so a.cpp
g++ -c b.cpp
g++ -c main.cpp
g++ -o main main.o b.o -L. -la -Wl,-rpath=.
./main
I AM MAIN
I am foo in a.cpp
I AM bar in b.cpp
现在用
liba.so
重建 -Bsymbolic
:
$ g++ -fPIC -shared -o liba.so a.cpp -Wl,-Bsymbolic
$ ./main
I AM MAIN
I am foo in a.cpp
I am bar in a.cpp
可能有一个标志要求 MacOS 链接器更喜欢全局范围,但我对 MacOS 不太了解。