[gcc+ld] странное поведение компилятора или линкера
void b {printf("b\n");}
тоже перестаёт работать, похоже инициализирующая секция куда-то девается или просто не вызывается.
думаю, линковщик не пихает в программу объекты из архива, которые в программе не используются. вот и всё.
bash-3.00$ g++ 1.cpp -c; ar r libx.a 1.o; ranlib libx.a; g++ 2.cpp libx.a -o 2
ar: creating libx.a
bash-3.00$ ./2
main
bash-3.00$ cat 1.cpp
#include <stdio.h>
#include "1.h"
A a(10);
bash-3.00$ cat 1.h
class A {
public:
A(int a= 0) { printf("A ctor\n"); x= a;}
int x;
};
extern A a;
bash-3.00$ cat 2.cpp
#include <stdio.h>
#include "1.h"
int main
{
printf("main\n");
}
bash-3.00$
после:
bash-3.00$ g++ 1.cpp -c; ar r libx.a 1.o; ranlib libx.a; g++ 2.cpp libx.a -o 2
ar: creating libx.a
bash-3.00$ ./2
A ctor
10 main
bash-3.00$ diff 2.cpp 2.cpp~
6d5
< printf("%d ", a.x);
bash-3.00$
Это документированное поведение? Соответствует стандарту (такие вообще бывают в отношении линкеров)? Если да, то можно ли как-нибудь побороть этот противоестественный интеллект?
У кого-нибудь есть доступ к другим линкерам? Проверьте, плз.
Спасибо! Теперь все понятно.
If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized. 31)
В сноске написано:
31) An object defined in namespace scope having initialization with size-effects must be initialized even if it is not used (3.7.1).
Насколько я понимаю, вывод на экран - это side-effect, и поэтому данный случай попадает под действие сноски. Так?
А почему, если скомпилировать твой код без предварительно запихивания объектника в архив, то экзешник пишет всё?
Ага, я тоже заметил, даже изменение других статических объектов из конструктора (ведь вызов принтфа, по большому счету, ничье состояние не меняет) не влияет на досрочную инициализацию.
вы все прикалываетесь что ли?
Совершенно очевидно, что модуль с переменной "A a;" не линкуется с программой, т.е. эта трансляция (а значит и переменная "a") не является частью программы. И почему это так, тоже совершенно очевидно: именно в этом весь смысл библиотек, чтобы линковать из них только те модули, которые используются программой, и так делает любой линкер от майкрософтовского до гнутого.
Если бы трансляция явно указанная в командной строке использовала что-то из трансляции с переменной "a", то конечно модуль подключился бы.
![](/images/graemlins/smile.gif)
а то я помню, что объектные файлы из архива включаются только целиком и не могу понять, почему класс включается, а глобальный объект -- нет.
я и не заметил, что класс тоже не используется в программе. так что всё правильно. :-)
Например, здесь у меня была такая ситуация. Модуль при инициализации регистрирует некоторый обработчик (callback т.е. он при инициализации сообщает, что умеет обрабатывать определенный тип данных. Поскольку явно функции модуля не вызываются, то модуль выкидывается, хотя он необходим для работы программы. Регистрация обработчиков при инициализации --- достаточно традиционная практика. В качестве примера можно взять какое-нибудь аудио-видео приложение, в котором плагины для обработки файлов разных форматов или кодеков регистрируются таким способом.
Более кратко: то, что я не использую функций из модуля, не означает, что он мне не нужен. Если линкер так считается --- это бага и ее надо лечить (КАК?)
Каким это интересно способом, он определяет, использую я модули или нет?На стадии линования самым элементарным способом: если какой-то из модулей программы ссылается на внешний символ (функцию, переменную, одним словом метку) - то есть который не определен ни в одном из модулей программы, то этот символ ищется в библиотеках, и тот библиотечный модуль, который содержит нужный символ и линкуется с программой.
немного не прав, тут не трансляции разные, а сами модули, разделяется все на этапе ar/ranlib, микрософтовский lib.exe дает такой же результат.
немного не прав, тут не трансляции разные, а сами модули, разделяется все на этапе ar/ranlib, микрософтовский lib.exe дает такой же результат.каждая трансляция компилится ровно в один модуль.
До и во время компиляции - это трансляция, а после компиляции - это модуль, точнее так: в терминах компилятора и языка програмирования - трансляция, в терминах линкера - модуль. А вообще-то речь об одном и том же.
На стадии линкования это конечно уже скорее модуль, но я употреблял слово трансляция, чтобы иногда говорить в терминах языка программирования. Вобщем пох.
g++ 1.o 2.cpp
даёт желаемый результат, при такой трактовке?
Более кратко: то, что я не использую функций из модуля, не означает, что он мне не нужен.Разумеется то что ты не используешь функций или переменных данного библиотечного модуля именно и означает, что он тебе не нужен. Есть очевидные способы указания того что он тебе нужен в данной проге: (1) указание данного модуля в командной строке явно, (2) использование любого символа определенного в данном модуле.
Если линкер так считается --- это бага и ее надо лечить (КАК?)конечно это не баг линкера, а баг твоей проги
как лечить уже сказал
Задумайся на минуту какой бред ты сказал: "Если линкер считает, что прога не использует какой-то библиотечный модуль (в случае, когда ты абсолютно ничем не дал понять линкеру, что прога все же использует этот модуль) - это баг".
Т.е. ты предлагаешь, чтобы линкер подключал все библиотечные модули, присутствующие в системе, при линковании любой проги? Ты хоть предсталяешь сколько их?
И как ты объяснишь то, что
g++ 1.o 2.cpp
даёт желаемый результат, при такой трактовке?
Очевидно, что все трансляции (модули явно указанные в командной строке, заведомо являются частью программы.
А библиотечные модули являются частью программы, только если они (1) содержатся в какой-то из явно или неявно подключаемых библиотек и (2) используются другими модулями, являющимися частью программы. Точный смысл слова "используются" я уже писал.
Я уже написал, что во многих типичных случаях такой подход неверен. Что ты скажешь относительно таких программ?
> конечно это не баг линкера, а баг твоей проги
То есть регистрировать плагины в медиа-приложениях методом статической инициализации - это баг?
> Т.е. ты предлагаешь, чтобы линкер подключал все библиотечные модули, присутствующие в системе, при линковании любой проги? Ты хоть предсталяешь сколько их?
Причему тут все модули, присутсвующие в системе? Система вообще раньше не упоминалась. Я даю четкое указание линкеру - прилинковать некоторую фиксированную библиотеку libxyz.a.
Плагины вроде обычно динамически подгружаются.
Как раз в типичных (и их гораздо больше, чем твоих "многих") случаях подход правилен. Библиотеки создаются, именно для того, чтобы не тащить лишнего.
> Я даю четкое указание линкеру - прилинковать некоторую фиксированную библиотеку libxyz.a.
Линковщик его так же чётко выполняет. Он совсем не обязан рюхать, что ты имел ввиду на самом деле, так как этой информации в библиотеке не содержится.
Если таки надо сделать подобный изврат, то копать в сторону ключа -u у gcc и ld для создания явных зависимостей и --whole-archive/--no-whole-archive у ld для подлючения библиотек целиком.
О! Вот это уже то, что надо! Спасибо!
> Разумеется то что ты не используешь функций или переменных данного модуля именно и означает, что он тебе не нужен. Есть очевидные способы указания того что он тебе нужен в данной проге: (1) указание данного модуля в командной строке явно, (2) использование любого символа определенного в данном модуле.какой подход?
Я уже написал, что во многих типичных случаях такой подход неверен. Что ты скажешь относительно таких программ?
каких программ?
Как ты думаешь почему все эти приложения с плагинами и прочая упомянутая тобой хренотень работают, несмотря на то что ВСЕ линкеры работают именно так как я описал? Может потому, что их авторы умеют программировать и знают как работают линкеры?
> конечно это не баг линкера, а баг твоей прогиобъясни зачем корчить из себя дурачка?
То есть регистрировать плагины в медиа-приложениях методом статической инициализации - это баг?
ты в самом деле не понимаешь о чем я говорю?
я уже задолбался тратить время
За одно часовое занатие научу статически инициализировать плагины в медиа-приложениях, без багов и с подключением всех нужных модулей. На примерах и с картинками.
![](/images/graemlins/grin.gif)
> Т.е. ты предлагаешь, чтобы линкер подключал все библиотечные модули, присутствующие в системе, при линковании любой проги? Ты хоть предсталяешь сколько их?Когда ты пишешь в командной строке библиотеку, ты инструктируешь линкер не прилинковать все модули этой библиотеки, а использовать эту библиотеку так, как всегда используются все библиотеки (указанные явно или неявно как именно я уже писал. Это просто такой факт, причем для любого линкера.
Причему тут все модули, присутсвующие в системе? Система вообще раньше не упоминалась. Я даю четкое указание линкеру - прилинковать некоторую фиксированную библиотеку libxyz.a
Как подключить нужный модуль совершенно очевидно: написать этот МОДУЛЬ в командной строке. Что еще непонятно?
Если таки надо сделать подобный изврат, то копать в сторону ключа -u у gcc и ld для создания явных зависимостей и --whole-archive/--no-whole-archive у ld для подлючения библиотек целиком.заметь что использование этих опций в подобной ситуации крайне неразумная практика
не зря назвал это извратом.
Оставить комментарий
Landstreicher
Объявляю статический объект с конструкторов. Должен вызываться при инициализации. Но не вызывается:По идее, должны выводиться две строки "A ctor", "main". В чем глюк?