目錄

名稱

perlhack - 如何對Perl進行黑客攻擊

描述

本文解釋了Perl開發的運作方式。其中包括Perl 5 Porters郵件列表、Perl存儲庫、Perl錯誤跟蹤器、補丁指南以及對Perl開發理念的評論。

超快速補丁指南

如果你只想提交一個小的補丁,比如pod修復、用於bug的測試、評論修復等,這很容易!以下是方法:

錯誤報告

如果您想要報告 Perl 中的錯誤,或瀏覽現有的 Perl 錯誤和修補程式,請使用 GitHub 的問題追蹤器:https://github.com/perl/perl5/issues

在提交錯誤報告之前,請查看 perl5-porters 列表的存檔(見下文)和/或錯誤追蹤系統。通常,您會發現該錯誤已經被報告。

您可以登錄到錯誤追蹤系統並對現有的錯誤報告進行評論。如果您有關於現有錯誤的其他信息,請添加它。這將有助於開發者修復錯誤。

PERL 5 PORTERS

perl5-porters (p5p) 郵件列表是 Perl 標準發行版的維護和開發地點。維護 Perl 的人也被稱為 "Perl 5 Porters"、"p5p" 或只是 "porters"。

列表的可搜索存檔可在以下位置找到:https://markmail.org/search/?q=perl5-porters。還有一個存檔位於:https://archive.develooper.com/perl5-porters@perl.org/

perl-changes 郵件列表

perl5-changes 郵件列表收到提交到 perl 庫維護和開發分支的每個补丁的副本。請參閱 https://lists.perl.org/list/perl5-changes.html 以獲取訂閱和存檔信息。

#p5p 在 IRC

許多開發者也在 irc://irc.perl.org/#p5p 頻道上活躍。歡迎加入該頻道並就 Perl 核心的開發問題提問。

獲取 Perl 源代碼

Perl 的所有源代碼都集中保存在 github.com 的 Git 存儲庫中。該存儲庫包含從 Perl 1 開始的許多 Perl 版本以及以前的版本控制系統 Perforce 的所有版本。

有關使用 Git 與 Perl 存儲庫的更多詳細信息,請參閱 perlgit

通過 Git 讀取

您需要在計算機上安裝 Git。您可以使用 git 協議獲取存儲庫的副本。

% git clone git@github.com:Perl/perl5.git perl

這將克隆存儲庫並在 perl 目錄中創建一個本地副本。

如果由於防火牆原因無法使用 git 協議,您也可以通過 http 克隆。

% git clone https://github.com/Perl/perl5.git perl

通過網絡讀取

您可以通過網絡訪問存儲庫。這使您可以瀏覽樹,查看最近的提交,訂閱存儲庫通知,搜索特定的提交等。您可以在 https://github.com/Perl/perl5 上訪問它。

通過 Git 寫入

如果您有提交權限,請參閱 perlgit 以獲取有關使用 Git 的更多詳細信息。

修補 Perl

如果您計劃進行比單個小修補更廣泛的工作,我們鼓勵您閱讀下面的文檔。這將幫助您專注於工作並使您的补丁更容易融入 Perl 源代碼中。

提交修補程式

如果您有一個小的修補程式要提交,請通過 GitHub Pull Request 流程提交。您也可以將修補程式發送到 p5p 列表。

修補程式在 GitHub 或 p5p 列表上進行審查和討論。簡單、無爭議的修補程式通常會在沒有任何討論的情況下應用。當修補程式應用後,票證將會更新,您將收到電子郵件。

在其他情況下,修補程式可能需要更多的工作或討論。我們鼓勵您參與討論並為您的修補程式辯護。有時您的修補程式可能會在忙碌中被遺忘。如果一個月內沒有採取任何行動,請給 p5p 發送一封提醒郵件是適當的。請記住,Perl 5 的開發人員都是志願者,請保持禮貌。

更改始終直接應用於主開發分支,稱為 "blead"。有些修補程式可能會被回溯應用到維護分支。如果您認為您的修補程式適合於維護分支(請參見perlpolicy 中的 "維護分支" 部分),請在提交時解釋原因。

確保您的修補程式被接受

如果您正在提交一個程式碼修補程式,有幾件事情可以幫助 Perl 5 Porters 接受您的修補程式。

修補程式風格

使用 GitHub Pull Request 流程,您的修補程式將自動以適當的格式可用。如果您希望將修補程式提交到 p5p 列表進行審查,請確保創建它的方式適當。

如果您使用 git 檢查 Perl 源代碼,那麼使用 git format-patch 將會產生一個適合 Perl 風格的修補程式。format-patch 命令會為您所做的每次提交產生一個修補程式文件。如果您希望對所有提交使用單個修補程式,可以使用 git diff

% git checkout blead
% git pull
% git diff blead my-branch-name

這將產生一個基於 "blead" 和您當前分支之間差異的修補程式。在產生差異之前,確保 "blead" 是最新的是很重要的,這就是為什麼我們首先呼叫 git pull

我們強烈建議您使用 git 如果可能的話。這將使您的生活更輕鬆,也使我們的生活更輕鬆。

然而,如果您不使用 git,您仍然可以生成一個適合的修補程式。您需要一個原始的 Perl 源代碼副本來與之進行對比。開發人員更喜歡統一的差異。使用 GNU diff,您可以生成如下所示的差異

% diff -Npurd perl.pristine perl.mine

確保在您的 Perl 副本中執行 make realclean 以刪除任何構建產物,否則您可能會得到混淆的結果。

提交訊息

當您製作每個打算提交到 Perl 核心的補丁時,撰寫好的提交訊息非常重要。如果您的提交將由一系列提交組成,這一點尤其重要。

提交訊息的第一行應該是一個沒有句號的簡短描述。最好不要超過電子郵件主題行的長度,50個字符是一個很好的參考準則。

許多 Git 工具(Gitweb、GitHub、git log --pretty=oneline等)在呈現提交摘要時只會顯示第一行(截斷到50個字符)。

提交訊息應該包括一個描述補丁正確的問題或新增功能的描述。

一般來說,您的提交訊息應該幫助了解 Perl 核心的程式設計師迅速了解您試圖做什麼,您試圖如何做以及為什麼對 Perl 進行更改很重要。

提交訊息並不是用來取代您的代碼中的註釋的。提交訊息應該描述您所做的更改,而代碼註釋應該描述代碼的當前狀態。

如果您剛實現了一個新功能,包括文檔、測試和註釋完善的代碼,一個簡短的提交訊息通常就足夠了。但是,如果您只是在解析器或詞法分析器中更改了一個字符,您可能需要寫一個小說來確保將來的讀者了解您做了什麼以及為什麼這樣做。

註釋,註釋,註釋

請務必對代碼進行充分的註釋。雖然每行註釋都是不必要的,但任何利用運算符的副作用,創建將在被修補的函數之外感知到的變化,或者他人可能會感到困惑的事物都應該進行文檔化。如果要出錯,添加太多註釋比添加太少更好。

最好的註釋解釋代碼為何執行特定操作,而不是單純描述它的功能。

風格

一般而言,請遵循您正在修補的代碼的特定風格。

特別是,遵循以下一般指南來修補 Perl 源代碼

測試套件

如果您的補丁更改了代碼(而不僅僅是更改文檔),則您還應包括一個或多個測試案例,這些案例說明您正在修復的錯誤或驗證您正在添加的新功能。一般而言,您應該更新現有的測試文件,而不是創建新的測試文件。

您的測試套件補充應該遵循這些指南(由 Gurusamy Sarathy <gsar@activestate.com> 提供)

修補核心模塊

這與修補其他內容的方式相同,只是多了一個考慮因素。

源代碼樹中 cpan/ 目錄中的模塊是在 Perl 核心之外維護的。當作者更新模塊時,更新就會被簡單地複製到核心中。有關在 https://metacpan.org/ 上報告錯誤和提交修補程序的更多信息,請參閱該模塊的文檔或其列表。

在大多數情況下,對 cpan/ 中的模塊進行的修補應該發送到上游,而不應該單獨應用到 Perl 核心。如果對 cpan/ 中的文件的修補絕對不能等待修補上游,發佈到 CPAN,並複製到 blead,您必須添加(或更新) Porting/Maintainers.pl 文件中的 CUSTOMIZED 項目以標記進行了本地修改。有關更多詳情,請參閱 Porting/Maintainers.pl

相反地,dist/ 目錄中的模組是在核心中維護的。

更新 perldelta

對於足以需要 pod/perldelta.pod 條目的重大更改,如果您提交實際更改與您的 delta 條目,開發人員將非常感激。重大更改包括但不限於

請確保將 perldelta 條目添加到 pod/perldelta.pod 中的正確部分。有關如何撰寫良好的 perldelta 條目的更多信息,請參閱 Porting/how_to_write_a_perldelta.pod 中的 Style 部分。

什麼是一個好的補丁?

對於語言的新功能和擴展可能會引起爭議。沒有一套特定的標準來確定哪些功能會被添加,但在開發補丁時可以考慮以下問題

這個概念是否符合 Perl 的一般目標?

我們的目標包括但不限於

  1. 保持快速、簡單和有用。

  2. 盡可能使功能/概念正交。

  3. 沒有任意限制(平台、數據大小、文化)。

  4. 使 Perl 在各處開放且令人興奮地使用/補丁/倡導。

  5. 要麼吸收新技術,要麼與它們建立橋樑。

實現在哪裡?

只談論而不實現是毫無意義的。幾乎在每種情況下,爭論要求添加新功能的人將被期望是實現它們的人。能夠編寫新功能的開發人員有他們自己的議程,並且不會為您(可能是好的)想法實現它們。

向後兼容性

破壞現有 Perl 程序是一個致命的錯誤。新警告可能會引起爭議——有人說發出警告的程序沒有問題,而其他人說有問題。添加關鍵字可能會破壞程序,改變現有標記序列或函數的含義可能會破壞程序。

Perl 5 核心包括幫助開發人員使向後不兼容的更改更加兼容的機制,例如 featuredeprecate 模組。請在適當時使用它們。

它可以是一個模組嗎?

Perl 5 具有擴展機制,模組和 XS,特別是為了避免不斷改變 Perl 解譯器的需要。您可以撰寫導出函數的模組,可以給這些函數添加原型,使其可以像內置函數一樣調用,甚至可以撰寫 XS 代碼來操作 Perl 解譯器的運行時數據結構,以實現非常複雜的功能。

在可能的情況下,新功能應該在 CPAN 模組中進行原型設計,然後才會考慮納入核心功能。

功能是否足夠通用?

這是否只是提交者想要添加到語言中的功能,還是廣泛可用?有時,端口可能會決定等待某人實現更通用的功能,而不是添加具有狹窄焦點的功能。

是否可能引入新的錯誤?

對 Perl 解譯器的大規模重寫可能會引入新的錯誤。

它有多大?

變更越小且局部化,越好。同樣,一系列小补丁比單個大补丁更受歡迎。

是否排除了其他理想的功能?

如果一個补丁封閉了未來的發展方向,則可能會被拒絕。例如,一個對原型定義施加真實和最終解釋的补丁可能會被拒絕,因為對於原型未來的選擇還沒有得到解決。

實現是否堅固?

好的补丁(代碼緊湊,完整,正確)更有可能被接受。粗糙或不正確的补丁可能被擱置,直到修復完成,或者可能完全被丟棄,而不再進行通知。

實現是否足夠通用以便可移植?

最糟糕的补丁使用了特定於系統的功能。非通用的 Perl 語言附加功能很可能不會被接受。

實現是否經過測試?

更改行為的补丁(修復錯誤或引入新功能)必須包含回歸測試,以驗證一切是否按預期運行。

沒有原始作者提供的測試,未來更改 perl 的任何其他人如何確定他們沒有無意中破壞补丁實現的行為?沒有測試,补丁的作者如何確信他/她的辛勤工作不會被未來的某個人無意中丟棄?

是否有足夠的文檔?

沒有文件說明的補丁可能是沒有好好考慮或不完整的。沒有文件說明,就不能添加或更改功能,因此提交適當 pod 文件的補丁以及源代碼是很重要的。

還有其他方法嗎?

拉里說:“雖然 Perl 的口號是有更多的方法來做到這一點,但我不願意讓一個事情有 10 種做法”。然而,這是一個棘手的啟發式方法--一個人認為必要的添加,對另一個人來說可能是毫無意義的累贅。

這會造成太多的工作嗎?

對於提交者、Perl 程序員、模組作者等都是一種工作,... Perl 應該是易於使用的。

補丁比言語更有說服力

有效的程式碼總是比虛幻的想法更受歡迎。添加功能的補丁比隨機的功能請求更有可能被添加到語言中,無論請求者如何熱烈地爭論。這也涉及到“它是否有用?”的問題,因為某人花時間製作補丁表明對功能的強烈渴望。

測試

核心使用與 Perl 其他部分相同的測試方式,通過 Test::Harness 簡單地運行“ok/not ok”,但有一些特殊考量。

在核心中有三種方式編寫測試:Test::Moret/test.pl和臨時的 print $test ? "ok 42\n" : "not ok 42\n"。選擇使用哪一種取決於您正在工作的測試套件的部分。這是為了防止高層次的失敗(例如 Config.pm 断裂)導致基本功能測試失敗的措施。

t/test.pl 库提供了一些 Test::More 的功能,但避免了加載大多數模組,並且盡可能少使用核心功能。

如果您自己編寫測試,請使用測試任意協定

當你執行 "make test" 時,Perl 使用 t/TEST 程式來運行測試套件(在 Win32 下使用 t/harness 代替)。所有測試都是從 t/ 目錄運行的,而不是從包含測試的目錄運行的。這會導致在 lib/ 中的測試出現一些問題,因此這裡有機會進行一些修補。

你必須特別注意跨平台的問題。這通常歸結為使用 File::Spec,避免使用像 fork()system() 這樣的功能,除非絕對必要,並且不要假設給定的字符具有特定的序數值(編碼點)或其 UTF-8 表示形式由特定的字節組成。

測試中有幾個可用於可移植指定字符和編碼點的函式。始終預載的函式 utf8::unicode_to_native() 及其反函式 utf8::native_to_unicode() 接受編碼點並進行適當的轉換。檔案 t/charset_tools.pl 中有一些可能有用的函式。它具有接受字符串作為輸入的前兩個函式的版本 - 而不是單個數字編碼點: uni_to_native()native_to_uni()。如果你必須查看 UTF-8 編碼字符串的個別字節,則 byte_utf8a_to_utf8n() 接受編碼為 ASCII 平台的字節的字符串作為輸入,並返回本機平台上的等效字符串。例如,byte_utf8a_to_utf8n("\xC2\xA0") 返回當前平台上形成 U+00A0 的 UTF-8 的字節序列,因為 "\xC2\xA0" 是該代碼點在 ASCII 平台上的 UTF-8 字節。該函式在 ASCII 平台上返回 "\xC2\xA0",在 EBCDIC 1047 平台上返回 "\x80\x41"

但最簡單的方法是,如果字符可以指定為文字,例如 "A""%",則使用它; 如果無法這樣指定,則可以使用 \N{} ,如果副作用不麻煩的話。只需使用十六進制指定所有字符,使用 \N{U+ZZ} 而不是 \xZZ\N{} 是 Unicode 名稱,因此它始終給出 Unicode 字符。 \N{U+41} 是其 Unicode 代碼點為 0x41 的字符,因此在所有平台上都是 'A'。副作用是

如果正在測試區域設置(請參閱 perllocale),則在 t/loc_tools.pl 中有幫助函數,可讓您查看當前平台上有哪些區域設置。

特殊 make test 目標

有各種特殊的 make 目標可用於以略有不同於標準 "test" 目標的方式測試 Perl。並非所有目標都預期能夠達到 100% 的成功率。其中許多具有多個別名,並且其中許多在某些操作系統上不可用。

並行測試

核心發行版現在可以在類 Unix 和 Windows 平台上並行運行其回歸測試。在 Unix 上,不要運行 make test,而是在環境中設置 TEST_JOBS 為要並行運行的測試數量,然後運行 make test_harness。在類 Bourne 的 shell 上,可以這樣做

TEST_JOBS=3 make test_harness  # Run 3 tests in parallel

使用環境變量,而不是並行 make 本身,是因為 TAP::Harness 需要能夠自己安排單個不衝突的測試腳本,而且沒有標準界面可與它們的作業調度器交互。

測試通常按邏輯順序運行,首先是完整性測試,然後是 Perl 核心功能的主要測試,然後是非核心模塊的測試。在許多核心系統上,這可能不會有效地使用硬件。通過還指定

TEST_JOBS=19 PERL_TEST_HARNESS_ASAP=1 make -j19 test_harness

您表明您希望測試以最短的實際時間完成。在完整性測試完成後,這導致其餘測試被緊密地打包到可用的核心中,以我們所知的方式。這對於較慢的多核系統效果最好。在一個過時的 24 核系統上,吞吐量提高了 20%;在較新的更快的系統上,核心較少。

請注意,上面的命令行添加了一個 -j 參數到 make,以便導致並行編譯。這在您的平台上可能有效或無效。

通常,測試花費的時間數據存儲在 t/test_state 中,但是您可以通過將 PERL_TEST_STATE_FILE 環境變量設置為其他文件名來更改這一點,或者設置為假值(0 或空字符串)以完全禁用狀態機制的使用。對狀態文件格式的變化沒有保護,因此如果您有與此文件相關的任何問題,您需要手動刪除文件,然後讓鏈接重新創建它,儘管文件格式不經常更改,因此這應該不會經常需要。

手動運行測試

您可以透過在 t/ 目錄下使用以下命令之一手動執行測試套件的一部分

./perl -I../lib TEST list-of-.t-files

或者

./perl -I../lib harness list-of-.t-files

(如果您沒有指定測試腳本,將運行整個測試套件。)

使用 t/harness 進行測試

如果您使用 harness 進行測試,您可以使用幾個命令行選項。這些參數按照必須出現的順序列出如下:

harness -v -torture -re=pattern LIST OF FILES TO TEST
harness -v -torture -re LIST OF PATTERNS TO MATCH

如果省略了 要測試的文件列表,則文件列表將從清單中獲取。文件列表可能包含通配符,這些通配符將被展開。

您可以通過類似以下的命令運行單個測試

./perl -I../lib path/to/foo.t

但是測試套件設置了一些可能會影響測試執行的環境變量

其他可能影響測試的環境變數

另請參閱 Test 和 Test::Harness 模組的文檔,以了解更多影響測試的環境變數。

性能測試

文件 t/perf/benchmarks 包含了預期通過 Porting/bench.pl 工具對一系列 Perl 進行基準測試的 Perl 代碼片段。如果您修復或增強了性能問題,您可能希望將一個代表性的代碼樣本添加到文件中,然後運行 bench.pl 對先前和當前的 Perl 進行基準測試,以查看其所做的差異,以及是否有其他東西因此變慢了。

文件 t/perf/opcount.t 設計用於測試特定代碼片段是否已編譯為包含指定數量特定 op 類型的 optree。這對於測試是否進行了修改 op 的優化,例如將 aelem op 轉換為 aelemfast op,非常有用。

文件 t/perf/speed.tt/re/speed.t 設計用於測試如果某個優化被破壞,會使某些操作變得數千倍更慢的事物(例如,長 utf8 字符串上的 utf8 長度緩存)。添加一個測試,正常情況下需要幾分之一秒,否則需要幾分鐘,導致測試文件在失敗時超時。

在舊提交上構建 Perl

在 Perl 核心發行版上進行修改的過程中,您可能會需要在舊的提交上配置、構建和測試 Perl。有時候,在此過程中 make 會失敗。如果發生這種情況,您可以嘗試使用來自 CPAN 的 Devel::PatchPerl 库(未包含在核心中)將該提交的源代碼轉換為可構建的狀態。

這裡有一個真實世界的例子,取自於解決 perl #10118 的工作。使用 Porting/bisect.pl 已經識別出提交 ba77e4cc9d1ceebf472c9c5c18b2377ee47062e6 是一個錯誤被修正的提交。為了確認,一位 P5P 開發者想要在提交 ba77e4c^(推測為“不好”)和 ba77e4c(推測為“好”)上配置並構建 perl。嘗試了正常的配置和構建。

$ sh ./Configure -des -Dusedevel
$ make test_prep

make,然而,失敗並輸出(節錄)如下:

cc -fstack-protector -L/usr/local/lib -o miniperl \
  gv.o toke.o perly.o pad.o regcomp.o dump.o util.o \
  mg.o reentr.o mro.o hv.o av.o run.o pp_hot.o sv.o \
  pp.o scope.o pp_ctl.o pp_sys.o doop.o doio.o regexec.o \
  utf8.o taint.o deb.o universal.o globals.o perlio.o \
  numeric.o mathoms.o locale.o pp_pack.o pp_sort.o  \
  miniperlmain.o opmini.o perlmini.o
pp.o: In function `Perl_pp_pow':
pp.c:(.text+0x2db9): undefined reference to `pow'
...
collect2: error: ld returned 1 exit status
makefile:348: recipe for target 'miniperl' failed
make: *** [miniperl] Error 1

另一位 P5P 貢獻者建議在這種情況下安裝並使用 Devel::PatchPerl,首先確定提交的 perl 版本,然後在該點修補源代碼以便進行構建。

$ perl -MDevel::PatchPerl -e \
    'print Devel::PatchPerl->determine_version("/path/to/sourcecode"),
           "\n";'
5.11.1
$ perl -MDevel::PatchPerl -e \
    'Devel::PatchPerl->patch_source("5.11.1", "/path/to/sourcecode");'

一旦源代碼被修補,就呼叫了 ./Configuremake test_prep 並成功完成,從而確認了 RT#72414 中的發現。

更多供核心開發者閱讀的資料

要修改 Perl 的核心,您需要閱讀以下資料

CPAN 測試員和 Perl Smokers

CPAN 測試員(http://cpantesters.org/)是一群志願者,他們在各種平台上測試 CPAN 模組。

Perl Smokers(https://www.nntp.perl.org/group/perl.daily-build/https://www.nntp.perl.org/group/perl.daily-build.reports/)自動在具有各種配置的平台上測試 Perl 源代碼發布。

這兩項努力都歡迎志願者加入。要參與 smoke 測試 Perl 本身,請訪問 https://metacpan.org/release/Test-Smoke。要開始 smoke 測試 CPAN 模組,請訪問 https://metacpan.org/release/CPANPLUS-YACSmokehttps://metacpan.org/release/minismokeboxhttps://metacpan.org/release/CPAN-Reporter

下一步是什麼?

如果您已經閱讀了本文檔中的所有文檔以及上面列出的文檔,那麼您已經準備好開始對Perl進行開發了。

以下是一些更多的建議

"道路永遠延伸著,從開始的門口一直向下延伸。"

如果您能做到這些事情,您已經踏上了Perl轉接的漫長道路。感謝您想要幫助改進Perl - 祝您愉快地進行編程!

隱喻引用

如果您認識上面有關道路的引用,那麼您很幸運。

大多數軟體項目在每個文件開頭都會有一個對該文件用途的文字描述。而Perl則是以文學典故開始每個文件的用途。

像許多書籍的章節一樣,所有頂級 Perl 源代碼文件(以及偶爾出現的一些其他文件)都以一句寓意深遠的題詞開始,間接而隱喻地指向你即將閱讀的內容。

引文取自J.R.R.托爾金有關他的虛構世界的著作,幾乎都來自《魔戒》。章節和頁碼使用以下版本提供:

其他J.R.R.托爾金的著作,如汤姆·邦巴迪尔历险记精灵宝钻未完成的故事胡林之子的故事,除了第一本由CJRT后humously集合外,都可以引用。但是,《魔戒》本身是完全可以引用的,可能是最好的引用來源,只要你能在那裡找到合適的引文。

因此,如果您要提供一個新的、完整的、頂級的源文件來添加到 Perl 中,您應該遵循這個奇怪的做法,自己從托爾金的著作中選擇一個適當的引文,保留原始的拼寫和標點,並使用與其餘引文相同的格式。間接和拐彎抹角是完全可以的;請記住,這是一個比喻,所以元是它的用途。

作者

本文最初由Nathan Torkington撰寫,由perl5-porters郵件列表維護。