[英]How to catch exception thrown from library in GCC C++?
當我使用 dlopen 動態加載庫時,似乎我無法捕獲該庫引發的異常。 據我了解,這是因為 dlopen 是一個 C 函數。
是否有另一種動態加載庫的方法,可以捕獲 GCC 中的庫引發的異常?
在 Windows 中,您可以使用 LoadLibrary,但對於 Linux,我只找到 dlopen,但在使用 dlopen 時,我無法捕獲異常。
編輯:我試過 void* handle = dlopen("myLib.so", RTLD_NOW | RTLD_GLOBAL); 而且我仍然無法捕獲 myLib.so 引發的異常
編輯 2 :我用自己的命名空間拋出自定義異常。 我希望能夠在庫之外捕獲這些異常。 我希望能夠在不同的編譯器上編譯,例如 GCC 3.2 和 GCC 4.1。
在 myLib2.so 我拋出異常,一個例子:
namespace MyNamespace {
void MyClass::function1() throw(Exception1) {
throw Exception1("Error message");
}
}
在 myLib1.so 中,我想捕獲該異常:
std::auto_ptr <MyNamespace::MyClass> obj = MyNamespace::getClass();
try {
obj->function1();
} catch (MyNamespace::Exception1& e) {
std::cout << e.what(); //This is not caught for some reason.
}
mylib1.so 動態加載 myLib2.so:
void* handle = dlopen("myLib2.so", RTLDNOW | RTLDGLOBAL);
這適用於 Windows (以捕獲我的異常),但我當然不使用 dlopen。
編輯 3 :myLib1.so 是動態鏈接的。
您需要為 dlopen 指定 RTLD_GLOBAL 標志。 這將允許正確的弱符號綁定,因此異常對象的每個 typeinfo 符號將指向同一個位置,這是異常處理 ABI 代碼所需要的。
這取決於您使用的 GCC 版本。
首先,確保使用“-fPIC”編譯所有內容並使用“-rdynamic”標志鏈接。
仍然需要 RTLD_NOW 標志。
您的設置有多個描述略有沖突。 因此,我的描述可能與您所擁有的不符,但希望它能解決您的問題。
庫的存根實現包含在此答案的底部,就像Makefile
一樣。 但基本組織是:
myLib.so
的類有一個會拋出異常的方法myLib1.so
具有加載myLib.so
並調用方法的函數然后我嘗試了各種版本的myTest.cpp
來看看有什么用。
RTLD_GLOBAL
不適用於myLib1.so
調用dlopen("./myLib1.so", RTLD_GLOBAL | RTLD_NOW)
就像嘗試將其鏈接到可執行文件中一樣。 我嘗試使用上述調用導致返回NULL
處理程序。 當我嘗試將其直接鏈接到可執行文件時,出現鏈接器錯誤。
g++ -g myTest.cpp ./myLib1.so -ldl -o myTest
./myLib1.so: undefined reference to `MyNamespace::MyClass::function1()'
./myLib1.so: undefined reference to `MyNamespace::getClass()'
collect2: error: ld returned 1 exit status
這是對使用RTLD_GLOBAL
失敗的原因的解釋。 它無法解析myLib.so
中定義的符號。 我也可以通過在鏈接行中包含myLib.so
來解決這個問題,但是根本不會發生動態加載。
RTLD_LAZY
可以工作如果您不堅持能夠直接調用代碼,則可以在myLib1.so
上使用RTLD_LAZY
。 這將需要 d dlsym()
調用來找到要調用的入口點函數。 但是該查找將觸發導致內部代碼成功的惰性符號解析機制。
下面是我使用的工作myTest.cpp
文件。
#include "myLib1.h"
#include <dlfcn.h>
int main () {
void * h = dlopen("./myLib1.so", RTLD_LAZY);
void (*foo)() = (void(*)())dlsym(h, "foo");
foo();
dlclose(h);
}
myLib.h
#pragma once
namespace MyNamespace {
struct Exception1 {
const char *what_;
Exception1(const char *what) : what_(what) {}
const char * what () const { return what_; }
};
struct MyClass {
friend MyClass * MyNamespace::getClass ();
void function1 () throw(Exception1);
private:
MyClass () {}
};
MyClass * getClass ();
}
myLib.cpp
#include "myLib.h"
namespace MyNamespace {
void MyClass::function1() throw(Exception1) {
throw Exception1("Error message");
}
MyClass * getClass () { return new MyClass(); }
}
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void foo ();
#ifdef __cplusplus
}
#endif
#include "myLib1.h"
#include "myLib.h"
#include <iostream>
#include <dlfcn.h>
void foo () {
void *h = dlopen("./myLib.so", RTLD_GLOBAL | RTLD_NOW);
MyNamespace::MyClass *p = MyNamespace::getClass();
try {
p->function1();
} catch (MyNamespace::Exception1 e) {
std::cout << e.what() << std::endl;
}
delete p;
dlclose(h);
}
all : myLib.so myLib1.so myTest
clean :
rm -f *.o *.so myTest
%.so : %.o
g++ -shared -o $@ $<
%.o : %.cpp
g++ -std=c++03 -W -Wall -Werror -fPIC -rdynamic -O3 -g -c $<
myLib.so : myLib.h
myLib1.so : myLib1.h myLib.h
myTest : myTest.cpp myLib1.h
g++ -g $< $(MYLIB) -ldl -o $@
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.