Odpowiedzi:
Istnieje zewnętrzny moduł CMake o nazwie „Cotire”, który automatyzuje użycie prekompilowanych nagłówków dla systemów kompilacji opartych na CMake, a także obsługuje kompilacje unity.
Używam następującego makra do generowania i używania prekompilowanych nagłówków:
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)
Powiedzmy, że masz zmienną $ {Moje źródła} ze wszystkimi plikami źródłowymi, kod, którego chciałbyś użyć, wyglądałby po prostu
ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})
Kod nadal działałby dobrze na platformach innych niż MSVC. Całkiem schludnie :)
list( APPEND ... )
zewnątrz zamknięcie endif()
. Zobacz pełny kod tutaj: pastebin.com/84dm5rXZ
/Yu
i /FI
, powinny być, ${PrecompiledHeader}
a nie ${PrecompiledBinary}
.
/YuC:/foo/bar.h
cię do przekazania /FpC:/foo/bar.h
flagi lub umieszczenia #include <C:/foo/bar.h>
na górze wszystkich twoich plików .cpp jako pierwsza instrukcja dołączania. MSVC porównuje #include
argumenty za pomocą ciągów , nie sprawdza, czy wskazuje na ten sam plik, do którego został podany /Yu
. Ergo, #include <bar.h>
nie zadziała i wyemituje błąd C2857.
CMake właśnie zyskał wsparcie dla PCH, powinno być dostępne w nadchodzącej wersji 3.16, która ma się pojawić 01.10.2019:
https://gitlab.kitware.com/cmake/cmake/merge_requests/3553
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
Trwa dyskusja na temat wspierania udostępniania PCH między celami: https://gitlab.kitware.com/cmake/cmake/issues/19659
Istnieje dodatkowy kontekst (motywacja, liczby) dostępny pod adresem https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/
Oto fragment kodu, który umożliwia użycie wstępnie skompilowanego nagłówka w projekcie. Dodaj następujące elementy do zastępowania CMakeLists.txt myprecompiledheaders
i myproject_SOURCE_FILES
odpowiednio:
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
jest skompilowany jako pierwszy? Z tego fragmentu wygląda na to, że zostanie skompilowany jako ostatni, więc może to może być przyczyną opóźnienia. myprecompiledheader.h
zawiera tylko najpopularniejsze nagłówki STL, których używa mój kod.
Skończyło się na tym, że użyłem zaadaptowanej wersji makra larsm. Użycie $ (IntDir) dla ścieżki pch powoduje oddzielenie prekompilowanych nagłówków do debugowania i kompilacji wydania.
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})
Zaadaptowane od Dave, ale bardziej wydajne (ustawia właściwości docelowe, nie dla każdego pliku):
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
w twoim przykładzie?
jeśli nie chce wyważać otwartych drzwi, wystarczy użyć Cotire jako górna odpowiedź sugeruje lub prostsze - cmake-prekompilowana-header tutaj . Aby z niego skorzystać, wystarczy dołączyć moduł i zadzwonić:
include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
CMake 3.16 wprowadził obsługę prekompilowanych nagłówków. Jest nowe polecenie CMake, target_precompile_headers
które robi wszystko, czego potrzebujesz pod maską. Więcej informacji można znaleźć w dokumentacji: https://cmake.org/cmake/help/latest/command/target_precompile_headers.html
„stdafx.h”, „stdafx.cpp” - nazwa prekompilowanego nagłówka.
Umieść poniższy plik w głównym pliku 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()
Umieść poniższy kod w pliku cmake projektu.
„src” - folder z plikami źródłowymi.
set_source_files_properties(src/stdafx.cpp
PROPERTIES
COMPILE_FLAGS "/Ycstdafx.h"
)
IMHO najlepszym sposobem jest ustawienie PCH dla całego projektu, jak sugerował martjno, w połączeniu z możliwością ignorowania PCH dla niektórych źródeł w razie potrzeby (np. Wygenerowane źródła):
# 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)
Tak więc, jeśli masz jakiś cel MY_TARGET i listę wygenerowanych źródeł IGNORE_PCH_SRC_LIST, po prostu zrobisz:
SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)
To podejście zostało przetestowane i działa doskonale.
Cóż, jeśli kompilacje trwają ponad 10 minut na czterordzeniowym komputerze, za każdym razem, gdy zmienisz jedną linię w dowolnym pliku projektu, pojawi się informacja, że należy dodać wstępnie skompilowane nagłówki dla systemu Windows. Na * nux po prostu użyłbym ccache i nie martwiłem się o to.
Zaimplementowałem w swojej głównej aplikacji i kilku bibliotekach, z których ona korzysta. Do tego momentu działa świetnie. Jedną rzeczą, która jest również potrzebna, jest utworzenie źródła pch i pliku nagłówkowego, aw pliku źródłowym uwzględnij wszystkie nagłówki, które chcesz prekompilować. Robiłem to przez 12 lat z MFC, ale zajęło mi kilka minut, aby to sobie przypomnieć.
Najprostszym sposobem jest dodanie opcji prekompilowanej jako opcji globalnej. W pliku vcxproj pojawi się jako<PrecompiledHeader>Use</PrecompiledHeader>
i nie będzie tego robić dla każdego pojedynczego pliku.
Następnie musisz dodać Create
opcję do StdAfx.cpp. Oto jak go używam:
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})
Jest to testowane i działa dla MSVC 2010 i utworzy plik MyDll.pch, nie przejmuję się nazwą pliku, więc nie starałem się go określić.
Ponieważ opcja prekompilowanego nagłówka nie działa dla plików rc, musiałem dostosować makro dostarczone przez 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)
Edycja: Użycie tych wstępnie skompilowanych nagłówków skróciło ogólny czas kompilacji mojego głównego projektu z 4 min 30 s do 1 min 40 s. To dla mnie naprawdę dobra rzecz. W nagłówku prekompilacji znajdują się tylko nagłówki, takie jak boost / stl / Windows / mfc.
Nawet tam nie idź. Wstępnie skompilowane nagłówki oznaczają, że za każdym razem, gdy zmieni się jeden z nagłówków, musisz wszystko odbudować . Masz szczęście, jeśli masz system kompilacji, który to rozumie. Najczęściej kompilacja kończy się niepowodzeniem, dopóki nie zdasz sobie sprawy, że zmieniłeś coś, co jest prekompilowane, i dlatego musisz przeprowadzić pełną przebudowę. Możesz tego uniknąć głównie poprzez prekompilowanie nagłówków, które nie zmienią się, co do której jesteś absolutnie pewny, ale wtedy również rezygnujesz z dużej części przyrostu szybkości.
Innym problemem jest to, że twoja przestrzeń nazw jest zanieczyszczona wszelkiego rodzaju symbolami, których nie znasz lub na których nie zależy ci w wielu miejscach, w których używałbyś prekompilowanych nagłówków.