views:

86

answers:

3

I develop my app in linux for both unix and win32(cross compile at each build) plataforms, so a ready to use function would be nice :). I'm using glib that has the 'gchar* g_get_current_dir(void)' function and it returns the current directory, but what I really need is the executable's dir. I'm inexperienced in C programming so any sugestions are welcome.

+1  A: 

GetModuleFileName in Windows. argv[0] in linux

NOTE: If you do cross-platform programming you should use also some cross platform libraries that hide this layer (Qt, wxWidgets, ACE, Boost[Don't know but I think it has something] ... )

Iulian Şerbănoiu
-1: `argv[0]` is not a useful or reliable method of getting the path in *nix.
Paul R
I was talking about linux - not unix
Iulian Şerbănoiu
Do you know any libraries I could use to abstract this? As I told I'm already using glib, but I didn't find any ready to use function that would get me executable's path
Thiado de Arruda
@Iulian: `*nix` means means Linux, Unix or any other Unix-like OS - `argv[0]` can contain just the name of the executable, a relative or full path to the executable, a null string, or just about anything else, depending on how the executable was launched. You should never rely on it.
Paul R
You can set `argv[0]` to whatever you want using `execv(3)` so it is not reliable.
cjg
Use some variables that are initialized at program startup and make some procedures to access them. (You initialized them in the platform dependant way - I don't think that there is something cross-platform without an additional abstraction layer - like those libraries mentioned above)
Iulian Şerbănoiu
+1: `GetModuleFileName()` is the only reliable way under Windows for the exact same reason than for *nix.
Adrien Plisson
i would add that, anyway, the executables for linux and windows will be different, so you can factor this into a function and use compile time flags (#if WINDOWS...#endif)
Adrien Plisson
@Paul,@cjg You are correct. I dug a little and I can confirm now that argv[0] is not as safe as I thought it would be. Thanks!
Iulian Şerbănoiu
+1 for the only MS Windows answer.
nategoose
A: 

I cannot speak to windows. However in UNIX, a fair percentage of the time it is possible, but it is not guaranteed. The reasons for this involve calls to exec from other programs like shell which in some circumstances can cloud where the executable lives, for example, a relative path like "../../../mybin/exe/myprogram". The PATH variable also makes it fun to track down an executable.

Let me ask: what are you trying to do, or, more correctly, why do you need to know? IMO you don't need to know. you can check getcwd() and if you are not running in a directory that works, exit. It should not matter where your executable image lives.

Here is one code hunk that works most of the time, not always!

requires a call from main, using argv[0], I am using popen() calls to shell to make the code fit in a small are, popen() is not always a great choice, this can fail if there are other executables earlier in the PATH with the same name:

char *
mypath(const char *src)
{
   FILE *cmd=NULL;
   static char path_2_me[PATH_MAX]={0x0};
   char tmp[PATH_MAX]={0x0};
   const char *basename=strrchr(src, '/');

   if(basename==NULL) 
        basename=src;
   else
        basename++;      

   if(memcmp(src, "./", 2)==0)      
     sprintf(path_2_me,"%s/%s", getcwd(tmp, PATH_MAX), basename);             
   else
   {
      sprintf(tmp, "/usr/bin/which %s", basename);
      cmd=popen(tmp, "r");      
      fgets(path_2_me, sizeof(path_2_me), cmd); /* one read only */
      pclose(cmd);
      /* check for what your version of which says on failure */
      if(memcmp(path_2_me, "no ", 3)==0)
         *path_2_me=0x0;
   }  

   return (*path_2_me) ?path_2_me: NULL;
}
jim mcnamara
A: 

Under Unix like operating systems that have the /proc directory you can readlink /proc/self/exe to get the actual executable files full path even when argv[0] does not have this.

This may not work, however, if the executable was started with fexecv (not available on many systems) and if that is implemented as a system call on your system. fexecv is just like execve except that it is passed an open file descriptor rather than a filename to run. Under Linux it is implemented by calling execve on the string generated by `"/proc/self/%i", fd", so the file would have to live in the file system at the time the program was started.

I think that GNU/Hurd supports fexecve natively.

It is possible for an executable file to be renamed or unlinked from the filesystem after it has been executed which makes it become an unnamed file which will go away as soon as it ceases to be open (in this context running a file usually requires it to be open by the kernel).

nategoose
Combining that and the #ifdefs preprocessor conditionals I think I can figure the rest myself, thanks.
Thiado de Arruda