2. Xây dựng CPython từ nguồn
2. Xây dựng CPython từ nguồn
Xây dựng CPython từ nguồn cung cấp cho bạn một trình thông dịch cục bộ mà bạn có thể kiểm tra, sửa đổi, gỡ lỗi và kiểm tra. Đây là bước thực tế đầu tiên trước khi đọc nội bộ một cách nghiêm túc.
Bản dựng nguồn cho phép bạn thực hiện những việc mà bản cài đặt Python đóng gói thường ẩn:```text change interpreter code add debug prints inspect object layout run CPython tests use debug-only assertions trace reference counts debug crashes in C compare bytecode across builds
CPython sống trong kho Git. Thanh toán cục bộ bình thường trông như thế này:```bash
git clone https://github.com/python/cpython.git
cd cpython
```Kho lưu trữ chứa trình thông dịch, thư viện chuẩn, bài kiểm tra, tài liệu, tệp xây dựng và mã hỗ trợ nền tảng.
Một cái nhìn đơn giản hóa:```text
cpython/
Include/ public and internal C headers
Objects/ core object implementations
Python/ compiler, runtime, interpreter loop
Parser/ tokenizer and parser support
Modules/ built-in and extension modules
Lib/ Python standard library
Lib/test/ regression test suite
Programs/ executable entry points
Tools/ developer tools
Doc/ documentation source
```Các thư mục quan trọng nhất cho công việc nội bộ là`Objects`, `Python`, `Include`, `Modules`, Và`Lib/test`.
## 2.2 Chọn Chế độ xây dựng
Có hai cách xây dựng phổ biến:
| Xây dựng | Mục đích |
| ------------- | ------------------------------------ |
| Phát hành bản dựng | Tương tự như Python được cài đặt bình thường |
| Bản dựng gỡ lỗi | Tốt hơn cho công việc nội bộ |
Đối với nghiên cứu nội bộ, trước tiên hãy sử dụng bản dựng gỡ lỗi. Nó cho phép xác nhận bổ sung, trình trợ giúp gỡ lỗi, hỗ trợ theo dõi tham chiếu và các chế độ lỗi an toàn hơn.
Quá trình xây dựng gỡ lỗi chậm hơn nhưng dễ kiểm tra hơn.
## 2.3 Xây dựng trên Linux hoặc macOS
Trên các hệ thống giống Unix, CPython sử dụng cấu hình và tạo luồng thông thường.```bash
./configure --with-pydebug
make -j
```Điều này tạo ra một tệp thực thi trong cây nguồn, thường có tên như sau:```bash
./python
```Chạy nó:```bash
./python -V
./python -c "print('hello from local CPython')"
```các`--with-pydebug`tùy chọn tạo bản dựng gỡ lỗi. Điều này thay đổi thẻ ABI và cho phép hoạt động gỡ lỗi.
Lệnh cấu hình phát triển phổ biến là:```bash
./configure --with-pydebug --with-trace-refs
make -j
```Sử dụng`--with-trace-refs`chỉ khi bạn cần theo dõi tài liệu tham khảo sâu hơn. Nó thay đổi bố cục đối tượng và có thể làm chậm trình thông dịch hơn nữa.
## 2.4 Xây dựng phụ thuộc
Bản dựng tối thiểu có thể thành công mà không cần mọi phụ thuộc tùy chọn, nhưng nhiều mô-đun thư viện tiêu chuẩn cần có thư viện hệ thống.
Các phụ thuộc phổ biến bao gồm:
| Tính năng | Sự phụ thuộc điển hình |
| ---------------------- | -------------------------- |
| SSL và HTTPS | OpenSSL |
| Nén | zlib, bzip2, xz |
| SQLite | Tiêu đề phát triển SQLite |
| Hỗ trợ vỏ Readline | readline hoặc libedit |
| Lời nguyền | ncurses |
| Tkinter | Tcl/Tk |
| Hỗ trợ UUID | libuuid |
| Hỗ trợ FFI | libfi |
Nếu thiếu phần phụ thuộc, CPython vẫn có thể được xây dựng nhưng một số mô-đun mở rộng sẽ bị bỏ qua.
Bạn có thể kiểm tra đầu ra của bản dựng để tìm thông báo về các mô-đun bị thiếu.
## 2.5 Bản dựng ngoài cây
Bạn có thể xây dựng CPython bên ngoài thư mục nguồn. Điều này giữ cho các tập tin được tạo riêng biệt.```bash
mkdir ../cpython-build-debug
cd ../cpython-build-debug
../cpython/configure --with-pydebug
make -j
```Kết quả thực thi được nằm trong thư mục bản dựng:```bash
./python
```Các bản dựng ngoài cây rất hữu ích khi bạn muốn có nhiều cấu hình từ một nguồn kiểm tra:```text
cpython/
cpython-build-debug/
cpython-build-release/
cpython-build-asan/
```## 2.6 Xây dựng trên Windows
Trên Windows, CPython sử dụng tệp xây dựng Visual Studio.
Từ Dấu nhắc lệnh của nhà phát triển:```bat
PCbuild\build.bat -d
```các`-d`flag xây dựng trình thông dịch gỡ lỗi.
Tệp thực thi thường ở dưới:```text
PCbuild\amd64\python_d.exe
```Bản dựng phát hành sử dụng:```bat
PCbuild\build.bat
```Các bản dựng Windows có tệp dự án, mã nền tảng và quy tắc xây dựng tiện ích mở rộng riêng. Bố cục khác với các bản dựng Unix, nhưng nguồn trình thông dịch có cùng mã lõi.
## 2.7 Xác minh bản dựng
Sau khi xây dựng, hãy kiểm tra tệp thực thi:```bash
./python -V
./python -m sysconfig
```Kiểm tra xem trình thông dịch cho rằng nó được cài đặt ở đâu:```bash
./python - <<'PY'
import sys
print(sys.executable)
print(sys.prefix)
print(sys.path)
PY
```Để phát triển cây nguồn,`sys.path`nên bao gồm địa phương`Lib`thư mục.
## 2.8 Chạy bộ thử nghiệm
Bộ thử nghiệm của CPython được chạy với:```bash
./python -m test
```Để kiểm tra lần đầu nhanh hơn:```bash
./python -m test test_sys test_gc test_dict test_compile
```Chạy thử nghiệm song song:```bash
./python -m test -j8
```Chạy lại các bài kiểm tra thất bại:```bash
./python -m test --fail-env-changed
```Chạy một tệp thử nghiệm:```bash
./python -m test test_dict
```Chạy một trường hợp thử nghiệm với`unittest`cú pháp:```bash
./python -m unittest Lib.test.test_dict.DictTest.test_constructor
```Bộ thử nghiệm là một phần của quy trình làm việc nội bộ. Khi bạn thay đổi CPython, các bài kiểm tra là biện pháp bảo vệ đầu tiên chống lại hành vi vi phạm ngôn ngữ.
## 2.9 Hành vi xây dựng gỡ lỗi
Bản dựng gỡ lỗi thay đổi cách CPython hoạt động nội bộ.
Nó cho phép kiểm tra bổ sung như:```text
assertions in C code
debug memory allocator checks
extra object consistency checks
reference leak tools
debug ABI marker
stricter failure behavior
```Bản dựng gỡ lỗi thường phát hiện lỗi sớm hơn. Việc sử dụng sai bộ nhớ có vẻ vô hại trong bản phát hành có thể bị hủy bỏ nhanh chóng trong bản dựng gỡ lỗi.
Điều này rất hữu ích. Công việc nội bộ sẽ thất bại nặng nề.
## 2.10 Kiểm tra cấu hình bản dựng
CPython hiển thị cấu hình xây dựng thông qua`sysconfig`.
```python
import sysconfig
print(sysconfig.get_config_var("Py_DEBUG"))
print(sysconfig.get_config_var("WITH_PYMALLOC"))
print(sysconfig.get_config_var("Py_GIL_DISABLED"))
print(sysconfig.get_config_var("CONFIG_ARGS"))
```Chạy nó trực tiếp:```bash
./python - <<'PY'
import sysconfig
for name in ["Py_DEBUG", "WITH_PYMALLOC", "Py_GIL_DISABLED", "CONFIG_ARGS"]:
print(name, "=", sysconfig.get_config_var(name))
PY
```Điều này cho bạn biết tính năng thời gian biên dịch nào đang hoạt động.
## 2.11 Mục tiêu xây dựng hữu ích
chung`make`mục tiêu:
| Mục tiêu | Mục đích |
| ------------------ | -------------------------------------- |
|`make`| Xây dựng trình thông dịch |
|`make -j`| Xây dựng song song |
|`make clean`| Xóa nhiều tệp được tạo |
|`make distclean`| Loại bỏ đầu ra cấu hình quá |
|`make test`| Chạy thử nghiệm |
|`make regen-all`| Tái tạo các tập tin đã tạo |
|`make profile-opt`| Xây dựng bằng cách tối ưu hóa theo hướng dẫn hồ sơ |
Đối với công việc nội bộ thông thường, hãy sử dụng:```bash
make -j
./python -m test test_name
```Đối với các tệp được tạo, chỉ sử dụng mục tiêu tái tạo khi bạn thay đổi thông tin đầu vào như ngữ pháp, định nghĩa phòng khám hoặc siêu dữ liệu opcode.
## 2.12 Tệp được tạo
Một số tệp CPython được tạo. Đừng chỉnh sửa chúng một cách mù quáng.
Các tạo phẩm được tạo ra có thể đến từ:```text
Grammar definitions
Argument Clinic input
opcode metadata
frozen modules
configuration scripts
documentation tools
```Argument Clinic đặc biệt phổ biến trong phần mở rộng C và các định nghĩa phương thức tích hợp. Nó tạo ra mã phân tích cú pháp và trình bao bọc từ các nhận xét có cấu trúc.
Tệp C có thể chứa các khối như:```c
/*[clinic input]
module.function
arg: object
Description here.
[clinic start generated code]*/
```Phần được tạo phải được tạo lại thông qua công cụ chính xác thay vì chỉnh sửa thủ công.
## 2.13 Xây dựng lại sau khi thay đổi
Một vòng chỉnh sửa bình thường:```bash
vim Objects/listobject.c
make -j
./python -m test test_list
```Đối với một thay đổi nhỏ trong mã C, việc xây dựng lại tăng dần thường nhanh chóng.
Để thay đổi thư viện chuẩn Python:```bash
vim Lib/pathlib/__init__.py
./python -m test test_pathlib
```Không cần xây dựng lại C cho các thay đổi Python thuần túy.
Đối với các thay đổi về trình phân tích cú pháp, mã opcode hoặc mã được tạo, bạn có thể cần tạo lại trước khi xây dựng.
## 2.14 Thêm bản in gỡ lỗi
Một cách đơn giản để xác nhận rằng bạn đang chạy trình thông dịch của riêng mình là thêm bản in gỡ lỗi tạm thời.
Ví dụ: trong hàm C:```c
fprintf(stderr, "debug: list append called\n");
```Sau đó xây dựng lại:```bash
make -j
```Chạy một chương trình nhỏ:```bash
./python - <<'PY'
x = []
x.append(1)
PY
```Các bản in tạm thời thô sơ nhưng hiệu quả. Loại bỏ chúng trước khi cam kết.
## 2.15 Sử dụng`gdb`hoặc`lldb`Bản dựng gỡ lỗi hoạt động tốt với trình gỡ lỗi gốc.
Với`gdb`:
```bash
gdb --args ./python script.py
```Bên trong`gdb`:
```gdb
break PyEval_EvalFrameDefault
run
bt
```Với`lldb`:
```bash
lldb -- ./python script.py
```Bên trong`lldb`:
```lldb
breakpoint set --name PyEval_EvalFrameDefault
run
bt
```Điểm dừng hữu ích:```text
Py_Initialize
PyEval_EvalFrameDefault
_PyEval_EvalFrameDefault
PyObject_Malloc
PyObject_Free
PyErr_SetString
_Py_Dealloc
```Tên biểu tượng chính xác có thể thay đổi theo phiên bản và cấu hình bản dựng.
## 2.16 Sử dụng Kiểm tra cấp độ Python
Không phải mọi câu hỏi nội bộ đều cần trình gỡ lỗi C.
Các mô-đun hữu ích:
| Mô-đun | Sử dụng |
| ------------- | -------------------------------------- |
|`dis`| Kiểm tra mã byte |
|`sys`| Trạng thái thời gian chạy và cài đặt trình thông dịch |
|`gc`| Kiểm tra người thu gom rác |
|`inspect`| Khung, chức năng, nguồn, chữ ký |
|`types`| Đối tượng loại thời gian chạy |
|`sysconfig`| Xây dựng cấu hình |
|`tracemalloc`| Theo dõi phân bổ Python |
Ví dụ:```python
import dis
import gc
import sys
def f(x):
return x + 1
dis.dis(f)
print(f.__code__)
print(sys.getrefcount(f))
print(gc.is_tracked(f))
```Phong cách này rất hữu ích trước khi rơi vào C.
## 2.17 Phân bổ bộ nhớ gỡ lỗi
CPython có móc gỡ lỗi cho bộ cấp phát bộ nhớ.
Chạy với:```bash
PYTHONMALLOC=debug ./python script.py
```Điều này cho phép kiểm tra thêm xung quanh việc phân bổ bộ nhớ. Nó có thể phát hiện việc sử dụng sai API, lỗi tràn bộ đệm, tràn bộ đệm và một số mẫu không sử dụng sau này.
Để theo dõi phân bổ:```bash
./python -X tracemalloc script.py
```Hoặc bên trong Python:```python
import tracemalloc
tracemalloc.start()
data = [bytearray(1024) for _ in range(1000)]
current, peak = tracemalloc.get_traced_memory()
print(current, peak)
tracemalloctheo dõi các đường dẫn phân bổ bộ nhớ cấp độ Python. Gỡ lỗi heap gốc vẫn cần các công cụ cấp thấp hơn.
Bản dựng công cụ vệ sinh 2.18
Đối với công việc cấp độ C nghiêm túc, hãy xây dựng bằng chất khử trùng.
addressSanitizer có thể phát hiện lỗi bộ nhớ:bash ./configure --with-pydebug --with-address-sanitizer make -j Und xác địnhBehaviorSanitizer có thể phát hiện hành vi C không xác định:```bash
./configure --with-pydebug --with-undefined-behavior-sanitizer
make -j
## 2.19 Bản phát hành có hướng dẫn hồ sơ
Bản dựng bản phát hành CPython được tối ưu hóa thông thường có thể sử dụng tính năng tối ưu hóa theo hướng dẫn hồ sơ.```bash
make profile-opt
```Điều này xây dựng CPython, chạy khối lượng công việc đào tạo và xây dựng lại bằng cách sử dụng dữ liệu hồ sơ.
Sử dụng điều này khi đo lường hiệu suất. Không so sánh bản dựng gỡ lỗi với bản phát hành Python và coi các con số là có ý nghĩa.
Đối với nghiên cứu nội bộ:```text
debug build for correctness and inspection
release build for speed comparison
PGO build for performance-sensitive measurement
```## 2.20 Các sự cố thường gặp khi xây dựng
| Triệu chứng | Nguyên nhân có thể |
| ---------------------------- | ---------------------------------------------- |
|`_ssl`mất tích | Tiêu đề hoặc thư viện OpenSSL không có sẵn |
|`_sqlite3`mất tích | Gói phát triển SQLite không có sẵn |
|`readline`mất tích | tiêu đề readline hoặc libedit không có sẵn |
| kiểm tra thất bại xung quanh miền địa phương | ngôn ngữ môi trường không phù hợp |
| kiểm tra lỗi xung quanh mạng | kiểm tra mạng bên ngoài hoặc giới hạn nền tảng |
| gỡ lỗi quá trình nhập bản dựng không khớp | chạy sai file thực thi hoặc sai`PYTHONPATH`|
| tập tin được tạo cũ | cần tái sinh |
| lỗi liên kết | thư viện hệ thống bị thiếu hoặc không tương thích |
Trước khi gỡ lỗi CPython, hãy xác nhận rằng bạn đang chạy trình thông dịch bạn vừa tạo:```bash
./python - <<'PY'
import sys
print(sys.executable)
print(sys.version)
PY
```## 2.21 Giữ nhiều bản dựng
Một thiết lập thực tế:```text
cpython/
cpython-build-debug/
cpython-build-release/
cpython-build-asan/
```Sử dụng mỗi bản dựng cho một công việc khác nhau:
| Xây dựng | Sử dụng |
| ------- | -------------------------------- |
| Gỡ lỗi | Đọc và xác nhận nội bộ |
| Phát hành | So sánh hành vi |
| ASAN | Phát hiện lỗi bộ nhớ |
| PGO | Đo lường hiệu suất |
Điều này tránh việc liên tục cấu hình lại một thư mục bản dựng.
## 2.22 Quy trình làm việc nội bộ tối thiểu
Một quy trình làm việc đầu tiên tốt:```bash
git clone https://github.com/python/cpython.git
cd cpython
./configure --with-pydebug
make -j
./python -V
./python -m test test_sys test_gc test_dict
```Sau đó kiểm tra mã byte:```bash
./python - <<'PY'
import dis
def f(x):
return x + 1
dis.dis(f)
PY
```Sau đó thay đổi một tệp nhỏ, xây dựng lại và chạy thử nghiệm được nhắm mục tiêu.
## 2.23 Bản dựng này kích hoạt những gì
Sau chương này, bạn sẽ có một tệp thực thi CPython cục bộ mà bạn có thể sử dụng cho phần còn lại của cuốn sách.
Bây giờ bạn có thể kiểm tra:```text
how source becomes bytecode
how frames execute
how objects are laid out
how reference counts change
how the garbage collector tracks containers
how built-in types are implemented
how tests protect behavior
how C-level bugs surface
```Bản dựng nguồn biến CPython từ một hộp đen thành một hệ thống mà bạn có thể bước qua, sử dụng công cụ và sửa đổi.