Precompiled Header (PCH)
Trong các dự án C/C++ lớn, thời gian biên dịch có thể trở thành điểm nghẽn nghiêm trọng. Việc tối ưu hoá thời gian biên dịch không chỉ giúp tăng hiệu suất làm việc mà còn cải thiện trải nghiệm lập trình. Một trong các kỹ thuật quan trọng nhất để đạt được điều đó là Precompiled Header (PCH).
Giới thiệu
Precompiled Header (PCH) là kỹ thuật giúp trình biên dịch biên dịch trước một số file header thường xuyên dùng (như <iostream>
, <vector>
, <windows.h>
,...) và lưu lại ở dạng nhị phân, để không cần biên dịch lại mỗi lần. Điều này giúp rút ngắn đáng kể thời gian build, nhất là trong dự án lớn.
Cách tạo và sử dụng PCH
Với g++
-
Không dùng CMake:
# Tạo precompiled header từ file pch.hpp
g++ -x c++-header pch.hpp -o pch.hpp.gch
# Biên dịch file source sử dụng PCH
# Cách 1: Dùng -include rõ ràng
g++ -include pch.hpp main.cpp -o main.exe
# Cách 2: Không dùng -include, nhưng trong source có #include "pch.hpp"
g++ main.cpp -o main.exe- Ghi chú:
g++
sẽ tự động sử dụng filepch.hpp.gch
nếu có file#include "pch.hpp"
trong mã nguồn và file.gch
nằm cùng thư mục vớipch.hpp
.- Tùy chọn
-include pch.hpp
sẽ ép trình biên dịch include file đó trước tất cả các file khác.
- Ghi chú:
-
Dùng CMake:
# CMakeLists.txt
add_executable(main main.cpp)
target_precompile_headers(main PRIVATE pch.hpp)- CMake sẽ tự động tạo và sử dụng
.gch
nếu trình biên dịch hỗ trợ.
- CMake sẽ tự động tạo và sử dụng
Với clang++
Cách làm tương tự g++
, vì clang++
tương thích với cú pháp GNU
Với clang-cl hoặc cl (MSVC style)
-
Không dùng CMake:
# Tạo PCH (.pch) và file .obj đi kèm
cl /c /Ycpch.hpp /Fppch.pch /Fopch.obj pch.cpp
# Biên dịch các file khác, dùng lại .pch (chỉ compile, không link)
cl /c /Yupch.hpp /Fppch.pch /Fomain.obj main.cpp- Ghi chú:
/Ycpch.hpp
để tạo PCH từ file header được include trongpch.cpp
. Filepch.cpp
bắt buộc phải chứa dòng#include "pch.hpp"
, nếu không trình biên dịch sẽ báo lỗi./Yupch.hpp
để sử dụng lại file.pch
đã tạo./Fppch.pch
để đặt tên file.pch
sinh ra./Fo"*.obj"
để đặt tên file.obj
sinh ra./c
để chỉ biên dịch, không liên kết (link). Bắt buộc khi tạo.pch
.
- Ghi chú:
-
Dùng CMake:
# CMakeLists.txt
add_executable(main main.cpp pch.cpp)
target_precompile_headers(main PRIVATE pch.hpp)- Với trình biên dịch MSVC, CMake sẽ sinh ra các cờ
/Yc
(create) và/Yu
(use) tự động.
- Với trình biên dịch MSVC, CMake sẽ sinh ra các cờ
Cách tổ chức file PCH
-
pch.hpp
: file header chứa các include thường dùng. -
pch.cpp
(chỉ với MSVC): file source chỉ includepch.hpp
, dùng để tạo.pch
ban đầu.Ví dụ nội dung
pch.hpp
:pch.hpp#ifndef PCH_HPP
#define PCH_HPP
// Các thư viện STL thường dùng
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <unordered_map>
#include <memory>
#include <algorithm>
// Nếu là ứng dụng Windows
// #include <windows.h>
#endifpch.cpp// pch.cpp (chỉ dùng với MSVC)
#include "pch.hpp" -
Bạn nên chọn lọc những thư viện thực sự dùng thường xuyên để đưa vào
pch.hpp
, tránh nhồi nhét quá nhiều gây giảm hiệu quả.
Kiểm tra liệu .pch có được áp dụng
- Có thể dùng cờ
-H
khi biên dịch để liệt kê tất cả thư viện đã được include (chỉ áp dụng vớig++
vàclang++
,clang-cl
vàcl
không có cờ tương đương) - Kiểm tra log build kết quả, nếu thấy
!
trước thư viện.gch
có nghĩa là PCH đã được áp dụng thành công. - Ví dụ kết quả log build:
! include/pch.hpp.gch
D:\src\test.cpp
. C:/msys64/ucrt64/include/c++/15.1.0/iostream
. C:/msys64/ucrt64/include/c++/15.1.0/vector
Lưu ý khi dùng PCH
- Không nên include code thay đổi thường xuyên (ví dụ: header của file bạn đang chỉnh sửa).
- Nếu include một file khác trong
pch.hpp
, bạn không nên thay đổi file đó thường xuyên. - Dùng
#pragma once
hoặc include guard để tránh include đệ quy. - PCH không bắt buộc, nhưng rất nên dùng trong dự án lớn để tăng tốc build.
- Không dùng PCH cho mọi file – chỉ nên dùng cho file nào thực sự cần.
Khi nào không nên dùng PCH?
- Dự án nhỏ, ít file, thời gian build không đáng kể.
- Khi phải liên tục thay đổi các file header – việc tạo lại PCH còn tốn thời gian hơn.
- Nếu bạn cần kiểm soát tuyệt đối thứ tự include (PCH có thể gây khó debug lỗi include).