包含多个 C 和 C++ 源文件的 mkoctfile

Posted

技术标签:

【中文标题】包含多个 C 和 C++ 源文件的 mkoctfile【英文标题】:mkoctfile with multiple C and C++ source files 【发布时间】:2019-01-14 22:58:03 【问题描述】:

我无法让mkoctfile 成功创建一个oct 文件,该文件是我的一些C++ 函数的包装器(例如void my_fun(double*,double))。特别是我的问题源于这样一个事实,包装器代码my_fun_wrap.cpp 需要包含仅提供C++ 标头的<octave/oct.h> 库(请参阅here),但my_fun 的原始代码也使用源C 中的代码。例如

// my_fun_wrapper.cpp

#include <octave/oct.h>
#include "custom_functions_libc.h"

DEFUN_DLD(my_fun_wrapper,args, , "EI MF network model A with delays (Brunel, JCN 2000)")

// Input arguments
NDArray xvar = args(0).array_value();
double x = xvar(0);

// Output arguments
double dy[4];
dim_vector dv (4,1);
NDArray dxvars(dv);

// Invoke my C function which also includes code in the lib file custom_functions_libc.c  
my_fun(dy,x);

// Then assign output value to NDArray
for(int i=0;i<4;i++) dxvars(i) = dy[i];

// Cast output as octave_value as required by the octave guidelines
return octave_value (dxvars);

然后假设我的custom_functions_libc.hcustom_functions_libc.c 文件位于文件夹&lt;path_to_folder&gt;/my_libs 中的某个位置。理想情况下,从 Octave 命令行,我将通过以下方式编译上述内容:

mkoctfile -g -v -O -I<path_to_folder>/my_libs <path_to_folder>/my_libs/custom_functions_libc.c my_fun_wrapper.cpp -output my_fun_wrapper -lm -lgsl -lgslcblas 

这实际上会根据需要生成my_fun_wrapper.oct。然后我可以在一些octave 代码中调用后者,例如

...
... 
xx = [0., 2.5, 1.];
yy = [1e-5, 0.1, 2.];    

dxv = test_my_function(xx,yy);


function dy = test_my_function(xx,yy)
    xx += yy**2;
    dy = my_fun_wrapper(xx);        
endfunction

事实证明,上面的代码将在test_my_function 中退出,并指出my_fun_wrapper 中的符号Zmy_fundd 无法识别。收到此类错误后,我怀疑链接过程出现问题。但奇怪的是,编译器并没有像我说的那样产生任何错误。然而,仔细检查编译器的详细输出后发现mkoctfile 正在根据扩展名在不同文件之间自动更改编译器。所以my_fun_wrapper.cpp 是由g++ -std=gnu++11 编译的,但custom_function_libc.c 是由gcc -std=gnu11 编译的,并且在与my_fun_wrapper.o 链接时,这个编译过程所产生的custom_function_libc.o 文件与未解析的符号不匹配。

上面的例子非常简单。实际上,在我的情况下,custom_function_libc 包含更多自定义的C 库。到目前为止,一种解决方法是将这些库的.c 源文件克隆到.cpp 文件中。但是我不太喜欢这个解决方案。

如何最终安全地混合C++C 代码并通过mkoctfile 成功编译它? octave 手册建议在前面加上一个 extern C 规范(见 here),恐怕我不是很熟悉。这是最好的方法吗?您能否建议我,一个潜在的替代解决方案?

【问题讨论】:

由于您没有提供足够的代码来编译此代码或最小示例,因此它不是“可验证的”,请参阅 Cris 评论中的链接。所以我的调试技巧是:剥离你的代码,以便 ei_modelA 只使用一些琐碎的计算并删除所有的杂物...... @CrisLuengo 是的,很抱歉。该代码不容易移植。让我先听从安迪的建议,把它分解成小块,看看我是否能找出问题所在。如果没有,我会尝试改进帖子。另一方面,如果成功,我会以更好的方式详细阐述我的帖子。感谢您的耐心等待(目前为 GMT+1)。 另外,是的,也许你需要做extern "C" \n #include "custom_functions_libc.h" \n 。 (试图用“\n”显示换行符) custom_functions_libc.h 是否定义了一个函数 my_fun,它被 C++ 编译器修改为 Zmy_fundd?如果是这样,添加extern "C" 应该可以解决问题。 所以主要问题是,您正在链接 C 代码(使用 gcc 编译)和 C++ 代码(使用 g++ 编译),这会给您带来名称修改问题(google it!)。与 GNU Octave 无关 【参考方案1】:

显然,根据我上面的帖子,最简单的解决方案是通过以下预处理器指令更正包装器:

// my_fun_wrapper.cpp

#include <octave/oct.h>

// ADDED code to include the C source code
#ifdef __cplusplus
extern "C"

#endif
// END ADDITION
#include "custom_functions_libc.h"
// ADDED code to include the C source code
#ifdef __cplusplus
  /* end extern "C" */
#endif
// END ADDITION

...
...

这将很好地编译和链接。

【讨论】:

由于您的包装器是 C++ 代码,因此您不需要其中的 #ifdef。它将始终使用 C++ 编译器进行编译。如果你把extern "C"命令放在C头文件中,那么你需要添加那些#ifdefs,那么头文件兼容C编译器和C++编译器。

以上是关于包含多个 C 和 C++ 源文件的 mkoctfile的主要内容,如果未能解决你的问题,请参考以下文章

C++ 一次播放多个 WAVE 资源文件

如何在 makefile 指令中同时包含 C 和 C++ 文件

.obj 中定义的 c++ 多个

C++——如何将一个字符串转换为多个整数?

c++ c语言 - 控件及概述补充

一次重命名多个文件的 C++ 程序