Использование предварительно скомпилированных заголовков с CMake - PullRequest
94 голосов
/ 29 сентября 2008

Я видел несколько (старых) постов в сети о том, как взломать некоторую поддержку предварительно скомпилированных заголовков в CMake. Все они кажутся немного повсюду, и у каждого есть свой способ сделать это. Каков наилучший способ сделать это в настоящее время?

Ответы [ 12 ]

71 голосов
/ 23 марта 2012

Существует сторонний модуль CMake с именем 'Cotire' , который автоматизирует использование предварительно скомпилированных заголовков для систем сборки на основе CMake, а также поддерживает единственные сборки.

34 голосов
/ 04 сентября 2009

Я использую следующий макрос для генерации и использования предварительно скомпилированных заголовков:

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. Довольно аккуратно:)

20 голосов
/ 04 ноября 2008

Вот фрагмент кода, позволяющий использовать предварительно скомпилированный заголовок для вашего проекта. Добавьте следующее в ваш файл 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)
13 голосов
/ 02 июня 2010

В итоге я использовал адаптированную версию макроса 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})
12 голосов
/ 09 июля 2010

Адаптировано из 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)
7 голосов
/ 02 февраля 2017

если вы не хотите изобретать велосипед, просто используйте Cotire, как подсказывает главный ответ, или более простой - cmake-precompiled-header здесь . Чтобы использовать его просто включите модуль и позвоните:

include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
4 голосов
/ 13 мая 2016

Пример использования предварительно скомпилированного заголовка с 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 голосов
/ 16 апреля 2015

ИМХО, лучший способ - установить 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 голосов
/ 08 сентября 2016

Поскольку опция предварительно скомпилированного заголовка не работает для файлов 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)

Edit: использование этих предварительно скомпилированных заголовков уменьшило общее время сборки моего основного проекта с 4 минут 30 секунд до 1 минуты 40 секунд. Это для меня действительно хорошая вещь. В заголовке прекомпиляции есть только заголовки, такие как boost / stl / Windows / mfc.

0 голосов
/ 07 января 2015

Самый простой способ - добавить предварительно скомпилированный параметр как глобальный параметр. В файле 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. Меня не беспокоит, какое имя файла используется, поэтому я не приложил никаких усилий, чтобы указать его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...