---
title: 章 3. 打造 Port 快速上手篇
prev: books/porters-handbook/new-port
next: books/porters-handbook/slow-porting
showBookMenu: true
weight: 3
params:
  path: "/books/porters-handbook/quick-porting/"
---

[[quick-porting]]
= 打造 Port 快速上手篇
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:sectnumoffset: 3
:partnums:
:source-highlighter: rouge
:experimental:
:images-path: books/porters-handbook/

ifdef::env-beastie[]
ifdef::backend-html5[]
:imagesdir: ../../../../images/{images-path}
endif::[]
ifndef::book[]
include::shared/authors.adoc[]
include::shared/mirrors.adoc[]
include::shared/releases.adoc[]
include::shared/attributes/attributes-{{% lang %}}.adoc[]
include::shared/{{% lang %}}/teams.adoc[]
include::shared/{{% lang %}}/mailing-lists.adoc[]
include::shared/{{% lang %}}/urls.adoc[]
toc::[]
endif::[]
ifdef::backend-pdf,backend-epub3[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
endif::[]

ifndef::env-beastie[]
toc::[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]

本節主要介紹如何來快速打造 port，然而實際應用時這快速方法可能不足，完整的 "慢速打造 Port" 的步驟在 crossref:slow-porting[slow-porting,Slow Porting] 詳述。

首先取得該應用程式的原始程式碼壓縮檔(tarball)，並把它放到 `DISTDIR`，預設路徑應該是 [.filename]#/usr/ports/distfiles#.

[NOTE]
====
這些步驟假設軟體可以直接編譯。也就是不需要任何修改就可以直接在 FreeBSD 上執行。如果需要修改，請參見crossref:slow-porting[slow-porting,Slow Porting]。
====

[NOTE]
====
在 porting 之前，建議在 [.filename]#/etc/make.conf# 設定 `DEVELOPER` man:make[1] 變數。

[source,shell]
....

# echo DEVELOPER=yes >> /etc/make.conf
....

這個設定開啟了 "developer mode" ，顯示已棄用警告並在使用 `make` 時檢查品質。
====

[[porting-makefile]]
== 編寫 [.filename]#Makefile#

最簡單的 [.filename]#Makefile# 大概是像這樣：

[.programlisting]
....
# $FreeBSD: head/zh_TW.UTF-8/books/porters-handbook/book.xml 48496 2016-03-29 01:37:53Z kevlo $

PORTNAME=	oneko
PORTVERSION=	1.1b
CATEGORIES=	games
MASTER_SITES=	ftp://ftp.cs.columbia.edu/archives/X11R5/contrib/

MAINTAINER=	youremail@example.com
COMMENT=	Cat chasing a mouse all over the screen

.include <bsd.port.mk>
....

嘗試了解此檔案，有關這點的細節部份，可以參閱 crossref:porting-samplem[porting-samplem,sample Makefile] 章節。

[[porting-desc]]
== 撰寫說明檔

無論是否打算再加工做成 package，有兩個檔案是任何 port 都必須要具備的。 這兩個檔分別是 [.filename]#pkg-descr# 及 [.filename]#pkg-plist# 。 他們檔名前面都有 [.filename]#pkg-# 以跟其他檔案做區別。

[[porting-pkg-descr]]
=== [.filename]#pkg-descr#

這是此 port 的詳細說明檔，請用一段或幾段文字來說明該 port 的作用

[NOTE]
====
請注意，這檔_絕非_「該軟體的說明手冊」或是「如何編譯、使用該 port 的說明」！ _若是從該軟體的 [.filename]#README# 或 manpage 直接複製過來的話，請注意_。他們常常不是正確的 port 描述或是格式並不適合。例如，manpage會對齊空白，這用monospace字型來看會特別糟糕。

另一方面， [.filename]#pkg-descr# 的內容必須比 crossref:makefiles[makefile-comment,COMMENT line from the Makefile] 還要詳細，要能詳細解釋此 port 相關的內容。
====

一個良好的 [.filename]#pkg-descr# 可以讓使用者清楚的了解軟體的功能而無須查詢文件或者訪問網站，提及特定的需求像是圖形工具、依賴、執行的環境跟實作的語言，能大大的幫助使用者了解這個 port 是怎麼運作的。

[NOTE]
====
過去在 #pkg-descr# 文件最後一行引入的 URL 已經移到 [.filename]#Makefile# 裡面了。
====

[[porting-pkg-plist]]
=== [.filename]#pkg-plist#

這是該 port 所會裝的所有檔案清單，另外因為 package 會由這清單所產生，因此也被稱為『"packing list (打包清單)"』。路徑是相對於安裝的 prefix (通常是 [.filename]#/usr/local# )。

這是一個簡單的例子：

[.programlisting]
....
bin/oneko
man/man1/oneko.1.gz
lib/X11/app-defaults/Oneko
lib/X11/oneko/cat1.xpm
lib/X11/oneko/cat2.xpm
lib/X11/oneko/mouse.xpm
....

關於 packing list 方面，可以詳閱 man:pkg-create[8] manual page 。

[NOTE]
====
建議清單內的檔名，依照字母順序作排序，那麼下次要升級時， 會比較清楚、方便來更新這份清單。 
====

[TIP]
====

手動產生這份清單實在太苦了。尤其若該 port 會裝一大堆檔案的話， 請多善用 <<plist-autoplist,自動產生 packing list>> 會比較省時省力唷。
====

只有在一種情況下可以省略 [.filename]#pkg-plist# 檔： 若安裝的 port 相當單純，只有裝一些檔案，那麼可以在 [.filename]#Makefile# 內改用 `PLIST_FILES` 來取代。 比如，可以在上述的 [.filename]#oneko# port 內不必附上 [.filename]#pkg-plist# ，而只需在 [.filename]#Makefile# 內加入下列幾行：

[.programlisting]
....
PLIST_FILES=	bin/oneko \
		man/man1/oneko.1.gz \
		lib/X11/app-defaults/Oneko \
		lib/X11/oneko/cat1.xpm \
		lib/X11/oneko/cat2.xpm \
		lib/X11/oneko/mouse.xpm
....

[NOTE]
====
`PLIST_FILES` 的使用不應該被濫用，人們通常透過在 ports tree 的 [.filename]#pkg-plist# 文件來了解 port ，在 [.filename]#Makefile# 中使用 `PLIST_FILES` 敘述會增加搜尋的難度。
====

[TIP]
====
如果 port 需要創建空的目錄，或者安裝時在 [.filename]#${PREFIX}# 之外創建目錄，請參考 crossref:plist[plist-dir-cleaning, Cleaning Up Empty Directories] 來獲得更多資訊。
====

[TIP]
====
因為 `PLIST_FILES` 是 man:make[1] 的變數，任何在此條目的 sapce 都必須被引入。舉例來說，如果使用 man:pkg-create[8] 和 crossref:plist[plist-keywords, Expanding Package List with Keywords] 描述的關鍵字，以下的條目必須被引入。

[.programlisting]
....
PLIST_FILES=	"@sample ${ETCDIR}/oneko.conf.sample"
....
====

後面會介紹到如何運用 [.filename]#pkg-plist#、 `PLIST_FILES` 這些技巧以因應crossref:plist[plist,更複雜的狀況]。

[[porting-checksum]]
== 產生 checksum 檔

只要打 `make makesum` 就好了， 接下來就會自動產生相對應的 [.filename]#distinfo# 檔了唷 。

[[porting-testing]]
== 測試 Port

接下來，必須檢驗是否有符合 port 的遊戲規則，包括打包該 port 為 package。 以下有幾個需要確認的重要地方：

* 若該 port 沒裝的東西，不要列在 [.filename]#pkg-plist# 內。
* 若該 port 有裝的東西，請務必列在 [.filename]#pkg-plist# 內。
* port 可以透過 `install` 來安裝，這可以確保安裝的 script 是正常運作的。
* port 可以透過 `uninstall` 來移除，這可以確保安裝的 script 是正常運作的。
* port 只有在 `featch` 目標時才能使用網路，這對 package builders 很重要，像是 package:ports-mgmt/poudriere[].
* 確保 `make package` 可以被一般使用者執行 (也就是說，非 `root` 使用者)，如果上述執行失敗，軟體很可能需要修改，請參考 crossref:uses[uses-fakeroot,`fakeroot`] 和 crossref:uses[uses-uidfix,`uidfix`]。

[.procedure]
====
*Procedure: 建議的測試順序*

. `make stage`
. `make check-orphans`
. `make package`
. `make install`
. `make deinstall`
. `pkg add _package-filename_`
. `make package` (as user)
====

確認在任何階段都沒有任何警告出現。

可以透過 package:ports-mgmt/tinderbox[] 或者 Ports Collection 的 package:ports-mgmt/poudriere[] 工具來完成自動化測試，參考 crossref:testing[testing-poudriere,Poudriere] 獲得更多的資訊。她維護 `jails` ，可以在不影響系統的情況下執行上述所有的測試。

[[porting-portlint]]
== 以 `portlint` 來作檢查 Port

請用 `portlint` 來檢查該 port 是否有遵循我們的規則。 package:ports-mgmt/portlint[] 是 ports collection 的其中一個套件。 它主要可以用來檢驗 <<porting-samplem,Makefile>> 內容是否正確以及 <<porting-pkgname,package>> 是否有正確命名。

[IMPORTANT]
====
不要盲目的相信 `portlint` 的輸出，他是一個 static lint 工具，並且有可能會出錯。
====

[[porting-submitting]]
== 提交新的 Port

提交新的 Port 前，請閱讀 <<porting-dads,DOs and DON'Ts>> 章節。

現在你很高興終於打造出 port 來囉，唯一剩下要做的就是把它正式放到 FreeBSD ports tree 內，才能讓每個人都能分享使用這個 port。

[IMPORTANT]
====
我們不需要 [.filename]#work# 目錄或是檔名像 [.filename]#pkgname.tgz# 的 package ，請現在刪除他們。
====

下一步，創建一個 man:patch[1] ，一個文件，假設此 port 叫做 `oneko` 並且屬於 `games` 類別。

[[porting-submitting-diff]]
.為新的 Port 創建 [.filename]#.diff#
[example]
====
透過 `git add .` 加入所有的檔案，然後透過 `git diff` 來檢查不同處，如下。

[source,shell]
....
% git add .
% git diff --staged
....

確保所有需要的檔案都被引入了，將更改提交到你本地分支並使用 `git format-patch` 產生 patch。

[source,shell]
....
% git commit
% git format-patch origin/main
....

使用 `git format-patch` 產生的 patch 會包含作者以及電子郵件，讓其他開發者更容易使用 (with `git am`) 以及給予回饋。


[IMPORTANT]
****
為了讓開發者更容易在他們的 ports tree 使用此 patch ，請基於你的 ports tree 來產生 [.filename]#.diff# 。
****

====

透過 https://bugs.freebsd.org/submit/[bug submission form] 繳交 [.filename]#oneko.diff# 。使用 "Ports & Packages" 產品和 "Individual Port(s)" 組件，然後跟著這裡的教學走，在 PR 的描述欄位 (也許是較短的 `COMMENT` ) 加入簡短的敘述，並且記得在附件中加入 [.filename]#oneko.diff# 。

[NOTE]
====
在問題回報系統中給一個好的總結可以讓 port 開發者更輕鬆的處理此 port ，我們預期的描述形式為 "[NEW PORT] _category/portname short description of the port_" ，使用此形式能讓我們更快的部屬新的 port 。
====

送出 port 之後，請耐心等候佳音。 有時候可能需要等個幾天或幾個月時間，才會在 FreeBSD ports tree 上正式出現。 等待中的 port PR 清單可以在 http://www.FreeBSD.org/cgi/query-pr-summary.cgi?category=ports[] 查閱。

在搜尋表單中選擇 _Open_ and  _Ports & Packages_ 來獲得  _open_ port PRs 的清單。

在看過新的 port 之後，如果需要的話，我們會回覆您，然後會將它提交到 port tree 。 您的大名會被列在 extref:{contributors}[Additional FreeBSD Contributors, contrib-additional] 列表上，以及其他檔案中。

也可以透過 man:shar[1] 檔案來提交 port ，請使用之前  `oneko` port 的例子。

.為新的 Port 創建  [.filename]#.shar#
[[porting-submitting-shar]]
[example]
====
前往 port 所在的目錄，使用 `tar`創建 shar archive:

[source,shell]
....
% cd ..
% tar cf oneko.shar --format shar oneko
....
====

可以使用跟提交 [.filename]#oneko.diff# 一樣的方式來提交 [.filename]#oneko.shar# 。