У меня есть проект, который в настоящее время не использует предварительно скомпилированные заголовки, но я бы хотел, чтобы это было так, поскольку я продемонстрировал, что это приводит к реальному улучшению скорости компиляции в проекте.
Я также хотел бы использовать /Zi
, чтобы использовать преимущества параллельной сборки, связанные с /Zf
, что подразумевается /Zi
.
Я использую компилятор VS2017 C ++, ноЯ использую систему сборки, которая не является Visual Studio, поэтому ответы, касающиеся настройки VS, бесполезны.
Что я обнаружил, так это то, что я могу настроить сборку на использование заранее скомпилированных заголовков, или я могу настроить ее на использование /Zi
просто отлично, но я не могу сформировать правильноесерия вызовов, чтобы сделать оба.Когда я пытаюсь сделать то, что считаю правильным, я получаю ошибку C2958
, останавливая сборку, и не вижу, что делаю неправильно.
Я создал игрушечный проект дляпродемонстрировать то, что я вижу.Заголовок pch.hpp
выглядит следующим образом:
#pragma once
#include <vector>
И мы делаем короткую главную строку в main.cpp
:
int main() {
std::vector<int> xs = { 1, 2, 3 };
return xs.size();
}
Обратите внимание, что это полное содержимое файла для main.cpp
Я ничего не пропустил.Я намеренно не , включая pch.hpp
здесь, потому что мы собираемся принудительно ввести его с /Fi
позже.Реальный проект не имеет строк для предварительно скомпилированного заголовка во всех нужных местах, и для этого потребуется обновить тысячи файлов.Обратите внимание, что подход, использующий /Fi
, действительно работает в приведенных ниже командных строках и имеет то преимущество, что механизм на основе forceinclude также может работать с предварительно скомпилированными заголовками в стиле GCC.
Если мы собираем вещи без /Zi
все идет хорошо:
cl /Fobuild\pch.obj /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /c pch.hpp /Yc /Fpbuild\pch.pch
pch.hpp
cl /Fobuild\main.obj /c main.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Yupch.hpp /Fpbuild/pch.pch
main.cpp
Мы находим файлы, которые ожидаем найти в каталоге сборки:
main.obj pch.obj pch.pch
Однако, если мы попытаемся использовать /Fi
и /Fd
для создания каждого файла .pdb
и управления его именем, он не работает вообще:
Мы можем скомпилировать предварительно скомпилированный заголовок следующим образом ОК:
cl /Fobuild\pch.obj /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /c pch.hpp /Yc /Fpbuild\pch.pch /Zi /Fdbuild\pch.pch.pdb
Ипока что все выглядит нормально в каталоге build
:
pch.obj pch.pch pch.pch.pdb
Но когда мы пытаемся построить объектный файл для main, все это разваливается:
cl /Fobuild\main.obj /c main.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Yupch.hpp /Fpbuild/pch.pch /Zi /Fdbuild\main.obj.pdb
main.cpp
main.cpp: error C2859: Z:\data\acm\src\example\build\main.obj.pdb is not the pdb file that was used when this precompiled header was created, recreate the precompiled header.
Этоочень странная ошибка, потому что сообщение об ошибке предполагает, что main.obj.pdb
как-то обрабатывается как input , но на самом деле это имя файла .pdb
, сгенерированного как output , за значение флага /Fd
для build из main.obj
.
Поиск в Google не дал много полезных советов с большим количеством советов по перенастройке настроек VS, что не очень полезно в случае сборки, управляемой чем-то другим.
Я также убедился, что моя хитрость с /Fi
из pch.hpp
не является проблемой.Если я обновлю main.cpp
до #include pch.hpp
и удаляю /Fipch.hpp
из строки компиляции для main.obj
, все равно будет возникать та же самая ошибка C2859
.
Я понимаю, что нужно получить много флаговПравильно, когда используются предварительно скомпилированные заголовки, в том числе флаги /Yc
и /Yu
и /Fp
, но я думаю, что я правильно их обработал.
Кто-нибудь видит, где у меня что-то не так?
Редактировать 1 - Демонстрация того, что / Fd может называть разные файлы PDB
В ответ на комментарий ниже, фактически это не тот случай, когда все целидолжен иметь аргумент /Fd
.Вот пример без использования предварительно скомпилированных заголовков, который демонстрирует, что:
Здесь мне нужно было добавить common.cpp
и создать main1.cpp
и main2.cpp
, которые оба связывают его:
Заголовок common.hpp
выглядит следующим образом:
#pragma once
int common(int arg);
При тривиальной реализации в common.cpp
:
#include "common.hpp"
int common(int arg) {
return arg + 42;
}
Затем введите две разные основные строки:
main1.cpp
:
#include "common.hpp"
int main() {
std::vector<int> xs = { 1, 2, 3 };
return common(xs.size());
}
И main2.cpp
:
#include "common.hpp"
int main() {
std::vector<int> xs = { 1, 2, 3, 4};
return common(xs.size());
}
Затем скомпилируйте все три объектных файла.Обратите внимание, что у нас все еще есть /Fipch.hpp
, чтобы правильно включить включения, но мы не используем какой-либо реальный механизм PCH:
cl /Fobuild\common.obj /c common.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\common.obj.pdb
cl /Fobuild\main1.obj /c main1.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\main1.obj.pdb
cl /Fobuild\main2.obj /c main2.cpp /TP /nologo /EHsc /errorReport:none /MD /O2 /Oy- /Zc:rvalueCast /Zc:strictStrings /volatile:iso /Zc:__cplusplus /permissive- /std:c++17 /Zc:inline /FIpch.hpp /Zi /Fdbuild\main2.obj.pdb
И мы находим то, что ожидаем в build
каталог:
common.obj common.obj.pdb main1.obj main1.obj.pdb main2.obj main2.obj.pdb
Затем мы можем продолжить и связать:
link /nologo /DEBUG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OUT:build\main1.exe /PDB:build\main1.pdb build\common.obj build\main1.obj
link /nologo /DEBUG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OUT:build\main2.exe /PDB:build\main2.pdb build\common.obj build\main2.obj
И мы обнаружим, что мы получаем как исполняемые файлы, так и файлы PDB для этих исполняемых файлов в каталоге build
:
common.obj main1.exe main1.obj.pdb main2.exe main2.obj.pdb
common.obj.pdb main1.obj main1.pdb main2.obj main2.pdb