How does one package a derived type with type-bound procedures into a dynamic-link library (DLL)?

How does one package a derived type with type-bound procedures into a dynamic-link library (DLL)?

How does one package a derived type with type-bound procedures into a dynamic-link library (DLL)? Specifically, what all does one needs to include in the system-definition (DEF) file for EXPORT definitions?

Say I have a module with a public derived type with one public type-bound procedure. Also, say this derived type includes several other private type-bound procedures as well as private variables that are of other derived types. And say the public type-bound procedure calls other private type-bound procedures within the same type as well as it makes use of other private derived types and their private type-bound procedures. If I want to package this all into a DLL, what all do I need to include in the EXPORTS section of the DEF file for the linker?

In the above, private and public refer to attributes of Fortran module elements and their scope as defined by PRIVATE and PUBLIC statements.  Note I do appreciate the fact that the requirement for export definitions of symbols in a DLL is totally different from these Fortran module-scope attributes.  I’m simply bringing up a situation where a contrived connection exists.

In my project for a caller (i.e., a main program that is supposed to invoke the above-mentioned DLL at run-time), the linker input includes a LIB file corresponding to the DLL.  The linker, however, throws "error LNK2001: unresolved external symbol" messages unless I include EXPORT definitions in the DLL DEF file for every type-bound procedure that the public type-procedure calls, whether directly or indirectly. (For those of you who use compiler directives (!DEC$) instead, it is as if ATTRIBUTES DLLEXPORT needs to be specified for every procedure that is called by the public type-bound procedure). Is this only to be expected? Or am I missing something in my setup?

Consider an example:

 
MODULE MyMod
 
   USE OtherProcsMod, ONLY : OtherProc1, OtherProc2
  
   PRIVATE
  
   TYPE, PUBLIC :: MyPubType
     PRIVATE
     INTEGER :: MyInt
     REAL    :: MyReal
   CONTAINS
     PRIVATE
     PROCEDURE, PASS(This) :: PrivProc1
     PROCEDURE, PASS(This) :: PrivProc2
     !.. PUBLIC
     PROCEDURE, PASS(This), PUBLIC :: PubProc
   END TYPE MyPubType
  
CONTAINS
 
   SUBROUTINE PubProc(This, Arg1, Arg2)
  
     ..
     ..
    
     CALL This%PrivProc1(Arg1)
     ..
     CALL This%PrivProc2(Arg2)
    
   END SUBROUTINE PubProc
  
   SUBROUTINE PrivProc1(This, Arg1, Var1)
  
     ..
     ..
    
     CALL OtherProc1(Var1)
     ..
    
   END SUBROUTINE PrivProc1
  
   SUBROUTINE PrivProc2(This, Arg2, Var2)
  
     ..
     ..
    
     CALL OtherProc2(Var2)
     ..
    
   END SUBROUTINE PrivProc2
  
END MODULE MyMod
 

 

In my case, it is as if the linker expects DLLEXPORT definitions for PrivProc1, PrivProc2, etc. as well as OtherProc1, OtherProc2, etc.

Note if one were to create a DLL for set of FORTRAN-77 procedures and if only subroutine PubProc was needed by callers, then one only needed to the export definition for it in the DEF file.   The linker for a main program that call such as DLL is satisfied with a LIB file with the symbol definitions of PubProc.  So what is different with derived type procedures?  I think I am missing something due to my rather limited understanding of type-bound procedures, linker requirements, and so on.

Thanks much in advance,

 

7 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.

In the above code snippet, please ignore any mismatch you might find in procedure interfaces - see the call for PrivProc1 versus its declaration.  The snippet is only pseudo-code and I made mistakes while typing it up.  The actual code doesn't have any such errors and therefore, coding errors are not the cause for linker issues.  Note the linker errors occur when a calling program is attempting to statically link to the DLL using the exported LIB file.

By the way, it would be nice if I could edit my posting.  But the forum only allows it for comments, not for original posts.

Bild des Benutzers Steve Lionel (Intel)

You should use

!DEC$ ATTRIBUTES DLLEXPORT :: procname

in each of the type-bound procedures, public and private, where "procname" is the name of the specific procedure. I recommend this over .DEF files, but if you must, you will need to know the decorated name of the procedure, such as MYMOD_mp_PRIVPROC1. The advantage of using the DLLEXPORT directive is that a USE of the module will automatically turn these into DLLIMPORT.

Steve

Steve,

Zitat:

You should use

!DEC$ ATTRIBUTES DLLEXPORT :: procname

in each of the type-bound procedures, public and private, where "procname" is the name of the specific procedure

Can you please explain why that is the case?

As I mentioned earlier,

Zitat:

Note if one were to create a DLL with a set of FORTRAN-77 procedures and if only subroutine PubProc was needed by calling programs, then one only needed to the export definition for it in the DEF file.  The routines called by PubProc needn't be exported.  So the linker for a main program that calls such a DLL is satisfied with a LIB file with the symbol definitions of just PubProc.  So what is different with derived type procedures?

Steve,

Zitat:

You should use

!DEC$ ATTRIBUTES DLLEXPORT :: procname

in each of the type-bound procedures, public and private, where "procname" is the name of the specific procedure. I recommend this over .DEF files

Thanks for your suggestion re: the use of DLLEXPORT over module-definition file.  You must be surely aware of the pros and cons of these two options.  For the benefit of other readers, I attach a link to Microsoft's MSDN site that explains it nicely:

Zitat:

Pros and Cons of Using .DEF Files

Exporting functions in a .def file gives you control over what the export ordinals are. When you add additional exported functions to your DLL, you can assign them higher ordinal values (higher than any other exported function). When you do this, applications using implicit linking do not have to relink with the new import library that contains the new functions. This is very important, for example, if you are designing a third-party DLL for use by many applications. You can continue to enhance your DLL by adding additional functionality while at the same time ensuring that existing applications continue to work properly with the new DLL. The MFC DLLs are built using .def files.

Another advantage to using a .def file is that you can export functions using the NONAME attribute, which places only the ordinal in the exports table in the DLL. For DLLs with a large number of exported functions, using the NONAME attribute can reduce the size of the DLL file. For information about writing a module definition statement, see Rules for Module-Definition Statements. For more information about ordinal export, see Exporting Functions from a DLL by Ordinal Rather Than by Name.

The major disadvantage of using .a def file is that if you are exporting functions in a C++ file, you either have to place the decorated names in the .def file or define your exported functions with standard C linkage by using extern "C" to avoid the name decoration done by the compiler.

If you need to place the decorated names in the .def file, you can obtain them by using the DUMPBIN tool or by using the linker /MAP option. Note that the decorated names produced by the compiler are compiler specific. If you place the decorated names produced by the Visual C++ compiler into a .def file, applications that link to your DLL must also be built using the same version of Visual C++ so that the decorated names in the calling application match the exported names in the DLL's .def file.

Pros and Cons of Using __declspec(dllexport)

Using __declspec(dllexport) is convenient because you do not have to worry about maintaining a .def file and obtaining the decorated names of the exported functions. This method is suitable if, for example, you are designing a DLL for use with an application that you control.  If you rebuild the DLL with new exports, you also have to rebuild the application because the decorated names for exported C++ functions might change if you recompile with a different version of the compiler.

My situation is more like that of a 3rd party DLL and I've been using the .DEF file approach with several libraries written in C and it has worked well.

Regards,

 

Steve,

This other topic on this forum seems related to my query, you agree?

Would you know what is the status of developer issue DPD200239418 you had opened in connection with that one?

Thanks,

Bild des Benutzers Steve Lionel (Intel)

Ok, I understand the problem a bit more. Yes, it does seem as if DPD200239418 is relevant and that bug is not yet fixed.  I will add your report to the list. But in general you do need to DLLEXPORT type-bound-procedures in the specific procedures themselves. Ideally, you shouldn't have to do this for private procedures.

Steve

Melden Sie sich an, um einen Kommentar zu hinterlassen.