Связывание собственной библиотеки stati c с управляемым проектом C ++ извлекает неиспользуемые (и неожиданные) зависимости в - PullRequest
0 голосов
/ 06 августа 2020

Синопсис:

Управляемый (/clr) проект C ++ (.dll) статически связывает собственную библиотеку C ++ (которая скомпилирована с /MD). Библиотека Stati c велика и ссылается на множество других библиотек, но функциональность, используемая управляемым кодом C ++, тривиальна и не требует дополнительных зависимостей.

Проблемы:

  1. не удается связать LNK2001 и LNK2019 с указанием символов, код которых определенно не зависит от
  2. , даже если я добавляю необходимые зависимости, переключая набор инструментов (например, переход с VS2017 на VS2019) приводит к возврату ошибок (на этот раз с упоминанием других зависимостей)

Что происходит:

По-видимому, переключатель /clr заставляет компилятор обрабатывать встроенные функции по-другому - они больше не встраиваются в файлы .obj (как «слабые символы»), вместо этого на них ссылаются в таблице импорта. Это означает, что компоновщик должен найти такие вещи, как:

"public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)

... что он и делает, и (поскольку библиотеки CRT - DEFAULTLIB и поэтому используются последними) обычно находит его в другой библиотеке (а именно, в вышеупомянутую stati c native lib). Итак, он находит первый .obj файл в stati c lib, который содержит std::exception::what(), и извлекает его - это означает, что теперь мы зависим от всего сказанного .obj зависит. Это объясняет проблему №1 (фиктивные ошибки компоновщика).

Теперь, если вы скомпилируете свою stati c lib с другим набором инструментов - obj файлы могут храниться в другом порядке, что приведет к проблеме №2.

Чтобы воспроизвести проблему, вы можете использовать этот код (убедитесь, что управляемый проект связывает stati c lib):

//--------------------
// statlib.cpp
//
#include <exception>

void this_is_a_trap() { throw std::exception(); }

extern int bar();

int foo() { return bar(); }


//--------------------
// clrdll.cpp (managed code)
//
#include <exception>

__declspec(dllexport) void oops()
{
    throw std::exception();
}

Если вы установите ссылку с флагом /VERBOSE, вы увидите что-то вроде :

1>    Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\oleaut32.lib:
1>    Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\uuid.lib:
1>    Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbc32.lib:
1>    Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbccp32.lib:
1>    Searching C:\tst\x64\Release\statlib.lib:
1>      Found "public: virtual char const * __cdecl std::exception::what(void)const " (?what@exception@std@@UEBAPEBDXZ)
1>        Referenced in clrdll.obj
1>        Loaded statlib.lib(statlib.obj)   <-- Now we depend on `bar()`

Вопрос

Как лучше всего справиться с этим?

Примечания:

  • добавление msvcrt.lib к входам компоновщика (перед другими stati c libs) помогает, но не всегда - некоторые символы (например, std::bad_weak_ptr::what() отсутствуют в msvcrt.lib)

  • эта проблема является root причиной этого сообщения SO

1 Ответ

0 голосов
/ 27 августа 2020

В смешанном (/clr и собственном) коде std::exception::what() (и другие подобные символы) do становятся встроенными, но эти определения управляемые (не собственные). Обычно это не проблема, но собственный код ссылается на определение native через vtable std::exception. Обычно такая ссылка (если она не может быть разрешена) перенаправляется на управляемое определение (которое создается, как указано выше), но в этом случае - собственное определение находится в другом объекте (случайный объект из собственной библиотеки stati c) до того, как сработает «перенаправление», в результате чего на этот объект будет сделана ссылка.

См. подробности здесь . MS пытается найти лучший способ справиться с этим.

...