包含多个 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.h
和custom_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.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头文件中,那么你需要添加那些#ifdef
s,那么头文件兼容C编译器和C++编译器。以上是关于包含多个 C 和 C++ 源文件的 mkoctfile的主要内容,如果未能解决你的问题,请参考以下文章