LINUX.ORG.RU

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

 , ,


0

1

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

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

★★

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

в том то и прелесть ентого /proc/self/exe — енто симлинк именно на бинарь который исполняется — ему пофиг из какого места он вызван.

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

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

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

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

Что это значит? Относительный путь от бинарника до данных так же зависит от дистрибутива как и абсолютный. Где-то это ../share/foo, где-то ../../share/foo (где-то бинарники игры кладут в bin/games) и т.д.

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

Это поведение CMake по умолчанию, удачи с этим.

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

Да, для всех. Если конечно использовать find_package, а не руками прописывать -L/-l в link_flags(). Вот последнее это действительно вредительство, и да, от этого приходится чистить.

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

Иди-ка ты читай документацию по линкеру. Результат линковки с -L/path/to/libs -lfoo и /path/to/libs/libfoo.so будет одинаковый (но разница в том что первый вариант легко ломается изменением порядка -L, и появлении новых библиотек в разных локациях), абсолютных путей в бинарнике не будет и рантайм линкер в любом случае ищет библиотеки руководствуясь своими путями, хинтами и LD_LIBRARY_PATH.

Не если взять, например, вариант dlopen который требует явного пути, конечно же туда должен быть прописан только абсолютный путь, иначе работать вообще ничего не будет. libcrypto.so.111, например, который тебе нужен через dlopen, лежит только и исключительно в /lib, куда бы ты не положил бинарник.

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

Относительный путь от бинарника до данных так же зависит от дистрибутива как и абсолютный.

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

Иди-ка ты читай документацию по линкеру.

Я про DT_RPATH, если что.

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

Вообще да. Но если подумать, ведь эта current_directory нужна для облегчения работы с другими функциями, которые читают/пишут фс. А зачем для этого знать путь к себе? Ведь этого пути может и не быть. Можно представить себе систему, в которой нет процессов, вернее, процесс всего один (и не факт, что файл с бинарем существует на носителе), и которая тем не менее будет работать с носителем через std::filesystems. Получение пути к себе в таком случае бессмысленно, т.к. себя в смысле ФС не существует.

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

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

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

ах ты об этом - отсутствие пути означает что сначала надо поискать в стандартных местах, а затем в текущем каталоге.

deep-purple ★★★★★
()
Ответ на: комментарий от seiken

сейкен не существует, по ту сторону экрана сидит ии.

deep-purple ★★★★★
()
Ответ на: комментарий от seiken

А зачем для этого знать путь к себе?

лично сча мне енто надо что бы в коде можно было пользоваться ресурсами, подобными аудиофайлам и т.д. — тоесть иерархия каталогов проги такая — в корне есть bin, lib, share — так вот в bin ессесна бинарь, в lib либы, а в share ресурсы.
как задействовать енти ресурсы из share если запуск проги не обязательно будет из bin?
если запуск проги будет из bin — то при юзании в коде относительного пути "./../share/audio.opus" все будет норм, а если запуск из другого каталога??? — все верно — ресурсы будут отсчитываться относительно него и их там скорее всего не окажется.

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

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

Читал, читал … А почему это не то?

pavlick-fm /tmp/kore/examples/generic/assets $ pwd
/tmp/kore/examples/generic/assets
pavlick-fm /tmp/kore/examples/generic/assets $ ../../../../a.out
"/tmp/a.out"
pavlick-fm /tmp/kore/examples/generic/assets $ cat ../../../../1.cc
#include <filesystem>
#include <iostream>
using namespace std;
using namespace filesystem;

int main(int argc, char **argv)
{
        auto cur = current_path();
        cur /= argv[0];
        cout << canonical(cur) << endl;
}

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

если запуск происходит по команде? скажем для моего случая енто будет Watcher — тут нет пути... как узнать то?

safocl ★★
() автор топика
Ответ на: комментарий от deep-purple
$ cat ~/vcs/scripts/argv0.c 
#include <stdio.h>
int main(int argc, char ** argv) {
        puts(argv[0]);
        return 0;
}
$ make ~/vcs/scripts/argv0
cc     vcs/scripts/argv0.c   -o vcs/scripts/argv0
$ which argv0
/home/me/vcs/scripts/argv0
$ argv0
argv0
$ cat run.c
#include <unistd.h>
int main() { execlp("argv0", "zhopa", NULL); }
$ make run
cc     run.c   -o run
$ ./run
zhopa

В argv[0] может находиться что-то странное, даже совсем не похожее на имя исполняемого файла.

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

Ясно, вроде случаев, когда исполняемый в ПАТХ. Зашивал пути при конфигурировании и не заморачиваюсь.

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

тут весь момент в том чо я хочу чо бы моя прога работала как установленная, так и портабельная — отсюда и необходимость относительных путей к ресурсам — ессесна под ресурсами не подразумеваются рантайм либы для линковки…

Ну начни с того что поддержи абсолютные пути чтобы она работала как установленная - претензий уже не будет. А что значит портабельная? Чтобы можно было принести каталог с бинарником и ресурсами и это заработало? Без либ? Не заработает, не трать время. Вообще же для такого достаточно загружать ресурсы относительно текущего каталога.

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

Как ни странно, обойти это можно при помощи #!-скриптов, поскольку при их запуске интерпретатор получает настоящий путь к файлу в argv[1]:

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

Поэтому иногда софт делают «портативным», добавляя в него шелл-обёртку, которая делает base="$(dirname "$(realpath "$0")")" и передаёт полученный путь бинарнику.

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

А что значит портабельная? Чтобы можно было принести каталог с бинарником и ресурсами и это заработало?

именно.

Без либ?

либы ставятся в системе...

Вообще же для такого достаточно загружать ресурсы относительно текущего каталога.

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

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

Удачи!

Это надо что-то странное делать, чтобы в argv[0] не было пути исполняемого файла или символьной ссылки. Во всех типичных сценариях (двойной клик, запуск из консоли/скрипта, *.desktop файл) это работает.

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

а если ты запускаешь командой которая не содержит путь???
ты же полюбому и сам юзаешь множество команд без указания пути, такие как — ls, git, make и подобные... тут же не содержится пути... его надо узнавать подставляя поочереди пути из переменной PATH.

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

Удачи!

Это надо что-то странное делать, чтобы в argv[0] не было пути исполняемого файла или символьной ссылки. Во всех типичных сценариях (двойной клик, запуск из консоли/скрипта, *.desktop файл) это работает.

execl( "./a.out", "trogai_kabachok_nu", ... );
Binkledum
()

Вот тебе еще нарыл: getauxval(AT_EXECFN), чтобы не ипать мозг с выделением буфера под неизвестную длину в readlink. Или даже getauxval(AT_EXECFD) вместе с openat.

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

И кто мешает это сделать?

Здравый смысл. Нафига писать логику под абсолютные пути / относительные пути / PATH c разбивкой строки и итерациями, если можно сделать по человечески?

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

если можно сделать по человечески?

Как? Другого относительно кроссплатформенного способа нет.

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

Как? Другого относительно кроссплатформенного способа нет.

Перестать упарываться по кроссплатформенности самому и предложить хайкуистам слать патчи.

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

либы ставятся в системе...

Либы поставленные в системе не имеют ничего общего с теми либами с которыми собран бинарник.

к argv[0] нет — он будет же содержать путь

Ещё раз, во всех случаях путь он содержать будет.

А вот когда будет установлено в систему, будет уже проблема, и надо будет пользоваться системными путями

В Linux ровно один стандартным метод распространения ПО - родными пакетами, поэтому ты прежде всего должен сделать так чтобы тут не было проблемы.

енто все должно содержаться в кроссплатформенных либах — желательно в СТЛ.

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

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

В Linux ровно один стандартным метод распространения ПО - родными пакетами

…, а именно RPM, ибо Linux Standard Base. Остальное (deb, nix) — нестандартные наколеночные поделки. Только пользователей наколеночных поделок слишком много.

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

В Linux ровно один стандартным метод распространения ПО - родными пакетами

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

В кроссплатформенных не должно и быть не может.

какая то дичайшая ахинеальная бредятина уже поехала — чо за сутулость? как минимум уже в sdl2 есть функция. Про «не должно» енто ваще лютейший бред — в каждой проге чо ли надо делать один и тот же код? Нафиг ваще тада делают либы?

Код не обязан запускаться из файла...

с чего ты взял чо речь вообще идет о каком то коде который запускается из файла? — я вроде бы ясно и недвусмысленно указал, что ресурсы — подобные аудиофайлам, видеофайлам, картинкам и т.д.

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

нет ничего что требовало бы наличия относительного пути от бинарника до данных.

а если у тебя портативная версия — где ты будешь искать ресы если не относительно бинарника?

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

Сделай себе переменную окружения *_CONFIG_DIRECTORY и читай её из программы. Если не найдешь - матюгайся в stderr и падай с EXIT_FAILURE.

Переменную окружения задавай в скрипте запуска.

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

а LFS тоже не следуемый ентому стандарту?

http://www.linuxfromscratch.org/lfs/view/stable/prologue/standards.html

Creating a complete LFS system capable of passing the LSB certifications tests is possible, but not without many additional packages that are beyond the scope of LFS. These additional packages have installation instructions in BLFS.

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