DLL symbol export

In Linux, all symbols seem to be exported in shared libraries. Under windows in C the __declspec(dllexport) seems to work without having to specify a .def file. Is there any way to do this in fortran as well? An option for windows that exported all global symbols would be really nice if it doesn’t exist. I know I can use the -Wl,-export option, but that gets messy in windows since you have to give the decorated name or it complains about ambiguities.

Chris

Hi Chris,

In Fortran, you would use the “DLLEXPORT” directive. I took the following example from Section 8.3 in the PGI User’s Guide.

PGI$ cat object1.f
       subroutine sub1(i)
!DEC$ ATTRIBUTES DLLEXPORT :: sub1
       integer i
       common /acommon/ adata
       integer adata
!DEC$ ATTRIBUTES DLLEXPORT :: /acommon/
       print *, "sub1 adata", adata
       print *, "sub1 i ", i
       adata = i
       end
PGI$ cat prog1.f
       program prog1
       common /acommon/ adata
       integer adata
       external sub1
!DEC$ ATTRIBUTES DLLIMPORT:: sub1, /acommon/
       adata = 11
       call sub1(12)
       print *, "main adata", adata
       end
PGI$ pgf90 -c object1.f -Munix
PGI$ pgf90 -Mmakedll -Munix -o object1.dll object1.obj
   Creating library object1.lib and object object1.exp
PGI$ pgf90 -Mdll -Munix -o prog1 prog1.f -defaultlib:object1
PGI$ prog1
 sub1 adata           11
 sub1 i            12
 main adata           12

Note that “-Munix” is only needed on Win32 with the 6.2 compilers to work around a naming issue. It is not needed on Win64 or with the upcoming 7.0 release of the compilers.

We do have an undocumented flag “-Mmakedll:export_all” that you can use which essentially creates a .def file for you. It’s still experimental so may contain some bugs.

  • Mat

How does that work with module data?

[chulbert@maxwell ~]$ cat testm.f90
MODULE TESTM
TYPE A_TYPE
INTEGER :: AN_INT
END TYPE A_TYPE

TYPE(A_TYPE) :: A
!DEC$ ATTRIBUTES DLLEXPORT :: A

CONTAINS
SUBROUTINE PRINT_A
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_A
WRITE(,) A%AN_INT
END SUBROUTINE

END MODULE
[chulbert@maxwell ~]$ cat testp.f90
USE TESTM
TYPE(A_TYPE) :: A
!DEC$ ATTRIBUTES DLLIMPORT :: A
A%AN_INT = 1
CALL PRINT_A
END


[chulbert@maxwell ~]$ pgf90 -Mmakedll testm.f90
Creating library testm.lib and object testm.exp
[chulbert@maxwell ~]$ pgf90 -I. testp.f90 testm.lib
PGF90-S-0155-a is use associated and cannot be redeclared (testp.f90: 2)
PGF90-S-0084-Illegal use of symbol a - must be defined for ATTRIBUTES (testp.f90: 3)
0 inform, 0 warnings, 2 severes, 0 fatal for MAIN
testp.f90:





If I remove the TYPE(A_TYPE) :: A definition in the program:
[chulbert@maxwell ~]$ pgf90 -I. testp.f90 testm.lib
PGF90-S-0155-a is use associated and cannot be redeclared (testp.f90: 2)
PGF90-S-0084-Illegal use of symbol a - must be defined for ATTRIBUTES (testp.f90: 2)
0 inform, 0 warnings, 2 severes, 0 fatal for MAIN
testp.f90:


If i remove the !DEC$ statement:
[chulbert@maxwell ~]$ pgf90 -I. testp.f90 testm.lib
testp.obj : warning LNK4217: locally defined symbol _testm_0 imported in function MAIN
testp.f90:
[chulbert@maxwell ~]$ ./testp.exe
0


Thanks for the experimiental -Mmakedll:export_all. I’ll check that out and see how it works.

Chris

Mat,
Any thoughts on my last post?

Hi Chris,

How I think it’s suppose to work is exactly how you have it in the second case (without the import) since the dllimport is already implied in the “.mod” file. However, it looks like we might have a namespace conflict or some other subtle bug where we have two copies of “A”. I’m not 100% this is the issue, but I’ll submit a TPR and have a compiler engineer look at it.

As a work around, if you put your variables into a common block and then export the common block, it seems to work ok.

Example:

PGI$ cat testm.f90
MODULE TESTM
TYPE A_TYPE
INTEGER :: AN_INT
END TYPE A_TYPE

COMMON /acommon/ A, B
TYPE(A_TYPE) :: A, B
!DEC$ ATTRIBUTES DLLEXPORT :: /acommon/
CONTAINS

SUBROUTINE PRINT_A
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_A
WRITE(*,*) A%AN_INT
END SUBROUTINE

SUBROUTINE PRINT_B
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_B
WRITE(*,*) B%AN_INT
END SUBROUTINE

END MODULE
PGI$ cat testp.f90
USE TESTM
A%AN_INT = 1
B%AN_INT = 2
CALL PRINT_A
CALL PRINT_B
END
PGI$ pgf90 -Mmakedll testm.f90 -o testm.dll
   Creating library testm.lib and object testm.exp
PGI$ pgf90 -Mdll -o testp.exe testp.f90 -defaultlib:testm
PGI$ testp.exe
            1
            2
  • Mat

This does not seem to work for me.

[chulbert@maxwell ~]$ cat testm2.f90
MODULE TESTM
TYPE A_TYPE
INTEGER :: AN_INT
END TYPE A_TYPE

COMMON /acommon/ A, B
TYPE(A_TYPE) :: A, B
!DEC$ ATTRIBUTES DLLEXPORT :: /acommon/
CONTAINS

SUBROUTINE PRINT_A
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_A
WRITE(,) A%AN_INT
END SUBROUTINE

SUBROUTINE PRINT_B
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_B
WRITE(,) B%AN_INT
END SUBROUTINE

END MODULE
[chulbert@maxwell ~]$ cat testp2.f90
USE TESTM
A%AN_INT = 1
B%AN_INT = 2
CALL PRINT_A
CALL PRINT_B
END
[chulbert@maxwell ~]$ pgf90 -V

pgf90 6.2-5 32-bit target on x86 Windows
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2006, STMicroelectronics, Inc. All Rights Reserved.
[chulbert@maxwell ~]$ pgf90 -Mdll -o testp2.exe testp2.f90 testm2.lib
testp2.obj : error LNK2019: unresolved external symbol __imp__acommon referenced in function MAIN
testp2.exe : fatal error LNK1120: 1 unresolved externals
testp2.f90:

For 6.2 32-bit Windows, add “-Munix”. Note that this will no longer needed with 7.0. Also, if you don’t mind, I’d like to send you a beta of 7.0 which has some of these issues fixed. I’ll email you with the details.

  • Mat

That would be great.

I also have windows x64 if you would like me to try compiling on that platform as well (although I do not yet have a license for 64-bit windows)l.

Mat,

The beta fixes the problem I got with the common block work around:

chulbert@hulbert ~
$ cat testm_com.f90
MODULE TESTM
TYPE A_TYPE
INTEGER :: AN_INT
END TYPE A_TYPE

COMMON /A_COM/ A
TYPE(A_TYPE) :: A
!DEC$ ATTRIBUTES DLLEXPORT :: /A_COM/

CONTAINS
SUBROUTINE PRINT_A
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_A
WRITE(,) A%AN_INT
END SUBROUTINE

END MODULE

chulbert@hulbert ~
$ cat testp.f90
USE TESTM
A%AN_INT = 1
CALL PRINT_A
END

chulbert@hulbert ~
$ pgf90 -V

pgf90 7.0-1 32-bit target on Windows
Copyright 1989-2000, The Portland Group, Inc. All Rights Reserved.
Copyright 2000-2006, STMicroelectronics, Inc. All Rights Reserved.

chulbert@hulbert ~
$ ./testp.exe
1

chulbert@hulbert ~
$ pgf90 -Mmakedll testm_com.f90
Creating library testm_com.lib and object testm_com.exp

chulbert@hulbert ~
$ pgf90 -otestp.exe -I. testp.f90 testm_com.lib
testp.f90:

chulbert@hulbert ~
$ ./testp.exe
1

However, without using the common block, they are still using different symbols:

chulbert@hulbert ~
$ cat testm.f90
MODULE TESTM
TYPE A_TYPE
INTEGER :: AN_INT
END TYPE A_TYPE

TYPE(A_TYPE),PUBLIC :: A
!DEC$ ATTRIBUTES DLLEXPORT :: A

CONTAINS
SUBROUTINE PRINT_A
!DEC$ ATTRIBUTES DLLEXPORT :: PRINT_A
WRITE(,) A%AN_INT
END SUBROUTINE

END MODULE

chulbert@hulbert ~
$ pgf90 -Mmakedll testm.f90
Creating library testm.lib and object testm.exp

chulbert@hulbert ~
$ pgf90 -otestp.exe -I. testp.f90 testm.lib
testp.obj : warning LNK4217: locally defined symbol _testm_0 imported in function MAIN
testp.f90:

chulbert@hulbert ~
$ ./testp.exe
0


This can be seen using dependency walker. In the first case, A_COM shows up as a symbol. In the second, A does not. If I look at the symbols of the object files, I can see that in testm.f90, the variable A gets mapped to _testm_0 (this I should have deduced from the warning about locally importing the symbol when compiling the exe). If I manually export that symbol in the DLL, I get the expected results (Note that this also works for 6.2-5).

chulbert@hulbert ~
$ pgf90 -Mmakedll -Wl,-export:testm_0 testm.f90
Creating library testm.lib and object testm.exp
testm.f90:

chulbert@hulbert ~
$ pgf90 -otestp.exe -I. testp.f90 testm.lib
testp.f90:

chulbert@hulbert ~
$ ./testp.exe
1

Hi Chris,

The beta was built on 12/20 before your report. I’ve logged this as TPR#4041 and a compiler engineer is looking into it. Hopefully we can have it fixed by the general release, but if not, it will go into a subsequent build of the month.

  • Mat