Problem importing Fortran routine from a dll

Problem importing Fortran routine from a dll

Аватар пользователя Mike K

I have a Fortran console application which is trying to import a routine from a Fortran dll.  I'm getting the following error message when linking.

error LNK2019: unresolved external symbol __imp__USELOG referenced in function _MAIN__

The interface for the routine is:
INTERFACE
   SUBROUTINE USELOG(logname, progname, version)
      !DEC$ ATTRIBUTES, ALIAS:'USELOG' :: USELOG
      !DEC$ ATTRIBUTES DLLIMPORT :: USELOG
      CHARACTER(LEN=26) :: logname
      CHARACTER(LEN=26) :: progname
      CHARACTER(LEN= 5) :: version
      !DEC$ ATTRIBUTES REFERENCE :: logname, progname, version
   END SUBROUTINE USELOG
END INTERFACE

The routine USELOG uses the following code for exporting:
   !DEC$ ATTRIBUTES DLLEXPORT :: USELOG
   !DEC$ ATTRIBUTES ALIAS:'USELOG' :: USELOG
   !DEC$ ATTRIBUTES REFERENCE :: logname_, progname_, version_

When I view the dll using dependency walker the routine is shown as USELOG without any decoration.

Could someone please tell me how to import this correctly.

Regards, Mike

 

12 сообщений / 0 новое
Последнее сообщение
Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.
Аватар пользователя Steve Lionel (Intel)

You need to link against the .lib generated when the DLL was built. If you tried linking to the DLL directly, that was ignored.

Steve
Аватар пользователя Mike K

I did link against the import lib.  I have it listed in the Linker/Advanced/Import Lib.

I also added the import lib to the project.

Mike

Аватар пользователя Steve Lionel (Intel)

Ah - I've seen that error before. That's not the right place to add that. You want it under Additional Dependencies. What you did was tell the linker to name the import library it creates, if it created one, which it won't for an executable project. Treat the import library the same as a static library.

Steve
Аватар пользователя Mike K

You are correct Steve.  I think I moved the import lib address from the Additional Dependencies in an attempt to fix the original problem which is an unresolved external.

I am trying to use the routine USELOG from the dll.  If I use an interface block in the calling program, I get this error:
error LNK2019: unresolved external symbol __imp__USELOG referenced in function _MAIN__ Besthb.obj

If I do not use an interface block, I get the following error:
error LNK2019: unresolved external symbol _USELOG referenced in function _MAIN__

Both errors say that the linker is looking for the routine USELOG with a prefix to the routine name.

Dependency Walker does not show any prefix when looking at the dll.

Mike

Аватар пользователя Mike K

I decided to try a different approach.  I created a static library to replace the dll.  I added that as the additional dependency instead of the dll import library.  I eliminated the Interface block.  However, I still get the error:
error LNK2019: unresolved external symbol _USELOG referenced in function _MAIN__

The USELOG routine does show up as _USELOG in a Dumpbin listing of the static library.

Mike

Аватар пользователя Mike K

I solved the underlying problem.

In the UseLog routine being exported from the dll, the DECORATE command was missing.

The codes should have read:
!DEC$ ATTRIBUTES DLLEXPORT :: USELOG
!DEC$ ATTRIBUTES DECORATE, ALIAS:'USELOG' :: USELOG
!DEC$ ATTRIBUTES REFERENCE :: logname_, progname_, version_

Question: Is it possible to tell the calling routine not to expect decoration?

Regards, Mike

 

Аватар пользователя Steve Lionel (Intel)

You could remove the ALIAS,DECORATE directive entirely in both the called routine and the caller. since all you're doing is restating the default.

When you use DLLIMPORT, the __imp__prefix is added. This is resolved by the import library and tells the linker to optimize the call (removes a few extra instructions. You don't see the prefix when examining the library or DLL. DLLIMPORT is optional when calling procedures, but is required if you are referencing variables or COMMON blocks in DLLs.

I will also comment that a nice way to handle this sort of thing is to put your DLL routine in a module, with DLLEXPORT. Then when the called program USEs the module, it will automatically get the interface AND do a DLLIMPORT. DO make sure that the executable links to the DLL run-time libraries.

Steve
Аватар пользователя Mike K

I use modules in VB, but haven't used them in Fortran.

Are you suggesting placing the entire routine in a module like the sample code below, or only a interface block?

MODULE MOD_TEST 
   SUBROUTINE UseLog(logname, progname, version)     
     
  !DEC$ ATTRIBUTES DLLEXPORT :: USELOG
  !DEC$ ATTRIBUTES REFERENCE :: logname, progname, version

   IMPLICIT NONE

   INTERFACE
     SUBROUTINE USE_LOG(logname, progname, version);  
       !DEC$ ATTRIBUTES DLLIMPORT :: USE_LOG
       !DEC$ ATTRIBUTES DECORATE, ALIAS:'use_log' :: USE_LOG 
       CHARACTER(LEN=26) :: logname
       CHARACTER(LEN=26) :: progname
       CHARACTER(LEN=5)  :: version
  
       !DEC$ ATTRIBUTES REFERENCE :: logname, progname, version
     END SUBROUTINE USE_LOG
   END INTERFACE
 
    ! Type call list variables
   CHARACTER(LEN=26), INTENT(IN) :: logname
   CHARACTER(LEN=26), INTENT(IN) :: progname
   CHARACTER(LEN=5),  INTENT(IN) :: version

   CALL Use_Log(logname, progname, version) 
  
   RETURN
   END SUBROUTINE UseLog
END MODULE_TEST

Mike

Аватар пользователя Steve Lionel (Intel)

You would take out the INTERFACE - a routine in a module provides its own interface. See Doctor Fortran Gets Explicit - Again! for more information. Then add a USE MOD_TEST to the main program where you want the subroutine to be visible. You'll need to make the .mod file created when the module was compiled visible to the "Includes" path when building the executable. If you simply make the DLL project a dependent of the executable project, everything will be done automatically.

Steve
Аватар пользователя Mike K

In the sample code, the INTERFACE is actually for the routine USE_LOG  which is a C routine in another dll.  The Fortran routine USELOG is calling USE_LOG.

Mike

Аватар пользователя Steve Lionel (Intel)

Ah, I see. Yes, you need an interface for the C routine.

Steve

Зарегистрируйтесь, чтобы оставить комментарий.