Комбинация PCH, PDB и Zi приводит к удивительной ошибке компиляции C2859 с VS2017 - PullRequest
0 голосов
/ 01 апреля 2019

У меня есть проект, который в настоящее время не использует предварительно скомпилированные заголовки, но я бы хотел, чтобы это было так, поскольку я продемонстрировал, что это приводит к реальному улучшению скорости компиляции в проекте.

Я также хотел бы использовать /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

1 Ответ

1 голос
/ 01 апреля 2019

Из документации Microsoft для C2859 и создания предварительно скомпилированных заголовков база данных, используемая для хранения отладочной информации, должна быть общей для всех исходных модулей с использованием предварительно скомпилированного заголовка. Хранение всей этой общей отладочной информации, хранящейся в одной базе данных, значительно уменьшает размер объектных файлов и ускоряет связывание, поскольку компоновщик не должен иметь дело со всем этим повторением.

Если вы хотите, чтобы все ваши скомпилированные файлы имели свои собственные копии отладочной информации, используйте параметр /Z7.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...