CMake के साथ पूर्व संकलित हेडर का उपयोग करना


104

मैंने सीएमके में पूर्व संकलित हेडर के लिए कुछ समर्थन को एक साथ हैक करने के बारे में 'नेट पर कुछ (पुराने) पोस्ट देखे हैं। वे सभी जगह एक सा लगता है और हर किसी के पास करने का अपना तरीका होता है। वर्तमान में इसे करने का सबसे अच्छा तरीका क्या है?

जवाबों:


79

वहाँ एक है तीसरे पक्ष CMake मॉड्यूल 'Cotire' नाम दिया जो CMake आधारित निर्माण प्रणालियों के लिए precompiled हेडर के उपयोग को स्वचालित है और यह भी एकता बनाता है समर्थन करता है।


1
मैंने मैक्रोज़ का एक सेट बनाया है जो आसान उपयोग के लिए यहां कॉटियर फ़ंक्शनलिटी (प्री-कंपोज़्ड हेडर्स एंड यूनिटी बिल्ड) को
लपेटता है

2
@onqtam यह कितना आसान है, यह इतना विशाल है कि मैं यह भी नहीं देख पा रहा हूँ कि कैसे केवल cmake और gcc के साथ काम करने के लिए पहले से तैयार हो जाओ
Pavel P

5
सीएमके 3.16 प्री-कंपाइल हेडर के लिए अंतर्निहित समर्थन पेश किया। मेरा उत्तर देखें stackoverflow.com/a/59514029/2799037 अब थर्ड पार्टी मॉड्यूल की कोई आवश्यकता नहीं है!
usr1234567

34

पूर्ववर्ती हेडर बनाने और उपयोग करने के लिए Im निम्नलिखित मैक्रो का उपयोग कर रहा है:

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- आधारित नहीं है, तो स्रोत की सूची में precompiled स्रोत नहीं जोड़ा जाएगा। इसलिए मेरा संशोधन बस list( APPEND ... )बाहर के समापन की ओर बढ़ता है endif()। यहां पूरा कोड देखें: pastebin.com/84dm5rXZ
void.pointer

1
@RobertDailey: यह वास्तव में जानबूझकर है - मैं पहले से तैयार किए गए स्रोत फ़ाइल को संकलित नहीं करना चाहता हूं जब पहले से तैयार हेडर का उपयोग नहीं किया जाता है - यह किसी भी प्रतीक को परिभाषित नहीं करना चाहिए।
लार्सोमा

1
@ इरम कृपया /Yuऔर /FIतर्क सही करें , उन्हें होना चाहिए ${PrecompiledHeader}और नहीं ${PrecompiledBinary}
मौद्र

क्या आप बता सकते हैं कि हमें "/ Fp" और "/ FI" झंडे की आवश्यकता क्यों है? Msdn.microsoft.com/en-us/library/z0atkd6c.aspx के अनुसार "/ Fp" का उपयोग अनिवार्य नहीं है। हालाँकि, अगर मैंने आपके मैक्रो से उन झंडों को काट दिया है तो कोई pch सेट नहीं है।
वृम वर्धमान

2
हालांकि पता है कि / यू के लिए तर्क बहुत शाब्दिक लिया जाता है। ईजी /YuC:/foo/bar.hआपको /FpC:/foo/bar.hध्वज को पास करने के लिए मजबूर करेगा या #include <C:/foo/bar.h>पहले शामिल बयान के रूप में अपनी .cpp फ़ाइलों के सभी में सबसे ऊपर रख देगा । MSVC #includeतर्कों की तुलना एक तार से करता है, यह जाँच नहीं करता है कि यह उसी फ़ाइल की ओर इशारा करता है जैसा कि दिया गया था /Yu। एर्गो, #include <bar.h>काम नहीं करेगा और त्रुटि C2857 का उत्सर्जन करेगा।
मनुजोर

21

सीएमके को सिर्फ पीसीएच के लिए समर्थन मिला है, यह आगामी 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/19479

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/…
एलेक्स चे


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)

धन्यवाद; मैं इसे जीसीसी के लिए एक बनाने के लिए एक गाइड के रूप में उपयोग करूंगा (यदि मैं कर सकता हूं)। मैं अपना जवाब जल्द से जल्द दूंगा। =]
स्ट्रेजर

@ जेयेन, नोप; मैंने अंततः इस परियोजना को छोड़ दिया और मूल रूप से फिर से सी ++ के झंझटों में नहीं पड़ा।
नागर 21'10

क्या पीसीएच को पूरे प्रोजेक्ट में सेट करना संभव है? क्योंकि cmake में ऑटोजेनरेटेड फ़ाइलों की सूची प्राप्त करना संभव नहीं है with set( CMAKE_AUTOMOC ON )
दिमित्री सोजोनोव

मैंने आपके समाधान का उपयोग किया है, लेकिन दुर्भाग्य से संकलन समय 2'10 "से 2'40" तक मिला है, ~ 130 फ़ाइलों के लिए। क्या मुझे यह सुनिश्चित करना होगा कि myprecompiledheader.cppपहले संकलित किया गया है? इस स्निपेट से ऐसा लगता है कि इसे अंतिम रूप से संकलित किया जाएगा, इसलिए शायद यही देरी का कारण हो सकता है। myprecompiledheader.hमेरे कोड का उपयोग करने वाले केवल सबसे सामान्य एसटीएल हेडर शामिल हैं।
ग्रिम फैंडैंगो

13

मैंने लार्स मैक्रो के एक अनुकूलित संस्करण का उपयोग करके समाप्त किया। 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} अमूर्त मददगार है। धन्यवाद।
गोपालकृष्ण पालम

12

डेव से अनुकूलित, लेकिन अधिक कुशल (प्रत्येक फ़ाइल के लिए लक्ष्य गुण सेट करता है):

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 फ़ाइलों (जैसे MIDL द्वारा निर्मित) पर भी लागू किया जाएगा, जो c ++ PCH को पसंद नहीं करेगा। डेव के समाधान का उपयोग करते समय, आप get_source_file_property (_language $ {src_file} LANGUAGE) का उपयोग कर सकते हैं, और केवल कंपाइलर फ़्लैग सेट कर सकते हैं यदि यह वास्तव में एक CXX फ़ाइल है।
एंड्रियास हैफेरबर्ग

मेरी पीठ की जेब में दूसरे समाधान की लचीलापन है, लेकिन यह वही है जिसकी मैं तलाश कर रहा था, धन्यवाद!
काइल्वम

अच्छा उत्तर। Set_source_files_properties के लिए गुम कोष्ठक से सावधान रहें।
अरनौद

2
यह चुनिंदा रूप से अलग-अलग फ़ाइलों के लिए बंद हो सकता है / y- के साथ set_source_files_properties
एमएलटी

abcआपके उदाहरण में क्या है ?
सैंडबर्ग

7

यदि आप पहिया को फिर से स्थापित नहीं करना चाहते हैं, तो या तो कॉटियर का उपयोग करें क्योंकि शीर्ष उत्तर का सुझाव दिया गया है या यहां एक सरल - सेमीके-प्रिकेल्ड-हेडर है । इसका उपयोग करने के लिए बस मॉड्यूल और कॉल शामिल करें:

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

5

सीएमके 3.16 ने प्रिकॉम्स्ड हेडर के लिए समर्थन पेश किया। एक नया सीएमके आदेश है target_precompile_headersजो हुड के तहत आपकी जरूरत के सभी काम करता है। अधिक जानकारी के लिए इसके दस्तावेज देखें: https://cmake.org/cmake/help/latest/command/target_precompile_headers.html


2
यह उत्तर अंतिम आधिकारिक दस्तावेज के लिंक को छोड़कर, आधे साल पहले पोस्ट किए गए जनीसोजौर के उत्तर के लिए कुछ भी नया नहीं जोड़ता है , जो संभवतः उस उत्तर के लिए एक टिप्पणी के रूप में बेहतर जोड़ा जाना चाहिए।
एलेक्स चे

4

सेमीकैप और विजुअल स्टूडियो 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 सबसे अच्छा तरीका है कि पूरे प्रोजेक्ट के लिए PCH सेट किया जाए, जैसा कि martjno ने सुझाव दिया है, यदि आवश्यक हो तो कुछ स्रोतों के लिए 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+ मिनट का समय लेते हैं तो आप किसी भी प्रोजेक्ट फाइल में एक ही लाइन को बदलते हैं, यह आपको विंडोज़ के लिए precompiled हेडर जोड़ने के लिए अपना समय बताता है। * नक्स पर मैं सिर्फ ccache का उपयोग करूंगा और इस बारे में चिंता नहीं करूंगा।

मैंने अपने मुख्य एप्लिकेशन और कुछ पुस्तकालयों में इसे लागू किया है जो इसका उपयोग करता है। यह इस बिंदु पर बहुत अच्छा काम करता है। एक बात जो भी आवश्यक है वह यह है कि आपको पीच स्रोत और हेडर फाइल बनानी होगी और सोर्स फाइल में वे सभी हेडर शामिल करने होंगे जिन्हें आप पहले से तैयार करना चाहते हैं। मैंने इसे 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

जैसा कि precompiled हेडर विकल्प आरसी फ़ाइलों के लिए काम नहीं करता है, मुझे जरी द्वारा आपूर्ति की गई मैक्रो को समायोजित करने की आवश्यकता है।

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

संपादित करें: इस पूर्वनिर्धारित हेडर के उपयोग ने मेरे मुख्य प्रोजेक्ट के समग्र निर्माण समय को 4min 30s से घटाकर 1min 40s कर दिया। यह मेरे लिए बहुत अच्छी बात है। Precompile हैडर में केवल हेडर जैसे बूस्ट / stl / Windows / mfc होते हैं।


-15

वहाँ भी मत जाओ। Precompiled हेडर का मतलब है कि जब भी हेडर में से कोई एक बदलता है, तो आपको सब कुछ पुनर्निर्माण करना होगा । आप भाग्यशाली हैं यदि आपके पास एक बिल्ड सिस्टम है जो यह महसूस करता है। अधिक से अधिक कभी नहीं, आपका निर्माण तब तक विफल हो जाएगा जब तक आपको एहसास नहीं हो जाता है कि आपने कुछ बदल दिया है जो कि पहले से तैयार किया जा रहा है, और इसलिए आपको पूर्ण पुनर्निर्माण करने की आवश्यकता है। आप ज्यादातर हेडर को प्राथमिकता देकर इससे बच सकते हैं कि आप बिल्कुल सकारात्मक नहीं हैं, लेकिन फिर आप गति हासिल करने का एक बड़ा हिस्सा भी दे रहे हैं।

दूसरी समस्या यह है कि आपका नामस्थान उन सभी प्रकार के प्रतीकों से प्रदूषित हो जाता है, जिन्हें आप नहीं जानते हैं या उन कई स्थानों की परवाह नहीं करते हैं जहाँ आप पहले से तैयार हेडर का उपयोग कर रहे हैं।


29
Precompiled हेडर सबसे उपयोगी होते हैं जब वे हेडर को संदर्भित करते हैं जो बदलते नहीं हैं ... एसटीएल, बूस्ट, अन्य तृतीय-पक्ष सामान। यदि आप अपने स्वयं के प्रोजेक्ट हेडर फ़ाइलों के लिए PCH का उपयोग कर रहे हैं, तो आप अधिकांश लाभ को बर्बाद कर रहे हैं।
टॉम

3
यहां तक ​​कि अगर आप अपने स्वयं के प्रोजेक्ट के हेडर के लिए पीसीएच का उपयोग कर रहे हैं, तो सीएमके जैसे बिल्ड सिस्टम का पूरा बिंदु यह सुनिश्चित करना है कि निर्भरता का सम्मान किया जाए। अगर मैं अपनी .h फ़ाइल (या उसकी निर्भरता में से एक) को बदल दूं, तो मैं .pch को फिर से चालू करना चाहता हूं । अगर मैं अपनी .h फ़ाइल को नहीं बदलता हूं, तो मैं .pch को पुनर्जीवित नहीं करना चाहता। मुझे लगता है कि ओपी का पूरा सवाल था: सीएमके का उपयोग करके मुझे यह कैसे हो सकता है?
क्क्सप्लसोन

1
जब तक C ++ मॉड्यूल सभी मुख्यधारा कंपाइलरों द्वारा समर्थित नहीं हो जाता है, तब तक कंपाइल किए गए हेडर कंपाइल समय को कम करने के लिए सबसे अच्छा साधन हैं। वे एक ऐसे मुद्दे को हल करते हैं जो सिर्फ टेम्प्लेट और हेडर-केवल पुस्तकालयों के बढ़ते उपयोग के साथ खराब हो गया। जब सही तरीके से उपयोग किया जाता है, तो कोई विकल्प नहीं होता है। बावजूद, यह पूछे जाने वाले प्रश्न का उत्तर नहीं बनता है, और केवल राय देता है। डाउन- और डिलीट-वोटेड।
IInspectable
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.