c++ dylib curiously not found by excel's 2011 VBA on mac

末鹿安然 提交于 2019-12-24 11:27:55

问题


I mainly tried to mimic this in an even simpler setting. No luck.

I wrote a simple fortran code :

      subroutine POWERTWO (n, nsquared)
      !DEC$ ATTRIBUTES DLLEXPORT :: POWERTWO
      integer, intent(in) :: n
      integer, intent(out) :: nsquared
      nsquared = n*n
      return
      end subroutine POWERTWO

that I compiled with gfortran as follows :

gfortran -m32 -dynamiclib ./tmp.f90 -o ./tmp.dylib

Note that my gfortran is configured as follows :

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)

In the same folder where the dylib is, I have an excel 2011 xslm spreadsheet, and in the VBA I put the following code :

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

Now, doing in cell A2 the formula =VBA_UDFPowerTwo(A1) gives me a #VALUE!. Same result if I put the whole path to the dylib in the VBA as :

Declare Function powertwo CDecl Lib "/Users/XXXXXX/Documents/GITHUBRepos/DYLIBS/MyFirstDylib/tmp.dylib" (n As Long, ByVal nsquared As Long)

or as

Declare Function powertwo CDecl Lib "Mackintosh HD:Users:XXXXXX:Documents:GITHUBRepos:DYLIBS:MyFirstDylib:tmp.dylib" (n As Long, ByVal nsquared As Long)

and same if I replace ByVal by ByRef. Even a

Declare Function powertwo CDecl Lib "Mackintosh HD:Users:ludwigvonmises:Documents:GITHUBRepos:DYLIBS:MyFirstDylibt:tmp.dylib" Alias "POWERTWO" (n As Long, ByRef nsquared As Long)

did not make my day. Am I missing something or doing something wrong ?

I did a nm on the dylib an get the following :

00000fa4 t ___x86.get_pc_thunk.ax
00000f87 T _powertwo_
         U dyld_stub_binder

whereas nm -gU gives me :

00000f87 T _powertwo_

Console.app told me the following while excel was opened and calculation in the A2 cell triggered :

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

and otool -L tmp.dylib showed the following :

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

EDIT

Resorting to :

Declare Function powertwo_ CDecl Lib "Macintosh HD:Users:XXXXXX:Documents:GITHUBRepos:DYLIBS:MyFirstDylib:tmp.dylib" (n As Long, ByRef nsquared As Long)

as Ken Thomases suggested, made excel crash when calculation triggered in cell A2, which shows at least that the exported function name is not powertwo but powertwo_, and that excel's VBA loads tmp.dylib indeed.


回答1:


Your attempt at doing this had a few issues:

  • mismatch in the procedure arguments

    Fortran passes by reference by default, as does VBA. In your multiple attempts at getting the interface right you didn't quite match them up.

  • mismatch in the procedure return value

    Your Fortran procedure is a subroutine, which returns no value. You need to declare the VBA procedure as a Sub, not a Function.

  • Use of Intel Fortran directives

    The !DEC$ directives (afaik) are just comments to gfortran and not interpreted.


Here is what I've done, and tested that it works. The Fortran has been re-written using the iso_c_binding C-interop features of Fortran 2003 to give more control over the exported procedure interface and ensure that you get what you want. You are using a modern Fortran compiler, so this is not an issue for you.

The 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 

This will produce an procedure with the C interface

void powertwo(long int* n, long int* squared)

I compiled this with gfortran 5.2 (from macports):

gfortran-mp-5 -m32 -dynamiclib -o test32.dylib test.f90

In Excel VBA, I have declared the procedure as:

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

Note the above also fixes a typo in your line VBAUDFPowerTwo = res, which is missing an underscore after VBA (doesn't match the Function name). I have also changed the imported function to be a Sub and explicitely declared its arguments as ByRef (which should be the default).

This produces the desired behavior:



来源:https://stackoverflow.com/questions/32158814/c-dylib-curiously-not-found-by-excels-2011-vba-on-mac

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!