【问题标题】:Undefined reference to shared library functions after converting from C to C++从 C 转换为 C++ 后对共享库函数的未定义引用
【发布时间】:2014-07-25 17:37:59
【问题描述】:

我有一个共享库“libsharedlib.so”,它曾经是从 C 文件生成的。由于该库现在需要使用来自第 3 方 C++ 库的函数,因此我想将我的共享库从 C 转换为 C++(代码相对简单)。根据我读到的here 的差异,我必须做的唯一调整是使用 stdlib 和 stdio 函数。标题从

#include <stdio.h>
#include <stlib.h>

#include <cstdlib>
#include <cstdio>

并且对这些库中函数的所有调用都以std::命名空间为前缀(例如std::malloc而不是malloc,我没有使用using namespace std)。源文件扩展名从 .c 更改为 .cpp。我还必须在每个文件的末尾添加换行符,并且必须转换我的malloc's。之后没有其他编译器反馈。使用以下命令编译共享库:

pgcpp -shared -I./inc/ -o ./lib/libsharedlib.so file1.cpp file2.cpp ...

并且不返回错误或警告。

我现在有一个 MEX 函数,mex_gateway.cpp,它从这个库中调用函数:

#include "sharedlibraryheader.h"
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],
             int nrhs, const mxArray *prhs[]){
...
function_from_library(data);
}

使用如下命令编译

mex -L./lib/ -lsharedlib -I./inc/ mex_gateway.cpp

哪个(添加详细标志-v时)实际执行以下命令:

g++ -c  -I./inc/ -I/opt/MATLAB/R2013b/extern/include -I/opt/MATLAB/R2013b/simulink/include -DMATLAB_MEX_FILE -ansi -D_GNU_SOURCE -fPIC -fno-omit-frame-pointer -pthread  -DMX_COMPAT_32 -O -DNDEBUG  "mex_gateway.cpp"

g++ -O -pthread -shared -Wl,--version-script,/opt/MATLAB/R2013b/extern/lib/glnxa64/mexFunction.map -Wl,--no-undefined -o  "mex_gateway.mexa64"  mex_gateway.o  -L./lib/ -lsharedlib -Wl,-rpath-link,/opt/MATLAB/R2013b/bin/glnxa64 -L/opt/MATLAB/R2013b/bin/glnxa64 -lmx -lmex -lmat -lm

我收到以下错误:

mex_gateway.o: In function `mexFunction':
mex_gateway.cpp:(.text+0x24e): undefined reference to `function_from_library(...arguments...)'
collect2: ld returned 1 exit status

    mex: link of ' "mex_gateway.mexa64"' failed.

当然,我三重检查了具有共享库的正确路径和库名称的构建命令。共享库确实有函数的定义:

[user@machine]$ nm lib/libsharedlib.so | grep function_from_library
000000000000198a t __function_from_library__FPCdN51dN27iiiiPdPdPdPdPdPdEND
0000000000001360 T function_from_library__FPCdN51dN27iiiiPdPdPdPdPdPd

那么问题出在哪里?

编辑:我的sharedlibraryheader.h 文件如下所示:

#ifndef __SHAREDLIBRARYHEADER_H__
#define __SHAREDLIBRARYHEADER_H__

#ifdef _cplusplus
extern "C"{
#endif

int function1 ( ... );
...
void function_from_library( ... );
...

#ifdef _cplusplus
}
#endif
#endif

【问题讨论】:

  • 如果是我,如果可行的话,我可能会把所有东西都留在 C 中。
  • 这不是一个选项,因为我必须从 C++ 库中调用函数。
  • 编写 shim 将 C++ 函数重新导出为 C 函数可能更容易。

标签: c++ c shared-libraries mex


【解决方案1】:

您必须执行以下操作:

extern "C" {
#include "sharedlibraryheader.h"
}

这将使编译器知道sharedlibraryheader.h 中定义的函数符合C ABI 而不是C++ ABI。通常,这是在标头本身中处理的,方式如下:

// Typically put headers outside extern "C"
#include "..."
#include "..."

#ifdef __cplusplus
extern "C" {
#endif

... rest of header here ...

#ifdef __cplusplus
}
#endif

在编译时,您必须对使用共享库共享库本身的代码执行此操作。

【讨论】:

  • 是的,这听起来确实像是名称修饰的问题,导致 C++ 编译器在 C 使用纯名称时生成/预期修饰函数名称。
  • 我忘了说我已经这样做了!但是,当 SO 是从 CPP 文件编译时,为什么要将它视为 C 库呢?
  • @lodhb 如果您已经这样做了,那么您需要编辑您的问题以包含该信息。链接器找不到 C++ 应用程序调用的 C 函数的主要原因是名称修改/外部“C”问题。
  • @lodhb:因为库本身实际上是从 C 文件编译而来的!但是现在您将其头文件(作为 your 项目的一部分)重新编译为 C++,突然定义与声明不匹配。
  • @PaulMcKenzie 抱歉,我刚刚修改了我的问题!
【解决方案2】:

您是否知道,如果您尝试编译的 .cpp 文件中没有 C++ 代码,您实际上可以将它们编译为 C 源代码(使用 GCC)并将其链接到您的 C++ 项目中吗?在我定期创建的 makefile 中,我会执行以下操作:

GPPWALL = g++ -Wall -c
GCCWALL = gcc -Wall -c

...

all: glxgraphics.o shadermanager.o sdlkeyboard.o sdlmouse.o main.cpp
    g++ main.cpp LevelGenerator.cpp $(ASSETSOURCE) $(GRAPHICSSOURCE) $(IOSOURCE) $(BASE)AudioManager.cpp -o avgame $(GLUTLIBS) $(GRAPHICSLIBS) $(PTHREADLIBS) $(OPENALLIBS)

...

sdlmouse.o: $(BASE)avg_mouse.c $(BASE)avg_mouse.h
    $(GCCWALL) $(BASE)avg_mouse.c $(GLUTLIBS)

请注意,我已将 C 编译代码链接到 C++ 中以避免“外部 C”保护,这些保护最终仍然是 C++ 代码?这是常见的做法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2017-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-14
    相关资源
    最近更新 更多