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

Variable import from DLL broken by upgrade

dougf
Beginner
3,885 Views

When I rebuild my code using Visual Fortran Composer XE 2013 SP1 Update 4, previously working (using version 13.0.1.119) imports of variables that are exported from a DLL (created in ObjectAda, if that matters) no longer work.  Imports of procedures still work, although it seems that I no longer need to include a DLLIMPORT directive for this.

Here's the code:

real(kind=8) :: DLLFunc

real(kind=8) :: LocalDouble

!DEC$ ATTRIBUTES DLLIMPORT:: DLLFunc

!DEC$ ATTRIBUTES DLLIMPORT:: DLLProc

!DEC$ ATTRIBUTES DLLIMPORT:: LocalDouble

When I rebuild using XE 2013 SP1 Update 4, I can access DLLFunc (a function) and DLLProc (a subroutine) just fine (although it also works now when I leave out the DLLIMPORT directives). However, I get the following compilation error for the imported variable LocalDouble:

error #6406: Conflicting attributes or multiple declaration of name. [LOCALDOUBLE]

I'd appreciate any thoughts regarding what I need to update to get this back in working order, and perhaps some information regarding what changes have been made to compiler support of DLLIMPORT.

0 Kudos
20 Replies
Steven_L_Intel1
Employee
3,871 Views

I'm not aware of any changes made in this area. Would you please put together a small example, for the DLL and the importer, that shows the problem? How are the variables defined in the DLL - are they in a module or something else? Showing just a snippet of code is not sufficient to understand the issue.

0 Kudos
dougf
Beginner
3,871 Views

I have attached a Fortran main program (adaTest.f90) and the source used to generate the Ada DLL I'm using for the test (hello.txt; had to change the extension from .ada to get it to allow me to attach the file.)

The DLL function (DLLFunc), procedure (DLLProc), and variable (LocalDouble) are all declared in the Ada package "P" and exported using pragma Export.

Once again, I can successfully call DLLFunc and DLLProc from program adaTest, but now the Fortran import directive

!DEC$ ATTRIBUTES DLLIMPORT:: LocalDouble

gives me an error 6406 during compilation.

 

0 Kudos
mecej4
Honored Contributor III
3,871 Views

The variable LocalDouble is declared to be real(KIND=8), initialized with a value in that declaration, and is then declared later as DLLIMPORT via a directive. These conflicting declarations are what the compiler is complaining about. Even the Compaq 6.6c Fortran compiler gives a corresponding error message for adaTest.f90. If you remove the initialization, the error message will go away.

0 Kudos
dougf
Beginner
3,871 Views

If I remove the initialization of LocalDouble, error #6406 goes away.  However, I still get a link error:

      error LNK2019: unresolved external symbol LOCALDOUBLE referenced in function _MAIN__

Just to clarify:  If I build this code using VFC XE 13.0.1.119, I get no link error and proper import of the DLL variable LOCALDOUBLE.

                        If I build it using VFC XE 14.0.4.237, I get the link error.

In both cases, the imports of DLLFunc and DLLProc work correctly.

0 Kudos
mecej4
Honored Contributor III
3,871 Views

I doubt that there are many forum readers who use Ada, but here is a link that may help with sharing data between a DLL and an EXE: https://software.intel.com/en-us/comment/reply/286496/1513030 . I assume that the Ada DLL contains a shared .DATA segment, which would be the case if the DLL was linked with the linker option /section:.DATA,RWS. You also need to declare the shared data in a Fortran module and link that along with the import library for the DLL when you build your Fortran program. It may help to use the following Fortran DLL code to work and then try to get the Ada DLL to work. File adadll.f90:

module shared_glob
!ada dll simulated in Fortran
double precision :: SharedDouble=acos(-1d0)
!DEC$  Attributes DLLExport :: SharedDouble
end module

subroutine DLLProc()
!DEC$ Attributes DLLExport :: DLLProc
write(*,*)'In DLLProc()'
return
end subroutine

function DLLFunc(x) result (y)
!DEC$ Attributes DLLExport :: DLLFunc
double precision :: x,y
y=x*x
write(*,*)'In DLLFunc ',x,y
return
end function

We build the DLL and import library using the command

ifort /LD adadll.f90 /link /section:.data,RWS

Here is a simplified version of the client program, adatest.f90:

    program adaTest
    use shared_glob ! declares shared data

    implicit none

   ! Import Ada DLL procedures
   real(kind=8) :: DLLFunc

   !DEC$ ATTRIBUTES DLLIMPORT:: DLLFunc
   !DEC$ ATTRIBUTES DLLIMPORT:: DLLProc

   ! Locals
   integer :: out_int = 5
   integer :: in_int
   integer(kind=2) :: local_int_2 = 6
   real(kind=8) :: out_double = 12.345678910111213_8
   real(kind=8) :: in_double, in_double_func

   call DLLProc()

   write(*,'(1x,"shareddouble: ",/)')
   write(*,*) shareddouble

   in_double_func = DLLFunc(out_double)

   write(*,'(1x,"Back In FortDrive: ",/)')
   write(6,1006) in_double_func
1006   format(1x,"Double input from Ada function: ", F18.15)

   end program adaTest

We build the EXE using the command:

ifort adaTest.f90 adadll.lib

We can then run and test the EXE for working correctly.

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

Your original code is in error, as noted by mecej4. You should not be DLLIMPORTing a symbol that is initialized.

I suggest you run your Ada DLL through DependencyWalker and see what the name is of the symbol it exports.

0 Kudos
dougf
Beginner
3,871 Views

I used DependencyWalker to confirm that the Ada DLL export name is LOCALDOUBLE, the same as I have in my Fortran DLLIMPORT.

As I said in my last post, the test code that I sent you (adaTest.f90, with the initialization correction) compiles, links and runs correctly (including import of LOCALDOUBLE from the Ada DLL) when I use VFC XE 13.0.1.119. However, if I build it using VFC XE 14.0.4.237, I get the link error

          error LNK2019: unresolved external symbol LOCALDOUBLE referenced in function _MAIN__.

This would seem to imply that a change in Composer XE is causing the difficulty.

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

What are you linking against? Please provide the .lib file from the Ada DLL.

Even if there was a change, it was to fix a bug as your original code is incorrect.

0 Kudos
dougf
Beginner
3,871 Views

Please see the attached .zip file, which includes:

Fortran source file (adaTest.f90), Composer XE solution and project files (adaTest.sln, adaTest.vfproj).

Ada source file (hello.ada), DLL (dll.dll), and .lib (dll.lib).

Thanks for looking into this.

 

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

Thanks - an interesting problem. I'll let you know what I find.

0 Kudos
mecej4
Honored Contributor III
3,871 Views

Here is a slight modification of the file adatest.f90 in #10, which builds and runs fine with IFort 15.0.1.

Browsing the Fortran Standard yielded the following extract:

15.3 Interoperation with C global variables
2 A C variable with external linkage may interoperate with a common block or with a variable declared
3 in the scope of a module. The common block or variable shall be specified to have the BIND attribute.

It is likely that the requirement that the global variable be in a module was not enforced in the older version of the compiler because many Fortran 2003 features had not yet been implemented in that compiler.

 

0 Kudos
dougf
Beginner
3,871 Views

The suggested code modification got rid of the link error, but the import of LOCALDOUBLE from the Ada DLL still does not work.  (The value of LOCALDOUBLE is still 1234.5 after return from the call to DLLProc.)  Note that this same behavior was seen for both compiler versions (13.0.1.119 and 14.0.4.237).

 

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

My knowledge of Ada dates from the 1980s, well before things like this pragma. I do know that sharing data from a DLL requires a special form of export and it is not clear to me that the pragma in the Ada code is doing this - maybe it is.  It would be useful to create a Fortran version of the Ada DLL - something just to verify that the data is being properly referenced - and see if the behavior is different.

0 Kudos
dougf
Beginner
3,871 Views

I did as you suggested and created a simple Fortran DLL that exports a subroutine and a variable (please see attached files).  When building main.f90, I get the link error

          error LNK2001: unresolved external symbol __imp_FDLL_DOUBLE

If I comment out the FDLL_DOUBLE DLLIMPORT statement in main, the code builds and accesses the imported subroutine FDLL just fine. 

Am I doing something wrong with the Fortran DLL data export/import?

 

Regarding the Ada DLL:  I keep coming back to the facts that 1) the procedure export/import works fine, and 2) the data export/import also works fine when I build with the previous version of Fortran Composer XE.

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

Because you put the variable in a module, by default its external name has the module name as well.

But yes, there indeed seems to be a bug here. The DLLIMPORT of the variable isn't referencing the import name, which should be __imp__FDLL_DOUBLE, and yes, 13.1 did it right. Looks like we broke this in 14.0. I also looked at various ways to work around the problem, using ALIAS and other things, but wasn't able to find one. I will report this to the developers and let you know of progress or if we find a workaround.

0 Kudos
dougf
Beginner
3,871 Views

OK, thanks very much!

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

I posted too soon - I found a workaround.

Create a separate source file with contents as follows:

module mystuff
real(8), bind(C,NAME="LOCALDOUBLE") :: LocalDouble
!DEC$ ATTRIBUTES DLLIMPORT :: LocalDouble
end module mystuff

You can change the name of "mystuff" to be whatever you want. Add a "use mystuff" in the program or routine where you want to use LocalDouble.

In your Ada code, change the external name of LocalDouble to be "_LOCALDOUBLE" with the underscore - this is what it should be. I wasn't able to find a way to preserve the name without the leading underscore and have everything else work.

Add the module source to your Fortran build, making sure it compiles first (if you do this in a VS project, it will.) This should all now work correctly.

0 Kudos
dougf
Beginner
3,871 Views

Steve,

This worked for both compiler versions and should allow me to press ahead.  Thanks again for your help.

0 Kudos
Steven_L_Intel1
Employee
3,871 Views

I'm glad I was able to find the workaround. Escalated as issue DPD200366023.

0 Kudos
Steven_L_Intel1
Employee
3,719 Views

This has been fixed for a release later this year.

0 Kudos
Reply