Подтвердить что ты не робот

Использование предварительно скомпилированных заголовков с CMake

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

Ответ 5

Адаптировано из 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)

Ответ 6

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

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

Ответ 7

IMHO лучший способ - установить 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 проверен и работает отлично.

Ответ 8

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

Ответ 9

Хорошо, когда сборка занимает 10 и более минут на четырехъядерной машине каждый раз, когда вы меняете одну строку в любом из файлов проекта, она сообщает вам о времени добавления предварительно скомпилированных заголовков для окон. На * nux я бы просто использовал ccache и не беспокоился об этом.

Я реализовал в своем основном приложении и нескольких библиотеках, которые он использует. Он отлично справляется с этим. Необходимо также создать файл источника и заголовочный файл pch, а в исходном файле - все заголовки, которые вы хотите предварительно скомпилировать. Я сделал это в течение 12 лет с MFC, но мне потребовалось несколько минут, чтобы вспомнить, что..

Ответ 10

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

Ответ 11

Поскольку прекомпилированный параметр заголовка не работает для файлов 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 секунд. Это для меня очень хорошая вещь. В заголовке precompile есть только заголовки, такие как boost/stl/Windows/mfc.

Ответ 12

CMake только что получил поддержку PCH, он должен быть доступен в предстоящем выпуске 3.16, который должен быть выпущен в 2019-10-01:

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/

Ответ 13

Даже не туда. Предварительно скомпилированные заголовки означают, что всякий раз, когда изменяется один из заголовков, вы должны перестроить все. Вам повезло, если у вас есть система сборки, которая это понимает. Чаще, чем никогда, ваша сборка просто закончится, пока вы не поймете, что вы изменили что-то, что было предварительно скомпилировано, и поэтому вам нужно выполнить полную перестройку. Вы можете избежать этого, главным образом, путем предварительной компиляции заголовков, которые вы абсолютно позитивны, не изменятся, но тогда вы также отказываетесь от значительной части коэффициента усиления скорости.

Другая проблема заключается в том, что ваше пространство имен загрязнено всеми видами символов, которые вы не знаете или не заботитесь во многих местах, где вы будете использовать предварительно скомпилированные заголовки.