Câu trả lời:
Có một mô-đun CMake của bên thứ ba có tên 'Cotire' tự động hóa việc sử dụng các tiêu đề được biên dịch trước cho các hệ thống xây dựng dựa trên CMake và cũng hỗ trợ các bản dựng thống nhất.
Tôi đang sử dụng macro sau để tạo và sử dụng các tiêu đề được biên dịch trước:
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)
Giả sử bạn có một biến $ {MySources} với tất cả các tệp nguồn của mình, mã bạn muốn sử dụng sẽ đơn giản là
ADD_MSVC_PRECOMPILED_HEADER("precompiled.h" "precompiled.cpp" MySources)
ADD_LIBRARY(MyLibrary ${MySources})
Mã sẽ vẫn hoạt động tốt trên các nền tảng không phải MSVC. Khá gọn gàng :)
list( APPEND ... )
bên ngoài đóng cửa endif()
. Xem mã hoàn chỉnh ở đây: pastebin.com/84dm5rXZ
/Yu
và /FI
đối số, chúng nên ${PrecompiledHeader}
và không ${PrecompiledBinary}
.
/YuC:/foo/bar.h
sẽ buộc bạn phải vượt qua /FpC:/foo/bar.h
cờ hoặc đặt #include <C:/foo/bar.h>
ở đầu tất cả các tệp .cpp của bạn làm câu lệnh bao gồm đầu tiên. MSVC thực hiện một so sánh chuỗi của các #include
đối số, nó không kiểm tra xem nó có trỏ đến cùng một tệp như những gì đã được cấp cho hay không /Yu
. Ergo, #include <bar.h>
sẽ không hoạt động và phát ra lỗi C2857.
CMake vừa nhận được hỗ trợ cho PCH, nó sẽ có sẵn trong bản phát hành 3.16 sắp tới, do 2019-10-01:
https://gitlab.kitware.com/cmake/cmake/merge_requests/3553
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
Đang có cuộc thảo luận về việc hỗ trợ chia sẻ PCH giữa các mục tiêu: https://gitlab.kitware.com/cmake/cmake/issues/19659
Có một số ngữ cảnh bổ sung (động lực, con số) có sẵn tại https://blog.qt.io/blog/2019/08/01/precompiled-headers-and-unity-jumbo-builds-in-upcoming-cmake/
Đây là đoạn mã để cho phép bạn sử dụng tiêu đề được biên dịch trước cho dự án của mình. Thêm phần sau vào CMakeLists.txt của bạn thay thế myprecompiledheaders
và myproject_SOURCE_FILES
nếu thích hợp:
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)
with set( CMAKE_AUTOMOC ON )
.
myprecompiledheader.cpp
được biên dịch trước không? Từ đoạn mã này, có vẻ như đoạn mã sẽ được biên dịch cuối cùng, vì vậy có lẽ đó là điều có thể gây ra sự chậm trễ. myprecompiledheader.h
chỉ chứa các tiêu đề STL phổ biến nhất mà mã của tôi sử dụng.
Tôi đã sử dụng một phiên bản macro larsm đã được điều chỉnh. Sử dụng $ (IntDir) cho đường dẫn pch giữ các tiêu đề được biên dịch trước để gỡ lỗi và phát hành các bản dựng riêng biệt.
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})
Được điều chỉnh từ Dave, nhưng hiệu quả hơn (đặt thuộc tính mục tiêu, không phải cho từng tệp):
if (MSVC)
set_target_properties(abc PROPERTIES COMPILE_FLAGS "/Yustd.h")
set_source_files_properties(std.cpp PROPERTIES COMPILE_FLAGS "/Ycstd.h")
endif(MSVC)
abc
ví dụ của bạn là gì?
nếu bạn không muốn phát minh lại bánh xe, chỉ cần sử dụng Cotire như câu trả lời hàng đầu gợi ý hoặc một câu trả lời đơn giản hơn - cmake-precompiled-header ở đây . Để sử dụng nó, chỉ cần bao gồm mô-đun và gọi:
include( cmake-precompiled-header/PrecompiledHeader.cmake )
add_precompiled_header( targetName StdAfx.h FORCEINCLUDE SOURCE_CXX StdAfx.cpp )
CMake 3.16 đã giới thiệu hỗ trợ cho các tiêu đề được biên dịch trước. Có một lệnh CMake mới target_precompile_headers
thực hiện mọi thứ bạn cần. Xem tài liệu của nó để biết thêm chi tiết: https://cmake.org/cmake/help/latest/command/target_precompile_headers.html
"stdafx.h", "stdafx.cpp" - tên tiêu đề được biên dịch trước.
Đặt phần sau vào tệp cmake gốc.
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()
Đặt phần sau vào tệp cmake của dự án.
"src" - một thư mục chứa các tệp nguồn.
set_source_files_properties(src/stdafx.cpp
PROPERTIES
COMPILE_FLAGS "/Ycstdafx.h"
)
IMHO cách tốt nhất là đặt PCH cho toàn bộ dự án, như martjno đã đề xuất, kết hợp với khả năng bỏ qua PCH cho một số nguồn nếu cần (ví dụ: nguồn được tạo):
# 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)
Vì vậy, nếu bạn có một số MY_TARGET mục tiêu và danh sách các nguồn được tạo IGNORE_PCH_SRC_LIST, bạn sẽ chỉ cần thực hiện:
SET_TARGET_PRECOMPILED_HEADER(MY_TARGET stdafx.h stdafx.cpp)
IGNORE_PRECOMPILED_HEADER(IGNORE_PCH_SRC_LIST)
Aproach này đã được thử nghiệm và hoạt động hoàn hảo.
Vâng, khi quá trình xây dựng mất hơn 10 phút trên máy lõi tứ mỗi khi bạn thay đổi một dòng trong bất kỳ tệp dự án nào, nó sẽ cho bạn biết thời gian để thêm các tiêu đề được biên dịch trước cho cửa sổ. Trên * nux, tôi sẽ chỉ sử dụng ccache và không lo lắng về điều đó.
Tôi đã triển khai ứng dụng chính của mình và một vài thư viện mà nó sử dụng. Nó hoạt động tuyệt vời cho đến thời điểm này. Một điều cũng cần thiết là bạn phải tạo tệp tiêu đề và mã nguồn pch và trong tệp nguồn bao gồm tất cả các tiêu đề mà bạn muốn được biên dịch trước. Tôi đã làm điều này trong 12 năm với MFC nhưng tôi phải mất vài phút để nhớ lại điều đó ..
Cách rõ ràng nhất là thêm tùy chọn được biên dịch trước làm tùy chọn chung. Trong tệp vcxproj, điều này sẽ hiển thị như <PrecompiledHeader>Use</PrecompiledHeader>
và không thực hiện việc này đối với mọi tệp riêng lẻ.
Sau đó, bạn cần thêm Create
tùy chọn vào StdAfx.cpp. Sau đây là cách tôi sử dụng nó:
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})
Điều này được thử nghiệm và hoạt động cho MSVC 2010 và sẽ tạo tệp MyDll.pch, tôi không bận tâm về tên tệp được sử dụng nên tôi không cố gắng chỉ định nó.
Vì tùy chọn tiêu đề được biên dịch trước không hoạt động cho các tệp rc, tôi cần điều chỉnh macro do jari cung cấp.
#######################################################################
# 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)
Chỉnh sửa: Việc sử dụng tiêu đề được biên dịch sẵn này đã giảm thời gian xây dựng Tổng thể của Dự án chính của tôi từ 4 phút 30 giây xuống 1 phút 40 giây. Đây là một điều thực sự tốt đối với tôi. Trong tiêu đề biên dịch trước chỉ có các tiêu đề như boost / stl / Windows / mfc.
Đừng đến đó. Các tiêu đề được biên dịch sẵn có nghĩa là bất cứ khi nào một trong các tiêu đề thay đổi, bạn phải xây dựng lại mọi thứ . Bạn thật may mắn nếu bạn có một hệ thống xây dựng nhận ra điều này. Thường xuyên hơn không bao giờ, bản dựng của bạn sẽ chỉ thất bại cho đến khi bạn nhận ra rằng bạn đã thay đổi thứ gì đó đang được biên dịch trước, và do đó bạn cần phải xây dựng lại toàn bộ. Bạn có thể tránh điều này chủ yếu bằng cách biên dịch trước các tiêu đề mà bạn hoàn toàn tích cực sẽ không thay đổi, nhưng sau đó bạn cũng đang từ bỏ một phần lớn tốc độ tăng.
Vấn đề khác là không gian tên của bạn bị ô nhiễm với tất cả các loại ký hiệu mà bạn không biết hoặc không quan tâm ở nhiều nơi mà bạn đang sử dụng các tiêu đề được biên dịch sẵn.