У меня есть библиотека, которая очень часто использует шаблоны, чтобы избежать многократного переписывания одного и того же кода. Но, как известно, это приводит к ужасным временам компиляции, а в Visual Studio - к тяжелому и медленному интеллекту, что делает кодирование на компьютере с 4 ГБ ОЗУ очень шумным.
Однако большинство классов разработаны так, что они могут только быть созданным с конкретными типами и шаблонами, чтобы избежать перезаписи для каждого типа, это заставило меня переместить большинство реализаций в .cpp
файлы и использовать там явное создание экземпляров шаблона.
Например, у меня есть:
// socket.h
template<class Protocol>
class socket
{
};
// socket.cpp
template class socket<tcp>;
template class socket<udp>;
template class socket<local::tcp>;
template class socket<local::udp>;
// sslstream.h
template<class NextLayer, class Engine>
class sslstream
{
};
// sslstream.cpp
template class sslstream<tcp::socket, openssl::engine>;
template class sslstream<tcp::socket, wolfssl::engine>;
template class sslstream<udp::socket, openssl::engine>;
template class sslstream<udp::socket, wolfssl::engine>;
// and so on
// websocket.h
template<class NextLayer>
class wsstream
{
};
// websocket.cpp
template class wsstream<tcp::socket>;
template class wsstream<sslstream<tcp::socket, openssl::engine>>;
// and so on for all possible layers
Проблемы начинаются, когда я пытаюсь использовать что-то вроде wsstream<tcp::socket>
в любом источнике, который ссылается на библиотеку. Линкер пытается включить все нестатические c функции и все экземпляры шаблонов по пути и выдаст ошибки для неразрешенных функций из библиотек openssl и wolfssl, если я не передам их компоновщику. Это увеличивает размер программы и включает в себя тонны неиспользуемого кода из openssl и wolfssl, даже если я вообще не использую ssl-функциональность! И десятки экземпляров шаблона будут включены и никогда не будут ссылаться только потому, что они создаются в одном и том же модуле перевода!
Я прочитал, что компоновщик в обычных обстоятельствах не может удалить неиспользуемые функции из объектного файла (либо нет включать его или включать весь объект), потому что функции l ie находятся в одной и той же сегментации кода, и компоновщик не может их легко разделить.
Затем я читаю о связывании на уровне функций, которое вводится для решения таких проблем ( Я думаю) и помещает каждую функцию в отдельный раздел, чтобы компоновщик мог выбросить неиспользуемые разделы
Вот что я сделал:
Включено связывание на уровне функций в проект библиотеки / Gy
Включить генерацию временного кода связи / LTCG в проекте программы, а также / Gy
Полученный файл lib был настолько огромным : более 60 МБ! Раньше было около 8 МБ.
Я ожидал, что теперь компоновщик не сможет включать неиспользуемый код, но результат exe не уменьшился в размере, а также имел много кода и строк из openssl и wolfssl!
Это ожидаемый результат? Или я что-то не так делаю? и если это предусмотрено, существует ли какой-либо метод, позволяющий отделить реализацию от шаблонных интерфейсов и не принуждать к включению целых экземпляров?