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

Understanding how dll works

Liang_W_1
Beginner
616 Views

We used to work with static library and now decided to switch to dll. Here is the problem that we are facing. I have a large source file that contains hundreds of subroutines, but they can be classified into two kind of subroutines, one kind is the system subroutines (syssrc.for) which can not be reached by the users, while the other kind is the user subroutines (usr.for which are called by some routines in syssrc.for) which users can modify or print out some data from them.

The procedure I did is that,

1.  Add  !DEC$ ATTRIBUTES DLLEXPORT :: "nameofsubroutines" under every subroutines in usr.for.

2. Build dll using usr.for to generate dllusr.dll and dllusr.lib files.

3. Add   !DEC$ ATTRIBUTES DLLEXPORT :: "nameofsubroutines" under every subroutines in syssrc.for

4. Build dll using syssrc.for and dllusr.lib (need dllusr.dll in the same folder), to generate dllsyssrc.dll and dllsyssrc.lib.

5. Create a application with main program and link dllsyssrc.lib. 

In this way, I could call the subroutines in both usr.for and syssrc.for. But the usr.for that should be modified by users can not be overwritten or replaced the one in usr.for since these subroutine are embedded in dllsyssrc.lib.

Does anyone has idea what kind of modifications or configurations should I set to let the project ignore the usr.for in dllsyssrc.lib and use the updated one?

Thank you

0 Kudos
1 Solution
Steven_L_Intel1
Employee
616 Views

That'a not the issue here. It has to do with which routine does the linker find first, and can you get the linker to avoid complaining about duplicates. I think it's possible but I have to work out an example.

A key is that the reference to the routine you want to substitute MUST be in the main program - it can't be referenced from the DLL.

View solution in original post

0 Kudos
7 Replies
Liang_W_1
Beginner
616 Views

Here are sample codes that I created to illustrate the function.

usr.for

      SUBROUTINE USRDIVD(A,B,C)   
      !DEC$ ATTRIBUTES DLLEXPORT :: USRDIVD
      IMPLICIT REAL*8(A-H,O-Z)
      WRITE(*,*) "PAUSE"
      PAUSE
      RETURN
      END

syssrc.for

      SUBROUTINE ADD(A,B,C)       
      IMPLICIT REAL*8(A-H,O-Z)
      !DEC$ ATTRIBUTES DLLEXPORT :: ADD      
      C = A+B
      WRITE(*,*) "C = A+B=",C
      CALL MINUS(A,B,C)
      CALL USRDIVD(A,B,C) 
      RETURN
      END
C      
      SUBROUTINE MINUS(A,B,C)
      !DEC$ ATTRIBUTES DLLEXPORT :: MINUS
      IMPLICIT REAL*8(A-H,O-Z)
      C = A-B
      WRITE(*,*) "C = A-B",C
      RETURN
      END     
C

Main program

      PROGRAM MAIN
      !DEC$ ATTRIBUTES DLLIMPORT :: ADD      
      IMPLICIT REAL*8 (A-H,O-Z)
      A = 10.D0
      B = 15.D0
      CALL ADD(A,B,C)    
      END PROGRAM MAIN
      
      SUBROUTINE USRDIVD(A,B,C)
	!DEC$ ATTRIBUTES DLLIMPORT :: USRDIVD      
      WRITE(*,*) "PAUSEHAHAH"
      PAUSE
      RETURN
      END      

How can I use user defined USRDIVD instead of the default one?

Thanks

0 Kudos
Michael7
Beginner
616 Views

Liang

You will need to create the Interface Module. It should something like this:

 Module myModule
  Interface
   Subroutine mySub(myArg1, myArg2,..)
    Integer::myArg1,...
    Real*8::myARg2,...
   End Subroutine
  End Interface
 End Module

Then you must compile the module and include the following statements in your calling program

 include myLib.LIB
 Use myModule

Michael

 

 

 

0 Kudos
Liang_W_1
Beginner
616 Views

Hi, Michael

I have created a module (mod.for) as you suggested

      MODULE DIVDMOD
      INTERFACE
         SUBROUTINE USRDIVD(A,B,C)
	   IMPLICIT REAL*8 (A-H,O-Z)
	   END SUBROUTINE USRDIVD
      END INTERFACE
      END MODULE DIVDMOD

and also modified the syssrc.for to be 

      SUBROUTINE ADD(A,B,C) 
      USE DIVDMOD      
      IMPLICIT REAL*8(A-H,O-Z)
	!DEC$ ATTRIBUTES DLLEXPORT :: ADD   
      C = A+B
      WRITE(*,*) "C = A+B=",C
      CALL MINUS(A,B,C)
      CALL USRDIVD(A,B,C) 
      RETURN
      END
C      
      SUBROUTINE MINUS(A,B,C)
	!DEC$ ATTRIBUTES DLLEXPORT :: MINUS
      IMPLICIT REAL*8(A-H,O-Z)
      C = A-B
      WRITE(*,*) "C = A-B",C
      RETURN
      END     

Then I compile these two files together with dllusr.lib to generate a new  dllsyssrc.lib.

It seems that it still doesn't work in this case. The multiple definitions that follows the main program is sill not able to replace the one in dll.

Thanks

0 Kudos
Michael7
Beginner
616 Views

Hi Liang

You also need to add the alias attribute:

 

!DEC$ATTRIBUTES DLLEXPORT :: xxx
!DEC$ATTRIBUTES ALIAS: 'xxx' :: xxx

 

0 Kudos
mecej4
Honored Contributor III
616 Views

In the compiler's examples directory you will find a "DLL_Shared_Data" example. The main point is that you have to get the linker to make the module variable appear in a shared data segment. Otherwise, the DLL and the EXE will have separate copies of the module data, causing updates in one to be unseen in the other.

0 Kudos
Steven_L_Intel1
Employee
617 Views

That'a not the issue here. It has to do with which routine does the linker find first, and can you get the linker to avoid complaining about duplicates. I think it's possible but I have to work out an example.

A key is that the reference to the routine you want to substitute MUST be in the main program - it can't be referenced from the DLL.

0 Kudos
Liang_W_1
Beginner
616 Views

Hello, I finally came up a solution. 

The user could actually create there own dllusr.dll by modifying the usr.for and then replace the one that exist in the final application folder.

For example, the user could save 

09   SUBROUTINE USRDIVD(A,B,C)
10 !DEC$ ATTRIBUTES DLLEXPORT :: USRDIVD     
11   WRITE(*,*) "PAUSEHAHAH"
12   PAUSE
13   RETURN
14

  END

in a separate file and generate a new dll file and replace the old one before compiling the application. 

0 Kudos
Reply