Почему компилятор добавляет встроенные методы класса в lib? - PullRequest
0 голосов
/ 10 октября 2018

Рассмотрим класс, который относится к проекту, связанному с динамической библиотекой (foo.dll), с foo.lib, сгенерированным также на стороне:

class IMP_EXP_DIRECTIVE_MACRO Foo
{
     void bar()
     {
         // do something
     }
 };

Затем есть еще одна панель проекта (генерирующая статический файл).библиотека bar.lib), которая включает этот класс.Проект не связывается с foo.

Наконец, есть проект приложения (в результате .exe), который связывается как с foo.lib, так и с bar.lib.Когда это происходит, компоновщик выдает ошибку LNK2005 о том, что Foo::bar уже определен как в файле foo.lib (что хорошо), так и в файле bar.lib, что является неожиданным и странным.

При обработке bar.lib с помощьюdumpbin.exe / SYMBOLS согласно выводу https://docs.microsoft.com/en-us/cpp/build/reference/symbols?view=vs-2017 показывает, что Foo::bar действительно определен в foo.lib (!).Это странно, поскольку согласно этому блестящему ответу https://stackoverflow.com/a/4955288 любая функция-член, объявленная и определенная в теле класса, неявно встроена, поэтому не вызывает проблем с ODR.

Наконец,самая интересная часть.При перемещении определения Foo::bar в файл .cpp и оставлении только объявления метода в теле класса проблема исчезает.

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

Среда: Visual Studio 10.

edit:
IMP_EXP_DIRECTIVE_MACRO имеет значение:
"__declspec (dllexport)", при сборке foo.dll
"", при сборке bar

edit 2:
Problemтакже пропал, когда в компилятор bar.lib добавлен флаг препроцессора, который вызывает использование class __declspec(dllimport) Foo вместо class Foo.
Это правильный путь?

1 Ответ

0 голосов
/ 10 октября 2018

Функция встроенная .

Но если вы берете его адрес &Foo::bar, компилятору все еще нужен реальный адрес.Это практически означает, что по указанному адресу не должно быть встроенного кода.Следствием этого является то, что компилятор должен поместить копию в каждый модуль перевода, и компоновщик выберет один из них - по одному на каждый выход компоновщика.Но компоновщик Foo.lib не может предсказать, что будет также копия в Bar.lib и наоборот.

...