Как найти местоположение исполняемого файла в C?
Есть ли способ в C/С++ найти местоположение (полный путь) текущей исполняемой программы?
(Проблема с argv[0]
заключается в том, что он не дает полного пути.)
Ответы
Ответ 1
Подводя итог:
-
В Unixes с /proc
действительно прямой и реалистичный способ:
-
readlink("/proc/self/exe", buf, bufsize)
(Linux)
-
readlink("/proc/curproc/file", buf, bufsize)
(FreeBSD)
-
readlink("/proc/self/path/a.out", buf, bufsize)
(Solaris)
-
В Unixes без /proc
(т.е. если выше не удается):
-
Если argv [0] начинается с "/" (абсолютный путь), это путь.
-
В противном случае, если argv [0] содержит "/" (относительный путь), добавьте его в cwd
(предполагая, что он еще не изменен).
-
В противном случае поиск каталогов в $PATH
для исполняемого argv[0]
.
Впоследствии может быть разумным проверить, не является ли исполняемый файл фактически символической ссылкой.
Если он разрешает это относительно каталога symlink.
Этот шаг не требуется в/proc-методе (по крайней мере для Linux).
Там процилинговая ссылка proc указывает на исполняемый файл.
Обратите внимание, что процесс вызова должен корректно установить argv[0]
.
Это правильно в большинстве случаев, однако есть случаи, когда вызывающему процессу нельзя доверять (например, исполняемый файл setuid).
-
В Windows: используйте GetModuleFileName(NULL, buf, bufsize)
Ответ 2
Используйте функцию GetModuleFileName(), если вы используете Windows.
Ответ 3
Обратите внимание, что следующие комментарии являются unix-only.
Педантичный ответ на этот вопрос заключается в том, что во всех случаях нет правильного общего способа ответить на этот вопрос. Как вы обнаружили, argv [0] может быть настроен на что-либо вообще родительским процессом и поэтому не должен иметь никакого отношения к фактическому имени программы или ее местоположению в файловой системе.
Тем не менее, следующая эвристика часто работает:
- Если argv [0] является абсолютным путем, предположим, что это полный путь к исполняемому файлу.
- Если argv [0] - относительный путь, т.е. он содержит
/
, определите текущий рабочий каталог с помощью getcwd(), а затем добавьте к нему argv [0].
- Если argv [0] является простым словом, найдите $PATH, ища argv [0], и добавьте argv [0] в любой каталог, в котором вы его нашли.
Обратите внимание, что все это можно обойти процессом, который вызвал рассматриваемую программу. Наконец, вы можете использовать специфичные для Linux методы, например, упомянутые emg-2. В других операционных системах, вероятно, есть эквивалентные методы.
Даже если предположить, что приведенные выше шаги дают вам правильное имя пути, вы все равно можете не иметь имя пути, которое вам действительно нужно (поскольку я подозреваю, что то, что вы на самом деле хотите сделать, это найти файл конфигурации где-нибудь). Наличие жестких ссылок означает, что вы можете иметь следующую ситуацию:
-- 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
Теперь подход выше (в том числе, я подозреваю, /proc/ $pid/exe) даст /some/where/else/foo
как реальный путь к программе. И, фактически, это реальный путь к программе, а не тот, который вы хотели. Обратите внимание, что эта проблема не возникает с символическими ссылками, которые на практике гораздо более распространены, чем жесткие ссылки.
Несмотря на то, что этот подход в принципе ненадежный, он работает достаточно хорошо на практике для большинства целей.
Ответ 4
На самом деле это не ответ, а просто примечание, которое нужно иметь в виду.
Как мы могли видеть, проблема поиска местоположения исполняемого исполняемого файла довольно сложна и специфична для платформы в Linux и Unix. Перед этим нужно подумать дважды.
Если вам требуется ваше место для поиска файлов конфигурации или ресурсов, возможно, вам следует следовать методу Unix по размещению файлов в системе: поместите конфиги в /etc
или /usr/local/etc
или в текущий домашний каталог пользователя и /usr/share
- хорошее место для размещения ваших файлов ресурсов.
Ответ 5
Во многих системах POSIX вы можете проверить simlink, расположенную под /proc/PID/exe. Несколько примеров:
# 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
Помните, что в Unix-системах двоичный файл может быть удален с момента его запуска. Это совершенно законно и безопасно для Unix. Последнее, что я проверил, Windows не позволит вам удалить исполняемый файл.
/proc/self/exe будет по-прежнему доступен для чтения, но на самом деле это не будет действующая символическая ссылка. Это будет... странно.
Ответ 7
Для Linux вы можете найти способ /proc/self/exe
делать вещи в комплекте с хорошей библиотекой binreloc, вы можете найти библиотеку по адресу:
Ответ 8
В Mac OS X используйте _NSGetExecutablePath
.
См. man 3 dyld
и этот ответ по аналогичному вопросу.
Ответ 9
Я бы
1) Используйте функцию basename(): http://linux.die.net/man/3/basename
2) chdir() в этот каталог
3) Используйте getpwd(), чтобы получить текущий каталог
Таким образом, вы получите каталог в аккуратной, полной форме, а не./или../bin/.
Возможно, вам захочется сохранить и восстановить текущий каталог, если это важно для вашей программы.