LINUX.ORG.RU

Автоматическое разруливание (очерёдность линковки) зависимостей системой сборки\линковщиком

 , ,


0

1

Вот расскажите, кто собаку съел на линковке, почему до сих пор приходится руками играться с очередностью линковки?
Вот скомпилировал я горсть .o/.a-шек, и хочу их слинковать вместе. Почему я в том же CMake до сих пор вынужден руками определять зависимости?
На первый взгляд задача выглядит тривиальной для автоматизации. Есть какая неочевидная хитрость?
Или это специфика некоторых сисием сборки и есть такие, которые делают это самостоятельно?


Потому что кресты и сишка созданы 100500 лет назад. Тогда это было норм.

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

-lx -ly -lx

Я линкер руками уж 100 лет не запускал. Это не опечатка?
Ты предлагяешь рандомно(?) руками(?) повторять либы пока они не слинкуются?

-lx -ly -lz

Ок, опечатка таки. Но если линкер умеет, то по какой причине CMake этим не пользуется?

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

По ссылке подробно описано как cmake строит граф зависимостей. Если у тебя есть идея как сделать лучше, пришли патч (открой реквест, хотя бы опиши словами в issue). А так ты просто ноешь.

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

Насколько я вижу не вникая в тему, они даже не пытаются выяснить какие «символы» в каком бинарнике. Они строят свои предположения отталкиваясь лишь от содержимого конфига.
Или я чего-то не вижу?

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

О, кроме костыля

target_link_libraries(main PRIVATE -Wl,--start-group ${LIBRARIES} -Wl,--end-group)

есть ещё костыль с указанием сколько раз пытаться линкануть

LINK_INTERFACE_MULTIPLICITY, IMPORTED_LINK_INTERFACE_MULTIPLICITY

Repetition count for STATIC libraries with cyclic dependencies.

When linking to a STATIC library target with cyclic dependencies the linker may need to scan more than once through the archives in the strongly connected component of the dependency graph. CMake by default constructs the link line so that the linker will scan through the component at least twice. This property specifies the minimum number of scans if it is larger than the default. CMake uses the largest value specified by any target in a component.
fluorite ★★★★★
()

Еще один пост про неосилил? И опять без примеров.

RussianWarShip
()

Почему я в том же CMake до сих пор вынужден руками определять зависимости?

Потому что CMake устарел и надо использовать Meson. Он умеет автоматически решать указанную проблему.

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

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

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

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

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

Вот только у меня сложилось спечатление что CMake – устоявшийся стандарт.

Некоторые и Autotools считают устоявшимся стандартом…

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

Нет. Стандарт это Makefile для make, только большинство его не осиливают и используют всякую дичь вроде cmake.

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

Я линкер руками уж 100 лет не запускал.

Вот учись.

firkax ★★★★★
()

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

См. Beginner’s Guide to Linkers.

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

Не, это отмазка. Для построения дерева зависимостей нам не нужно держать все библиотеки в памяти одновременно.

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

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

Речь идёт о зависимостях между символами, а не библиотеками. Также имеет значения в каких объектниках символы лежат в случае статических библиотек, используются ли отдельные секции для каждой функции и т.д.

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

Ну я и говорю что нам нужен лишь список символов и в каких конкретно они лежат объектниках. Зачем держать сами объектники?

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

Детали форматов я не знаю, но метаданные объектников в них же и хранятся в ELF. И обработка каждого следующего объектника может потребовать символ из произвольной библиотеки. Вот и получается, что они нужны подольше, ну или надо копировать данные обо всём, что не используется.

Есть посты от автора GNU gold https://www.airs.com/blog/archives/38, может там есть ответ. Кстати, интересно как это делает самый современный mold.

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

Я всё равно не понимаю куда ты клонишь. Берёшь объектник, выколупываешь оттуда «метаданные» и дальше с ними работаешь.

И вообще, я не говорю про эффективность. Я сейчас говорю про автоматизацию. Пусть машина хоть час возится, это дешевле и приятней чем даже 10 минут работы человека.

Usruser
() автор топика

Вот расскажите, кто собаку съел на линковке, почему до сих пор приходится руками играться с очередностью линковки?

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

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

ps:

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

такое надо слегка переписывать.

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

И вообще, я не говорю про эффективность. Я сейчас говорю про автоматизацию. Пусть машина хоть час возится, это дешевле и приятней чем даже 10 минут работы человека.

Так ты попробуй собирать большие проекты, эффективность и по времени и по памяти тут как раз важна. Особенно, если учитывать, что команда линковки пишется один раз, а исполняется 100500.

Вообще, в каких-то дистрибутивах добавляли -Wl,--start-group в spec-файлы, но потом, кажется, перестали.

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

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

Так всегда говорят до тех пор пока не связываются со сборкой например какого-нибудь ядра, браузера или игры на не самом мощном железе. А потом ноют, а пачаму усё собирается 24 часа, а не 24 секунды.

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

Очень слабый аргумент. Ты выступаешь против автоматизации рутины лишь на том основании, что в некоторых граничных ситуациях эта автоматизация может требовать значительного количества ресурсов.

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

То есть тебе тяжело написать

target_link_libraries(nomenus-rex AnyOption Rules Tests Progressator config++)
target_link_libraries(nomenus-rex ICU::data ICU::i18n ICU::uc ICU::dt)

И это должен сделать Cmake?

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

Я недавно был вынужден менять последовательность этих библиотек. Это должен был сделать Cmake.

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

У меня такое было с qmake, в случае со старым линкером из GCC 5.4. Это особенность, о которой уже позабыли.

It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.

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

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

Почему разработчики Cmake не сделали поиск символов в библиотеках? Скорее всего ограничение связано с кроссплатформенностью и кросмкомпиляторностью.

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

Что приводит к забавному вопросу: а что вообще делает эта махина? Просто сравнивает дату изменения исходника со временем создания бинарника? Не маловато ли будет? Может всё-таки было бы неплохо начать помогать программисту, а не лишь озадачивать его ребусами?

После небольшого изменения в коде, линкер стал ругаться на невозможность найти конструктор\деструктор одного класса, который я добавил. Я сначала подумал что я чего-то наворотил и насоздавались методы по умолчанию. Или наоборот, перестали создаваться. Или ещё что. Потом глазами смотрел в бинарики чтобы убедиться, что ф-ции таки есть. Это заняло кучу времени и ещё больше нервов.

В итоге оказалось что нужно переставить местами названия библиотек в конфиге. Причём у меня всё равно остался вопрос как это РАНЬШЕ работало. Но я уже приучился не задавать вопросы, связанные с CMake, потому что ответов обычно нет. Вразумительных, во всяком случае.

Это нехорошо.

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

Вразумительный ответ уже звучал. Цель Rules имеет зависимость от ICU, но в конфиге это не показано. Под Windows (допустим, что проект кроссплатформенный) сборка этой цели завершилась бы ошибками компиляции из-за отсутствующих заголовочников. Потому что цель в Cmake может содержать не только пути к библиотеке, но и пути к заголовочникам и опции компиляции. Так вот в Linux эта цель компилируется потому, что заголовочники лежат, как правило, в одном месте, о котором компилятор знает. А в Windows библиотека и заголовочники могут быть где попало. И если find_package находит библиотеку, то находит и заголовочники. И эта одна из причин, почему нужно явно указывать зависимости.

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

Не очень понятно, как по твоему cmake должен искать символы. Вот в своём коде я написал

extern Foo bar;

Где искать реализацию?

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

Где искать реализацию?

CMake знает о всех библиотеках, которые пользователь подключает. Как внутренних, так и внешних. Вот в масштабе этих библиотек пусть и ищет. А если не найдёт, значит пользователь что-то забыл и ему об этом нужно сообщить.

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

CMake знает о всех библиотеках, которые пользователь подключает.

Вот смотри: foo_linux.cpp, собираю в liblinux.a

void foo() { // linux specific code }

foo_bsd.cpp, собираю в libbsd.a

void foo() { // bsd specific code }

main.cpp

void foo();
int main() { foo(); }

Что подключать?

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

В таких случаях можно спросить у пользователя. А в 99% других случаев, когда всё однозначно – не спрашивать.

И вообще, я изначально говорил про очерёдность скармливания библиотек линковщику.

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

в 99%

очерёдность скармливания библиотек линковщику не имеет значения. В остальных - можно попросить пользователя использовать start-group/end-group.

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

очерёдность скармливания библиотек линковщику не имеет значения.

Имеет. И тред именно об этом.

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

Это что, документацию читать? Чукча не читатель.

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

Но ведь тред именно об этом: зачем указывать то, что машина в 99% случаев может высчитать самостоятельно?

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

Видимо тебя ждали.

Видимо CMake не привязан к С++ и на плюсовые проблемы им просто плевать. Так что пусть ждут дальше.

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

И это будет выглядеть так

  • Cmake пытается собрать Rules/ruleFilename.cpp и валится с ошибкой, потому что ICU из дистрибьютива староват и поэтому самособранный ICU лежит в /opt.

  • Cmake парсит вывод компилятора и понимает, что нужен заголовочник unicode/unistr.h, затем ищет его и находит в ICU.

    И конечно Cmake умеет парсить не только GCC, но и других тулчейнов.

  • Нужный путь добавлен и Cmake опять пробует скомпилять.

  • На этапе линковки те же пляски.

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