2017-02-15 14 views
2

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

Ли линкеры (в частности, GCC или Clang) поддерживают некоторый метод «дифференциального связывания», в котором содержится достаточная информация о взаимосвязях между всеми другими связанными частями, так что единственная работа, которая должна выполняться, когда одна часть перекомпилирована, это ее отношения к другим частям + объединение их в двоичный файл?

Примечание: меня интересует только C++, но я предполагаю, что этот вопрос обобщает, по крайней мере, на C и, возможно, на другие скомпилированные языки.

ответ

1

В MSVC это называется «инкрементным связыванием». Интересно, что то, что я обнаружил, что GCC может в некоторой степени поддержать это, попробуйте использовать параметры «» или «-Wl,-r» для GCC (на самом деле также должен поддерживаться CLang, поскольку эти параметры «-Wl» передаются только ld) ,


Я никогда не использовал его раньше, но я сделал эту работу со следующим Makefile:

OBJS := a.o b.o c.o main.o 

all: test_app 

test_app: test_app.reloc 
    g++ -o [email protected] $^ 

# build a "relocatable" object for incremental linking (either -i or -r) 
test_app.reloc: $(OBJS) 
    g++ -Wl,-i -nostdlib -nostartfiles -o [email protected] $^ 

$(OBJS): makefile 

%.o: %.cpp 
    g++ -c -o [email protected] $< 

Это создает приложение, но я не совсем уверен, что он делает внутри, если это на самом деле делает что-то вроде «инкрементной привязки», выполненной в MSVC.

В частности, параметр «-nostdlib» необходим при использовании «-Wl, -i», так что libs по умолчанию не будет передан в ld (который тогда не может найти их - без него ошибка «/usr/bin/ld: cannot find -lgcc_s»).


другой версии, которые могли бы на самом деле лучше работать (не уверен, это необходимо будет испытываться на большее применение, чтобы увидеть, если есть какой-то выигрыш во время связи для отдельных обновлений объекта):

OBJS := a.ro b.ro c.ro main.ro 

all: test_app 

test_app: $(OBJS) 
    g++ -o [email protected] $^ 

%.o: %.cpp 
    g++ -c -o [email protected] $< 

%.ro: %.o 
    g++ -Wl,-i -nostdlib -nostartfiles -o [email protected] $< 
  • В основном создается перемещаемый файл для каждого объекта (который может быть, пожалуй, значительной частью связывания файлов obj в исполняемый файл), а затем просто обновляет необходимые перемещения. Для окончательного этапа ссылки с использованием перемещаемых элементов для соединения всех вместе (но часть связи уже была сделана раньше).

Также возможно создать «группы» объектных файлов, которые будут сгруппированы в один перемещаемый, так что в конце их будет меньше (не уверен, что это принесло бы что-нибудь в конце, хотя) ,

+0

Можете ли вы написать еще несколько слов о том, что такое рабочий процесс, когда я использую эти параметры? например предположим, что мои исходные файлы - 'a.cpp',' b.cpp' и 'c.cpp', скомпилированные отдельно, без включений, и я хочу иметь возможность делать меньше ссылок, когда перекомпилирую' a.cpp'. Что я должен запускать изначально и что мне следует запускать с новым 'a.o'? – einpoklum

+0

Обновление с примером makefile – axalis

+0

О втором make-файле: Дело в том, что gcc может легко объединить файлы .ro в один исполняемый файл. Хорошо, но тогда - зачем нам вообще нужен шаг .cpp -> .o? Почему бы просто не сделать .cpp -> .ro немедленно? – einpoklum