具有多个C和C++源文件的mkoctfile

mkoctfile with multiple C and C++ source files

本文关键字:C++ 源文件 mkoctfile      更新时间:2023-10-16

我无法让mkoctfile成功创建作为我的某些C++函数(例如void my_fun(double*,double))包装器的oct文件。特别是,我的问题源于这样一个事实,即包装代码my_fun_wrap.cpp需要包含仅提供C++标头的<octave/oct.h>库(请参阅此处),但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文件位于文件夹<path_to_folder>/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.cppg++ -std=gnu++11编译,而custom_function_libc.cgcc -std=gnu11编译,并且在某种程度上,当与my_fun_wrapper.o链接时,该编译过程所产生的custom_function_libc.o文件与未解析符号不匹配。

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

如何最终安全地混合C++C代码,并通过mkoctfile成功编译它?octave手册建议准备一个extern C规范(见此处),恐怕我不太熟悉。这是最好的方法吗?你能给我一个替代方案吗?

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

// 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
...
...

这将编译和链接良好。