my_library — это моя библиотека, которую я хочу поставлять без исходников в виде статической (*.a) или динамической библиотеки (*.so).
some_exe — это некий исполняемый файл, использующий мою библиотеку
my_library использует boost вполне конкретной версии, но снаружи это никак не видно. То есть ни один заголовочный файл my_library не включает заголовочники Буста.
some_exe также использует boost для каких-то своих целей и собираться он будет на чужой машине, про которую известно лишь, что версия g++ там >= 4.1.0, а версия boost >= 1.40.0
С компиляцией проблем очевидно нет. Вопрос как организовать линковку и какие баги могут вылезти в рантайме?
Здравствуйте, Mazay, Вы писали:
M> Вопрос как организовать линковку и какие баги могут вылезти в рантайме?
на правах КО: линковать надо ту версию буста, которую использует реально либа (даже в кишках)
мешать разные версии буста в одном бинаре нельзя (даже если там все в хедерах сделано)
Здравствуйте, uzhas, Вы писали:
M>> Вопрос как организовать линковку и какие баги могут вылезти в рантайме? U>на правах КО: линковать надо ту версию буста, которую использует реально либа (даже в кишках) U>мешать разные версии буста в одном бинаре нельзя (даже если там все в хедерах сделано)
Так в том-то и беда, что экзешник может оказаться отлаженным с другой версией буста и не заработать с версией my_library.
Теоретически, мне нужна частичная линковка, то есть чтобы имена буста резолвились при сборке my_library и уже не экспортировались из неё. Тогда можно будет спокойно линковать my_library параллельно с любой версией буста — подставлять уже ничего не надо будет.
Но пока я не могу заставить g++ подставлять символы иначе как при линковке готового экзешника, и это печально. Даже динамические библиотеки не могут самостоятельно линковаться до запуска экзещника.
Здравствуйте, Mazay, Вы писали:
M>Так в том-то и беда, что экзешник может оказаться отлаженным с другой версией буста и не заработать с версией my_library.
из первого поста я так и не понял о статической либе речь или о динамической
в случае динамической — проблем нет, то есть ваша my_library может слинковаться с буст 1.0, а клиент my_app может влинковать в себя буст 2.0 и использовать вашу my_library.so
в случае статической ваша либа депендится на конкретную версию буста и клиент обязан с ней работать (статические либы имеют много зависимостей и с этим надо жить). вы можете также предоставить несколько статических либ под каждую версию буста (в имени файла это можно отразить)
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, Mazay, Вы писали:
M>>Так в том-то и беда, что экзешник может оказаться отлаженным с другой версией буста и не заработать с версией my_library. U>из первого поста я так и не понял о статической либе речь или о динамической U>в случае динамической — проблем нет, то есть ваша my_library может слинковаться с буст 1.0, а клиент my_app может влинковать в себя буст 2.0 и использовать вашу my_library.so
Хм. А можно пример сборки динамической библиотеки со связыванием с символами другой библиотеки? Я делаю вот так:
% cat mystuff.cpp
#include"boost.hpp"// подключаем заголовочник boost, в котором объявлена функция int foost();int do_stuff()
{
return 10 + foost(); // здесь вызов функции foost() из некой библиотеки boost
}
% g++ -fPIC -c mystuff.cpp // копиляция mystuff.cpp в mystuff.o
% ld -shared -o mystuff.so mystuff.o // !!! линковка динамической либы mystuff.so.
// Обратите внимание, что здесь мы не указываем ни boost.so, ни boost.a, ни boost.o!
% nm mystuff.so
0000000000200440 d DW.ref.__gxx_personality_v0
0000000000200300 a _DYNAMIC
0000000000200420 a _GLOBAL_OFFSET_TABLE_
U _Z5foostv // флажок U означает, что этот символ в библиотеке не определён (undefined)
00000000000002b0 T _Z8do_stuffv
0000000000200448 A __bss_start
U __gxx_personality_v0
0000000000200448 A _edata
0000000000200448 A _end
Как видите, я даже не компилировал boost.cpp, в котором определена int foost(). То есть всё связывание откладывается на момент сборки экзешника, и все 'undefined reference' или 'multiple definition' вылезут именно там.
Так как вы предлагаете слинковывать my_library с буст 1.0?
U>в случае статической ваша либа депендится на конкретную версию буста и клиент обязан с ней работать (статические либы имеют много зависимостей и с этим надо жить). вы можете также предоставить несколько статических либ под каждую версию буста (в имени файла это можно отразить)
Для начала попробуем хотя бы динамическую либу сделать.
M>% g++ -fPIC -c mystuff.cpp // копиляция mystuff.cpp в mystuff.o M>% ld -shared -o mystuff.so mystuff.o // !!! линковка динамической либы mystuff.so. M> // Обратите внимание, что здесь мы не указываем ни boost.so, ни boost.a, ни boost.o! M>% nm mystuff.so
а почему вы не указываете версию того буста.so, который предоставит нужные функции?
ваш mystuff.so должен тянуть boost1.0.so
а myapp должен тянуть boost2.0.so + mystuff.so
думаю, через ld все это можно сделать
Здравствуйте, Mazay, Вы писали:
M>Здравствуйте, uzhas, Вы писали:
U>>Здравствуйте, Mazay, Вы писали:
M>>>Так в том-то и беда, что экзешник может оказаться отлаженным с другой версией буста и не заработать с версией my_library. U>>из первого поста я так и не понял о статической либе речь или о динамической U>>в случае динамической — проблем нет, то есть ваша my_library может слинковаться с буст 1.0, а клиент my_app может влинковать в себя буст 2.0 и использовать вашу my_library.so M>Хм. А можно пример сборки динамической библиотеки со связыванием с символами другой библиотеки? Я делаю вот так: M>
Здравствуйте, Mazay, Вы писали:
M>Здравствуйте, uzhas, Вы писали:
M>>> Вопрос как организовать линковку и какие баги могут вылезти в рантайме? U>>на правах КО: линковать надо ту версию буста, которую использует реально либа (даже в кишках) U>>мешать разные версии буста в одном бинаре нельзя (даже если там все в хедерах сделано)
M>Так в том-то и беда, что экзешник может оказаться отлаженным с другой версией буста и не заработать с версией my_library.
M>Теоретически, мне нужна частичная линковка, то есть чтобы имена буста резолвились при сборке my_library и уже не экспортировались из неё. Тогда можно будет спокойно линковать my_library параллельно с любой версией буста — подставлять уже ничего не надо будет.
M>Но пока я не могу заставить g++ подставлять символы иначе как при линковке готового экзешника, и это печально. Даже динамические библиотеки не могут самостоятельно линковаться до запуска экзещника.
Здравствуйте, uzhas, Вы писали:
M>>% g++ -fPIC -c mystuff.cpp // копиляция mystuff.cpp в mystuff.o M>>% ld -shared -o mystuff.so mystuff.o // !!! линковка динамической либы mystuff.so. M>> // Обратите внимание, что здесь мы не указываем ни boost.so, ни boost.a, ни boost.o! M>>% nm mystuff.so U>а почему вы не указываете версию того буста.so, который предоставит нужные функции?
Я вообще не указываю никаких библиотек, потому что в момент сборки so-шки связывания не происходит. От того что я укажу там библиотеку boost1.0.so ничего не изменится. Она просто будет включена в mystuff.so, но связывание будет делаться только при сборке экзешника. Если я при этом укажу ещё и boost2.0.so, то я просто получу multiple definitions. U>ваш mystuff.so должен тянуть boost1.0.so U>а myapp должен тянуть boost2.0.so + mystuff.so U>думаю, через ld все это можно сделать
Я тоже так полагаю. Но вот как это сделать?
Здравствуйте, uzhas, Вы писали:
U>>>думаю, через ld все это можно сделать M>>Я тоже так полагаю. Но вот как это сделать? U>думаю, что достаточно передать ld соответствующий файл .so и он сделает привязку к конкретной .so U>гипотетический пример: ld -o my_libray.so my_lib.o boost1.0.so
Не сделает он так никакой привязки. Просто тупо свалит определения функций в my_libray.so, а собственно связывание произойдёт уже при линковке экзешника.
U>можно погуглить U>http://www.risc.jku.at/education/courses/ws2003/intropar/origin-new/MproCplrDbx_TG/sgi_html/ch03.html#Z86160
Интересно. Покурю. U>http://unixhelp.ed.ac.uk/CGI/man-cgi?ld
Здравствуйте, Mazay, Вы писали:
U>>гипотетический пример: ld -o my_libray.so my_lib.o boost1.0.so M>Не сделает он так никакой привязки. Просто тупо свалит определения функций в my_libray.so, а собственно связывание произойдёт уже при линковке экзешника.
не понял
что куда он свалит и о каком ехешнике речь?
в этой строчке мы линкуем динамическую my_library.so, которая должна загружать boost1.0.so
список депендов можно проверить тулзой ldd (если она в вашем юниксе есть) http://www.opennet.ru/man.shtml?topic=ldd&category=1
ldd my_library.so должна показать список .so, которые требуются для загрузки my_library.so
можете поиграться ею с другими бинарями. очень полезная=)
On 06.06.2011 14:09, Mazay wrote: > С компиляцией проблем очевидно нет. Вопрос как организовать линковку и какие > баги могут вылезти в рантайме?
Зависит от того, какие библиотеки boost-а используются.
Если используются в обоих местах (или хотя бы в одном)
только header-only библиотеки (шаблонные библиотеки без
статически генерируемого объектного кода), то всё должно
быть ОК. Если кто-то использует статические библиотеки,
(например как boost::regex), то эти библиотеки надо
будет подлинковывать к приложению (или его модулям).
Ну и если ОБА пользователя будут использовать статические
либы, при этом ОДИНАКОВЫЕ, будут конфликты.
Легче всего наверное (если есть конфликты) перейти
скопом на более новую версию буста.
On 06.06.2011 17:12, uzhas wrote:
> из первого поста я так и не понял о статической либе речь или о динамической > в случае динамической — проблем нет, то есть ваша my_library может слинковаться > с буст 1.0, а клиент my_app может влинковать в себя буст 2.0 и использовать вашу > my_library.so
Это не так, могут быть проблемы и в случае статической линковки буста,
и в случае динамической ( в виде .dll).
Здравствуйте, Mazay, Вы писали: M>Я вообще не указываю никаких библиотек, потому что в момент сборки so-шки связывания не происходит.
Это неверно. Приведу простой пример — разработка плагинов.
Здравствуйте, MasterZiv, Вы писали:
>> С компиляцией проблем очевидно нет. Вопрос как организовать линковку и какие >> баги могут вылезти в рантайме?
MZ>Зависит от того, какие библиотеки boost-а используются. MZ>Если используются в обоих местах (или хотя бы в одном) MZ>только header-only библиотеки (шаблонные библиотеки без MZ>статически генерируемого объектного кода), то всё должно MZ>быть ОК. Если кто-то использует статические библиотеки, MZ>(например как boost::regex), то эти библиотеки надо MZ>будет подлинковывать к приложению (или его модулям). MZ>Ну и если ОБА пользователя будут использовать статические MZ>либы, при этом ОДИНАКОВЫЕ, будут конфликты.
А если либы динамические? У них же ЕМНИП даже кучи раздельные.
On 07.06.2011 18:04, Mazay wrote:
> MZ>Ну и если ОБА пользователя будут использовать статические > MZ>либы, при этом ОДИНАКОВЫЕ, будут конфликты.
> А если либы динамические? У них же ЕМНИП даже кучи раздельные.
Ну, будет ещё больший конфликт.
А у динамических либов могут быть как одна куча, так и разные.
Нормальная ситуация -- когда куча одна.
Здравствуйте, Mazay, Вы писали:
M>Здравствуйте, uzhas, Вы писали:
U>>>>думаю, через ld все это можно сделать M>>>Я тоже так полагаю. Но вот как это сделать? U>>думаю, что достаточно передать ld соответствующий файл .so и он сделает привязку к конкретной .so U>>гипотетический пример: ld -o my_libray.so my_lib.o boost1.0.so M>Не сделает он так никакой привязки. Просто тупо свалит определения функций в my_libray.so, а собственно связывание произойдёт уже при линковке экзешника.
Это не так, попробуй прописать rpath в опциях линковки библиотеки и потом натрави ldd на твою my_libray.so с предварительно обнуленным LD_LIBRARY_PATH — увидишь захардкоженный путь к той библиотеке, которую ты указал при линковке.
Здравствуйте, jazzer, Вы писали:
U>>>>>думаю, через ld все это можно сделать M>>>>Я тоже так полагаю. Но вот как это сделать? U>>>думаю, что достаточно передать ld соответствующий файл .so и он сделает привязку к конкретной .so U>>>гипотетический пример: ld -o my_libray.so my_lib.o boost1.0.so M>>Не сделает он так никакой привязки. Просто тупо свалит определения функций в my_libray.so, а собственно связывание произойдёт уже при линковке экзешника. J>Это не так, попробуй прописать rpath в опциях линковки библиотеки и потом натрави ldd на твою my_libray.so с предварительно обнуленным LD_LIBRARY_PATH — увидишь захардкоженный путь к той библиотеке, которую ты указал при линковке.
Это говорит лишь о том, что когда будет происходить связывание, библиотека будет в первую очередь искаться по указанному пути. Но собственно связывание будет делаться либо при сборке экзешника, либо вообще при запуске. Вот наглядный пример:
///prog.cpp#include"mystuff.hpp"#include"boost.hpp"#include <iostream>
using namespace std;
int main()
{
cout << "hi!\n";
cout << "exe boost version == " << foost() << endl;
cout << "mystuff boost version == " << do_stuff() << endl;
}
%g++ -c -fPIC *.cpp // Компилируем всё.
%ld -shared -o boost.1.so boost.1.o // Сборка динамического буста версии 1.
%ld -shared -o boost.2.so boost.2.o // Сборка динамического буста версии 2.
// Простая сборка библиотеки mystuff, типа заточеной под boost.1.
// Вариант 1. При сборке mystuff.boost.1.so библиотек не указываем вообще.
%ld -shared -o mystuff.boost.1.so mystuff.o
%nm mystuff.boost.1.so
00000000002002a8 a _DYNAMIC
0000000000200398 a _GLOBAL_OFFSET_TABLE_
U _Z5foostv // Всё правильно, U - значит символ не определён.
0000000000000260 T _Z8do_stuffv // T - значит символ определён. Тоже логично.
00000000002003b8 A __bss_start
00000000002003b8 A _edata
00000000002003b8 A _end
%ldd mystuff.boost.1.so
statically linked // Внешних динамических связей нет
// Собираем нашу программу, указывая нужные библиотеки
%g++ -o prog prog.o -L. -l:mystuff.boost.1.so -l:boost.2.so
%./prog
hi!
exe boost version == 2 // Сам экзешник работает со вторым бустом как и положено
mystuff boost version == 12 // Ай-яй-яй! Библиотека тоже подхватила новую версию, чего быть не должно.
// Наверное надо указать библиотеку boost.1 при сборке mystuff.boost.1.so
// Вариант 2. При сборке mystuff.boost.1.so указываем boost.1.so.
%ld -shared -o mystuff.boost.1.so mystuff.o -L. -l:boost.1.so
%nm mystuff.boost.1.so
00000000002002b8 a _DYNAMIC
00000000002003b8 a _GLOBAL_OFFSET_TABLE_
U _Z5foostv // Здесь без изменений.
0000000000000270 T _Z8do_stuffv // Аналогично
00000000002003d8 A __bss_start
00000000002003d8 A _edata
00000000002003d8 A _end
%ldd mystuff.boost.1.so
linux-vdso.so.1 => (0x00007fff0f1ff000)
boost.1.so => ./boost.1.so (0x00007f0d632be000) // Ага! Теперь наша mystuff.boost.1.so железно прибита к boost.1.so.
// Собираем нашу программу.
%g++ -o prog prog.o -L. -l:mystuff.boost.1.so
/usr/bin/ld: prog.o: undefined reference to symbol 'foost()' // Хм. Почему-то boost.1.so из mystuff.boost.1.so не подхватилась.
/usr/bin/ld: note: 'foost()' is defined in DSO .//boost.1.so so try adding it to the linker command line
.//boost.1.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
// Пробуем указать boost.1.so явно:
%g++ -o prog prog.o -L. -l:mystuff.boost.1.so -l:boost.1.so
%./prog
hi!
exe boost version == 1 // Вроде работает. Но нам нужно, чтобы экзешник использовал boost.2
mystuff boost version == 11 // Здесь всё ОК. mystuff работает с boost.1
// Пробуем указать boost.2.so явно, а boost.1.so для mystuff.boost.1.so пусть сам ищет (должен найти судя по выводу ldd mystuff.boost.1.so):
%g++ -o prog prog.o -L. -l:mystuff.boost.1.so -l:boost.2.so
%./prog
hi!
exe boost version == 2 // Здесь всё ОК. Экзешник работает с boost.2
mystuff boost version == 12 // Опаньки! Косяк! И клал он большой и толстый на то,
// что в mystuff.boost.1.so захардкожено имя ./boost.1.so
// В порыве отчаяния пробуем бредовый вариант с двумя версиями:
%g++ -o prog prog.o -L. -l:boost.1.so -l:mystuff.boost.1.so -l:boost.1.so
%./prog
hi!
exe boost version == 1
mystuff boost version == 11 // Разумеется и тут облом
// Вариант 3. При сборке mystuff.boost.1.so статически линкуемся с boost.1.a.
%ar -q -o boost.1.a boost.1.o // собираем статический boost.1
ar: creating boost.1.a
%nm boost.1.a
boost.1.o:
0000000000000000 T _Z5foostv
%ld -shared -o mystuff.boost.1.so mystuff.o -L./ -l:boost.1.a // собираем mystuff.boost.1.so со статической boost.1.a
%nm mystuff.boost.1.so
00000000002002d8 a _DYNAMIC
00000000002003c8 a _GLOBAL_OFFSET_TABLE_
0000000000000270 T _Z5foostv // Ага! Здесь у нас foost() определена
0000000000000260 T _Z8do_stuffv
00000000002003e8 A __bss_start
00000000002003e8 A _edata
00000000002003e8 A _end
%ldd mystuff.boost.1.so
statically linked // Всё ОК.
//Собираем программу:
%g++ -o prog prog.o -L. -l:mystuff.boost.1.so // По крайней мере собрались без явного указания boost.1.
// Спасибо статической линковке. Видимо связывание таки уже произошло.
%./prog
hi!
exe boost version == 1 // Разумеется. Везде единички, так как boost.2 вообще не упоминался,
mystuff boost version == 11 // а с boost.1 мы уже слинковались.
// Теперь попробуем заставить программу работать с новым бустом.
%g++ -o prog prog.o -L. -l:mystuff.boost.1.so -l:boost.2.so
%./prog
hi!
exe boost version == 1
mystuff boost version == 11 // Хм. Опять единички.
// Ладно. Попробуем поменять порядок библиотек. Это важно.
%g++ -o prog prog.o -L. -l:boost.2.so -l:mystuff.boost.1.so
%./prog
hi!
exe boost version == 2 // Отлично!
mystuff boost version == 12 // Как!!!!! Как такое может быть?! Мы же уже слинковались с boost.1,
// ещё на этапе сборки mystuff.boost.1.so. Видимо нифига не слинковались
Ну вот как-то так. К сожалению, я так и не разобрался как же именно влияет rpath на собранный so-шник. Но из чтения документации у меня сложилось впечатление, что он нужен чтобы подсунуть программе библиотеку не из стандартного /usr/lib, а из другой папки. Но мне этого не требуется, так-как имена библиотек разные (boost.1.so и boost.2.so).
P.S.
Кажется исходную проблемму можно решить запретив экспорт чужих имён из so-шки. Сейчас копну в этом направлении.
P.P.S.
И это, народ, давайте уже завязывать с теоретизированием. Предлагаете какой-то вариант — пишите пример.