it-swarm.com.de

Verwendung von vorkompilierten Headern mit CMake

Ich habe ein paar (alte) Posts im Internet gesehen, in denen es darum ging, Unterstützung für vorkompilierte Header in CMake zu hacken. Sie scheinen alle ein bisschen überall zu sein und jeder hat seine eigene Art, es zu tun. Wie geht das derzeit am besten?

96
Glutinous

Es gibt ein CMake-Modul eines Drittanbieters mit dem Namen 'Cotire' , das die Verwendung vorkompilierter Header für CMake-basierte Build-Systeme automatisiert und auch Unity-Builds unterstützt.

73
sakra

Ich benutze das folgende Makro, um vorkompilierte Header zu generieren und zu verwenden:

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)

Nehmen wir an, Sie haben eine Variable $ {MySources} mit all Ihren Quelldateien. Der Code, den Sie verwenden möchten, wäre einfach

ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})

Der Code funktioniert auch auf Nicht-MSVC-Plattformen einwandfrei. Ziemlich ordentlich :)

34
larsmoa

Hier ist ein Code-Snippet, mit dem Sie vorkompilierte Header für Ihr Projekt verwenden können. Fügen Sie Ihrer CMakeLists.txt Folgendes hinzu, indem Sie myprecompiledheaders und myproject_SOURCE_FILES Entsprechend ersetzen:

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)
20
Dave Hillier

Am Ende habe ich eine angepasste Version des Larsm-Makros verwendet. Durch die Verwendung von $ (IntDir) für pch path werden vorkompilierte Header für Debug- und Release-Builds getrennt.

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})
13
jari

Adaptiert von Dave, aber effizienter (setzt Zieleigenschaften, nicht für jede Datei):

if (MSVC)
   set_target_properties(abc PROPERTIES COMPILE_FLAGS "/Yustd.h")
   set_source_files_properties(std.cpp PROPERTIES COMPILE_FLAGS "/Ycstd.h")
endif(MSVC)
12
martjno

wenn Sie das Rad nicht neu erfinden möchten, verwenden Sie einfach entweder Cotire, wie es die beste Antwort nahelegt, oder einen einfacheren - cmake-precompiled-header hier . Um es zu benutzen, geben Sie einfach das Modul ein und rufen Sie auf:

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

IMHO ist der beste Weg, PCH für das gesamte Projekt festzulegen, wie von martjno vorgeschlagen, kombiniert mit der Fähigkeit, PCH für einige Quellen zu ignorieren, falls erforderlich (z. B. generierte Quellen):

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

Wenn Sie also ein Ziel MY_TARGET und eine Liste der generierten Quellen IGNORE_PCH_SRC_LIST haben, tun Sie einfach Folgendes:

SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)

Dieser Ansatz ist getestet und funktioniert einwandfrei.

4
Vram Vardanian

Ein Beispiel für die Verwendung eines vorkompilierten Headers mit cmake und Visual Studio 2015

"stdafx.h", "stdafx.cpp" - Name des vorkompilierten Headers.

Fügen Sie Folgendes in die Root-cmake-Datei ein.

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

Fügen Sie Folgendes in die Projektdatei cmake ein.

"src" - ein Ordner mit Quelldateien.

set_source_files_properties(src/stdafx.cpp
    PROPERTIES
    COMPILE_FLAGS "/Ycstdafx.h"
)
4
Maks

Wenn die Erstellung auf einem Quad-Core-Computer mehr als 10 Minuten dauert, werden Sie aufgefordert, vorkompilierte Header für Windows hinzuzufügen, sobald Sie eine einzelne Zeile in einer der Projektdateien ändern. Unter * nux würde ich nur ccache benutzen und mich nicht darum kümmern.

Ich habe in meiner Hauptanwendung und in einigen der Bibliotheken, die sie verwendet, implementiert. Bis hierher funktioniert es großartig. Außerdem müssen Sie die pch-Quell- und -Header-Datei erstellen und in die Quelldatei alle Header einfügen, die Sie vorkompilieren möchten. Ich habe das 12 Jahre lang mit MFC gemacht, aber ich habe ein paar Minuten gebraucht, um mich daran zu erinnern.

0
John M Drescher

CMake hat gerade die Unterstützung für PCHs erhalten. Es sollte in der kommenden Version 3.16 verfügbar sein, voraussichtlich am 01.10.2019:

https://gitlab.kitware.com/cmake/cmake/merge_requests/355

  target_precompile_headers(<target>
    <INTERFACE|PUBLIC|PRIVATE> [header1...]
    [<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])

Es wird derzeit diskutiert, wie PCHs zwischen Zielen ausgetauscht werden können: https://gitlab.kitware.com/cmake/cmake/issues/19659

Unter https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming- ist ein zusätzlicher Kontext (Motivation, Zahlen) verfügbar. cmake /

0
janisozaur

Am saubersten ist es, die vorkompilierte Option als globale Option hinzuzufügen. In der vcxproj-Datei wird dies als <PrecompiledHeader>Use</PrecompiledHeader> Angezeigt und nicht für jede einzelne Datei.

Anschließend müssen Sie die Option Create zur Datei StdAfx.cpp hinzufügen. Das Folgende ist, wie ich es benutze:

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

Dies ist getestet und funktioniert für MSVC 2010 und es wird eine MyDll.pch-Datei erstellt. Es ist mir egal, welcher Dateiname verwendet wird, daher habe ich mich nicht bemüht, ihn anzugeben.

0
uncletall

Da die vorkompilierte Header-Option für rc-Dateien nicht funktioniert, musste ich das von jari bereitgestellte Makro anpassen.

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

Bearbeiten: Die Verwendung dieser vorkompilierten Header reduzierte die Gesamtaufbauzeit meines Hauptprojekts von 4 Minuten 30 Sekunden auf 1 Minute 40 Sekunden. Das ist für mich eine wirklich gute Sache. Im Vorkompilierungsheader befinden sich nur Header wie boost/stl/Windows/mfc.

0
schorsch_76