web-dev-qa-db-fra.com

Comment trouver l'emplacement de l'exécutable en C?

Existe-t-il un moyen en C/C++ de trouver l'emplacement (chemin complet) du programme en cours d'exécution?

(Le problème avec argv[0] est que cela ne donne pas le chemin complet.)

140
eran

Résumer:

  • Sur les Unix avec /proc, Le moyen le plus simple et le plus réaliste est de:

    • readlink("/proc/self/exe", buf, bufsize) (Linux)

    • readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)

    • readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)

  • Sous Unix sans /proc (C'est-à-dire si cela échoue):

    • Si argv [0] commence par "/" (chemin absolu), il s'agit du chemin.

    • Sinon, si argv [0] contient "/" (chemin relatif), ajoutez-le à cwd (en supposant qu'il n'ait pas encore été modifié).

    • Sinon, recherchez les répertoires dans $PATH Pour l'exécutable argv[0].

    Ensuite, il peut être raisonnable de vérifier si le fichier exécutable n’est pas réellement un lien symbolique. Si c'est le cas, résolvez-le par rapport au répertoire des liens symboliques.

    Cette étape n'est pas nécessaire dans la méthode/proc (du moins pour Linux). Là, le lien symbolique proc pointe directement vers l'exécutable.

    Notez que c'est au processus appelant de définir correctement argv[0]. C’est vrai la plupart du temps, mais il arrive parfois que le processus d’appel ne puisse pas être approuvé (ex. Setuid exécutable).

  • Sous Windows: utilisez GetModuleFileName(NULL, buf, bufsize)

188
lispmachine

Utilisez la fonction GetModuleFileName () si vous utilisez Windows.

21
Shino C G

Veuillez noter que les commentaires suivants sont uniquement Unix.

La réponse pédante à cette question est qu'il n'y a pas de général moyen de répondre correctement à cette question dans tous les cas. Comme vous l'avez découvert, argv [0] peut être défini sur n'importe quoi par le processus parent et n'a donc aucune relation avec le nom réel du programme ou son emplacement dans le système de fichiers.

Cependant, l'heuristique suivante fonctionne souvent:

  1. Si argv [0] est un chemin absolu, supposons qu'il s'agit du chemin complet de l'exécutable.
  2. Si argv [0] est un chemin relatif, c'est-à-dire qu'il contient un /, Déterminez le répertoire de travail actuel avec getcwd (), puis ajoutez-y argv [0].
  3. Si argv [0] est un mot simple, recherchez $ PATH à la recherche de argv [0] et ajoutez argv [0] au répertoire dans lequel vous le trouvez.

Notez que tout cela peut être contourné par le processus qui a appelé le programme en question. Enfin, vous pouvez utiliser des techniques spécifiques à Linux, telles que mentionnées par emg-2. Il existe probablement des techniques équivalentes sur d'autres systèmes d'exploitation.

Même en supposant que les étapes ci-dessus vous donnent un nom de chemin valide, vous n’auriez peut-être toujours pas le nom de chemin que vous voulez réellement (puisque je soupçonne que ce que vous voulez réellement faire est de trouver un fichier de configuration quelque part). La présence de liens durs signifie que vous pouvez avoir la situation suivante:

-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo     # create a hard link to foo
$ /some/where/else/foo

Maintenant, la démarche ci-dessus (y compris, je suppose,/proc/$ pid/exe) donnera /some/where/else/foo Comme véritable chemin d'accès au programme. Et, en fait, c’est un chemin réel du programme, mais pas celui que vous vouliez. Notez que ce problème ne se produit pas avec les liens symboliques qui sont beaucoup plus courants dans la pratique que les liens physiques.

Bien que cette approche soit en principe peu fiable, elle fonctionne assez bien dans la pratique pour la plupart des objectifs.

17
Dale Hagglund

Pas une réponse en fait, mais juste une note à garder à l'esprit.

Comme nous avons pu le constater, le problème de la localisation de l’exécutable en cours d’exécution est assez délicat et spécifique à la plate-forme sous Linux et Unix. Il faut réfléchir à deux fois avant de faire ça.

Si vous avez besoin de votre emplacement exécutable pour découvrir des fichiers de configuration ou de ressources, suivez peut-être la méthode Unix pour placer des fichiers dans le système: mettez configs dans /etc ou /usr/local/etc ou dans le répertoire de base de l'utilisateur actuel, et /usr/share est un bon endroit pour mettre vos fichiers de ressources.

10
Michael

Dans de nombreux systèmes POSIX, vous pouvez vérifier un lien virtuel situé sous/proc/PID/exe. Quelques exemples:

# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond
6
anon

Rappelez-vous que sur les systèmes Unix, le binaire peut avoir été supprimé depuis son démarrage. C'est parfaitement légal et sûr sur Unix. La dernière fois que j'ai vérifié, Windows ne vous permettra pas de supprimer un binaire en cours d'exécution.

/ proc/self/exe sera toujours lisible, mais ce ne sera pas vraiment un lien symbolique fonctionnel. Ce sera ... étrange.

4
Thomas

Sous Mac OS X, utilisez _NSGetExecutablePath .

Voir man 3 dyld et cette réponse à une question similaire.

3
Tim Ruddick

Pour Linux, vous pouvez trouver le /proc/self/exe manière de faire les choses dans une jolie bibliothèque appelée binreloc, vous pouvez la trouver à:

3
Grumbel

Je voudrais

1) Utilisez la fonction basename (): http://linux.die.net/man/3/basename
2) chdir () dans ce répertoire
3) Utilisez getpwd () pour obtenir le répertoire actuel

De cette façon, vous obtiendrez le répertoire sous une forme nette et complète au lieu de ./ ou ../bin/.

Peut-être voudrez-vous sauvegarder et restaurer le répertoire actuel, si cela est important pour votre programme.

0
JCCyC