2008-11-14 5 views
10

У меня есть куча устаревшего кода, для которого мне нужно написать модульные тесты. Он использует предварительно скомпилированные заголовки везде, поэтому почти все файлы .cpp имеют зависимость от stdafx.h, что затрудняет разбиение зависимостей, чтобы писать тесты.Есть ли способ использовать предварительно скомпилированные заголовки в VC++ без требования stdafx.h?

Мой первый инстинкт - удалить все эти файлы stdafx.h, которые по большей части содержат директивы #include и помещают их #includes непосредственно в исходные файлы по мере необходимости.

Это потребовало бы отключения предварительно скомпилированных заголовков, поскольку они зависят от наличия файла, такого как stdafx.h, чтобы определить, где остановлены предварительно скомпилированные заголовки.

Есть ли способ сохранить предварительно скомпилированные заголовки без зависимостей stdafx.h? Есть ли лучший способ подойти к этой проблеме?

+0

Лично я использую предварительно скомпилированные заголовки (как для обычного кода, так и для модульных тестов), но используйте имя Precompiled.h/cpp. Предварительно скомпилированные заголовки для модульных тестов включают в себя дополнительные заголовки, так что компиляция выполняется быстрее. – Daemin 2008-11-14 14:18:08

+0

ПОЖАЛУЙСТА, ГОЛОСУЙТЕ НА ЭТО: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4931119-allow-precompiled-headers-to-be-shared-between-pro – 2013-11-08 09:28:01

+0

Да, есть лучшее путь. Для каждого исходного файла может использоваться только один предварительно скомпилированный заголовок, но pch можно указать fore * каждый * исходный файл или набор исходных файлов. Вы также можете указать, какие исходные файлы использовать или не использовать предварительно скомпилированный заголовок. См. Мой ответ ниже. – riderBill 2016-02-20 04:17:47

ответ

9

Да, есть лучший способ.

Проблема, IMHO, с «волшебным стилем» прекомпилированных заголовков заключается в том, что они поощряют необработанную связь и делают повторное использование кода сложнее, чем должно быть. Кроме того, код, который был написан с помощью «всего-навсего в стиле stdafx.h», подвержен болью, чтобы поддерживать, поскольку изменение чего-либо в любом файле заголовка, вероятно, приведет к перекомпиляции всей кодовой базы каждый раз. Это может сделать простой рефакторинг навсегда, поскольку каждое изменение и перекомпиляция цикла занимает гораздо больше времени, чем нужно.

Лучшим способом, опять же ИМХО, является использование #pragma hdrstop и/Yc и/Yu. Это позволяет легко настраивать конфигурации сборки, которые используют прекомпилированные заголовки, а также создавать конфигурации, которые не используют предварительно скомпилированные заголовки. Файлы, которые используют предварительно скомпилированные заголовки, не имеют прямой зависимости от предварительно скомпилированного заголовка в исходном файле, который позволяет им строить с или без предварительно скомпилированного заголовка. Файл проекта определяет, какой исходный файл создает предварительно скомпилированный заголовок, а строка #pragma hdrstop в каждом исходном файле определяет, какие из них берутся из предварительно скомпилированного заголовка (если используется) и которые берутся непосредственно из исходного файла ... Это означает, что когда при выполнении обслуживания вы будете использовать конфигурацию, которая не использует предварительно скомпилированные заголовки, и только код, который требуется перестроить после изменения файла заголовка, будет восстановлен. При выполнении полной сборки вы можете использовать предварительно скомпилированные конфигурации заголовков, чтобы ускорить процесс компиляции.Еще одна хорошая вещь о том, что опция сборки не-прекомпилированных заголовков заключается в том, что она гарантирует, что ваши файлы cpp включают только то, что им нужно, и включают все, что им нужно (что-то, что сложно, если вы используете «стиль мастера» предварительно скомпилированного заголовка.

Я написал немного о том, как это работает здесь: http://www.lenholgate.com/blog/2004/07/fi-stlport-precompiled-headers-warning-level-4-and-pragma-hdrstop.html (игнорировать материал о/FI), и у меня есть некоторые примеры проектов, которые строят с #pragma hdrstop и метод/YC/Ю. здесь:. http://www.lenholgate.com/blog/2008/04/practical-testing-16---fixing-a-timeout-bug.html

Конечно, переход от привычного использования заголовка «стиль мастера» в более управляемый стиль часто нетривиален ...

2

Нет, возможно, есть NOT лучший способ.

Однако для данного индивидуального .cpp-файла вы можете решить, что вам не нужен предварительно скомпилированный заголовок. Вы можете изменить настройки для этого .cpp-файла и удалить строку stdafx.h.

(На самом деле, я не понимаю, как предварительно скомпилированная схема заголовка мешает написанию ваших модульных тестов).

+0

Да, есть лучший способ. См. Мой ответ ниже. Ответ @Len Holgate также работает. – riderBill 2016-02-20 04:19:00

2

Нет. Предварительно скомпилированные заголовки полагаются на один заголовок, включенный всеми источниками, скомпилированными таким образом. вы можете указать для одного источника (или всех) не использовать предварительно скомпилированные заголовки вообще, но это не то, что вы хотите.

В прошлом компилятор Borland C++ делал предварительную компиляцию без определенного заголовка. Однако, если два источника файлы включены одни и те же заголовки, но в другом порядке , они были составлены отдельно, так как, в самом деле, порядок заголовочных файлов в C++ может иметь значение ...

Таким образом, это означает, что Борланд пре- скомпилированные заголовки действительно сэкономили время, только если вы очень жестко включили источники в том же порядке или имели один включенный файл (сначала) всеми другими файлами ... - звучит знакомо?!?!

+0

Неверно; вы можете указать другой предварительно скомпилированный заголовок для каждого отдельного исходного файла или указать, что некоторые файлы suce используют его, а другие нет. – riderBill 2016-02-20 04:22:21

1

Мой совет - не удаляйте предварительно скомпилированные заголовки, если вы не хотите, чтобы ваши сборки мучительно медленно. Вы в основном есть три варианта здесь:

  1. Избавьтесь от скомпилированных заголовков (не рекомендуется)
  2. Создайте отдельную библиотеку для унаследованного кода; таким образом вы можете построить его отдельно.
  3. Используйте несколько предварительно скомпилированных заголовков в рамках одного проекта. Вы можете выбрать отдельные файлы C++ в своем обозревателе решений и сообщить им, какой премаркированный заголовок использовать. Вам также необходимо настроить свой файл OtherStdAfx.h/cpp для генерации предварительно скомпилированного заголовка.
0

Я использую предварительно скомпилированные заголовки для кода, который должен включать в себя материал afx___ - обычно это просто интерфейс, который я не тестирую unit-test. UI-код обрабатывает пользовательский интерфейс и вызывает функции, которые имеют модульные тесты (хотя большинство из них в настоящее время не связано с тем, что приложение устарело).

Для большей части кода я не использую предварительно скомпилированные заголовки.

G.

4

Когда вы обычно используете предварительно скомпилированные заголовки, «stdafx.h» выполняет 2 цели. Он определяет набор стабильных общих файлов include. Также в каждом .cpp-файле он служит маркером, где заканчиваются прекомпилированные заголовки.

Похоже, что вы хотите сделать, это:

  • Leave прекомпилирована заголовок включен.
  • Оставьте «stdafx.h» включенным в каждый .cpp-файл.
  • Исключить из категории "stdafx.h".
  • Для каждого .cpp-файла необходимо выяснить, какие из них были необходимы из старого «stdafx.h». Добавьте их перед #include "stdafx.h" в каждый .cpp-файл.

Итак, у вас есть минимальный набор зависимостей, и вы все еще используете предварительно скомпилированные заголовки. Потеря заключается в том, что вы не предварительно скомпилируете свой общий набор заголовков только один раз. Это было бы большим ударом для полной перестройки. В режиме разработки, где вы только перекомпилируете несколько файлов за раз, это будет менее хит.

2

Да. Имя «stdafx.h/stdafx.pch» - это просто соглашение. Вы можете предоставить каждому .cpp свой собственный предварительно скомпилированный заголовок. Это, вероятно, было бы проще всего сделать с помощью небольшого скрипта для редактирования XML в вашем .vcproj. Даунсайд: вы получаете большой стек предварительно скомпилированных заголовков, и они не разделяются между TU.

Возможно, но умный? Не могу сказать точно.

1

Предварительно скомпилированные заголовки основаны на идее, что все будет включать в себя один и тот же набор материалов. Если вы хотите использовать предварительно скомпилированные заголовки, вам нужно жить с зависимостями, которые это подразумевает. Это сводится к компромиссу зависимостей от скорости сборки. Если вы можете построить в разумные сроки, когда предварительно скомпилированные заголовки отключены, обязательно сделайте это.

Другая вещь, которую следует учитывать, состоит в том, что у вас может быть один pch на библиотеку. Таким образом, вы можете разделить свой код на более мелкие библиотеки и иметь каждый из них более жесткий набор зависимостей.

0

Предварительно скомпилированные заголовки могут сэкономить много t ime при перестройке проекта, но если изменяется прекомпилированный заголовок, то каждый исходный файл в зависимости от заголовка будет перекомпилирован, влияет ли на него изменение. К счастью, предварительно скомпилированные заголовки используются для компиляции, а не link; каждый исходный файл не должен использовать тот же предварительно скомпилированный заголовок.

pch1.h:

#include <bigHeader1.h> 
#include ... 


pch1.cpp:

#include "pch1.h" 


source1.cpp:

#include "pch1.h" 
[code] 


pch2.h:

#include <bigHeader2.h> 
#include ... 


pch2.cpp:

#include "pch2.h" 


source2.cpp

#include "pch2.h" 
[code] 

Выберите pch1.cpp, щелкните правой кнопкой мыши, свойства, Свойства конфигурации, C/C++, предварительно скомпилированных заголовков.
Скомпилированная Заголовок: Создать (/ Yc)
Скомпилированная Заголовок файла: pch1.h
Скомпилированная Заголовок выходного файла: $ (intDir) pch1.pch

Выберите source1.cpp
Скомпилированная Заголовок: Использование (/ Yu)
Скомпилированная Заголовочный файл: pch1.h
Скомпилированная Заголовок выходного файла: $ (intDir) pch1.pch (я не думаю, что это имеет значение для/Ю)

Сделайте то же самое для pch2.cpp и source2.каст, за исключением установки заголовка файла и заголовка выходного файла к pch2.h и pch2.pch. Это подходит для меня.