奇怪的是 excel 的 2011 VBA 在 mac 上找不到 c++ dylib
c++ dylib curiously not found by excel's 2011 VBA on mac
我主要尝试在更简单的设置中模仿 this。运气不好。
我写了一个简单的 fortran 代码:
subroutine POWERTWO (n, nsquared)
!DEC$ ATTRIBUTES DLLEXPORT :: POWERTWO
integer, intent(in) :: n
integer, intent(out) :: nsquared
nsquared = n*n
return
end subroutine POWERTWO
我用 gfortran 编译如下:
gfortran -m32 -dynamiclib ./tmp.f90 -o ./tmp.dylib
注意我的gfortran
配置如下:
COLLECT_LTO_WRAPPER=/usr/local/lvm/gcc-5.2.0/libexec/gcc/x86_64-apple-darwin14.4.0/5.2.0/lto-wrapper
Target: x86_64-apple-darwin14.4.0
Configured with: ../configure --prefix=/usr/local/lvm/gcc-5.2.0 --enable-checking=release --with-gmp=/usr/local/lvm/gmp-6.0.0 --with-mpfr=/usr/local/lvm/mpfr-3.1.2 --with-mpc=/usr/local/lvm/mpc-1.0.3 --enable-languages=c,c++,fortran,objc,obj-c++ --with-isl=/usr/local/lvm/isl-0.14 --with-cloog=/usr/local/lvm/cloog-0.18.4
Thread model: posix
gcc version 5.2.0 (GCC)
在 dylib 所在的同一个文件夹中,我有一个 excel 2011 xslm 电子表格,在 VBA 中我输入了以下代码:
Declare Function powertwo CDecl Lib "tmp.dylib" (n As Long, ByVal nsquared As Long)
Function VBA_UDFPowerTwo(n As Long) As Long
Dim res As Long
res = 0
Call powertwo(n, res)
VBAUDFPowerTwo = res
End Function
现在,在单元格 A2 中执行公式 =VBA_UDFPowerTwo(A1)
得到 #VALUE!
。如果我将 dylib 的整个路径放在 VBA 中,结果相同:
Declare Function powertwo CDecl Lib "/Users/XXXXXX/Documents/GITHUBRepos/DYLIBS/MyFirstDylib/tmp.dylib" (n As Long, ByVal nsquared As Long)
或
Declare Function powertwo CDecl Lib "Mackintosh HD:Users:XXXXXX:Documents:GITHUBRepos:DYLIBS:MyFirstDylib:tmp.dylib" (n As Long, ByVal nsquared As Long)
如果我将 ByVal
替换为 ByRef
,则相同。甚至一个
Declare Function powertwo CDecl Lib "Mackintosh HD:Users:ludwigvonmises:Documents:GITHUBRepos:DYLIBS:MyFirstDylibt:tmp.dylib" Alias "POWERTWO" (n As Long, ByRef nsquared As Long)
没有让我开心。我是不是遗漏了什么或做错了什么?
我在 dylib 上做了一个 nm
并得到以下结果:
00000fa4 t ___x86.get_pc_thunk.ax
00000f87 T _powertwo_
U dyld_stub_binder
而 nm -gU
给我:
00000f87 T _powertwo_
Console.app 在打开 excel 并触发 A2 单元格中的计算时告诉我以下内容:
22/08/15 19:37:32,892 Microsoft Excel[2971]: WARNING: The Gestalt selector gestaltSystemVersion is returning 10.9.5 instead of 10.10.5. Use NSProcessInfo's operatingSystemVersion property to get correct system version number.
Call location:
22/08/15 19:37:32,892 Microsoft Excel[2971]: 0 CarbonCore 0x96a01291 ___Gestalt_SystemVersion_block_invoke + 135
22/08/15 19:37:32,893 Microsoft Excel[2971]: 1 libdispatch.dylib 0x92c4f0b5 dispatch_once_f + 251
22/08/15 19:37:32,893 Microsoft Excel[2971]: 2 libdispatch.dylib 0x92c500d8 dispatch_once + 31
22/08/15 19:37:32,893 Microsoft Excel[2971]: 3 CarbonCore 0x9697a69d _Gestalt_SystemVersion + 1050
22/08/15 19:37:32,893 Microsoft Excel[2971]: 4 CarbonCore 0x969797c0 Gestalt + 150
22/08/15 19:37:32,893 Microsoft Excel[2971]: 5 MicrosoftComponentPlugin 0x01bdb27e McpInitLibrary_ + 505
22/08/15 19:37:32,893 Microsoft Excel[2971]: 6 MicrosoftComponentPlugin 0x01bdb0ae McpInitLibrary_ + 41
和 otool -L tmp.dylib
显示如下:
./tmp.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/local/lvm/gcc-5.2.0/lib/i386/libgfortran.3.dylib (compatibility version 4.0.0, current version 4.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
/usr/local/lvm/gcc-5.2.0/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lvm/gcc-5.2.0/lib/i386/libquadmath.0.dylib (compatibility version 1.0.0, current version 1.0.0)
编辑
求助于:
Declare Function powertwo_ CDecl Lib "Macintosh HD:Users:XXXXXX:Documents:GITHUBRepos:DYLIBS:MyFirstDylib:tmp.dylib" (n As Long, ByRef nsquared As Long)
如Ken Thomases所建议,在单元格A2中触发计算时导致excel崩溃,这至少表明导出的函数名称不是powertwo
而是powertwo_
, excel 的 VBA 确实加载了 tmp.dylib。
您的尝试存在一些问题:
过程参数不匹配
Fortran 默认按引用传递,VBA 也是如此。在您多次尝试使界面正确时,您并没有完全匹配它们。
程序不匹配return值
您的 Fortran 过程是一个子例程,return没有价值。您需要将 VBA 过程声明为 Sub
,而不是 Function
。
使用 Intel Fortran 指令
!DEC$
指令 (afaik) 只是对 gfortran 的注释,未被解释。
这是我所做的,并测试了它是否有效。 Fortran 已使用 Fortran 2003 的 iso_c_binding
C-interop 功能重新编写,以提供对导出过程接口的更多控制并确保您获得所需内容。您使用的是现代 Fortran 编译器,因此这对您来说不是问题。
Fortran:
subroutine POWERTWO (n, nsquared) bind(C, name='powertwo')
use iso_c_binding, only: c_long
implicit none
integer(kind=c_long), intent(in) :: n
integer(kind=c_long), intent(out) :: nsquared
nsquared = n*n
return
end subroutine POWERTWO
这将生成一个带有 C 接口的过程
void powertwo(long int* n, long int* squared)
我用 gfortran 5.2(来自 macports)编译了这个:
gfortran-mp-5 -m32 -dynamiclib -o test32.dylib test.f90
在 Excel VBA 中,我已将程序声明为:
Declare Sub powertwo CDecl Lib "/Users/casey/code/so/xlstest/test32.dylib" (ByRef n As Long, ByRef nsquared As Long)
Function VBA_UDFPowerTwo(n As Long) As Long
Dim res As Long
res = 0
Call powertwo(n, res)
VBA_UDFPowerTwo = res
End Function
请注意,以上内容还修复了 VBAUDFPowerTwo = res
行中的错字,即 VBA 后缺少下划线(与函数名称不匹配)。我还将导入的函数更改为 Sub
并将其参数明确声明为 ByRef
(这应该是默认值)。
这会产生所需的行为:
我主要尝试在更简单的设置中模仿 this。运气不好。
我写了一个简单的 fortran 代码:
subroutine POWERTWO (n, nsquared)
!DEC$ ATTRIBUTES DLLEXPORT :: POWERTWO
integer, intent(in) :: n
integer, intent(out) :: nsquared
nsquared = n*n
return
end subroutine POWERTWO
我用 gfortran 编译如下:
gfortran -m32 -dynamiclib ./tmp.f90 -o ./tmp.dylib
注意我的gfortran
配置如下:
COLLECT_LTO_WRAPPER=/usr/local/lvm/gcc-5.2.0/libexec/gcc/x86_64-apple-darwin14.4.0/5.2.0/lto-wrapper
Target: x86_64-apple-darwin14.4.0
Configured with: ../configure --prefix=/usr/local/lvm/gcc-5.2.0 --enable-checking=release --with-gmp=/usr/local/lvm/gmp-6.0.0 --with-mpfr=/usr/local/lvm/mpfr-3.1.2 --with-mpc=/usr/local/lvm/mpc-1.0.3 --enable-languages=c,c++,fortran,objc,obj-c++ --with-isl=/usr/local/lvm/isl-0.14 --with-cloog=/usr/local/lvm/cloog-0.18.4
Thread model: posix
gcc version 5.2.0 (GCC)
在 dylib 所在的同一个文件夹中,我有一个 excel 2011 xslm 电子表格,在 VBA 中我输入了以下代码:
Declare Function powertwo CDecl Lib "tmp.dylib" (n As Long, ByVal nsquared As Long)
Function VBA_UDFPowerTwo(n As Long) As Long
Dim res As Long
res = 0
Call powertwo(n, res)
VBAUDFPowerTwo = res
End Function
现在,在单元格 A2 中执行公式 =VBA_UDFPowerTwo(A1)
得到 #VALUE!
。如果我将 dylib 的整个路径放在 VBA 中,结果相同:
Declare Function powertwo CDecl Lib "/Users/XXXXXX/Documents/GITHUBRepos/DYLIBS/MyFirstDylib/tmp.dylib" (n As Long, ByVal nsquared As Long)
或
Declare Function powertwo CDecl Lib "Mackintosh HD:Users:XXXXXX:Documents:GITHUBRepos:DYLIBS:MyFirstDylib:tmp.dylib" (n As Long, ByVal nsquared As Long)
如果我将 ByVal
替换为 ByRef
,则相同。甚至一个
Declare Function powertwo CDecl Lib "Mackintosh HD:Users:ludwigvonmises:Documents:GITHUBRepos:DYLIBS:MyFirstDylibt:tmp.dylib" Alias "POWERTWO" (n As Long, ByRef nsquared As Long)
没有让我开心。我是不是遗漏了什么或做错了什么?
我在 dylib 上做了一个 nm
并得到以下结果:
00000fa4 t ___x86.get_pc_thunk.ax
00000f87 T _powertwo_
U dyld_stub_binder
而 nm -gU
给我:
00000f87 T _powertwo_
Console.app 在打开 excel 并触发 A2 单元格中的计算时告诉我以下内容:
22/08/15 19:37:32,892 Microsoft Excel[2971]: WARNING: The Gestalt selector gestaltSystemVersion is returning 10.9.5 instead of 10.10.5. Use NSProcessInfo's operatingSystemVersion property to get correct system version number.
Call location:
22/08/15 19:37:32,892 Microsoft Excel[2971]: 0 CarbonCore 0x96a01291 ___Gestalt_SystemVersion_block_invoke + 135
22/08/15 19:37:32,893 Microsoft Excel[2971]: 1 libdispatch.dylib 0x92c4f0b5 dispatch_once_f + 251
22/08/15 19:37:32,893 Microsoft Excel[2971]: 2 libdispatch.dylib 0x92c500d8 dispatch_once + 31
22/08/15 19:37:32,893 Microsoft Excel[2971]: 3 CarbonCore 0x9697a69d _Gestalt_SystemVersion + 1050
22/08/15 19:37:32,893 Microsoft Excel[2971]: 4 CarbonCore 0x969797c0 Gestalt + 150
22/08/15 19:37:32,893 Microsoft Excel[2971]: 5 MicrosoftComponentPlugin 0x01bdb27e McpInitLibrary_ + 505
22/08/15 19:37:32,893 Microsoft Excel[2971]: 6 MicrosoftComponentPlugin 0x01bdb0ae McpInitLibrary_ + 41
和 otool -L tmp.dylib
显示如下:
./tmp.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/local/lvm/gcc-5.2.0/lib/i386/libgfortran.3.dylib (compatibility version 4.0.0, current version 4.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
/usr/local/lvm/gcc-5.2.0/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lvm/gcc-5.2.0/lib/i386/libquadmath.0.dylib (compatibility version 1.0.0, current version 1.0.0)
编辑
求助于:
Declare Function powertwo_ CDecl Lib "Macintosh HD:Users:XXXXXX:Documents:GITHUBRepos:DYLIBS:MyFirstDylib:tmp.dylib" (n As Long, ByRef nsquared As Long)
如Ken Thomases所建议,在单元格A2中触发计算时导致excel崩溃,这至少表明导出的函数名称不是powertwo
而是powertwo_
, excel 的 VBA 确实加载了 tmp.dylib。
您的尝试存在一些问题:
过程参数不匹配
Fortran 默认按引用传递,VBA 也是如此。在您多次尝试使界面正确时,您并没有完全匹配它们。
程序不匹配return值
您的 Fortran 过程是一个子例程,return没有价值。您需要将 VBA 过程声明为
Sub
,而不是Function
。使用 Intel Fortran 指令
!DEC$
指令 (afaik) 只是对 gfortran 的注释,未被解释。
这是我所做的,并测试了它是否有效。 Fortran 已使用 Fortran 2003 的 iso_c_binding
C-interop 功能重新编写,以提供对导出过程接口的更多控制并确保您获得所需内容。您使用的是现代 Fortran 编译器,因此这对您来说不是问题。
Fortran:
subroutine POWERTWO (n, nsquared) bind(C, name='powertwo')
use iso_c_binding, only: c_long
implicit none
integer(kind=c_long), intent(in) :: n
integer(kind=c_long), intent(out) :: nsquared
nsquared = n*n
return
end subroutine POWERTWO
这将生成一个带有 C 接口的过程
void powertwo(long int* n, long int* squared)
我用 gfortran 5.2(来自 macports)编译了这个:
gfortran-mp-5 -m32 -dynamiclib -o test32.dylib test.f90
在 Excel VBA 中,我已将程序声明为:
Declare Sub powertwo CDecl Lib "/Users/casey/code/so/xlstest/test32.dylib" (ByRef n As Long, ByRef nsquared As Long)
Function VBA_UDFPowerTwo(n As Long) As Long
Dim res As Long
res = 0
Call powertwo(n, res)
VBA_UDFPowerTwo = res
End Function
请注意,以上内容还修复了 VBAUDFPowerTwo = res
行中的错字,即 VBA 后缺少下划线(与函数名称不匹配)。我还将导入的函数更改为 Sub
并将其参数明确声明为 ByRef
(这应该是默认值)。
这会产生所需的行为: