Длительное время компиляции в Visual C++ 2010 с большими статическими массивами
У нас есть проект C++, в котором есть несколько больших статических таблиц данных (массивов структур), сгенерированных инструментом предварительной обработки и скомпилированных в наш проект. Мы использовали VC++ 2008 до сих пор, но готовимся к переходу на 2010 год, и эти таблицы данных неожиданно требуют очень много времени для компиляции.
Например, одна такая таблица содержит около 3000 записей, каждая из которых представляет собой структуру, содержащую несколько целых и указателей, причем все они инициализируются статически. Этот файл занимает ~15 секунд для компиляции в VC++ 2008, но занимает 30 минут в VC++ 2010!
В качестве эксперимента я попытался разбить эту таблицу на 8 таблиц, каждая в своем собственном файле.cpp, и они компилируются за 20-30 секунд каждая. Это заставляет меня думать, что что-то внутри компилятора равно O(n^2) по длине этих таблиц.
Использование памяти для платформ cl.exe составляет около 400 МБ (на моей машине установлено 12 ГБ ОЗУ), и я не вижу активности ввода-вывода после этого, поэтому я считаю, что это не проблема кэширования диска.
У кого-нибудь есть идея, что здесь может происходить? Есть ли какая-то функция компилятора, которую я могу отключить, чтобы вернуться к нормальному времени компиляции?
Вот образец данных в таблице:
// cid (0 = 0x0)
{
OID_cid,
OTYP_Cid,
0 | FOPTI_GetFn,
NULL,
0,
NULL,
(PFNGET_VOID) static_cast<PFNGET_CID>(&CBasic::Cid),
NULL,
CID_Basic,
"cid",
OID_Identity,
0,
NULL,
},
// IS_DERIVED_FROM (1 = 0x1)
{
OID_IS_DERIVED_FROM,
OTYP_Bool,
0 | FOPTI_Fn,
COptThunkMgr::ThunkOptBasicIS_DERIVED_FROM,
false,
NULL,
NULL,
NULL,
CID_Basic,
"IS_DERIVED_FROM",
OID_Nil,
0,
&COptionInfoMgr::s_aFnsig[0],
},
// FIRE_TRIGGER_EVENT (2 = 0x2)
{
OID_FIRE_TRIGGER_EVENT,
OTYP_Void,
0 | FOPTI_Fn,
COptThunkMgr::ThunkOptBasicFIRE_TRIGGER_EVENT,
false,
NULL,
NULL,
NULL,
CID_Basic,
"FIRE_TRIGGER_EVENT",
OID_Nil,
0,
NULL,
},
// FIRE_UNTRIGGER_EVENT (3 = 0x3)
{
OID_FIRE_UNTRIGGER_EVENT,
OTYP_Void,
0 | FOPTI_Fn,
COptThunkMgr::ThunkOptBasicFIRE_UNTRIGGER_EVENT,
false,
NULL,
NULL,
NULL,
CID_Basic,
"FIRE_UNTRIGGER_EVENT",
OID_Nil,
0,
NULL,
},
Как видите, он включает в себя различные целые и перечисления, а также несколько литеральных строк, указателей на функции и указателей на другие таблицы статических данных.
5 ответов
Возможно, стоит отключить всю оптимизацию этого файла (в любом случае, он ничего вам не купит) на случай, если оптимизатор выберет N^2.
У меня была такая же проблема. Был константный массив данных, который имел приблизительно 40 000 элементов. Время компиляции составило около 15 секунд. Когда я изменил "const uint8_t pData[] = { ... }" на "static const uint8_t pData [] = {...}", время компиляции сократилось до 1 секунды.
Вы можете попробовать отключить поддержку Pure MISL CLR в настройках C/C++. Работал на меня.
Я видел (не помню где) технику для преобразования больших статических данных непосредственно в объектные файлы. Ваш код C++ затем объявляет массив как extern
и компоновщик соответствует двум вместе. Таким образом, данные массива никогда не проходят этап компиляции вообще.
Инструмент Microsoft C/C++ CVTRES.exe
работал по схожему принципу, но он не генерировал символы, а имел отдельный ресурсный раздел, для доступа к которому требовались специальные API (FindResource
, LoadResource
, LockResource
).
Ааа, вот один из инструментов, которые я запомнил, найдя: bin2coff
У автора есть целая куча связанных инструментов
В качестве альтернативы вы можете попытаться уменьшить зависимости, чтобы конкретный исходный файл никогда не нуждался в перекомпиляции. Тогда минимальная перестройка будет автоматически использовать существующий файл.obj. Может быть, даже проверить этот файл.obj в системе контроля версий.
Попробуйте сделать ваш массив статическим const, это сокращает время компиляции (но не размер файла) в аналогичном случае, который я видел вплоть до нематериального.