Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Annonces
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

Understanding how dll works

Liang_W_1
Débutant
1 552 Visites

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 Compliments
1 Solution
Steven_L_Intel1
Employé
1 552 Visites

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.

Voir la solution dans l'envoi d'origine

0 Compliments
7 Réponses
Liang_W_1
Débutant
1 552 Visites

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 Compliments
Michael7
Débutant
1 552 Visites

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 Compliments
Liang_W_1
Débutant
1 552 Visites

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 Compliments
Michael7
Débutant
1 552 Visites

Hi Liang

You also need to add the alias attribute:

 

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

 

0 Compliments
mecej4
Contributeur émérite III
1 552 Visites

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 Compliments
Steven_L_Intel1
Employé
1 553 Visites

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 Compliments
Liang_W_1
Débutant
1 552 Visites

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 Compliments
Répondre