Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

DLLEXPORT and unresolved external reference

Brian_Murphy
New Contributor II
2,377 Views
I'm compiling a fortran DLL project. I have two subroutines in the same .f file. The first one shown below calls the second one, but I'm getting unresolved external symbol. The problem must be how I'm exporting them so they can be called from Excel VBA. I have iface set to Default for this project. The unresolved error goes away if I remove the !DEC statement from SUBB, but I need it. All the argument variables are numeric except for the one called rtn. What the heck am I doing wrong?!@#$ subroutine SUBA(nx, alfa_r, alfa_i, z_r, z_i, nev, irvec, & Lindex_k, Lvalue_k, index_k, value_k, ne_k, & Lindex_m, Lvalue_m, index_m, value_m, ne_m, & W, ierr, rtn) !DEC$ ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE, ALIAS:"SUBA" :: SUBA character(10) :: rtn !DEC$ ATTRIBUTES REFERENCE :: rtn subroutine SUBB(nx, Lindex, Lvalue, index, value, ne_, ierr) !DEC$ ATTRIBUTES DLLEXPORT, STDCALL, REFERENCE, ALIAS:"SUBB" :: SUBB
0 Kudos
19 Replies
JVanB
Valued Contributor II
2,377 Views

Put both procedures in the same module.

      module M
         contains
! All your stuff goes here
      end module M

That way the interface to SUBB will be explicit in SUBA so it can be invoked correctly. This will work because of the !DEC$ ATTRIBUTES ALIAS directives so the VBA code will be able to see the procedures even though they are in a Fortran module.

0 Kudos
Steven_L_Intel1
Employee
2,377 Views

RO may have guessed correctly that SUBA calls SUBB, but that isn't shown in your post. If so, the issue is that you've changed the global name for SUBB so SUBA can't find it. You could add:

!DEC$ ATTRIBUTES ALIAS:"SUBB" :: SUBB

in SUBA and that should take care of it. 

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

Thanks again, Steve.  Adding ALIAS statements did indeed clear up those errors, and I'm back in business.

This code essentially ran the way it was when built with CVF.  Is there an easy explanation for why these are needed now?

Thanks,

Brian

0 Kudos
Steven_L_Intel1
Employee
2,377 Views

If SUBA and SUBB were in the same source file, I suppose it's possible that CVF noticed the name change. Sometimes this isn't what you want, though! I no longer have CVF available to try for myself.

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

I must be dense.  I don't see why you say the name has changed?  You're talking about SUBB, right?

In this case SUBA and SUBB are in the same file.  But I have others that are not, and adding ALIAS statements cleared up those unresolved errors, too.  CVF didn't have any trouble with those, either.

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

I'll bet it's the addition of the DLLEXPORT ALIAS statement in SUBB makes the rest of program think the name has been changed, even though it really hasn't.  Is that it?

 

0 Kudos
JVanB
Valued Contributor II
2,377 Views

I'm kind of curious as to how the ALIAS statement fixes things. Reading the ifort docs, /iface:default seems to set the calling convention to C, but SUBA is not given any information about SUBB's required calling convention, which is STDCALL. How does the compiler figure out that it should set up a STDCALL invocation?

 

0 Kudos
Steven_L_Intel1
Employee
2,377 Views

Since you are using STDCALL, which was the CVF default, CVF would try to call SUBB from SUBA as _SUBB@28. Since you used ALIAS to change the name of SUBB to "SUBB" I would not expect CVF to match these. I do know that CVF also would have emitted an alias of _SUBB (with the underscore) but that should not have matched what other callers wanted.

I don't know if you did the "Extract CVF project items" to convert the project - if you did, then /iface:cvf would be applied and it should behave the same way. If not, then Intel Fortran would try to call _SUBB and it still wouldn't match.

I can't explain the behavior you claim for CVF and am no longer able to verify it on my own. But what I told you to do is what should have been needed regardless, and back in my CVF days I often had to give this advice to users.

RO had good general advice about putting procedures in modules. If that was done, then the compiler sees the declaration of the routine including its alias and calling convention. But it's slightly more work than just adding the alias to the callers.

0 Kudos
mecej4
Honored Contributor III
2,377 Views

Repeat Offender wrote:

I'm kind of curious as to how the ALIAS statement fixes things. Reading the ifort docs, /iface:default seems to set the calling convention to C, but SUBA is not given any information about SUBB's required calling convention, which is STDCALL. How does the compiler figure out that it should set up a STDCALL invocation?

I don't think that it does, and therefore it is likely that the DLL will crash when it is run. There are three compatibility requirements (at least): order of passing arguments, stack cleanup responsibility and name decoration. The ALIAS attribute fixes things up so that the linker does not issue any error messages. In other words, name decoration works correctly. The other two issues, even if not addressed, will not be detected at build time.

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

I sort of understand.  But argument calling conventions, modules and interfaces are topics I have yet to master.

This IVF solution was put together from several CVF projects (one DLL and several LIB's).  The DLL was "converted" and the LIB's I made from scratch in IVF.  To get things working, I had to change /iface:cvf to default for the DLL project.  So as it is now, everything is /iface default.

At the moment the code runs without crashing.  Excel VBA calls fortran, and fortran does it's part correctly, but there are some other weird things happening on the VBA side that haven't happened before.  That's what I'm working on now.

0 Kudos
Steven_L_Intel1
Employee
2,377 Views

Yes, if /iface:default is used, then SUBA needs to also add STDCALL, REFERENCE to the ATTRIBUTES directive for SUBB.

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

I am using /iface:default (although the linker command line doesn't contain iface anywhere).  Right now the extra DEC's only contain ALIAS, without STDCALL and REFERENCE.  I thought the code was running this way, but part is and other parts throw exceptions in fortran.  So I'll be adding these other keywords and crossing my fingers.

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

Success!  After adding the keywords, the crashing stopped, and also the weirdness on the VBA side is gone.  This turning out to be a good day for me!

0 Kudos
mecej4
Honored Contributor III
2,377 Views

Brian Murphy wrote:

I am using /iface:default (although the linker command line doesn't contain iface anywhere). 

At the time the compiler driver gives control to the linker, the code generation is already completed and the compiled code is in .OBJ files, so it is too late to do anything to affect the linkage conventions used.

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

oops!  I should have said compiler command line, not linker.

 

0 Kudos
Steven_L_Intel1
Employee
2,377 Views

Since /iface:default is the default, it isn't put on the command line.

0 Kudos
JVanB
Valued Contributor II
2,377 Views

I kind of disagree that putting everything in modules is more work. Looking back at Quote #14 it can be seen that the O.P. had no way of directly knowing that the interfaces matched and still doesn't. Does /warn:interfaces work for a multi-project solution such as this? If so, it doesn't seem to have been applied because the mismatched interfaces weren't caught by ifort. There's more than just STDCALL and REFERENCE because individual arguments can be given attributes as well, see SUBA above. If the interfaces aren't made explicit by putting everything in modules, it seems to me to be almost a necessity to bring /warn:interfaces to bear on the problem to have any hope that all the mismatches have indeed been found.

 

0 Kudos
Brian_Murphy
New Contributor II
2,377 Views

I have /warn:interfaces turned off because of scalers being passed to array dummy arguments.  I realize this is asking for trouble, but this code I'm porting from CVF to IVF has been in heavy use for over 10 years.  I'm trying to get it working with the minimum of edits to the source.

0 Kudos
Steven_L_Intel1
Employee
2,377 Views

Actually. /warn:interface does work for a multi-project application. But I am wholly in favor of use of modules.

0 Kudos
Reply