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.)
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)
Utilisez la fonction GetModuleFileName () si vous utilisez Windows.
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:
/
, Déterminez le répertoire de travail actuel avec getcwd (), puis ajoutez-y argv [0].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.
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.
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
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.
Sous Mac OS X, utilisez _NSGetExecutablePath
.
Voir man 3 dyld
et cette réponse à une question similaire.
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 à:
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.