Есть ли способ сделать так, чтобы компоновщик извлекал часть объектного файла из библиотеки для компоновки? - PullRequest
0 голосов
/ 09 февраля 2019

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

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

Например:

old library.lib:

file1.o
file2.o
file3.o
file4.o
file5.o
file6.o

new library.lib:

translation_unit_1.o
translation_unit_2.o

translation_unit_1.c:

#include "file1.c"
#include "file2.c"
#include "file3.c"

translation_unit_2.c:

#include "file4.c"
#include "file5.c"
#include "file6.c"

Таким образом, они компилируются в: translation_unit_1.o и translation_unit_2.o.И библиотека - это новый library.lib, показанный выше.

Теперь скажите, что у меня есть программа, которую я хочу связать с library.lib, которая ссылается на функцию в file2.c.Но имеет другую версию file1.c, которая компилирует, которая дублирует символы в file1.c в библиотеке, так что для связывания нужен только file2.c из library.lib.Или, возможно, мне нужно связать код из file1.c, но я не могу связать file2.c, потому что у него есть зависимость, на которую я не хочу полагаться (пример ниже).

program:

main.o
file1.o
library.lib

Есть ли способ с любым известным вам компоновщиком получить компоновщик только для извлечения кода из file2.c из объектного кода translation_unit_1.o и использования его для связи main.o с целью создания программы?

Альтернативой может быть разделение translation_unit_1.o на file1.o, file2.o, file3.o, если это возможно, а затем передать его компоновщику.

Спасибо залюбая помощь.

edit 1

Это для единой кодовой базы, которая скомпилирована как для платформы ARM с открытым исходным кодом, использующей ELF, скомпилированную с ARM ADS 1.2, так и дляплатформа Windows, которая использует набор инструментов Visual Studio.Однако, мысли о том, как подойти к проблеме на других платформах и инструментальных цепочках, приветствуются.

Вот конкретный пример на MacOS с использованием clang.

Пример кода ниже приведен здесь: https://github.com/awmorgan/single_translation_unit_lib_link

библиотека:

file1.c этот файл необходим для связи

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

main.c:

int main( void ) {
    extern int file1_a( void );
    int x = file1_a();
}

file1.c:

int file1_a(void) {
    return 1;
}

file2.c:

int file2_a( void ) {
    extern int file3_a( void );
    return file3_a(); // file3_a() is located somewhere else
}

single_translation_unit.c:

#include "file1.c"
#include "file2.c"

это работает для создания program1.out:

++ clang -c file1.c -o file1.o
++ clang -c file2.c -o file2.o
++ libtool -static file1.o file2.o -o library1.lib
++ clang -c main.c -o main1.o
++ clang main1.o library1.lib -o program1.out

это не приводит к program2.out:

++ clang -c single_translation_unit.c -o single_translation_unit.o
++ libtool -static single_translation_unit.o -o library2.lib
++ clang -c main.c -o main2.o
++ clang main2.o library2.lib -o program2.out
Undefined symbols for architecture x86_64:
  "_file3_a", referenced from:
      _file2_a in library2.lib(single_translation_unit.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

изменение порядка ссылок также не работает:

++ clang library2.lib main2.o -o program2.out
Undefined symbols for architecture x86_64:
  "_file3_a", referenced from:
      _file2_a in library2.lib(single_translation_unit.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

С помощью набора инструментов GCC / binutils ELF или подходящим образом совместимых инструментов вы можете сделать это:

  1. Компиляция single_translation_unit.c с параметрами -ffunction-sections, -fdata-sections
  2. Связывание program2.out с опцией компоновщика -gc-sections.

Например (в Linux):

$ gcc -ffunction-sections -fdata-sections -c single_translation_unit.c -o single_translation_unit.o
$ ar rcs library2.a single_translation_unit.o # On Mac OS, use libtool to make the static library if you prefer.
$ gcc -c main.c -o main2.o
$ gcc main2.o library2.a -Wl,-gc-sections -o program2.out

Вы можете заменить gcc на clang повсюду.

Связывание успешно выполнено, потому что:

  • При компиляции -ffunction-sections указывает компилятору выдавать каждыйОпределение функции в отдельном разделе кода объектного файла, не содержащем ничего другого, вместо объединения их всех в один раздел .text, по умолчанию.
  • В связи -Wl,-gc-sections направил компоновщик котбрасывать неиспользуемые разделы, то есть разделы, в которых программа не ссылалась ни на какие символы.
  • Определение функции без ссылки file2_a получило отдельный фрагмент кода, не содержащий ничего другого, что поэтому не использовалось.Компоновщик смог отбросить этот неиспользованный раздел, а вместе с ним неразрешенную ссылку на file3_a в определении file2_a.

Так что никаких ссылок на file2_a или file3_a не былонаконец, связаны, как мы видим:

$ nm program2.out | egrep '(file2_a|file3_a)'; echo Done
Done

И если мы повторно сделаем связь, запрашивающую файл карты:

$ gcc main2.o library2.a -Wl,-gc-sections,-Map=mapfile -o program2.out

, тогда файл карты покажет нам:

...
...
Discarded input sections

 ...
 ...
 .text.file2_a  0x0000000000000000        0xb library2.a(single_translation_unit.o)
 ...
 ...

что функциональная секция text.file2.a, созданная в library2.a(single_translation_unit.o), действительно была выброшена.

Кстати ...

Из-за путив связке используется статическая библиотека, нет смысла архивировать один объектный файл single_translation_unit.o в статическую библиотеку library2 и затем связывать вашу программу с library2, если вы знаете, что ваша программа ссылается любой символ, определенный в single_translation_unit.o.Вы можете также пропустить создание library2 и просто вместо ссылки single_translation_unit.o.Учитывая, что символы, определенные в single_translation_unit.o, необходимы, связь:

$ gcc main2.o library2.a [-Wl,-gc-sections] -o program2.out

точно такая же, как:

$ gcc main2.o single_translation_unit.o [-Wl,-gc-sections] -o program2.out

с -Wl,-gc-sections.

И ...

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

0 голосов
/ 10 февраля 2019

Есть ли способ с clang, gcc, microsoft или любым компоновщиком

Ни один из clang, gcc или microsoft не является компоновщиком (первые два являются компиляторамии третий - корпорация).

Ответ также зависит от платформы (которую вы не указали).

ЕСЛИ вы работаете на Linux или другой платформе ELF,Вы можете скомпилировать свой код с помощью -ffunction-sections -fdata-sections, и компоновщик будет автоматически делать то, что вы хотите.

Есть ли способ заставить компоновщик извлечь часть объектного файла избиблиотека для связывания?

Как правило, линкеры работают с разделами и не могут разбивать разделы на части (вы получаете все или ничего).

Без -ffunction-sections, все функциив одной единице перевода заканчиваются в одной секции .text (это приближение - экземпляры шаблонов и определения функций вне строки для inline функций обычно заканчиваются в своем собственном разделе).Поэтому компоновщик не может выбрать некоторые, но не все части .text.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...