Fortran & Matlab 链接——未定义的符号
Posted
技术标签:
【中文标题】Fortran & Matlab 链接——未定义的符号【英文标题】:Fortran & Matlab linking -- undefined symbols 【发布时间】:2014-01-02 18:34:35 【问题描述】:我继承了这个用 fortran 90 编写的 mex 代码,但我无法正确构建。所有目标文件都编译得很好,但链接失败。 幸运的是,我有几条线索可以继续找出问题所在。
链接器唯一的抱怨是
Undefined symbols for architecture x86_64:
"_mxgetstring_", referenced from:
_mexfunction_ in qgstep_mex.o
ld: symbol(s) not found for architecture x86_64
现在mxGetString
只在qgstep_mex.f90
的一处被调用
status = mxGetString(prhs(3), prmfname, STRLEN)
所以如果我把它改成
status = 0
和硬编码prmfname
,包构建得很好。但我当然不想硬编码。
然而,我设法构建了另一个使用mxGetString()
的程序,即 Matlab 提供的示例文件revord.f
这两个程序都由 mex 发出的同一命令链接
gcc -O -Wl,-twolevel_namespace -undefined error -arch x86_64 -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/ -mmacosx-version-min=10.5 -bundle -Wl,-exported_symbols_list,/Applications/MATLAB_R2012a.app/extern/lib/maci64/fexport.map -o "revord.mexmaci64" revord.o -L/Applications/MATLAB_R2012a.app/bin/maci64 -lmx -lmex -lmat -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3/../../.. -lgfortran -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3 -lgfortranbegin
除了 revord.F
被 qgstep_mex.f90
替换并且输出名称类似。
revord.F
中有一条include语句
#include "fintrf.h"
编译时flag所指向的
-I/Applications/MATLAB_R2012a.app/extern/include
但是,如果我尝试将其放入 qgstep_mex.f90
,链接器只会抱怨
Warning: qgstep_mex.f90:1: Illegal preprocessor directive.
那么,有谁知道如何让它工作?
更新(响应 M.S.B. 的回答)
将扩展名的大小写更改为 .F90 没有任何效果,但 -cpp
标志似乎起到了作用。但是,现在它给出了一个我不太理解的错误(在编译期间,而不是链接)(我对 Fortran 不是很好)
$ gfortran-mp-4.7 -c -I/Applications/MATLAB_R2012a.app/extern/include -I/Applications/MATLAB_R2012a.app/simulink/include -fexceptions -m64 -fbackslash -DMX_COMPAT_32 -O -cpp "qgstep_mex.f90"
qgstep_mex.f90:102.11:
status = mxGetString700(prhs(3), prmfname, STRLEN)
1
Error: Function 'mxgetstring700' at (1) has no IMPLICIT type
包含文件中的相关行似乎是
#if defined(MX_COMPAT_32)
.
.
.
#define mxGetString mxGetString700
响应 M.S.B. 的更新而更新
啊哈。毕竟我似乎不应该包括fintrf.h
。项目目录中还有一个文件mexf90.f90
,其中包含
module mexf90_mod
interface
function mxGetString(p, string, STRLEN)
integer(8) :: mxGetString
integer(8) :: p
character*(*) :: string
integer(4) :: STRLEN
end function mxGetString
function mxGetPr(pm)
integer(8), pointer :: mxGetPr
integer(8) :: pm
end function mxGetPr
.
.
奇怪的是,mxGetPr 在qgstep_mex.f90
中调用得很好,在 mxGetString 之前,但调用 mxGetString 失败,错误消息如上所述。这是我使用的链接命令(为清楚起见插入了换行符)
gfortran-mp-4.7 -O -Wl,-twolevel_namespace -undefined error -arch x86_64
-Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/
-mmacosx-version-min=10.5 -bundle -Wl,-exported_symbols_list,/Applications/MATLAB_R2012a.app/extern/lib/maci64/fexport.map
-o "QG_step_f.mexmaci64" utils.o parameters.o helmholtz.o calc.o qgflux.o qgstep.o mexf90.o qgstep_mex.o
-L/Applications/MATLAB_R2012a.app/bin/maci64 -lmx -lmex -lmat -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3/../../..
-lgfortran -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3 -lgfortranbegin
可以看出,目标文件的顺序似乎也正确。
更新
该软件包在 linux 系统上构建得很好。因此,我想编译器之间一定存在一些差异。这是linux系统上使用的链接代码:
gfortran -O -pthread -shared -Wl,--version-script,/ufs/local/matlab-2012a/extern/lib/glnxa64/fexport.map -Wl,--no-undefined
-o "QG_step_f.mexa64" utils.o parameters.o helmholtz.o calc.o qgflux.o qgstep.o mexf90.o qgstep_mex.o
-Wl,-rpath-link,/ufs/local/matlab-2012a/bin/glnxa64 -L/ufs/local/matlab-2012a/bin/glnxa64 -lmx -lmex -lmat -lm
【问题讨论】:
【参考方案1】:尝试将文件名 qgstep_mex.f90 更改为 qgstep_mex.F90。这将导致 gfortran 运行 C 预处理器。还有一个编译器选项会导致这种情况。
编辑以响应问题更新:
编译器希望输入函数mxGetString7001
。有几种方法可以做到这一点。理想的方法是将函数的源代码放在一个模块中。然后当调用者use
s 该模块时,编译器知道函数的返回类型及其参数的类型。也许这存在,您需要将源代码文件添加到您的编译语句中......在使用此函数的文件之前。如果没有,您可以编写一个 interface
块来提供此信息。或者您可以声明该函数并使用 external
语句,但这确实是一种变通方法,使用 FORTRAN 77 方法。
【讨论】:
【参考方案2】:fortran 中的 include 语句没有 #
include "fintrf.h"
在构建时,为什么不使用 gfortran 而不是 gcc。让编译器不必弄清楚你在编译什么。
【讨论】:
我相信 include 语句是针对预处理器的,这就是它的语法不同的原因。以上是关于Fortran & Matlab 链接——未定义的符号的主要内容,如果未能解决你的问题,请参考以下文章
Fortran Mex 文件 - 传回 Matlab 的值不正确