Respuestas:
Existe un módulo CMake de terceros llamado 'Cotire' que automatiza el uso de encabezados precompilados para sistemas de compilación basados en CMake y también admite compilaciones unitarias.
Estoy usando la siguiente macro para generar y usar encabezados precompilados:
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)
Digamos que tiene una variable $ {MySources} con todos sus archivos fuente, el código que le gustaría usar sería simplemente
ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})
El código también funcionaría bien en plataformas que no sean MSVC. Con buena pinta :)
list( APPEND ... )
exterior del cierre endif()
. Vea el código completo aquí: pastebin.com/84dm5rXZ
/Yu
y /FI
, deberían serlo ${PrecompiledHeader}
y no ${PrecompiledBinary}
.
/YuC:/foo/bar.h
lo obligará a pasar la /FpC:/foo/bar.h
bandera o colocarlo #include <C:/foo/bar.h>
en la parte superior de todos sus archivos .cpp como la primera declaración de inclusión. MSVC hace una comparación de cadenas de los #include
argumentos, no verifica si apunta al mismo archivo que se le dio /Yu
. Ergo, #include <bar.h>
no funcionará y emitirá el error C2857.
CMake acaba de obtener soporte para PCH, debería estar disponible en la próxima versión 3.16, con fecha de 2019-10-01:
https://gitlab.kitware.com/cmake/cmake/merge_requests/3553
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
Existe un debate en curso sobre el apoyo a compartir PCH entre objetivos: https://gitlab.kitware.com/cmake/cmake/issues/19659
Hay un contexto adicional (motivación, números) disponible en https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/
Aquí hay un fragmento de código que le permite utilizar un encabezado precompilado para su proyecto. Agregue lo siguiente a su CMakeLists.txt reemplazando myprecompiledheaders
y myproject_SOURCE_FILES
según corresponda:
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
se compile primero? A partir de este fragmento, parece que se compilará en último lugar, por lo que quizás eso sea lo que podría estar causando el retraso. myprecompiledheader.h
contiene solo los encabezados STL más comunes que usa mi código.
Terminé usando una versión adaptada de larsm macro. El uso de $ (IntDir) para la ruta pch mantiene separados los encabezados precompilados para depurar y publicar versiones.
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})
Adaptado de Dave, pero más eficiente (establece propiedades de destino, no para cada archivo):
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
en tu ejemplo?
si no desea reinventar la rueda, simplemente use Cotire como sugiere la respuesta principal o una más simple: cmake-precompiled-header aquí . Para usarlo solo incluye el módulo y llama:
include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
CMake 3.16 introdujo soporte para encabezados precompilados. Hay un nuevo comando CMake target_precompile_headers
que hace todo lo que necesita bajo el capó. Consulte su documentación para obtener más detalles: https://cmake.org/cmake/help/latest/command/target_precompile_headers.html
"stdafx.h", "stdafx.cpp": nombre de encabezado precompilado.
Coloque lo siguiente a continuación en el archivo cmake raíz.
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()
Ponga lo siguiente a continuación en el archivo cmake del proyecto.
"src": una carpeta con archivos de origen.
set_source_files_properties(src/stdafx.cpp
PROPERTIES
COMPILE_FLAGS "/Ycstdafx.h"
)
En mi humilde opinión, la mejor manera es configurar PCH para todo el proyecto, como sugirió martjno, combinado con la capacidad de ignorar PCH para algunas fuentes si es necesario (por ejemplo, fuentes generadas):
# 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)
Entonces, si tiene un MY_TARGET objetivo y una lista de fuentes generadas IGNORE_PCH_SRC_LIST, simplemente hará:
SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)
Este enfoque está probado y funciona perfectamente.
Bueno, cuando las compilaciones toman más de 10 minutos en una máquina de cuatro núcleos, cada vez que cambia una sola línea en cualquiera de los archivos del proyecto, le indica que es hora de agregar encabezados precompilados para Windows. En * nux solo usaría ccache y no me preocuparía por eso.
Lo he implementado en mi aplicación principal y en algunas de las bibliotecas que utiliza. Funciona muy bien en este punto. Una cosa que también es necesaria es que debe crear el archivo fuente y de encabezado pch y en el archivo fuente incluir todos los encabezados que desea que se compilen previamente. Hice esto durante 12 años con MFC, pero me tomó unos minutos recordarlo ...
La forma más limpia es agregar la opción precompilada como una opción global. En el archivo vcxproj esto se mostrará como<PrecompiledHeader>Use</PrecompiledHeader>
y no lo hará para cada archivo individual.
Luego, debe agregar la Create
opción a StdAfx.cpp. Lo siguiente es cómo lo uso:
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})
Esto está probado y funciona para MSVC 2010 y creará un archivo MyDll.pch, no me molesta qué nombre de archivo se usa, así que no hice ningún esfuerzo para especificarlo.
Como la opción de encabezado precompilado no funciona para archivos rc, necesitaba ajustar la macro proporcionada por 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)
Editar: El uso de estos encabezados precompilados redujo el tiempo de compilación general de mi proyecto principal de 4min 30s a 1min 40s. Esto es para mí algo realmente bueno. En el encabezado de precompilación solo hay encabezados como boost / stl / Windows / mfc.
Ni siquiera vayas allí. Los encabezados precompilados significan que cada vez que cambia uno de los encabezados, debe reconstruir todo . Tienes suerte si tienes un sistema de construcción que se dé cuenta de esto. La mayoría de las veces, su compilación fallará hasta que se dé cuenta de que cambió algo que se está compilando previamente y, por lo tanto, debe realizar una reconstrucción completa. Puede evitar esto principalmente compilando los encabezados de los que está absolutamente seguro de que no cambiarán, pero también está renunciando a una gran parte de la ganancia de velocidad.
El otro problema es que su espacio de nombres se contamina con todo tipo de símbolos que no conoce o que no le interesan en muchos lugares donde estaría usando los encabezados precompilados.