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
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
I suggest Windows API GetModuleFileName also as indicated in Quote #2:
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:
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
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).
args will contain only "program.exe"
GetModuleFilename is the unique solution under windows.
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
I am not sure about Linux when the program is launched via Symbolic Link. IOW does arg 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.
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.
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.
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
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.