在 Linux 中构建共享库时如何使链接器因未定义的引用而失败
How to make linker fail for undefined references when building shared library in Linux
我正在尝试在 Ubuntu 中用 C++ 构建一个共享库(我将在运行时使用 dlopen
加载它),但我注意到共享库构建得很好,即使有一些缺少的依赖项。如果我要构建一个可执行文件,我会得到一个 undefined reference
linker 错误,这是我希望在这里看到的。
这个例子中可能有一些细节太多了,但我不完全确定如何削减它并使其具有代表性。
Base.h
class Base{
public:
virtual void foo()=0;
};
extern "C" {
Base* CreateBase();
}
extern "C" {
void DestroyBase(Base* b);
}
Derived.h
#include "Base.h"
class Derived : public Base {
public:
void foo();
};
extern "C" {
Base* CreateBase() {
return new Derived;
}
}
extern "C" {
void DestroyBase(Base* b) {
delete b;
}
}
Derived.cc
#include "Derived.h"
#include "OtherClass.h"
#include <iostream>
void Derived::foo(){
std::cout << "Derived::foo()" << std::endl;
std::cout << "Calling OtherClass::bar()" << std::endl;
OtherClass other;
other.bar();
}
OtherClass.h
class OtherClass{
public:
void bar();
};
我构建共享库的命令行是
g++ -shared -fPIC -o libtest_dll.so Derived.cc
问题是我没有 Derived::foo()
调用的 OtherClass::bar()
的定义,但是 libtest_dll.so
构建时没有错误或警告。据我了解,在 Visual Studio in Windows 中,如果我要使用此代码构建 DLL,它将无法 link。如何使用 Ubuntu/Linux 中的 g++
获得该行为?
运行 g++ 8.3.0-6 Ubuntu 19.04
当我构建并希望避免这种情况时,我使用以下选项编译库:-Wl,--no-allow-shlib-undefined -Wl,-z,defs
第一个选项在代码中没有定义符号的情况下导致共享库link失败,当与第二个选项结合使用时,导致linker 报告丢失的符号。
这可以很好地防止在 运行 时间丢失符号,方法是在 link 时间检测它们。但是,我确实需要 link .so
及其使用的所有库,否则将无法构建。
样本 (src.c):
#include <math.h>
extern
double share_the_stuff(double val)
{
return acos(val * val);
}
构建缺少符号:
gcc -shared -o src.so src.c -Wl,--no-allow-shlib-undefined -Wl,-z,defs
/usr/bin/ld: /tmp/ccFmD5uY.o: in function `share_the_stuff':
src.c:(.text+0x17): undefined reference to `acos'
collect2: error: ld returned 1 exit status
link 在 libm.so:
gcc -shared -o src.so src.c -Wl,--no-allow-shlib-undefined -Wl,-z,defs -lm
它与缺少内部符号的行为相同。
我正在尝试在 Ubuntu 中用 C++ 构建一个共享库(我将在运行时使用 dlopen
加载它),但我注意到共享库构建得很好,即使有一些缺少的依赖项。如果我要构建一个可执行文件,我会得到一个 undefined reference
linker 错误,这是我希望在这里看到的。
这个例子中可能有一些细节太多了,但我不完全确定如何削减它并使其具有代表性。
Base.h
class Base{
public:
virtual void foo()=0;
};
extern "C" {
Base* CreateBase();
}
extern "C" {
void DestroyBase(Base* b);
}
Derived.h
#include "Base.h"
class Derived : public Base {
public:
void foo();
};
extern "C" {
Base* CreateBase() {
return new Derived;
}
}
extern "C" {
void DestroyBase(Base* b) {
delete b;
}
}
Derived.cc
#include "Derived.h"
#include "OtherClass.h"
#include <iostream>
void Derived::foo(){
std::cout << "Derived::foo()" << std::endl;
std::cout << "Calling OtherClass::bar()" << std::endl;
OtherClass other;
other.bar();
}
OtherClass.h
class OtherClass{
public:
void bar();
};
我构建共享库的命令行是
g++ -shared -fPIC -o libtest_dll.so Derived.cc
问题是我没有 Derived::foo()
调用的 OtherClass::bar()
的定义,但是 libtest_dll.so
构建时没有错误或警告。据我了解,在 Visual Studio in Windows 中,如果我要使用此代码构建 DLL,它将无法 link。如何使用 Ubuntu/Linux 中的 g++
获得该行为?
运行 g++ 8.3.0-6 Ubuntu 19.04
当我构建并希望避免这种情况时,我使用以下选项编译库:-Wl,--no-allow-shlib-undefined -Wl,-z,defs
第一个选项在代码中没有定义符号的情况下导致共享库link失败,当与第二个选项结合使用时,导致linker 报告丢失的符号。
这可以很好地防止在 运行 时间丢失符号,方法是在 link 时间检测它们。但是,我确实需要 link .so
及其使用的所有库,否则将无法构建。
样本 (src.c):
#include <math.h>
extern
double share_the_stuff(double val)
{
return acos(val * val);
}
构建缺少符号:
gcc -shared -o src.so src.c -Wl,--no-allow-shlib-undefined -Wl,-z,defs
/usr/bin/ld: /tmp/ccFmD5uY.o: in function `share_the_stuff':
src.c:(.text+0x17): undefined reference to `acos'
collect2: error: ld returned 1 exit status
link 在 libm.so:
gcc -shared -o src.so src.c -Wl,--no-allow-shlib-undefined -Wl,-z,defs -lm
它与缺少内部符号的行为相同。