У меня есть динамическая библиотека, которую я хочу загрузить. Я определил функцию add()
:
#include <iostream>
#include "mymath.h"
#define EXPORT __attribute__((visibility("default")))
EXPORT
int mymath::add(int a, int b) {
return a + b;
}
Этот символ находится в пространстве имен под названием mymath
:
namespace mymath {
int add(int, int);
}
Я скомпилировал эту библиотеку с помощью следующей команды:
llvm-g++ -Iinclude -dynamiclib -std=c++17 src/mymath.cpp -current_version 1.0 -compatibility_version 1.0 -fvisibility=hidden -o bin/mymath.dylib
Теперь я хочу использовать его в другой программе, загружающей этот символ во время выполнения. Я пришел к следующему коду:
#include <iostream>
#include <dlfcn.h>
#include "mymath.h"
int main() {
const char* libName = "bin/mymath.dylib";
void *libHandle;
std::cout << "# main() starts" << std::endl;
libHandle = dlopen(libName, RTLD_NOW);
if (libHandle == NULL) {
std::cerr << "Error opening mymath:\n" << dlerror() << std::endl;;
return 1;
}
void (*mymath_add) = dlsym(libHandle, "mymath:add");
if (mymath_add == NULL) {
std::cerr << "Error opening while getting address of mymath::add:\n" << dlerror() << std::endl;;
return 2;
}
std::cout << "# main() exits" << std::endl;
return 0;
}
И получить эту ошибку при запуске
$ make
clang++ -Wall -Wextra -std=c++17 -g -Iinclude -Llib src/main.cpp -o bin/main
wgonczaronek Wiktor-Gonczaronek ~/Projects/…/macos-pt2 master ?
$ ./bin/main
# main() starts
Error opening while getting address of mymath::add:
dlsym(0x7ffac9402a90, mymath:add): symbol not found
Я пробовал использовать символы, найденные с помощью команды nm
, но получаю ту же ошибку. Как я могу загрузить этот символ, используя пространство имен?
Смотрите эту страницу для лучшего объяснения (https://en.wikipedia.org/wiki/Имя_манглинг).
Имена символов искажаются, если они не включены в библиотеку. В C++ изменение имени кодирует пространства имен, аргументы шаблона (если есть), аргументы функции (если есть). Это создаст странный символ, например _ZN9Wikipedia7article6formatE
. Изменение С++ определяется реализацией и может меняться от компилятора к компилятору, поэтому попытка декодировать его в лучшем случае рискованна. Я предлагаю переместить функцию из пространства имен и добавить префикс extern "C"
, чтобы принудительно изменить имя в стиле C. Изменение имен в стиле C четко определено, стандартно и будет работать с любым компилятором. Так
extern "C" int add(int a, int b) {
return a + b;
}
а также:
void (*mymath_add) = dlsym(libHandle, "_add");