Множественное определение в статической библиотеке - PullRequest
3 голосов
/ 04 октября 2019

У меня есть вопрос, который очень тесно связан с Линкер не выдает многократную ошибку определения, когда один и тот же символ сосуществует в объектном файле и статической библиотеке , но касается немного другой ситуации. Как и здесь, у меня есть два файла .cpp (скажем: test1.cpp и test2.cpp), каждый из которых содержит реализацию одной и той же функции, то есть void testfunc(). У меня также есть заголовочный файл test.h, где я объявляю testfunc, а также файл main.cpp с главной функцией, которая содержит вызов testfunc(), например:

include "test.h"
int main() {
    testfunc();
}

Я компилируюотдельно .cpp файлы, вызвав g++ -c *.cpp, а затем создайте из них статическую библиотеку с ar rvs libtest.a test1.o test2.o. При связывании main.o с библиотекой теперь компоновщик не жалуется, как я ожидал:

gcc main.o -L. -ltest -o main

Полученный исполняемый файл работает отлично - вызывая одну из двух реализаций testfunc(). Честно говоря, я ожидал, что произойдет какая-то ошибка типа multiple definition of.... Поэтому у меня следующие вопросы:

  1. Почему это действительно работает - причина в ar, который добавляет в библиотеку только один из двух объектных файлов или библиотека содержит оба объектных файла& причина такого поведения скорее должна быть найдена в процессе компоновки, где компоновщик прекращает поиск в lib после того, как он нашел одно определение testfunc?
  2. Могу ли я как-то повлиять на то, какое определение testfunc являетсяна самом деле используется или это вообще определяется? То есть, может быть, это порядок аргументов ar, который решает, какой из них используется?
  3. Это поведение одинаково для любого компоновщика / версии ar или это может зависеть от системы?

1 Ответ

2 голосов
/ 04 октября 2019

Библиотека - это просто набор объектных файлов, содержащих экспортированные символы. Он может содержать любое количество дубликатов (точно так же, как библиотеки реальных книг могут содержать много книг с одинаковым названием). Связывание не задействовано.

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

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

...