CMakeでプリコンパイル済みヘッダーを使用する


104

CMakeのプリコンパイル済みヘッダーに対するいくつかのサポートを一緒にハッキングすることについて、ネット上にいくつかの(古い)投稿を見ました。それらはすべて少し変わっているようで、誰もが独自の方法でやっています。現在それを行う最良の方法は何ですか?

回答:


79

CMakeベースのビルドシステムのプリコンパイル済みヘッダーの使用を自動化し、Unityビルドもサポートする、「Cotire」という名前のサードパーティのCMakeモジュールがあります。


1
私はラップcotire機能(ヘッダをプリコンパイルし、団結ビルド)というマクロのセットを作成して、ここで簡単に使用するために
onqtam

2
@onqtamこれは簡単です。巨大なので、cmakeとgccを使用して単純にプリコンパイルを行う方法さえわかりません
Pavel P

5
CMake 3.16は、プリコンパイル済みヘッダーの組み込みサポートを導入しました。私の回答をご覧くださいstackoverflow.com/a/59514029/2799037サードパーティのモジュールはもう必要ありません!
usr1234567 2019

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

1
@RobertDailey:これは実際には意図的なものです-プリコンパイル済みヘッダーを使用していないときにプリコンパイル済みソースファイルをコンパイルしたくありません-とにかくシンボルを定義しないでください。
larsmoa 2011年

1
@Iarsam修正してください/Yu/FI引数は、彼らがあるべき${PrecompiledHeader}ではなく${PrecompiledBinary}
Mourad 2013年

"/ Fp"および "/ FI"フラグが必要な理由を説明できますか?msdn.microsoft.com/en-us/library/z0atkd6c.aspxによると、「/ Fp」の使用は必須ではありません。ただし、これらのフラグをマクロから削除した場合、pchは設定されません。
Vram Vardanian 2015

2
ただし、/ Yuへの引数は文字どおりに解釈されることに注意してください。たとえば、最初のincludeステートメントとして、フラグを/YuC:/foo/bar.h渡すか、すべての.cppファイルの最上部に/FpC:/foo/bar.h置くように強制します#include <C:/foo/bar.h>。MSVCは#include引数の文字列比較を行います。MSVCは、渡されたものと同じファイルを指しているかどうかをチェックしません/Yu。Ergoは機能#include <bar.h>せず、エラーC2857を出力します。
Manuzor 2015

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/...は
アレックス・チェ

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用に作成します(可能な場合)。完了したらすぐに回答を投稿します。=]
ストレージャー、2009年

@Jayen、いいえ; 私は最終的にプロジェクトをドロップし、基本的にはC ++の煩わしさには二度と入りませんでした。
ストレッジャー、2011年

PCHをプロジェクト全体に設定することは可能ですか?cmakeで自動生成されたファイルのリストを取得することができないためwith set( CMAKE_AUTOMOC ON )です。
Dmitry Sazonov 2014年

私はあなたのソリューションを使用しましたが、残念ながらコンパイル時間は2'10 "から2'40"になりました(130ファイルまで)。それmyprecompiledheader.cppが最初にコンパイルされることを確認する必要がありますか?このスニペットから、最後にコンパイルされるように見えるので、おそらくそれが遅延を引き起こしている可能性があります。myprecompiledheader.h私のコードが使用する最も一般的なSTLヘッダーのみが含まれています。
Grim Fandango 2014

13

最終的には、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})

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 2014年

2
/ Y-を使用して個々のファイルに対してset_source_files_properties
mlt

abcあなたの例には何がありますか?
サンドバーグ

7

ホイールを再発明したくない場合は、トップの回答が示唆するようにCotireを使用するか、より簡単なもの-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の回答に新しいものを何も追加していませんが、最終的な公式ドキュメントへのリンクは、おそらくその回答へのコメントとして追加する必要があります。
アレックスチェ

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)

このアプローチはテストされ、完全に機能します。


0

ビルドがクアッドコアマシンで10分以上かかると、プロジェクトファイルの1行を変更するたびに、Windowsのプリコンパイル済みヘッダーを追加する時期がわかります。* nuxでは、私はccacheだけを使用し、それについては心配しません。

メインアプリケーションと、それが使用するいくつかのライブラリに実装しました。これまでのところうまくいきます。また、pchソースファイルとヘッダーファイルを作成し、ソースファイルにプリコンパイルするすべてのヘッダーを含める必要があることも必要です。私はMFCで12年間これを行いましたが、それを思い出すのに数分かかりました。


0

最もクリーンな方法は、プリコンパイル済みオプションをグローバルオプションとして追加することです。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ファイルを作成します。どのファイル名が使用されるかわからないので、指定する手間はありませんでした。


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

そこに行かないでください。プリコンパイル済みヘッダーは、ヘッダーの1つが変更されるたびに、すべてを再構築する必要があることを意味します。これを実現するビルドシステムがあれば幸いです。ほとんどの場合、ビルドは、プリコンパイルされているものを変更したことに気づくまで失敗するため、完全な再ビルドを行う必要があります。あなたが絶対に肯定的であるヘッダーが変更されないことを事前にコンパイルすることによってこれを主に回避することができますが、それからあなたは同様にスピードゲインの大部分を放棄しています。

もう1つの問題は、プリコンパイル済みヘッダーを使用している多くの場所で、知らないか気にしていないあらゆる種類のシンボルで名前空間が汚染されることです。


29
プリコンパイル済みヘッダーは、変更されないヘッダーを参照している場合に最も役立ちます... STL、Boost、その他のサードパーティのもの。独自のプロジェクトヘッダーファイルにPCHを使用している場合、ほとんどのメリットを無駄にしています。
トム

3
自分のプロジェクトのヘッダーにPCHを使用している場合でも、CMakeのようなビルドシステムの重要な点は、依存関係尊重されるようにすることです。私は私の.hファイル(またはその依存関係の1つ)を変更した場合、私が欲しい .PCHを再生しているように。.hファイルを変更しない場合、.pchを再生成したくありません。OP全体の質問は次のとおりだったと思います:CMakeを使用してこれを実現するにはどうすればよいですか?
Quuxplusone 2014年

1
プリコンパイル済みヘッダーは、C ++モジュールがすべての主流のコンパイラーでサポートされるまでコンパイル時間を短縮するための最良のツールです。彼らは、テンプレートとヘッダーのみのライブラリの使用がますます増加することで悪化した問題を解決します。適切に使用すると、代替品はありません。いずれにせよ、これは尋ねられている質問に対する回答ではなく、単に意見を表明するだけのものです。反対投票と削除投票。
IInspectable 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.