CMake에서 미리 컴파일 된 헤더 사용


104

CMake에서 미리 컴파일 된 헤더에 대한 일부 지원을 함께 해킹하는 것에 대한 'net'의 몇 가지 (오래된) 게시물을 보았습니다. 그것들은 모두 사방에있는 것처럼 보이며 모두가 자신 만의 방식을 가지고 있습니다. 현재 가장 좋은 방법은 무엇입니까?

답변:


79

있다 'Cotire'라는 이름 타사 CMake 모듈 CMake 기반 빌드 시스템에 미리 컴파일 된 헤더의 사용을 자동화하고도 단결 빌드를 지원합니다.


1
나는 랩 cotire 기능 (헤더를 미리 컴파일하고 단결 빌드) 것을 매크로 세트를 만들었습니다 여기에 쉬운 사용을 위해
onqtam

2
@onqtam 그게 얼마나 쉬운 지, 너무 거 대해서 cmake와 gcc로 간단히 미리 컴파일하는 방법도 보지 못합니다
Pavel P

5
CMake 3.16은 미리 컴파일 된 헤더에 대한 기본 제공 지원을 도입했습니다. 내 대답을 참조하십시오. stackoverflow.com/a/59514029/2799037 더 이상 타사 모듈이 필요하지 않습니다!
usr1234567

34

다음 매크로를 사용하여 미리 컴파일 된 헤더를 생성하고 사용합니다.

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가 아닌 플랫폼에서도 여전히 잘 작동합니다. 꽤 깔끔한 :)


2
이 매크로에는 1 개의 결함이 있습니다. 생성기가 MSVC 기반이 아닌 경우 미리 컴파일 된 소스가 소스 목록에 추가되지 않습니다. 그래서 내 수정은 단순히 list( APPEND ... )닫는 바깥쪽으로 이동합니다 endif(). 전체 코드는 여기에서 확인하세요 : pastebin.com/84dm5rXZ
void.pointer 2011 년

1
@RobertDailey : 이것은 실제로 의도적 인 것입니다. 미리 컴파일 된 헤더를 사용하지 않을 때 미리 컴파일 된 소스 파일을 컴파일하고 싶지 않습니다. 어쨌든 기호를 정의해서는 안됩니다.
larsmoa

1
@Iarsam을 수정하십시오 /Yu/FI인수, 그들은해야 ${PrecompiledHeader}하지 ${PrecompiledBinary}.
Mourad 2013-06-28

"/ Fp"및 "/ FI"플래그가 필요한 이유를 설명해 주시겠습니까? msdn.microsoft.com/en-us/library/z0atkd6c.aspx 에 따르면 "/ Fp"의 사용은 필수가 아닙니다. 그러나 매크로에서 해당 플래그를 잘라 내면 pch가 설정되지 않습니다.
Vram Vardanian 2015

2
/ Yu에 대한 인수는 문자 그대로 받아 들여집니다. 예 를 들어 첫 번째 include 문으로 플래그 /YuC:/foo/bar.h를 전달 /FpC:/foo/bar.h하거나 #include <C:/foo/bar.h>모든 .cpp 파일의 맨 위에 놓 도록 강제합니다 . MSVC는 #include인수 의 문자열 비교를 수행하지만에 제공된 것과 동일한 파일을 가리키는 지 여부는 확인하지 않습니다 /Yu. Ergo #include <bar.h>가 작동하지 않고 오류 C2857이 발생합니다.
Manuzor

21

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/ 에서 몇 가지 추가 컨텍스트 (동기 부여, 숫자)를 사용할 수 있습니다.


2
다음은 공식 CMake 문서에 대한 링크입니다. cmake.org/cmake/help/latest/command/…
Alex Che

2
PCH에 포함 할 헤더를 파악하는 MSVC 팀의 게시물 : devblogs.microsoft.com/cppblog/…
janisozaur

19

다음은 프로젝트에 미리 컴파일 된 헤더를 사용할 수있는 코드 스 니펫입니다. 당신의 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)

감사; 이것을 GCC 용으로 빌드하기위한 가이드로 사용할 것입니다 (가능한 경우). 완료되는대로 답변을 게시하겠습니다. =]
strager

@Jayen, Nope; 나는 결국 프로젝트를 중단하고 기본적으로 다시는 C ++의 번거 로움에 빠지지 않았습니다.
strager

전체 프로젝트에 PCH를 설정할 수 있습니까? cmake에서 자동 생성 된 파일 목록을 가져올 수 없기 때문입니다 with set( CMAKE_AUTOMOC ON ).
Dmitry Sazonov

솔루션을 사용했지만 안타깝게도 ~ 130 개의 파일에 대해 컴파일 시간이 2'10 "에서 2'40"로 늘어났습니다. myprecompiledheader.cpp먼저 컴파일 되었는지 확인해야 합니까? 이 스 니펫에서 마지막으로 컴파일 될 것으로 보이므로 지연을 유발할 수 있습니다. myprecompiledheader.h내 코드에서 사용하는 가장 일반적인 STL 헤더 만 포함되어 있습니다.
Grim Fandango

13

나는 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})

2
$ {IntDir} 추상화가 유용합니다. 감사.
Gopalakrishna Palem 2014 년

12

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)

2
이 솔루션을 사용했지만 프로젝트에 C ++ 파일 만 포함 된 경우에만 작동합니다. COMPILE_FLAGS는 모든 소스 파일에 적용되므로 c ++ PCH를 좋아하지 않는 c 파일 (예 : MIDL에서 생성 된 파일)에도 적용됩니다. Dave의 솔루션을 사용할 때 get_source_file_property (_language $ {src_file} LANGUAGE)를 사용할 수 있으며 실제로 CXX 파일 인 경우에만 컴파일러 플래그를 설정할 수 있습니다.
Andreas Haferburg 2012

내 뒷주머니에 다른 솔루션의 유연성이 있다는 것은 좋지만 이것이 제가 찾던 솔루션입니다. 감사합니다!
kylewm

좋은 대답입니다. set_source_files_properties에 대한 누락 된 괄호에주의하십시오.
Arnaud

2
set_source_files_properties를 사용하여 / Y- 로 개별 파일에 대해 선택적으로 끌 수 있습니다.
mlt

abc당신의 예 는 무엇입니까 ?
Sandburg

7

바퀴를 재발 명하고 싶지 않다면 최고의 답변이 제안하는대로 Cotire를 사용하거나 여기에서 더 간단한 one- cmake-precompiled-header를 사용 하십시오 . 그것을 사용하려면 모듈을 포함하고 다음을 호출하십시오.

include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )

5

CMake 3.16은 미리 컴파일 된 헤더에 대한 지원을 도입했습니다. target_precompile_headers내부적으로 필요한 모든 것을 수행하는 새로운 CMake 명령 이 있습니다. 자세한 내용은 설명서를 참조하십시오 : https://cmake.org/cmake/help/latest/command/target_precompile_headers.html


2
이 답변 최종 공식 문서에 대한 링크를 제외하고 반년 전에 게시 된 janisozaur의 답변에 새로운 내용을 추가하지 않으며 아마도 해당 답변에 대한 의견으로 추가해야 할 것입니다.
Alex Che

4

cmake 및 Visual Studio 2015를 사용하여 미리 컴파일 된 헤더 사용 예

"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"
)

3

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는 테스트를 거쳐 완벽하게 작동합니다.


0

프로젝트 파일에서 한 줄을 변경할 때마다 쿼드 코어 머신에서 빌드하는 데 10 분 이상 걸리면 미리 컴파일 된 Windows 용 헤더를 추가 할 시간을 알려줍니다. * nux에서는 ccache를 사용하고 그것에 대해 걱정하지 않습니다.

내 주 응용 프로그램과 사용하는 몇 가지 라이브러리에서 구현했습니다. 이 시점까지 잘 작동합니다. 또한 필요한 한 가지는 pch 소스 및 헤더 파일을 작성하고 소스 파일에 미리 컴파일하려는 모든 헤더를 포함해야한다는 것입니다. MFC에서 12 년 동안이 작업을했지만 기억하는 데 몇 분이 걸렸습니다 ..


0

가장 깨끗한 방법은 미리 컴파일 된 옵션을 전역 옵션으로 추가하는 것입니다. vcxproj 파일에서 이것은 <PrecompiledHeader>Use</PrecompiledHeader>모든 개별 파일에 대해이 작업을 수행하지 않고 로 표시 됩니다.

그런 다음 CreateStdAfx.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 파일을 만들 것입니다. 어떤 파일 이름이 사용되는지 신경 쓰지 않으므로 지정하려고 노력하지 않았습니다.


0

미리 컴파일 된 헤더 옵션이 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와 같은 헤더 만 있습니다.


-15

거기도 가지마. 미리 컴파일 된 헤더는 헤더 중 하나가 변경 될 때마다 모든 것을 다시 빌드해야 함을 의미합니다 . 이것을 실현하는 빌드 시스템이 있다면 운이 좋습니다. 대부분의 경우, 미리 컴파일되는 내용을 변경했음을 인식 할 때까지 빌드가 실패하므로 전체 재 빌드를 수행해야합니다. 절대적으로 긍정적 인 헤더를 미리 컴파일하면이를 방지 할 수 있지만 속도 향상의 상당 부분을 포기하게됩니다.

또 다른 문제는 미리 컴파일 된 헤더를 사용하는 많은 곳에서 알지 못하거나 신경 쓰지 않는 모든 종류의 기호로 네임 스페이스가 오염된다는 것입니다.


29
미리 컴파일 된 헤더는 변경 되지 않는 헤더를 참조 할 때 가장 유용합니다 . STL, Boost, 기타 타사 항목. 자체 프로젝트 헤더 파일에 PCH를 사용하는 경우 대부분의 이점을 낭비하게됩니다.

3
자체 프로젝트의 헤더에 PCH를 사용하는 경우에도 CMake와 같은 빌드 시스템의 요점은 종속성 존중 되는지 확인하는 것 입니다. .h 파일 (또는 그 종속성 중 하나)을 변경 하면 .pch를 다시 생성 하고 싶습니다 . .h 파일을 변경 하지 않으면 .pch가 다시 생성되는 것을 원하지 않습니다 . OP의 전체 질문은 CMake를 사용하여 어떻게 발생합니까?
Quuxplusone 2014 년

1
미리 컴파일 된 헤더는 모든 주류 컴파일러에서 C ++ 모듈을 지원할 때까지 컴파일 시간을 줄이는 가장 좋은 도구입니다. 템플릿 및 헤더 전용 라이브러리의 사용이 계속 증가하면서 악화 된 문제를 해결합니다. 제대로 사용하면 대체품이 없습니다. 그럼에도 불구하고 이것은 질문에 대한 답변을 구성하지 않으며 단지 의견을 표명합니다. 찬성 및 삭제 투표.
IInspectable
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.