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

loadlibrary relative path problem

Pedersen__M
Beginner
2,636 Views

I have a problem when calling loadlibrary with relative paths:

- compiled with default static libs, the loadlibrary does not work with relative paths after a call to DAXPY

- compiled with libs:dll, relative paths does not work at all

Details:

- intel fortran 2020 (Intel® Parallel Studio XE 2020 Composer Edition for Fortran Windows* Integration for Microsoft Visual Studio* 2019, Version 19.1.0055.16) - Visual studio 2019 (Microsoft Visual Studio Professional 2019, Version 16.4.5)

- compile options: /Od /warn:interfaces /module:"Debug\\" /object:"Debug\\" /Fd"Debug\vc160.pdb" /traceback /check:bounds /check:stack /libs:static /threads /Qmkl:sequential /c - linker options: /OUT:"Debug\Console13.exe" /INCREMENTAL:NO /NOLOGO /MANIFEST:NO /SUBSYSTEM:CONSOLE /IMPLIB:"C:\Users\mmpe\source\repos\Console13\Console13\Debug\Console13.lib"

 

Minimal example:

program Test
  use dfwin, only: loadlibrary
  implicit none

  print *, "rel path", loadlibrary('./tmp/tmp.dll')/=0
  CALL DAXPY(3,[1d0,2d0,3d0],[2d0,2d0,2d0], 1, [3d0,3d0,3d0],1)
  print *, "abs path after daxpy",  loadlibrary('C:/tmp/tmp.dll')/=0
  print *, "rel path after daxpy", loadlibrary('./tmp/tmp.dll')/=0
  end program

Output (multithreaded):

rel path T

abs path after daxpy T

rel path after daxpy F

 

Output (multithreaded dll):

rel path F

abs path after daxpy T

rel path after daxpy F

0 Kudos
12 Replies
jimdempseyatthecove
Honored Contributor III
2,636 Views

I suspect that your execuitable's (at time of launch) current directory is not what you expect. Note, depending on how you launch the application, the current directory is not necessarily the same directory as that of the .exe.

I haven't tested this, you can experiment:

INQUIRE (DIRECTORY=dir, EXIST=ex [, DIRSPEC=dirspec] [, ERR=label] [, ID=id-var] [, IOMSG=msg-var] [, SIZE=sz] [, IOSTAT=i-var])

where you would use "." as the directory, you add a character variable dirspec of sufficient size (say 500 characters), and you supply the DIRSPEC= argument as well as additional arguments as you see fit.

Place the INQUIRE and PRINT *,dirspec before and after the call to DAXPY

Jim Dempsey 

0 Kudos
andrew_4619
Honored Contributor III
2,636 Views

What do you want? I often get the path of the exe from the command line args function and then use that as part of an absolute path. Windows has a complicated hierarchy of saving folder locations that varies dependant on windows version and the current phase of the moon.

 

0 Kudos
Steve_Lionel
Honored Contributor III
2,636 Views

The program shown is incorrect. The path string supplied to LoadLibrary should be NUL-terminated and should use backslashes. If it works at all it is accidental.

When a program is run from Visual Studio, the current directory is the one with the project folder, not the executable.

0 Kudos
GVautier
New Contributor II
2,636 Views

andrew_4619 wrote:

I often get the path of the exe from the command line args function

Under certain circumstances, that doesn't work. Use GetModuleFileName instead and GetLongPathName next if the executable has been launched by its short name.

 

0 Kudos
Pedersen__M
Beginner
2,636 Views

Thank you for your fast replies

I have modified the example program according to your suggestions, see below.
I set the working dir from visual studio: project settings - debugging - current working directory: c:\

Findings:

- The current working directory is c:\ both before and after DAXPY as expected

- Intel fortran 2019 update 5: relative path works

- Intel fortran 2020, Multithreaded: relative path works only before DAXPY

- Intel fortran 2020, Multithreaded DLL: relative path does not work

 

 

Example program

    program Test
    use dfwin, only: loadlibrary
    implicit none
    character*255 dirspec
    LOGICAL ex
    INQUIRE (DIRECTORY='.', EXIST=ex, DIRSPEC=dirspec)
    print *, "CWD: ", trim(dirspec)
    print *, "rel path", loadlibrary('.\tmp\tmp.dll'//char(0))/=0
    CALL DAXPY(3,[1d0,2d0,3d0],[2d0,2d0,2d0], 1, [3d0,3d0,3d0],1)
    INQUIRE (DIRECTORY='.', EXIST=ex, DIRSPEC=dirspec)
    print *, "CWD: ", trim(dirspec)
    print *, "abs path after daxpy",  loadlibrary('C:\tmp\tmp.dll'//char(0))/=0
    print *, "rel path after daxpy", loadlibrary('.\tmp\tmp.dll'//char(0))/=0
    end program

Intel fortran 2019 update 5, Version 19.0.0052.16 (both "multithreaded" and "multithreaded dll")
 CWD: C:\
 rel path T
 CWD: C:\
 abs path after daxpy T
 rel path after daxpy T
 
 
Intel fortran 2020, Version 19.1.0055.16
Multithreaded
 CWD: C:\
 rel path T
 CWD: C:\
 abs path after daxpy T
 rel path after daxpy F
 
Multithreaded Dll
 CWD: C:\
 rel path F
 CWD: C:\
 abs path after daxpy T
 rel path after daxpy F

0 Kudos
GVautier
New Contributor II
2,636 Views

Call getlasterror after loadlibrary fails. The error code may help.

0 Kudos
Pedersen__M
Beginner
2,636 Views

getlasterror returns 0

0 Kudos
GVautier
New Contributor II
2,636 Views

So it's like DllMain returns false.

0 Kudos
GVautier
New Contributor II
2,636 Views

The write statement may reset the last error.

Try

iret=loadlibrary(...)

ierr=getlasterror()

write(...)... ret/=0,ierr

 

 

0 Kudos
LRaim
New Contributor I
2,636 Views

You may call:

DWORD GetCurrentDirectory( DWORD  nBufferLength,  LPTSTR lpBuffer)
before and after DAXPY and LoadLibrary to see what is changed. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,636 Views

I cannot say this for certain, the return of False may be a case of "The specified library was not loaded... because it is already present".

IOW

Implementation 1: The specified library is loaded
Implementation 2: The load operation succeeded

These two results are only equivalent when the specified library was not present in memory when the function call was made.

Suggestions:

1) Save the return handle from LoadLibrary into a SAVE (or module) integer(handle) variable or array of said variables in the event you have multiple libraries you desire to control. Initialize these with 0 to indicate not loaded.
2) Test saved handle prior to LoadLibrary and use that in place of performing redundant load library
3) After step 2), use GetProcAddress to obtain (first time) or confirm (second and later) entry points to desired procedures.
4) When finished with a given library, issue FreeLibrary (and remember to zero out saved handle, and all saved procedure entry points for that library)

See: https://docs.microsoft.com/en-us/windows/win32/dlls/using-run-time-dynamic-linking

Jim Dempsey

0 Kudos
Pedersen__M
Beginner
2,636 Views

@Luigi R: I was not able to call GetCurrentDirectory (In which module is it defined?). I have tried with both inquire as Jim suggest and with getcwd. In both cases the path is as expected and unchanged after DAXPY

@jimdempseyatthecove (Blackbelt): It is not related to opening the dll twice. It is the same if I invoke loadlibrary once after DAXPY

It seems to be related to visual studio in combination with intel fortran 2020 as it works when I compile from commandline with:

ifort test_rel_path.f90 /Qmkl:sequential /libs:static /fpp /list

I have attached the lst-files generated via cmd and VS.

0 Kudos
Reply