LINUX.ORG.RU

Проприетарная программа


1

3

Здравствуйте. Допустим, я делаю проприетарную программу для Linux. Хочу, чтобы она запускалась на как можно большем количестве дистрибутивов, распространяю в виде tar.gz с каталогом файлов программы. С какими параметрами нужно компилировать программу? При этом её нельзя распространять как статическую сборку, потому что зависит от OpenGL, и потому что тогда она включит в себя старый glibc с уязвимостями безопасности.

Первая проблема - в зависимостях. Вот игра gish: официальный бинарник, и бинарник, скомпилированный мной на основе открытого исходного кода:

zenitur@athlon_neo ~/gish153 $ ldd gish
linux-gate.so.1 => 
libGL.so.1 => /usr/lib32/opengl/ati/lib/libGL.so.1
libSDL-1.2.so.0 => /usr/lib32/libSDL-1.2.so.0
libopenal.so.1 => /usr/lib32/libopenal.so.1
libvorbis.so.0 => /usr/lib32/libvorbis.so.0
libogg.so.0 => /usr/lib32/libogg.so.0
libvorbisfile.so.3 => /usr/lib32/libvorbisfile.so.3
libc.so.6 => /lib32/libc.so.6
libm.so.6 => /lib32/libm.so.6
libpthread.so.0 => /lib32/libpthread.so.0
libXext.so.6 => /usr/lib32/libXext.so.6
libgcc_s.so.1 => /lib32/libgcc_s.so.1
libdl.so.2 => /lib32/libdl.so.2
librt.so.1 => /lib32/librt.so.1
/lib/ld-linux.so.2
libX11.so.6 => /usr/lib32/libX11.so.6
libxcb.so.1 => /usr/lib32/libxcb.so.1
libXau.so.6 => /usr/lib32/libXau.so.6
libXdmcp.so.6 => /usr/lib32/libXdmcp.so.6
zenitur@athlon_neo ~/gish153 $ ldd gish64
linux-vdso.so.1 => 
libSDL-1.2.so.0 => /usr/lib/libSDL-1.2.so.0
libpthread.so.0 => /lib/libpthread.so.0
libopenal.so.1 => /usr/lib/libopenal.so.1
libGLU.so.1 => /usr/lib/libGLU.so.1
libGL.so.1 => /usr/lib64/opengl/ati/lib/libGL.so.1
libSM.so.6 => /usr/lib/libSM.so.6
libICE.so.6 => /usr/lib/libICE.so.6
libX11.so.6 => /usr/lib/libX11.so.6
libXext.so.6 => /usr/lib/libXext.so.6
libvorbis.so.0 => /usr/lib/libvorbis.so.0
libvorbisfile.so.3 => /usr/lib/libvorbisfile.so.3
libpng14.so.14 => /usr/lib/libpng14.so.14
libz.so.1 => /lib/libz.so.1
libc.so.6 => /lib/libc.so.6
libm.so.6 => /lib/libm.so.6
libasound.so.2 => /usr/lib/libasound.so.2
libaudio.so.2 => /usr/lib/libaudio.so.2
libggi.so.2 => /usr/lib/libggi.so.2
libaa.so.1 => /usr/lib/libaa.so.1
libdl.so.2 => /lib/libdl.so.2
libcaca.so.0 => /usr/lib/libcaca.so.0
/lib64/ld-linux-x86-64.so.2
librt.so.1 => /lib/librt.so.1
libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6
libgcc_s.so.1 => /lib/libgcc_s.so.1
libuuid.so.1 => /lib/libuuid.so.1
libxcb.so.1 => /usr/lib/libxcb.so.1
libogg.so.0 => /usr/lib/libogg.so.0
libXt.so.6 => /usr/lib/libXt.so.6
libXau.so.6 => /usr/lib/libXau.so.6
libncurses.so.5 => /lib/libncurses.so.5
libXxf86vm.so.1 => /usr/lib/libXxf86vm.so.1
libgii.so.1 => /usr/lib/libgii.so.1
libXxf86dga.so.1 => /usr/lib/libXxf86dga.so.1
libXdmcp.so.6 => /usr/lib/libXdmcp.so.6
libgg.so.1 => /usr/lib/libgg.so.1
libncursesw.so.5 => /lib/libncursesw.so.5
libglut.so.3 => /usr/lib/libglut.so.3
zenitur@athlon_neo ~/gish153 $

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

Часто те библиотеки, без которых никак, но которые есть не у всех, кладутся либо рядом с игрой:

zenitur@athlon_neo /usr/games/braid $ ldd braid
linux-vdso.so.1 => 
libpthread.so.0 => /lib/libpthread.so.0
libCg.so => /usr/games/braid/libCg.so
libCgGL.so => /usr/games/braid/libCgGL.so
libGL.so.1 => /usr/lib64/opengl/ati/lib/libGL.so.1
libSDL-1.2.so.0 => /usr/games/braid/libSDL-1.2.so.0
libstdc++.so.6 => /usr/games/braid/libstdc++.so.6
libm.so.6 => /lib/libm.so.6
libgcc_s.so.1 => /usr/games/braid/libgcc_s.so.1
libc.so.6 => /lib/libc.so.6
/lib64/ld-linux-x86-64.so.2
libXext.so.6 => /usr/lib/libXext.so.6
libdl.so.2 => /lib/libdl.so.2
libX11.so.6 => /usr/lib/libX11.so.6
libxcb.so.1 => /usr/lib/libxcb.so.1
libXau.so.6 => /usr/lib/libXau.so.6
libXdmcp.so.6 => /usr/lib/libXdmcp.so.6
zenitur@athlon_neo /usr/games/braid $

Либо в каталог libs, и игра запускается не бинарником, а скриптом запуска LD_LIBRARY_PATH=./libs game:

zenitur@athlon_neo ~/NewSupaplex $ ldd NewSupaplexX
       linux-vdso.so.1 =>
       libclanApp.so.1 => not found
       libclanGL.so.1 => not found
       libclanGUI.so.1 => not found
       libclanDisplay.so.1 => not found
       libclanCore.so.1 => not found
       libclanSignals.so.1 => not found
       libbass.so => not found
       libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6
       libm.so.6 => /lib/libm.so.6
       libgcc_s.so.1 => /lib/libgcc_s.so.1
       libc.so.6 => /lib/libc.so.6
       libGL.so.1 => /usr/lib64/opengl/ati/lib/libGL.so.1
       libpthread.so.0 => /lib/libpthread.so.0
       /lib64/ld-linux-x86-64.so.2
       libXext.so.6 => /usr/lib/libXext.so.6
       libX11.so.6 => /usr/lib/libX11.so.6
       libxcb.so.1 => /usr/lib/libxcb.so.1
       libdl.so.2 => /lib/libdl.so.2
       libXau.so.6 => /usr/lib/libXau.so.6
       libXdmcp.so.6 => /usr/lib/libXdmcp.so.6
zenitur@athlon_neo ~/NewSupaplex $ cat run.sh
#!/bin/sh
export LD_LIBRARY_PATH=./Lib:/usr/local/lib:$LD_LIBRARY_PATH
exec ./NewSupaplexX $*

zenitur@athlon_neo ~/NewSupaplex $ cd Lib/
zenitur@athlon_neo ~/NewSupaplex/Lib $ ls
libbass.so          libclanGL.so.1             libjpeg.so.62
libclanApp.so.1     libclanGUI.so.1            libpng12.so.0
libclanCore.so.1    libclanGUIStyleSilver.so.1
libclanDisplay.so.1 libclanSignals.so.1
zenitur@athlon_neo ~/NewSupaplex/Lib $
Причём библиотеки тоже скомпилированы так, чтобы почти ни от чего не зависеть. И так все игры: Quake, Unreal Tournament, DooM, Heretic II... Как это вообще сделано?! Вторая проблема: ядро и glibc. Я уже давно понял: в любом, даже самом старом, дистрибутиве можно запустить любую проприетарную программу, если обновить glibc, и любое оборудование, если обновить ядро. Ну, ядро ладно: любая программа, собранная в 2.6.x, запустится на нём. А вот если не обновить glibc, то некоторые программы не запускаются. Например, Вангеры 2009 года не запустились в дистрибутиве 2006-го. TeeWorlds тоже не захотел, а перекомпиляция помогла. А теперь внимание: http://www.linuxgamepublishing.com/info.php?id=37
Minimum Requirements	
Operating System: 2.2.x or better Linux kernel with glibc-2.1 or later and X-Windows (XFree86 3.3.x or later)
Processor: 1.0 GHz x86 Processor
Memory: 256 MB
Disc Space: 3.7 GB
CD Rom: 1 x DVD Rom
Graphics Card: Hardware Accelerated 3D Graphics card with 32 MB video memory
Sound Card: OSS or ALSA Compatible
Игра портирована в 2009 году. Похоже, она запускается в любом дистрибутиве. При этом поддерживает ядра 2.2, 2.4, 2.6, и glibc 2.1, даже на древнем Red Hat времён этой игры. Как это сделано?!

Java. Тоже один пакет rpm/deb, и работает везде. Тот что deb не знаю где, а rpm скомпилирован в SuSE 9. В дистрибутиве 2000 года конечно не запустится, но можно сказать, что запускается в любом. OpenOffice.org. Я когда-то заказывал диск с ним, тогда ещё amd64 не был повсеместен, как и deb, и на нём лежал пакет RPM, который работал везде. Сейчас всё так же, только добавились deb и x86_64.

Как вообще это осуществляется? Что почитать? Есть же какие-то статьи, старые и новые, в том числе и на русском языке. Я не нашёл. Решил спросить здесь. Хотелось бы так же попрактиковаться, и сделать сборку какой-либо свободной Linux-овой программы, которая запустится везде. Хочется знать тонкости: когда-то в Mandrake с новым ядром 2.6 у меня сбоили маленькие линуксовые гонки из Интернета (я думал что из-за ядра, хотя я наверное не прав). А недавно в теме про игру Jasper кто-то писал о проблемах с glibc 2.4. Я так понял, что запустилось, но с ошибками в работе. Хочу попрактиковаться: взять исходник Linux-овой программы с определённым набором зависимостей, и сделать из неё бинарник, который запустится во всех дистрибутивах, не применяя статическую линковку. В крайнем случае положить необходимые библиотеки в архив, и я не знаю как это сделать.

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

> Для этого нужно прописать в твоих elf-файлах rpath на директорию, куда ты инсталлируешь so-шки.

Можно подробнее? Вот например Ioquake3. Куда это надо прописать, чтобы libopenal брался не из системы, а из каталога программы?

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

> Как это сделано?!

1. линковать все что можно статически.

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

3. удалять лишние зависимости, которые автоматом прописывает libtool. например, при линковке к gtk, libtool вполне может добавить зависимость к libpng14, даже если программа не использует его напрямую. в итоге это не взлетит на системе с libpng12 или 13.

4. даже если у динамической библиотеки есть стабильный API с обратной совместимостью — надо линковаться с минимально возможной версией этой библиотеки. пример: линк с gtk 2.20 не взлетит на системе с gtk 2.12, но линк с 2.12 взлетит на системе с 2.20.

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

многие из вышеперечисленных задач решает набор утилит autopackage (в частности, apgcc из него).

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

> удалять лишние зависимости, которые автоматом прописывает libtool

Сложности возникли уже на этом. А как? ./configure --disable-xxx?

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

> использовать только те динамические библиотеки, у которых стабильный API

Во-первых, не API, а ABI.
Во-вторых, любые библиотеки его рано или поздно ломают.

Единственное известное мне исключение - это glibc.

Так что самый портабельный вариант - таскать so-шки с собой.

libtool вполне может добавить зависимость к libpng14, даже если программа не использует его напрямую. в итоге это не взлетит на системе с libpng12 или 13


Проще включить libpng14 в поставку, и не париться. Более того, лицензия libpng разрешает статическую линковку..

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

> Сложности возникли уже на этом. А как? ./configure --disable-xxx?

нет. это не те зависимости. эту проблему решает apgcc.

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

> Во-вторых, любые библиотеки его рано или поздно ломают.

Единственное известное мне исключение - это glibc.
Так что самый портабельный вариант - таскать so-шки с собой.

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

Проще включить libpng14 в поставку, и не париться.

это был лишь пример. таких зависимостей могут быть десятки только от линковки с gtk. может половина системы «случайно» в неявные зависимости попасть.

Более того, лицензия libpng разрешает статическую линковку..

при динамической линковке к все тому же gtk — это никак не поможет.

альтернативный пример: программа линкуется к libX11, это автоматически добавляет на моей системе зависимость от libxcb, но на другой системе libxcb может не быть, и libX11 может работать без него. такие зависимости apgcc тоже фиксит.

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

У меня вопрос. Как слинковать GTK с минимумом зависимостей и положить, например, с программой установки? Или libSDL, вот он вообще постоянно кем-то используется. В UT2004 его нужно взять из своей системы и положить в каталог игры (либо символьная ссылка), в более новых играх он свой, уже сделанный правильно:

zenitur@athlon_neo ~ $ cd /home/zenitur/jasper_linux_i386_3
zenitur@athlon_neo ~/jasper_linux_i386_3 $ ldd libSDL
libSDL-1.2.so.0        libSDL_mixer-1.2.so.0
zenitur@athlon_neo ~/jasper_linux_i386_3 $ ldd libSDL-1.2.so.0
        linux-gate.so.1 =>  (0xffffe000)
        libm.so.6 => /lib32/libm.so.6 (0xf760b000)
        libdl.so.2 => /lib32/libdl.so.2 (0xf7607000)
        libpthread.so.0 => /lib32/libpthread.so.0 (0xf75ee000)
        libc.so.6 => /lib32/libc.so.6 (0xf7493000)
        /lib/ld-linux.so.2 (0xf76f6000)
zenitur@athlon_neo ~/jasper_linux_i386_3 $ cd /usr/games/aquaria
zenitur@athlon_neo /usr/games/aquaria $ ldd libSDL-1.2.so.0
        linux-gate.so.1 =>  (0xffffe000)
        libm.so.6 => /lib32/libm.so.6 (0xf762e000)
        libdl.so.2 => /lib32/libdl.so.2 (0xf762a000)
        libpthread.so.0 => /lib32/libpthread.so.0 (0xf7611000)
        libc.so.6 => /lib32/libc.so.6 (0xf74b6000)
        /lib/ld-linux.so.2 (0xf771e000)
zenitur@athlon_neo /usr/games/aquaria $ cd ../braid/
zenitur@athlon_neo /usr/games/braid $ ldd libSDL-1.2.so.0
        linux-vdso.so.1 =>  (0x00007fffb41ff000)
        libm.so.6 => /lib/libm.so.6 (0x00007f92b5f5f000)
        libdl.so.2 => /lib/libdl.so.2 (0x00007f92b5d5b000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x00007f92b5b3d000)
        libc.so.6 => /lib/libc.so.6 (0x00007f92b57d7000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f92b64ae000)
zenitur@athlon_neo /usr/games/braid $ cd /usr/lib
zenitur@athlon_neo /usr/lib $ ldd libSDL-1.2.so.0.11.3
        linux-vdso.so.1 =>  (0x00007fff8b8c7000)
        libasound.so.2 => /usr/lib/libasound.so.2 (0x00007f9023b89000)
        libaudio.so.2 => /usr/lib/libaudio.so.2 (0x00007f902396f000)
        libggi.so.2 => /usr/lib/libggi.so.2 (0x00007f90236b9000)
        libc.so.6 => /lib/libc.so.6 (0x00007f9023353000)
        libaa.so.1 => /usr/lib/libaa.so.1 (0x00007f9023132000)
        libm.so.6 => /lib/libm.so.6 (0x00007f9022eb0000)
        libdl.so.2 => /lib/libdl.so.2 (0x00007f9022cac000)
        libcaca.so.0 => /usr/lib/libcaca.so.0 (0x00007f90229d6000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x00007f90227b8000)
        librt.so.1 => /lib/librt.so.1 (0x00007f90225af000)
        libXt.so.6 => /usr/lib/libXt.so.6 (0x00007f9022341000)
        libXau.so.6 => /usr/lib/libXau.so.6 (0x00007f902213c000)
        libncurses.so.5 => /lib/libncurses.so.5 (0x00007f9021ee3000)
        libXxf86vm.so.1 => /usr/lib/libXxf86vm.so.1 (0x00007f9021cdc000)
        libgii.so.1 => /usr/lib/libgii.so.1 (0x00007f9021ab2000)
        libXxf86dga.so.1 => /usr/lib/libXxf86dga.so.1 (0x00007f90218ab000)
        libXext.so.6 => /usr/lib/libXext.so.6 (0x00007f9021695000)
        libX11.so.6 => /usr/lib/libX11.so.6 (0x00007f9021345000)
        libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00007f9021125000)
        libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00007f9020f1e000)
        libgg.so.1 => /usr/lib/libgg.so.1 (0x00007f9020d10000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f902413e000)
        libncursesw.so.5 => /lib/libncursesw.so.5 (0x00007f9020aab000)
        libglut.so.3 => /usr/lib/libglut.so.3 (0x00007f902085d000)
        libGLU.so.1 => /usr/lib/libGLU.so.1 (0x00007f90205d2000)
        libGL.so.1 => /usr/lib64/opengl/ati/lib/libGL.so.1 (0x00007f90203cd000)
        libz.so.1 => /lib/libz.so.1 (0x00007f90201b3000)
        libSM.so.6 => /usr/lib/libSM.so.6 (0x00007f901ffaa000)
        libICE.so.6 => /usr/lib/libICE.so.6 (0x00007f901fd8c000)
        libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6 (0x00007f901fa77000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f901f860000)
        libuuid.so.1 => /lib/libuuid.so.1 (0x00007f901f65a000)
zenitur@athlon_neo /usr/lib $ 
ZenitharChampion ★★★★★
() автор топика
Ответ на: комментарий от ZenitharChampion

> Как слинковать GTK с минимумом зависимостей и положить, например, с программой установки?

я это не пробовал. линкуюсь к gtk2.12 динамически, через apgcc.

процесс выглядит примерно так:

берем gtk,atk,glib,pango (и может еще что-то, не помню точно) devel пакеты из debian lenny. распаковываем куда-нибудь (например в ~/gtk2.12).

делаем export CC=apgcc

дальше собираем свое приложение так чтобы использовало gtk из этой папки. я вручную указываю все CFLAGS и LDFLAGS, без pkgconfig.

Или libSDL, вот он вообще постоянно кем-то используется

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

waker ★★★★★
()

Теперь у меня возникла та самая потребность, о которой я говорил. Биткойнеры, обратите внимание. http://forum.bitcoin.org/index.php?topic=3486.0 - хороший майнер на CPU. Лучше чем этот http://forum.bitcoin.org/index.php?topic=1925.0 . Под Linux работает, но только в 32 битах. А у меня 64-битная система. Казалось бы, в чём проблема скомпилировать 32-битную программу в 64-битной системе, ведь зависимостей только две: libcurl и libpcre. Но вот у меня не получается. Во-первых, include-файлы для 32- и 64-битной системы для libcurl отличаются, правда одной строчкой (точнее одной цифрой, в 32-битной системе должна быть 4, в 64-битной - 8), во-вторых, после успешной компиляции всё работает, но библиотек зависимостей полцчается целый ворох, в-третьих, я хочу сделать такой бинарник, который запустится везде, и который не стыдно выложить на сайт программы прямо под строчкой Windows binary. Для этого у меня есть старый дистрибутив SuSE 10.1. Что нужно сделать?

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