Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[C/Unix] Chemin d'un exécutable

7 réponses
Avatar
JKB
Bonjour à tous,

Je me heurte à un problème très bête mais que je n'arrive pas à
résoudre (d'autant qu'une solution portable serait appréciée). Je
cherche à connaître le chemin absolue de l'exécutable en cours (truc
écrit en C). J'arrive sans problème à avoir le répertoire de
travail, le nom apparaissant sur la ligne de commande, mais comment
trouver ce {|@|^\@| de chemin de l'exécutable ? Cela m'éviterait de
devoir coder des trucs en dur lors de la compilation...

Toute aide sera la bienvenue,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.

7 réponses

Avatar
Stephane Chazelas
2007-06-19, 14:27(+00), JKB:
[...]
Je me heurte à un problème très bête mais que je n'arrive pas à
résoudre (d'autant qu'une solution portable serait appréciée). Je
cherche à connaître le chemin absolue de l'exécutable en cours (truc
écrit en C). J'arrive sans problème à avoir le répertoire de
travail, le nom apparaissant sur la ligne de commande, mais comment
trouver ce {|@|^@| de chemin de l'exécutable ? Cela m'éviterait de
devoir coder des trucs en dur lors de la compilation...

Toute aide sera la bienvenue,
[...]


Il n'y a pas de methode portable, et parfois l'information n'est
meme pas disponible. Il faut voir aussi que quelqu'un peut
charger ton code sans faire de exec(2), donc le chemin de
l'executable ne fait pas forcement de sens.

Comme heuristique, tu peux utiliser argv[0] et parcourir $PATH
si argv[0] ne contient pas de "/".

Ca marchera dans la plupart des cas.

Sous linux, readlink("/proc/self/exe");

--
Stéphane

Avatar
JKB
Le 19-06-2007, à propos de
Re: [C/Unix] Chemin d'un exécutable,
Stephane Chazelas écrivait dans fr.comp.os.unix :
2007-06-19, 14:27(+00), JKB:
[...]
Je me heurte à un problème très bête mais que je n'arrive pas à
résoudre (d'autant qu'une solution portable serait appréciée). Je
cherche à connaître le chemin absolue de l'exécutable en cours (truc
écrit en C). J'arrive sans problème à avoir le répertoire de
travail, le nom apparaissant sur la ligne de commande, mais comment
trouver ce {|@|^@| de chemin de l'exécutable ? Cela m'éviterait de
devoir coder des trucs en dur lors de la compilation...

Toute aide sera la bienvenue,
[...]


Il n'y a pas de methode portable, et parfois l'information n'est
meme pas disponible. Il faut voir aussi que quelqu'un peut
charger ton code sans faire de exec(2), donc le chemin de
l'executable ne fait pas forcement de sens.

Comme heuristique, tu peux utiliser argv[0] et parcourir $PATH
si argv[0] ne contient pas de "/".


Cela ne fonctionnera pas pour moi (le truc doit aussi pouvoir
fonctionner sous OpenVMS), ou alors il faudra que j'écrive une
routine par système ou type de systèmes.

Ca marchera dans la plupart des cas.

Sous linux, readlink("/proc/self/exe");


Tiens, c'est vrai, mais cela reste un truc qui ne fonctionnera que
sous Linux.

Je crois que je vais jouer au akwet pour déterminer ça correctement
à la compilation.

Merci en tout cas,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.


Avatar
Paul Gaborit
À (at) Tue, 19 Jun 2007 14:35:53 GMT,
Stephane Chazelas écrivait (wrote):
2007-06-19, 14:27(+00), JKB:
[...]
Je me heurte à un problème très bête mais que je n'arrive pas à
résoudre (d'autant qu'une solution portable serait appréciée). Je
cherche à connaître le chemin absolue de l'exécutable en cours (truc
écrit en C).
[...]


Il n'y a pas de methode portable, et parfois l'information n'est
meme pas disponible.


Et même si l'information est disponible, il se peut qu'elle n'est
aucune sens. Par exemple, si l'exécutable a été effacé depuis son
lancement... C'est un cas assez courant sur une machine où on fait des
mises à jour.

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>


Avatar
Jean-Louis Liagre
[...]

Sous linux, readlink("/proc/self/exe");


Tiens, c'est vrai, mais cela reste un truc qui ne fonctionnera que
sous Linux.


L'équivalent sous Solaris:

sprintf(path,"/proc/%d/path/a.out", getpid());
readlink(path, buf, size);


Avatar
JKB
Le 20-06-2007, à propos de
Re: [C/Unix] Chemin d'un exécutable,
Jean-Louis Liagre écrivait dans fr.comp.os.unix :
[...]

Sous linux, readlink("/proc/self/exe");


Tiens, c'est vrai, mais cela reste un truc qui ne fonctionnera que
sous Linux.


L'équivalent sous Solaris:

sprintf(path,"/proc/%d/path/a.out", getpid());
readlink(path, buf, size);


Intéressant. Sachant que je ne cherche dans cette application que le
_chemin_ de l'exécutable (et que je me contrefiche royalement de
savoir si cet exécutable est toujours sur le disque) car je cherche
un moyen de dire que si mon exécutable est danc /a/b/c/executable,
il doit lancer un préprocesseur qui est /a/b/c/preprocesseur (et non
pas en faisant confiance au PATH), est-il possible d'imaginer
un bout de code capable de récupérer ce path quitte à le terminer
par des grands coups de #define ? Le problème majeur étant que je
n'ai pas tous les systèmes sous la main pour tester...

Pour l'instant, j'ai codé le truc en dur avec une option dans le
script configure, mais cela ne me plaît que moyennement. Je ne peux
pas utiliser la variable PATH car celle-ci peut trouver un
preprocesseur _avant_ le préprocesseur officiel et provoque un trou
de sécurité.

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.



Avatar
Marc
Jean-Louis Liagre wrote:

L'équivalent sous Solaris:

sprintf(path,"/proc/%d/path/a.out", getpid());
readlink(path, buf, size);


Je ne vois pas de /proc/*/path sous solaris 9 en tout cas. Sous solaris
on peut utiliser getexecname par exemple. Sinon dlinfo avec RTLD_SELF et
RTLD_DI_ORIGIN est bien pratique aussi.

Il me semble que le projet autopackage a une bibliothèque qui essaie de
faire ça sur plein de plate-formes en abstrayant l'aspect non portable.

Avatar
amaury-dlv
JKB a écrit le 19/06/2007 à 16h27 :
Bonjour à tous,

Je me heurte à un problème très bête mais que je
n'arrive pas à
résoudre (d'autant qu'une solution portable serait
appréciée). Je
cherche à connaître le chemin absolue de l'exécutable en
cours (truc
écrit en C). J'arrive sans problème à avoir le
répertoire de
travail, le nom apparaissant sur la ligne de commande, mais comment
trouver ce {|@|^@| de chemin de l'exécutable ? Cela m'éviterait
de
devoir coder des trucs en dur lors de la compilation...

Toute aide sera la bienvenue,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il
représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que
nous
consommons tous les jours.


Salut

j'ai écrit une petite fonction dans ce but (cf get_exec ci dessous). Je l'ai testé sous windows, linux et je pense que ca devrait marcher sans doute sous BSD et Solaris.

Cordialement


#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_PATH_LEN 1000


#ifdef _WIN32
const char *path_sep = "";
#else
const char *path_sep = "/";
#endif

/**********************************************************************
In a string (str_from), this function replaces all occurences
of a substring (str_find) with a smaller string (str_replace)
**********************************************************************/
void replace_smaller_substring_all(char *str_from, const char *str_find, const char *str_replace)
{
char *ptr_begin;

size_t len_find, len_replace;

len_find = strlen(str_find);
len_replace = strlen(str_replace);

if (len_replace <= len_find)
{
while ((ptr_begin=strstr(str_from,str_find)) != NULL)
{
memmove(ptr_begin, str_replace, len_replace);
memmove(ptr_begin + len_replace, ptr_begin + len_find, strlen(ptr_begin) + len_find + 1); // +1 is to include the '' at the end
}
}
}


/**********************************************************************
Copies the full path of the current executable into exec_full_path
argv[0] must be passed to the function
It is advised to call this function at the beginning of main()
so that the directory from where the user launched the executable
still corresponds to the current work directory returned by getcwd.
**********************************************************************/
void get_exec(char *exec_full_path, const char *argv0)
{
char *tail_char;
#ifdef _WIN32
/* On windows argv[0] always represents the full path to the executable */
strcpy(exec_full_path, argv0);
#else
char current_work_dir[MAX_PATH_LEN]="";
char exec_path[MAX_PATH_LEN]="";
char str_to_replace[4]="";

/* If argv[0] starts with "./", we remove it */
if ((*argv0 == '.') && (*(argv0+1) == *path_sep)) strcpy(exec_path, (argv0+2));
else strcpy(exec_path, argv0);

/* We replace the string "/./" by "/" anywhere in argv[0]
This is usefull if we want later on to move up and down in the path */
sprintf(str_to_replace, "%c.%c", *path_sep, *path_sep);
replace_smaller_substring_all(exec_path, str_to_replace, path_sep);

if (getcwd(current_work_dir, MAX_PATH_LEN) == NULL)
{
perror("Error from getcwd in function get_exec_directory");
abort();
}

/* Usually getcwd returns a path with no "/" at the end
but in case it does we remove it (by replacing it with '').
It is at least the case when the current work directory is the root (just "/") */
if (strlen(current_work_dir) >= 1)
{
tail_char = current_work_dir + strlen(current_work_dir) - 1;
if (*tail_char == *path_sep) *tail_char = '';
}

/* If argv[0] is a relative path (not starting with "/")
we add in front the current work directory */
if (*exec_path != *path_sep) sprintf(exec_full_path, "%s%c%s", current_work_dir, *path_sep, exec_path);
/* If argv[0] is already the full path. Note that on some Unix shells,
argv[0] will contain the full path if you have typed ".." in the command */
else sprintf(exec_full_path, "%s", exec_path);
#endif
}

int main(int argc, char *argv[])
{
char exec_full_path[MAX_PATH_LEN]="";

get_exec(exec_full_path,argv[0]);

printf("%sn",exec_full_path);
}