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

get name of the exe file

dboggs
New Contributor I
988 Views

I distribute various versions of an executable file to various people for testing and comment. The versions are distinguished by the name of the file, e.g. "testfile_1a.exe", testfile_2b.exe", etc. The program produces a text file output. I would like the first line of this text file to contain the name of the executable that produced it (so that when they return with their sample output I can tell how they actually got it). Is this possible? I cannot find an intrinsic or extended Fortran function that does this. Perhaps an environment variable?

0 Kudos
9 Replies
mecej4
Honored Contributor III
988 Views

You can call GETARG(0,..), but you will not have any protection from your users changing the EXE name (for any number of reasons, including not wanting to have a long name, not having a name that is already used for another file, etc).

0 Kudos
andrew_4619
Honored Contributor II
988 Views

The F2003?8  std GET_COMMAND_ARGUMENT does that aslo(arg 0) though why not just code a versionID in the software

0 Kudos
dboggs
New Contributor I
988 Views

Thanks for the suggestions, I will check them out.

The reason I do not code a version ID in the source file is it's "dangerous": It's too easy to forget to update it when preparing a new version, or worse yet to revert it to a previous version when I want to make a minor-minor change in that. Also, it's VERY beneficial for the users/testers to SEE which particular exe file version they want to run without waiting for the output file to tell them they chose the right or wrong one.

So, its best (for this case anyway) to code the version into the file name, and make it automatic to appear correctly in the output.

Of course users CAN change the file name (accidentally or maliciously or with good intentions), so it may not be a good system in general.

0 Kudos
Steve_Lionel
Honored Contributor III
988 Views

The best way to do this on Windows is:

1. Call the Windows API routine GetModuleHandle , passing a NULL argument. This gets you the handle to the current EXE

2. Call GetModuleFileName on the returned handle.

0 Kudos
dboggs
New Contributor I
988 Views

Yes, perhaps the best way in Windows, but how portable is it? Eventually, the program will need to work with other compilers and other operating systems, including Linux and (maybe even!) Unix. It's a huge code, been around for many years, has had various coders work on it, and all have been very careful to use only intrinsic Fortran operations.

0 Kudos
Steve_Lionel
Honored Contributor III
988 Views

There is no truly portable way to do this. GET_COMMAND_ARGUMENT (and the nonstandard GETARG) will work sometimes, but "argument 0" is specified as being the "command" that invoked the program, not necessarily the name or path to the executable.

0 Kudos
JVanB
Valued Contributor II
988 Views

There is a way that's supposed to be portable using C interoperability. Suppose we create a file version.txt:

This is version 1.0.1

We can use the objcopy utility that comes with gfortran to make this into an object file:

D:\>objcopy --input binary --output pe-x86-64 --binary-architecture i386:x86-64 version.txt version.o

This is suitable for Windows x64 programs. Now we can write a program that uses C interoperability to read the embedded data:

module M
   use ISO_C_BINDING
   implicit none
   character(KIND=C_CHAR), bind(C,name='_binary_version_txt_start'), target :: version_start
   integer(C_INT), bind(C,name='_binary_version_txt_size'), target :: version_len
end module M

program P
   use ISO_C_BINDING
   use M
   implicit none
   character(LEN=:,KIND=C_CHAR), pointer :: version
   type(C_PTR) version_ptr, len_ptr
   version_ptr = C_LOC(version_start)
   len_ptr = C_LOC(version_len)
write(*,*) transfer(version_ptr,0_C_INTPTR_T)
write(*,*) transfer(len_ptr,0_C_INTPTR_T)
   BLOCK
      character(LEN=transfer(len_ptr,0_C_INTPTR_T),KIND=C_CHAR), pointer :: temp
      call C_F_POINTER(version_ptr,temp)
      version=>temp
   END BLOCK
   write(*,'(a)') version
end program P

Now we can link this with the version.o file we made earlier:

D:\>gfortran P.f90 version.o -oP

D:\>P
              4206608
                   23
This is version 1.0.1

So we get our embedded data back. Unfortunately ifort+link.exe doesn't feel the same way about this as ld.exe does; I don't know whether that's a problem with the linkers or with the Fortran compilers. It seems reasonable enough, though, and gfortran likes it OK, so I don't know what the problem is with ifort. I guess we might be able to work around this situation with _binary_version_txt_end instead:

module M
   use ISO_C_BINDING
   implicit none
   character(KIND=C_CHAR), bind(C,name='_binary_version_txt_start'), target :: version_start
   character(KIND=C_CHAR), bind(C,name='_binary_version_txt_end'), target :: version_end
end module M

program P
   use ISO_C_BINDING
   use M
   implicit none
   character(LEN=:,KIND=C_CHAR), pointer :: version
   type(C_PTR) version_ptr
   integer(C_INTPTR_T) version_len
   version_ptr = C_LOC(version_start)
   version_len = transfer(C_LOC(version_end),0_C_INTPTR_T)-transfer(version_ptr,0_C_INTPTR_T)
write(*,*) transfer(version_ptr,0_C_INTPTR_T)
write(*,*) version_len
   BLOCK
      character(LEN=version_len,KIND=C_CHAR), pointer :: temp
      call C_F_POINTER(version_ptr,temp)
      version=>temp
   END BLOCK
   write(*,'(a)') version
end program P

Now, I get the same result with

D:\>gfortran P2.f90 version.o -oP2

D:\>P2
              4206608
                   23
This is version 1.0.1

And a positive result this time with ifort:

D:\>ifort /nologo P2.f90 version.o
ifort: command line warning #10161: unrecognized source type 'version.o'; object
 file assumed

D:\>P2
       140699452588044
                    23
This is version 1.0.1

So it looks like this should be portable to anything gcc has been ported to which may be a superset of platforms supporting Fortran 2003.

Reference: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967

0 Kudos
LRaim
New Contributor I
988 Views

The windows function GetCommandLine returns the execution command completed with the full path of the .exe module.
​This feature is quite useful but is not implemented in the Fortran function GET_COMMAND or GET_COMMAND_ARGUMENT.

 

0 Kudos
dboggs
New Contributor I
988 Views

I have been experimenting with two intrinsic routines, GETARG (0, buffer) and GET_COMMAND (buffer). Both of these return the entire path spec of the command in buffer. The documentation is not very clear on this. I prefer to get the command only, so I use SPLITPATHQQ to get that.

The suggested methods using Windows API and C interoperability seem way too much trouble, at least for my current casual need.

And just to be clear, routines GET_COMMAND and GET_COMMAND_ARGUMENT are standard. GETARG appears to be a nonstandard equivalent to GET_COMMAND_ARGUMENT.

0 Kudos
Reply