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

how to get a console program's folder location at run time

Brian_Murphy
New Contributor II
2,167 Views

This question is specific to the Windows OS.  Is the code below the recommended way for a console program to get the folder in which it is located at run time?  Note I do not want the "current working folder" or "default path".  I want the location of the EXE file.  This code is from a very old post.

Subroutine get_exe_path(gpth,npth) !get exe path from cmd line 
    implicit none 
    integer, intent(out)          :: npth 
    character(len=*), intent(out) :: gpth 
    integer                       :: ilen, istat   
    character(len=512)            :: garg 
    gpth=' ' 
    npth=0 
    call get_command_argument (0, garg, ilen, istat) !an intrinsic function
    if(istat == 0) then 
        npth=index(garg,'\',.true.) !an intrinsic function, true means search backward
        gpth=garg(1:npth) 
    endif 
end subroutine

 

0 Kudos
11 Replies
Paul_Curtis
Valued Contributor I
2,167 Views

I use a different WinAPI; in the example, the .exe file is always located in a \bin subdirectory to the root directory for the program itself:

!   get local root path from opsys
localroot = ''
nc = GetModuleFileName(GetModuleHandle('MYPROG.EXE'C), fpname, LEN(fpname))
IF (nc > 0) THEN
    CALL updncase (fpname, 1)
    nc = INDEX(fpname, '\BIN\MYPROG.EXE')
    IF (nc > 0) localroot = fpname(1:nc - 1)
END IF

 

0 Kudos
FortranFan
Honored Contributor III
2,167 Views

I suggest Windows API GetModuleFileName also as indicated in Quote #2:

https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamea

Re: "way for a console program to get the folder in which it is located at run time," note in Microsoft documentation, "A handle to the loaded module whose path is being requested. If this parameter is NULL, GetModuleFileNameretrieves the path of the executable file of the current process."

You may know Intel Fortran team provides an interface to said API in their KERNEL32 Fortran module:

https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-supplied-windows-api-modules

0 Kudos
Brian_Murphy
New Contributor II
2,167 Views

Thanks.  Is this recommended over using pure fortran ?  If so, why?  I prefer an all fortran approach in case this code is ever ported to Unix.  The following is a slight revision I plan  to use.  When I append the name of a file to gpth, I evidently have to use TRIM(gpth).  How does one take advantage of automatic deallocation and reallocation of strings such that gpth = gpth(1:len(trim(gpth))) would shorten the string?

Subroutine get_exe_path(gpth) !get exe path from cmd line with trailing backslash 
    implicit none 
    character(len=*), intent(out) :: gpth 
    integer                       :: ilen, istat, i
    character(len=4096)           :: s 
    call get_command_argument(0, s, ilen, istat) 
    i=0
    if(istat == 0) i = index(s,'\',.true.) 
    gpth = ' '
    if(i .gt. 0) gpth = s(1:i)
end subroutine  

0 Kudos
GVautier
New Contributor II
2,167 Views

Hi

Your approach will not work under windows if the program is launched from a console without path in the command line (program in current directory or in the path).

Ex:

cd programdir

program.exe

args[0] will contain only "program.exe"

GetModuleFilename is the unique solution under windows.

 

 

 

 

0 Kudos
Brian_Murphy
New Contributor II
2,167 Views

I see what you mean, and I confirmed it with a test.  The following seems to do the trick:

Subroutine get_exe_path(exepath) !get exe path with trailing backslash
    use KERNEL32
    implicit none 
    character(len=*), intent(out) :: exepath 
    integer                       :: ilen, i
    character(len=4096)           :: s 
    ilen = GetModuleFileName(NULL, s, 4096) 
    i = index(s,'\',.true.) 
    exepath = ' '
    if(i .gt. 0) exepath = s(1:i)
end subroutine 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,167 Views

I am not sure about Linux when the program is launched via Symbolic Link. IOW does arg[0] contain the path of the Symbolic Link or the path of the target of the Symbolic Link. This is something you would have to check out.

Jim Dempsey

0 Kudos
Brian_Murphy
New Contributor II
2,167 Views

What is IOW?  The need to support Unix/Linux is not absolutely required at this time.  Please correct me if I'm wrong, but since the Fortran standard does not provide a way for an executable to determine the folder where it is located, I'll use the Windows API to get it.  I suppose it makes sense that doing so would be OS dependent.  The reason for wanting the location of this folder is to access other files which are co-located with the EXE file.  In this case those other files are being read, but are not written to.

0 Kudos
Steve_Lionel
Honored Contributor III
2,167 Views

IOW = In Other Words

You are correct that the Fortran standard does not specify a method to do what you want.  On Windows, GetModuleFileName is exactly correct if you want a path to the executable.

0 Kudos
GVautier
New Contributor II
2,167 Views

If you want your code  to be OS independent, the path separator will in every case be a problem. You must write a function that determine the current OS and first set the actual path separator \ for Windows, / for Linux. Then you must write path management functions and use them everywhere in your code where you use pathes. And so on  It's not as so easy as it may appear at the first look.

 

Grouping all OS dependent subroutines, functions and constants in an "OS" named module may be a good approch. You only have to link the appropropriate module to generate the exe for a specific OS

 

0 Kudos
Brian_Murphy
New Contributor II
2,167 Views

The immediate need is just Windows.  Since supporting another OS depends on the OS, that will be addressed when the need arises.

0 Kudos
GVautier
New Contributor II
2,167 Views

Yes, immediately not, but if you do the job for Windows now, the work to implement another OS will be half done because you will not have to review all your code to port the program to Linux, but just write a new OS module and link it to the rest of the code.

 

 

0 Kudos
Reply