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.gchnếu có file#include "pch.hpp"trong mã nguồn và file.gchnằm cùng thư mục vớipch.hpp.- Tùy chọn
-include pch.hppsẽ é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
.gchnế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.cppbắ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.pchsinh ra./Fo"*.obj"để đặt tên file.objsinh 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.pchban đầ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ờ
-Hkhi biên dịch để liệt kê tất cả thư viện đã được include (chỉ áp dụng vớig++vàclang++,clang-clvàclkhông có cờ tương đương) - Kiểm tra log build kết quả, nếu thấy
!trước thư viện.gchcó 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 oncehoặ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).