답변:
있다 'Cotire'라는 이름 타사 CMake 모듈 CMake 기반 빌드 시스템에 미리 컴파일 된 헤더의 사용을 자동화하고도 단결 빌드를 지원합니다.
다음 매크로를 사용하여 미리 컴파일 된 헤더를 생성하고 사용합니다.
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 파일의 맨 위에 놓 도록 강제합니다 . MSVC는 #include
인수 의 문자열 비교를 수행하지만에 제공된 것과 동일한 파일을 가리키는 지 여부는 확인하지 않습니다 /Yu
. Ergo #include <bar.h>
가 작동하지 않고 오류 C2857이 발생합니다.
CMake는 PCH에 대한 지원을 방금 얻었으며 2019-10-01까지 다가오는 3.16 릴리스에서 사용할 수 있습니다.
https://gitlab.kitware.com/cmake/cmake/merge_requests/3553
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
대상 간 PCH 공유 지원에 대한 논의가 진행 중입니다 : 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 매크로의 적응 된 버전을 사용하게되었습니다. pch 경로에 $ (IntDir)를 사용하면 디버그 및 릴리스 빌드를 위해 미리 컴파일 된 헤더가 별도로 유지됩니다.
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})
Dave에서 수정되었지만 더 효율적입니다 (각 파일이 아닌 대상 속성 설정) :
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를 사용하거나 여기에서 더 간단한 one- cmake-precompiled-header를 사용 하십시오 . 그것을 사용하려면 모듈을 포함하고 다음을 호출하십시오.
include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
CMake 3.16은 미리 컴파일 된 헤더에 대한 지원을 도입했습니다. target_precompile_headers
내부적으로 필요한 모든 것을 수행하는 새로운 CMake 명령 이 있습니다. 자세한 내용은 설명서를 참조하십시오 : 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가 가장 좋은 방법은 martjno가 제안한대로 전체 프로젝트에 대해 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)
이 aproach는 테스트를 거쳐 완벽하게 작동합니다.
프로젝트 파일에서 한 줄을 변경할 때마다 쿼드 코어 머신에서 빌드하는 데 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와 같은 헤더 만 있습니다.
거기도 가지마. 미리 컴파일 된 헤더는 헤더 중 하나가 변경 될 때마다 모든 것을 다시 빌드해야 함을 의미합니다 . 이것을 실현하는 빌드 시스템이 있다면 운이 좋습니다. 대부분의 경우, 미리 컴파일되는 내용을 변경했음을 인식 할 때까지 빌드가 실패하므로 전체 재 빌드를 수행해야합니다. 절대적으로 긍정적 인 헤더를 미리 컴파일하면이를 방지 할 수 있지만 속도 향상의 상당 부분을 포기하게됩니다.
또 다른 문제는 미리 컴파일 된 헤더를 사용하는 많은 곳에서 알지 못하거나 신경 쓰지 않는 모든 종류의 기호로 네임 스페이스가 오염된다는 것입니다.