LINUX.ORG.RU

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

 , ,


0

1

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

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

★★

Последнее исправление: safocl (всего исправлений: 2)

я так понимаю std::filesystem не содержит такой возможности?

надо будет по подобию which делать ?

safocl ★★
() автор топика

относительные пути

Относительные относительно бинаря или таки рабочего каталога?

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

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

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

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

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

еееее — даааа —

fs::read_symlink("/proc/self/exe")
работает именно так как я хотел

думаю можно закрывать.

для винды аналог как я понимаю енто GetModuleFileName?

спс всем.

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

Правильно сказали - конфигурировать пути при cборке.

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

X512 ★★★★★
()
Ответ на: комментарий от 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
()

fs::read_symlink(«/proc/self/exe»)

Хрена вы норкоманы.

int main(int argc, char* argv[]) {

   std::cout << std::filesystem::absolute(argv[0]) << std::endl;
   return 0;
}

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

Но в целом, глобальную проблему ТС решает именно такой подход, только и правда последние два пункта надо свапнуть.

pon4ik ★★★★★
()

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

Резолвить 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
()
Ответ на: комментарий от anonymous

Лол, значит я был не прав, интересный факт, спасибки.

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

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

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

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

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

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

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

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

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

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

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

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

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

safocl ★★
() автор топика

кстати нашел один кроссплатформенный способ — через SDL2/SDL_filesystem.h — функция SDL_GetBasePath() возвращает реальный путь нахождения проги.

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

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

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

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

Можно натравить which или своровать код поиска (по списку путей в PATH).

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

так а способ с применением sdl2 который я выше привел он что не везде работает где есть sdl2?

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

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

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

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

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

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

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

Едва ли от автора можно ожидать что он знает как получить путь к бинарнику на всех существующих системах.

Я допишу (для Haiku). Дело 5 минут.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

да все в общем то норм ищется...

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

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

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

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

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

deep-purple ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.