Ответы:
Существует сторонний модуль CMake под названием Cotire, который автоматизирует использование предварительно скомпилированных заголовков для систем сборки на основе CMake, а также поддерживает сборки Unity.
Я использую следующий макрос для создания и использования предварительно скомпилированных заголовков:
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(PrecompiledBinary "${CMAKE_CURRENT_BINARY_DIR}/${PrecompiledBasename}.pch")
SET(Sources ${${SourcesVar}})
SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_OUTPUTS "${PrecompiledBinary}")
SET_SOURCE_FILES_PROPERTIES(${Sources}
PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_DEPENDS "${PrecompiledBinary}")
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
Допустим, у вас есть переменная $ {MySources} со всеми вашими исходными файлами, код, который вы хотели бы использовать, будет просто
ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})
Код все равно будет нормально работать и на платформах, отличных от MSVC. Довольно аккуратно :)
list( APPEND ... )
закрытие наружу endif()
. Смотрите полный код здесь: pastebin.com/84dm5rXZ
/Yu
и /FI
аргументы, их должно быть ${PrecompiledHeader}
и нет ${PrecompiledBinary}
.
/YuC:/foo/bar.h
, вы будете вынуждены либо передать /FpC:/foo/bar.h
флаг, либо поместить его #include <C:/foo/bar.h>
в начало всех ваших файлов .cpp в качестве первого оператора include. MSVC выполняет строковое сравнение #include
аргументов, но не проверяет, указывает ли он на тот же файл, что и был задан /Yu
. Ergo, #include <bar.h>
не будет работать и выдаст ошибку C2857.
CMake только что получил поддержку PCH, он должен быть доступен в следующем выпуске 3.16, который выйдет 01.10.2019:
https://gitlab.kitware.com/cmake/cmake/merge_requests/3553
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
Продолжается обсуждение поддержки совместного использования ПКП между целями: https://gitlab.kitware.com/cmake/cmake/issues/19659
Дополнительный контекст (мотивация, числа) доступен по адресу https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/
Вот фрагмент кода, позволяющий использовать предварительно скомпилированный заголовок для вашего проекта. Добавьте следующее в свой CMakeLists.txt, заменив myprecompiledheaders
и myproject_SOURCE_FILES
при необходимости:
if (MSVC)
set_source_files_properties(myprecompiledheaders.cpp
PROPERTIES
COMPILE_FLAGS "/Ycmyprecompiledheaders.h"
)
foreach( src_file ${myproject_SOURCE_FILES} )
set_source_files_properties(
${src_file}
PROPERTIES
COMPILE_FLAGS "/Yumyprecompiledheaders.h"
)
endforeach( src_file ${myproject_SOURCE_FILES} )
list(APPEND myproject_SOURCE_FILES myprecompiledheaders.cpp)
endif (MSVC)
with set( CMAKE_AUTOMOC ON )
.
myprecompiledheader.cpp
сначала убедиться, что он скомпилирован? Судя по этому фрагменту, он будет скомпилирован последним, так что, возможно, именно это может быть причиной задержки. myprecompiledheader.h
содержит только самые распространенные заголовки STL, которые использует мой код.
В итоге я использовал адаптированную версию макроса larsm. Использование $ (IntDir) в качестве пути к pch сохраняет предварительно скомпилированные заголовки для отладочной и выпускной сборок отдельно.
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(PrecompiledBinary "$(IntDir)/${PrecompiledBasename}.pch")
SET(Sources ${${SourcesVar}})
SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_OUTPUTS "${PrecompiledBinary}")
SET_SOURCE_FILES_PROPERTIES(${Sources}
PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_DEPENDS "${PrecompiledBinary}")
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
ADD_MSVC_PRECOMPILED_HEADER("stdafx.h" "stdafx.cpp" MY_SRCS)
ADD_EXECUTABLE(MyApp ${MY_SRCS})
Адаптировано от Дэйва, но более эффективно (задает целевые свойства, а не для каждого файла):
if (MSVC)
set_target_properties(abc PROPERTIES COMPILE_FLAGS "/Yustd.h")
set_source_files_properties(std.cpp PROPERTIES COMPILE_FLAGS "/Ycstd.h")
endif(MSVC)
abc
в твоем примере?
если вы не хотите изобретать велосипед, просто используйте либо Cotire, как предлагает верхний ответ, либо более простой - cmake-precompiled-header здесь . Чтобы использовать его, просто включите модуль и вызовите:
include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
CMake 3.16 представил поддержку предварительно скомпилированных заголовков. Есть новая команда CMake, target_precompile_headers
которая делает все, что вам нужно, под капотом. См. Его документацию для получения дополнительных сведений: https://cmake.org/cmake/help/latest/command/target_precompile_headers.html
"stdafx.h", "stdafx.cpp" - имя предварительно скомпилированного заголовка.
Поместите следующее в корневой файл cmake.
if (MSVC)
# For precompiled header.
# Set
# "Precompiled Header" to "Use (/Yu)"
# "Precompiled Header File" to "stdafx.h"
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Yustdafx.h /FIstdafx.h")
endif()
Поместите следующее в файл cmake проекта.
«src» - папка с исходными файлами.
set_source_files_properties(src/stdafx.cpp
PROPERTIES
COMPILE_FLAGS "/Ycstdafx.h"
)
IMHO, лучший способ - установить PCH для всего проекта, как предложил Мартино, в сочетании с возможностью игнорировать PCH для некоторых источников, если это необходимо (например, сгенерированные источники):
# set PCH for VS project
function(SET_TARGET_PRECOMPILED_HEADER Target PrecompiledHeader PrecompiledSource)
if(MSVC)
SET_TARGET_PROPERTIES(${Target} PROPERTIES COMPILE_FLAGS "/Yu${PrecompiledHeader}")
set_source_files_properties(${PrecompiledSource} PROPERTIES COMPILE_FLAGS "/Yc${PrecompiledHeader}")
endif(MSVC)
endfunction(SET_TARGET_PRECOMPILED_HEADER)
# ignore PCH for a specified list of files
function(IGNORE_PRECOMPILED_HEADER SourcesVar)
if(MSVC)
set_source_files_properties(${${SourcesVar}} PROPERTIES COMPILE_FLAGS "/Y-")
endif(MSVC)
endfunction(IGNORE_PRECOMPILED_HEADER)
Итак, если у вас есть цель MY_TARGET и список сгенерированных источников IGNORE_PCH_SRC_LIST, вы просто сделаете:
SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)
Этот подход проверен и отлично работает.
Хорошо, когда сборка занимает 10+ минут на четырехъядерном компьютере каждый раз, когда вы меняете одну строку в любом из файлов проекта, он сообщает вам, что пора добавить предварительно скомпилированные заголовки для Windows. В * nux я бы просто использовал ccache и не беспокоился об этом.
Я реализовал свое основное приложение и несколько библиотек, которые оно использует. На данный момент он отлично работает. Также необходимо создать исходный файл pch и файл заголовка, а в исходный файл включить все заголовки, которые вы хотите предварительно скомпилировать. Я делал это с MFC 12 лет, но мне потребовалось несколько минут, чтобы вспомнить это ..
Самый простой способ - добавить предварительно скомпилированный параметр в качестве глобального параметра. В файле vcxproj это будет отображаться как, <PrecompiledHeader>Use</PrecompiledHeader>
а не для каждого отдельного файла.
Затем вам нужно добавить эту Create
опцию в StdAfx.cpp. Вот как я его использую:
MACRO(ADD_MSVC_PRECOMPILED_HEADER SourcesVar)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /YuStdAfx.h")
set_source_files_properties(StdAfx.cpp
PROPERTIES
COMPILE_FLAGS "/YcStdAfx.h"
)
list(APPEND ${${SourcesVar}} StdAfx.cpp)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
file(GLOB_RECURSE MYDLL_SRC
"*.h"
"*.cpp"
"*.rc")
ADD_MSVC_PRECOMPILED_HEADER(MYDLL_SRC)
add_library(MyDll SHARED ${MYDLL_SRC})
Это проверено и работает для MSVC 2010 и создаст файл MyDll.pch, меня не беспокоит, какое имя файла используется, поэтому я не пытался его указать.
Поскольку параметр предварительно скомпилированного заголовка не работает для файлов rc, мне нужно было настроить макрос, предоставляемый jari.
#######################################################################
# Makro for precompiled header
#######################################################################
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(PrecompiledBinary "$(IntDir)/${PrecompiledBasename}.pch")
SET(Sources ${${SourcesVar}})
# generate the precompiled header
SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Zm500 /Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_OUTPUTS "${PrecompiledBinary}")
# set the usage of this header only to the other files than rc
FOREACH(fname ${Sources})
IF ( NOT ${fname} MATCHES ".*rc$" )
SET_SOURCE_FILES_PROPERTIES(${fname}
PROPERTIES COMPILE_FLAGS "/Zm500 /Yu\"${PrecompiledHeader}\" /FI\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
OBJECT_DEPENDS "${PrecompiledBinary}")
ENDIF( NOT ${fname} MATCHES ".*rc$" )
ENDFOREACH(fname)
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
Изменить: использование этих предварительно скомпилированных заголовков сократило общее время сборки моего основного проекта с 4 минут 30 секунд до 1 минуты 40 секунд. Для меня это действительно хорошо. В заголовке прекомпиляции есть только заголовки типа boost / stl / Windows / mfc.
Даже не ходи туда. Предварительно скомпилированные заголовки означают, что всякий раз, когда изменяется один из заголовков, вам нужно все перестраивать . Вам повезло, если у вас есть система сборки, которая это понимает. Чаще, чем никогда, ваша сборка просто терпит неудачу, пока вы не поймете, что изменили что-то, что предварительно скомпилировано, и поэтому вам нужно выполнить полную перестройку. Вы можете избежать этого в основном, предварительно скомпилировав заголовки, которые, как вы абсолютно уверены, не изменятся, но тогда вы также отказываетесь от значительной части прироста скорости.
Другая проблема заключается в том, что ваше пространство имен загрязняется всевозможными символами, которые вы не знаете или не заботитесь во многих местах, где вы будете использовать предварительно скомпилированные заголовки.