LINUX.ORG.RU

C++ как получить путь запущенного приложения?

 , ,


0

1

использую c++17 c++20
имеется приложение, которое использует ресурсы используя относительные пути — как выяснить реальный путь в файловой системе до самого бинаря внутри кода?

апд
в общем найдено несколько способов:
1. только для систем с procfs — C++ как получить путь запущенного приложения? (комментарий)
2. по идее кроссплатформенный через sdl2 — C++ как получить путь запущенного приложения? (комментарий)
3. использовать метод нахождения используемый в which (определять является ли argv путем, если да то каким — относительным или абсолютным, если нет, то искать название бинарника по путям в env var PATH)

★★

Ответ на: комментарий от anonymous

относительные именно бинаря... — я просто юзаю файлы ресурсов — скажем бинарь может быть в /usr/bin, а ресы в /usr/share — неплоха было бы просто сделать ../share

но файл может же запускаться и просто по имени — тогда такой фокус не проходит по arcv[0].

safocl ★★ ()
Ответ на: комментарий от slovazap

Кроме винды и линукса есть ещё куча операционных систем.

Ещё один #elif __OSNAME__ дописать. Можно ещё через argv[0] путь получить, но там могут быть символьные ссылки и относительные пути.

X512 ★★★ ()
Ответ на: комментарий от X512

в argv[0] еще может быть ваще другое — енто же не путь запускного файла — енто команда запуска — она может состоять из вообще других слов, нежели путь к exe.

в ентом то и проблема — пока я не начал устанавливать прогу в /usr/bin все было норм — но когда поставил туда и запустил не путем а командой — тоесть просто по названию проги — перестали действовать относительные пути к ресурсам.

я просто изначально думал чо в std::filesystem реализован механизм обнаружения пути к exe — но увы — нет...

safocl ★★ ()
Последнее исправление: safocl (всего исправлений: 2)
Ответ на: комментарий от X512

потому что данные программа должна собирать с приоритетами:

  1. переменная среды MY_PROG_DATA

  2. через сборку препроцессора, $MY_PROG_DATA

  3. глобальное хостовые пути xdg

  4. пользовательские пути xdg

anonymous ()

Кросс-платформенного способа нет.

Резолвить argv[0] до абсолютного пути не помогает, если программа не была запущена по абсолютному пути:

$ cat ~/vcs/scripts/argv0.c 
#include <stdio.h>
int main(int argc, char ** argv) {
        puts(argv[0]);
        return 0;
}
$ make ~/vcs/scripts/argv0
cc     argv0.c   -o argv0
$ which argv0
/home/me/vcs/scripts/argv0
$ argv0
argv0

(Не говоря уже о том, что в системном вызове execve в argv[0] можно подставить любую чушь, не имеющую ничего общего с путём к исполняемому файлу.)

anonymous ()
Ответ на: комментарий от safocl

а ресы в /usr/share — неплоха было бы просто сделать ../share

Так делать глупо.

После старта бинарники:

  1. Он считывает переменные окружения PATH_БЛАБЛА_ДЛЯ_БЛА и т.п. Если их нет, то использует дефолт (man hier).

  2. Использует параметры, если их нет, то использует дефолты (man hier).

  3. Он читает конфиг, где определены пути. Если его нет, то использует дефолт (man hier).

  4. Он использует стандартные пути (man hier).

Полные пути рулят.

anonymous ()
Ответ на: комментарий от pon4ik

чуть выше уже был коммент на счет argv[0] — енто не путь исполняемого файла — а команда запуска программы — она может быть ваще не путем, да и ваще не особо относиться к названию бинаря проги.

safocl ★★ ()
Ответ на: комментарий от safocl

Разговор же идёт про обычный вариант сборки (/usr/bin, /usr/share и т.п.). С портабельной версией придётся работать через переменные окружения или ./бла-бла. Тут даже спорить не нужно.

anonymous ()
Ответ на: комментарий от safocl

Это linux-специфично и непереносимо.

Это если надо переносимо. Решение, естественно, неточное - нужно чтобы совпали алгоритмы и данные для поиска пути у приложения и у системы.

anonymous ()
Ответ на: комментарий от X512

Это ещё хуже. Бинарник и данные должны работать из любого места.

  • Кто это сказал?
  • Какие аргументы?
  • В каких пределах это должно работать?

Потому что либо ты хардкодишь абсолютный путь, либо относительный. В первом случае ты можешь бинарник переносить куда угодно и он продолжит работать. Во втором можешь переносить только параллельно с данными. В разных случаях может потребоваться разное.

Претензия здесь не к одному из этих вариантов, потому что требование ровно одно - бинарник должен работать так как его установили, и ему удовлетворяют оба. Но к способу получения пути к бинарнику который непереносим, и быдлокод с /proc/self/exe просто сломается на *bsd, haiku, macos и ещё куче систем.

slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

Но к способу получения пути к бинарнику который непереносим, и быдлокод с /proc/self/exe просто сломается на *bsd, haiku, macos и ещё куче систем.

ессесна — надо делать разные пути для проверки — сам способ не меняется на юникс подобных системах. — но выше же и сказано чо енто непереносимо...

safocl ★★ ()
Ответ на: комментарий от X512

Ещё один #elif OSNAME дописать.

Это говённый код который надо допиливать под каждую новую систему чтобы запустить. Едва ли от автора можно ожидать что он знает как получить путь к бинарнику на всех существующих системах. И потом всё уткнётся в систему где этого сделать вообще нельзя и всё равно будет добавлен универсальный способ с абсолютным путём.

В итоге получаем:

  • Коллекцию способов получить путь к бинарнику на несколько страниц мёртвого кода, из которого тестируется только тот что работает на системе автора
  • Теряем поддержку относительной переносимости, потому что она уже не везде работает

Поэтому собственно везде и всегда используются абсолютные пути, и это единственный правильный способ.

Можно ещё через argv[0] путь получить, но там могут быть символьные ссылки и относительные пути.

Нельзя, если бинарник запущен через $PATH там вообще пути не будет. Поведение зависит от шелла и на самом деле там вообще не обязано оказаться что-либо осмысленное.

slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

Какие аргументы?

В разных дистрибутивах разные пути. Если хранить данные относительно бинарника, то будет работать везде. Часто даже без перекомпиляции. Встречал вредителей, которые даже абсолютный путь к динамическим библиотекам при линковке бинарника прописывают. А потом долго ищешь почему нужная динамическая библиотека не загружается.

X512 ★★★ ()
Ответ на: комментарий от X512

Встречал вредителей, которые даже абсолютный путь к динамическим библиотекам при линковке бинарника прописывают.

я хароший — такого вроде еще не делал)) вухахахахах

safocl ★★ ()
Ответ на: комментарий от X512

В разных дистрибутивах разные пути. Если хранить данные относительно бинарника, то будет работать везде.

Разные пути в том числе и относительные, так что мимо.

Встречал вредителей, которые даже абсолютный путь к динамическим библиотекам при линковке бинарника прописывают.

Абсолютный путь при линковке нужно прописывать обязательно (так делает cmake например), потому что так разрешаются неоднозначности между разными версиями библиотек, а также статическими и данамическими библиотеками. Это никак не влияет на то как рантайм линкер ищет библиотеки.

slovazap ★★★★★ ()
Ответ на: комментарий от safocl

Ты не понял сути того что я пытаюсь донести

  • Это не полный список и никакой список не будет полным
  • Ты не сможешь протестировать код подо все системы
  • Это просто не нужно, ничего не даёт относительно абсолютных путей и не стоит усилий
slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

Разные пути в том числе и относительные

Нет. Относительные пути можно выбрать любые как захочет автор программы.

Абсолютный путь при линковке нужно прописывать обязательно

Нашёлся вредитель. Потом приходится руками от этого чистить.

так делает cmake например

Нет. По крайней мере не для всех ОС/дистрибутивов.

Это никак не влияет на то как рантайм линкер ищет библиотеки.

Ещё как влияет. Это ломает перемещение директории с программой и поиск библиотек (они могут оказаться в месте, отличным от прошитого во время линковки).

X512 ★★★ ()
Последнее исправление: X512 (всего исправлений: 2)
Ответ на: комментарий от slovazap

Но к способу получения пути к бинарнику который непереносим

Вариант с чтением и нормализацией (перевод в абсолютный путь и проход по символьным ссылкам) argv[0] во время запуска программы будет работать в большинства случаев. Можно использовать, когда не написан ОС-специфичный код.

X512 ★★★ ()