跳至內容
出自 Arch Linux 中文维基

makepkg 是一個軟體包自動化構建腳本,使用時需要一個具備構建條件的 Unix 環境和一個 PKGBUILD 文件。

makepkg 是由 pacman 包提供的。

配置

全局配置位於 /etc/makepkg.conf,還可以通過 $XDG_CONFIG_HOME/pacman/makepkg.conf~/.makepkg.conf 進行用戶特定配置。你還可以添加 /etc/makepkg.conf.d/makepkg.conf 文件進行系統全局配置更改。在構建軟體包前,建議先檢查 makepkg 配置。

提示:devtools helper scripts for building packages in a clean chroot use the /usr/share/devtools/makepkg.conf.d/arch.conf configuration file instead.

更多信息請參考 makepkg.conf(5)

打包人信息

每個軟體包都會有元數據信息,其中就包含 packager。默認情況下,用戶自己打包的軟體標記為 Unknown Packager。如果多個用戶會在系統上編譯,或者需要發布軟體包給其他人,最好提供真實的聯繫人。打包人信息可以通過 makepkg.conf 中的 PACKAGER 變量進行設置。

要檢查已安裝軟體包的打包人:

$ pacman -Qi package
...
Packager       : John Doe <john@doe.com>
...

要自動化簽名過程,請同時在 makepkg.conf 中設置 GPGKEY 變量.

包輸出

makepkg 默認會在工作目錄創建軟體包,並把原始碼下載到 src/ 目錄。可以配置到自定義的路徑,比如將所有構建出的軟體包放到 ~/build/packages/ 目錄,所有源文件放到 ~/build/sources/ 目錄下。

根據需求不同,可以配置 makepkg.conf 下的這些變量:

  • PKGDEST - 軟體包構建輸出目錄
  • SRCDEST - 用於存放源數據的目錄(在指向其它位置的情況下,軟連結將被放置到 src/ 目錄下)
  • SRCPKGDEST - 原始碼包構建輸出目錄(通過 makepkg -S 構建)
提示:可以參考 pacman#清理軟體包緩存 用命令(例如 paccache -c ~/build/packages/)清理 PKGDEST 目錄

你還可以#在包目錄下使用相對路徑

驗證簽名

注意:makepkg 中的簽名驗證並不使用 pacman 的密鑰環, 而是使用用戶的密鑰[1]

如果簽名文件是以 .sig.asc 形式作為 PKGBUILD 源碼數組的一部分提供,makepkg 會自動驗證軟體包。如果用戶未提供需要的簽名公鑰,makepkg 會停止安裝過程並提示用戶說無法驗證 PGP 密鑰。

如果缺少軟體包所需的公鑰,那麼 PKGBUILD 很可能帶有 validpgpkeys 項,其中包含了所需的密鑰 ID。你可以手動進行導入,也可以在在公鑰伺服器上進行查找,然後導入。運行 makepkg 時使用 --skippgpcheck 選項可以臨時禁用簽名檢查。

使用

繼續之前,確保已安裝base-devel包組 軟體包組。屬於這個組的軟體包不會被要求列在 PKGBUILD 文件的構建時依賴(makedepends)中。

注意:
  • Make sure sudo is configured properly for commands passed to pacman. Alternatively a different authorization command can be specified with PACMAN_AUTH in the makepkg.conf(5) configuration file.
  • Running makepkg itself as root is disallowed.[2] Besides how a PKGBUILD may contain arbitrary commands, building as root is generally considered unsafe.[3] Users who have no access to a regular user account should run makepkg as the nobody user, e.g. using the command runuser -u nobody makepkg.

要構建軟體包,用戶必須首先創建一個 PKGBUILD 文件或編譯腳本(在創建軟體包中有詳細描述),或者從 Arch 構建系統(ABS)AUR 或其他來源獲取。獲取到 PKGBUILD 後,切換到該文件所在文件夾中,然後執行以下命令構建軟體包:

$ makepkg

如果需要的依賴不滿足,makepkg 會輸出一個警告然後失敗。想要編譯軟體包並自動安裝必須的依賴,只需添加 -s/--syncdeps 參數:

$ makepkg --syncdeps

如果添加了 -r/--rmdeps 選項,makepkg 會在結束後刪除不再需要的編譯依賴。如果需要持續編譯軟體包,請考慮定期刪除未使用軟體包

注意:
  • 這些依賴必須在已配置的軟體源之中存在,具體信息請參考 pacman#軟體倉庫。另外,用戶也可以在編譯前手動安裝需要的依賴:(pacman -S --asdeps dep1 dep2)。
  • 在安裝依賴包時,只使用全局值,即不會使用拆分包打包功能中的任何覆蓋值。

在滿足所有依賴並成功編譯軟體包後,一個軟體包文件(pkgname-pkgver.pkg.tar.zst)將會被創建在工作目錄下。如需安裝,請使用 -i/--install 參數(與 pacman -U pkgname-pkgver.pkg.tar.zst 相同):

$ makepkg --install

要清理殘餘的文件和目錄(如解壓到 $srcdir 的文件),請使用 -c/--clean 選項。這對於在使用同一個文件夾多次編譯同一個軟體包或者升級軟體包版本時很有用。它可以防止過期或殘餘的文件被呈遞到新的構建任務中:

$ makepkg --clean

更多信息請閱讀 makepkg(8)

優化

默認選項與 devtools官方倉庫構建軟體包使用的選項一致[4]。因此,用戶可以通過調整以下選項來適應本地環境,以獲得或多或少的收益。

優化編譯結果

通過啟用針對主機的編譯器優化,可以提高打包後軟體的性能。缺點是,為特定處理器架構編譯的二進制文件無法在其他機器上正常運行。在 x86_64 機器上,重新構建官方軟體包通常不會有顯著的性能提升,因此不值得為此投入時間。

不過,使用 「非標準」 編譯器標誌很容易降低性能。許多編譯器優化僅在某些情況下有用,不應對軟體包隨意應用。除非有評測數據證明某項優化更快,否則很有可能會導致性能下降!Gentoo 的 GCC 優化安全的 CFLAGS 文章提供了有關編譯器優化的更多信息。

傳遞到 C/C++ 編譯器(例如 gccclang)的選項是通過 CFLAGSCXXFLAGSCPPFLAGS 環境變量傳入的。在使用 Arch 構建系統時,makepkg 會將 makepkg.conf 中的配置項作為這些環境變量進行傳遞。默認值會生成通用的二進制文件,可安裝在各種機器上。

注意:
  • 記住,不是所有的構建系統都會使用 makepkg.conf 中設置的變量。例如,cmake 不會遵循 CPPFLAGS 預處理器選項環境變量。因此,很多 PKGBUILD 都包含了針對打包軟體所使用的構建系統而設置的選項。
  • 源碼提供的 Makefile 或編譯命令行中指定的參數優先級更高,並有可能會取代掉 makepkg.conf 中的配置。

GCC 可以自動檢測架構,並應用安全的架構特定優化項。要使用該特性,首先需要移除所有 -march-mtune 標誌,然後添加 -march=native,例如:

/etc/makepkg.conf
CFLAGS="-march=native -O2 -pipe ..."
CXXFLAGS="${CFLAGS} ..."

要查看該操作會啟用的選項,執行:

$ gcc -march=native -v -Q --help=target
注意:如果沒有指定 -march=native-Q --help=target不會起作用[5]。具體啟用的選項需要編譯後才能知道。詳細步驟請參考[6]

pacman 5.2.2 開始,makepkg.conf 還包含了對 RUSTFLAGS 環境變量的覆寫,用於替換 Rust 編譯器的標誌。通過在 RUSTFLAGS 中添加 -C target-cpu=native,Rust 編譯器還能檢測並應用架構特定優化項:

/etc/makepkg.conf.d/rust.conf
RUSTFLAGS="-C opt-level=2 -C target-cpu=native"

查看該操作會已啟用的 CPU 特性:

$ rustc -C target-cpu=native --print cfg

在不包含 -C target-cpu=native 的情況下運行 --print cfg 將輸出默認配置。可以根據需要將 opt-level 參數更改為 3sz。詳情請參見 Rust 編譯器文檔

減少編譯時間

並行編譯

make 編譯系統使用 MAKEFLAGS 環境變量指定 make 的額外選項。這個值也可以在 makepkg.conf 文件中進行設置。

使用多核/多處理器系統的用戶可以設定同時運行的任務數。可以用 nproc(1) 獲得可用處理器的個數,例如:MAKEFLAGS="--jobs=$(nproc)"

有些 PKGBUILD 會強制使用 -j1,因為某些版本會產生衝突或者軟體包本身並不支持。如果出現軟體包因為此原因無法編譯,請在確認錯誤是由 MAKEFLAGS 引起的前提下,在 bug 跟蹤系統中進行報告(如果是 AUR 包,則向包維護者報告)。

完整可用選項請參考 make(1)

使用內存文件系統進行編譯

編譯過程需要大量的讀寫操作,要處理很多小文件。將工作目錄移動到 tmpfs 可能會減少編譯時間。

使用 BUILDDIR 變量可以臨時將 makepkg 的編譯目錄設置到現有 tmpfs,例如:

$ BUILDDIR=/tmp/makepkg makepkg

makepkg.conf 中的 BUILDDIR 選項取消注釋可以永久變更編譯目錄,具體位於 /etc/makepkg.conf 文件末尾的 BUILD ENVIRONMENT 一節。設置此變量為 BUILDDIR=/tmp/makepkg 可以利用 Arch 默認的 /tmp 臨時文件系統。

注意:
  • tmpfs 中構建大型軟體包時可能會內存不足。
  • 掛載 tmpfs 目錄時不能使用 noexec 選項,否則編譯命令無法執行。
  • tmpfs 中構建好的包重啟後會消失,設置 PKGDEST 選項可以將構建結果保存到其它目錄。

使用編譯緩存

ccache 可以將編譯結果緩存起來供下次編譯使用,減少編譯時間。

使用 mold 連結器

moldld/lld 連結器的直接替代,據稱其速度稍微較快。

要使用 mold,需添加 -fuse-ld=moldLDFLAGS,例如:

/etc/makepkg.conf
LDFLAGS="... -fuse-ld=mold"

要向 mold 添加額外選項,可以將它們添加到 LDFLAGS 中,例如:

/etc/makepkg.conf
LDFLAGS="... -fuse-ld=mold -Wl,--separate-debug-file"

要為 Rust 軟體包使用 mold,可以將 -C link-arg=-fuse-ld=mold 添加到 RUSTFLAGS 中,例如:

/etc/makepkg.conf.d/rust.conf
RUSTFLAGS="... -C link-arg=-fuse-ld=mold"

禁用調試包和 LTO

包含在 2024 年 2 月 pacman 6.0.2-9 版本90bf367e 號提交默認啟用了 debuglto 選項。

構建調試包能讓官方倉庫為用戶提供更多的問題排查工具(archlinux/packaging/packages/pacman#23#note_173528),但在自行構建軟體包時,調試包不是必需的,而且會減慢構建進程。參見 archlinux/packaging/packages/pacman#23#note_173782

連結時優化可以生成更優化的二進制文件,但會增加構建耗時(archlinux/packaging/packages/pacman#23#note_173678),不一定是一個理想的權衡。

如需禁用這些選項,可以在 OPTIONS=() 數組中的這些選項前直接添加 ! 符號,例如:OPTIONS=(...!debug !lto...)

壓縮

使用其它壓縮算法

為了加快打包和安裝速度,您可以更改 PKGEXT,代價是生成的軟體包文件更大。

例如,以下命令可以跳過壓縮步驟,使得安裝時無需解壓:

$ PKGEXT='.pkg.tar' makepkg

另一個例子使用 lz4 算法,可以提升速度:

$ PKGEXT='.pkg.tar.lz4' makepkg

要使這些設置之一永久生效,請在 /etc/makepkg.conf 中設置 PKGEXT

在壓縮時使用多個 CPU 核心

zstd 支持對稱多處理(SMP),通過添加 -T/--threads 標誌可以加速壓縮。默認情況下,/etc/makepkg.conf 中的 COMPRESSZST 數組包含了 -T0 標誌,使得 zstd 儘可能使用多的物理 CPU 核心來壓縮軟體包。可以通過 --auto-threads=logical 標誌讓 zstd 根據邏輯 CPU 核心數進一步提升調用數:

COMPRESSZST=(zstd -c -T0 --auto-threads=logical -)

lz4xz 默認使用多線程,不需要對 /etc/makepkg.conf 進行修改。

pigzgzip 的一個替代、並行實現,它默認使用所有可用的CPU核心(可以使用 -p/--processes 標誌來使用較少的核心):

COMPRESSGZ=(pigz -c -f -n)

pbzip2bzip2 的一個替代、並行實現,它也默認使用所有可用的CPU核心。可以使用 -p# 標誌來使用較少的核心(注意:-p 和核心數之間沒有空格):

COMPRESSBZ2=(pbzip2 -c -f)

lbzip2bzip2 的另一個替代、並行實現,它也默認使用所有可用的CPU核心。可以使用 -n 標誌來使用較少的核心。

COMPRESSBZ2=(lbzip2 -c -f)

plzipAURlzip 的一個多線程實現,它也默認使用所有可用的 CPU 核心。可以使用 -n/--threads 標誌來使用較少的核心。

COMPRESSLZ=(plzip -c -f)

修改壓縮等級

有幾種壓縮算法(包括 zstd 和 xz)支持設定壓縮等級,以在速度、內存占用和壓縮效率間進行取捨。

小技巧

減少下載和解壓時間

設定源文件位置

特別是在編譯 VCS 軟體包時,使用 SRCDEST 可以縮短重新構建時獲取和解壓原始碼的時間。

生成新校驗和

安裝 pacman-contrib,然後在 PKGBUILD 文件所在目錄中執行以下命令來生成新校驗和:

$ updpkgsums

updpkgsums 使用 makepkg --geninteg 生成校驗和,查看 此論壇 了解詳情

也可以用如 sha256sum 命令生成校驗和並手動加入到 sha256sums 數組中。

從本地源文件生成

如果您想對原始碼進行更改,可以使用-o--nobuild下載原始碼,而無需構建軟體包,僅進行下載和解壓縮文件選項。

$ makepkg -o

您現在可以對原始碼進行更改,然後使用-e--noextract 不提取源文件(使用現有的$srcdir/ dir)選項構建軟體包。使用-f選項覆蓋已經生成的和現有的包。

$ makepkg -ef

顯示具有特定打包程序的包

expac 是一個pacman資料庫提取工具。此命令顯示系統上安裝的所有打包程序名為packagername的包:

$ expac "%n %p" | grep "packagername" | column -t

這將顯示系統上安裝的所有軟體包, /etc/makepkg 變量 PACKAGER僅顯示在中定義的存儲庫中的包 /etc/pacman.conf

$ . /etc/makepkg.conf; grep -xvFf <(pacman -Qqm) <(expac "%n\t%p" | grep "$PACKAGER$" | cut -f1)

在 64 位系統上構建 32 位軟體包

參考32位軟體包打包準則

Unattended package signing

本文或本章節可能需要合併到GnuPG#Unattended_passphrase

附註: This is not specific to makepkg.(在 Talk:Makepkg 中討論)

這篇文章的某些內容需要擴充。

原因:Another option is gnupg-set-passphrase(1)[失效連結 2022-06-25] (在 Talk:Makepkg 中討論)

A person may not be available to provide the passphrase for the gpg private key used to sign with in automated build environments such as Jenkins. It is ill-advised to store a private gpg key on a system without a passphrase.

A resulting zst package made with makepkg can still be signed after creation:

$ gpg --detach-sign --pinentry-mode loopback --passphrase --passphrase-fd 0 --output NewlyBuilt.pkg.tar.zst.sig --sign NewlyBuilt.pkg.tar.zst 

where the GPG passphrase is securely provided and obscured by your automation suite of choice.

The resulting zst and sig file can be referenced by pacman clients expecting a valid signature and repositories created with repo-add --sign when hosting your own repo.

Magnet URIs

Support for magnet URIs resources (with magnet:// prefix) in the source field can be added using the transmission-dlagentAUR download agent.

Running makepkg in a systemd control group

If the package you are building takes too many resources to build with your default make flags, which are otherwise set properly for most packages, you can try running it in its own control group. makepkg-cgAUR is a wrapper for makepkg that achieved this via systemd control groups (see systemd.resource-control(5)).

Running with idle scheduling policy

Package build process can lead to high CPU utilization, especially in case of #Parallel compilation. Under heavy CPU load, the system can issue a significant slowdown up to becoming unusable, even with the highest nice(1) value. User interface and foreground applications may stutter or even became unresponsive.

This can be worked around by changing the scheduling policy to SCHED_IDLE before running makepkg. It ensures that package building process does not interfere with regular tasks and only utilizes remaining unused CPU time.

From sched(7) § SCHED_IDLE: Scheduling very low priority jobs:

This policy is intended for running jobs at extremely low priority (lower even than a +19 nice value with the SCHED_OTHER or SCHED_BATCH policies).

The SCHED_IDLE policy can be set by running chrt(1) command with the -i flag, specifying priority 0 (the only valid option for SCHED_IDLE) and specifying the PID of the current shell.

For most shells:

$ chrt -iap 0 $$
提示:You can apply this command for every build by placing it into makepkg.conf.

For the fish shell, where $$ is not set:

$ chrt -iap 0 %self

在包目錄下使用相對路徑

Instead of using absolute paths for the package output options, you can also configure relative paths inside each package directory.

注意:The following options might cause problems with some AUR helpers, as they might use makepkg.conf in a context where $startdir is not defined. So be careful.

For example, you can define target paths in your makepkg.conf file as follows. The $startdir variable refers to the directory where a PKGBUILD is located when you build a package.

PKGDEST="$startdir/build/packages/"
SRCDEST="$startdir/build/sources/"
SRCPKGDEST="$startdir/build/srcpackages/"
LOGDEST="$startdir/logs/"

This will result in:

  • Built packages will be stored in: "package directory"/build/packages/
  • All downloaded source files will be stored in: "package directory"/build/sources/
  • Built source packages will be stored in: "package directory"/build/srcpackages/
  • All logs will be stored in: "package directory"/logs/

makepkg will still create a src/ and pkg/ directories a usual, so this is expected behaviour.

問題處理

Specifying install directory for QMAKE based packages

The makefile generated by qmake uses the environment variable INSTALL_ROOT to specify where the program should be installed. Thus this package function should work:

PKGBUILD
...
package() {
	cd "$srcdir/${pkgname%-git}"
	make INSTALL_ROOT="$pkgdir" install
}
...

Note, that qmake also has to be configured appropriately. For example put this in the corresponding .pro file:

YourProject.pro
...
target.path = /usr/local/bin
INSTALLS += target
...

WARNING: Package contains reference to $srcdir

由於某種原因,有時 $pkgdir$srcdir 中的字面字符串會進入到軟體包中的文件[7]

可以在 makepkg 構建文件夾中執行以下命令進行檢測:

$ grep -R "$PWD/src" pkg/

一個可能是 C/++ 代碼使用了 __FILE__ 宏並將完整路徑傳遞給了編譯器。

Makepkg fails to download dependencies when behind proxy

When makepkg calls dependencies, it calls pacman to install the packages, which requires administrative privileges via sudo. However, sudo does not pass any environment variables to the privileged environment, and includes the proxy-related variables ftp_proxy, http_proxy, https_proxy, and no_proxy.

In order to have makepkg working behind a proxy, invoke one of the following methods.

Enable proxy by setting its URL in XferCommand

The XferCommand can be set to use the desired proxy URL in /etc/pacman.conf. Add or uncomment the following line in pacman.conf:

/etc/pacman.conf
...
XferCommand = /usr/bin/curl --proxy http://username:password@proxy.proxyhost.com:80 --location --continue-at - --fail --output %o %u
...

Enable proxy via sudoer's env_keep

Alternatively, one may want to use sudoer's env_keep option, which enables preserving given variables the privileged environment. See Pacman#Pacman does not honor proxy settings for more details.

Makepkg fails, but make succeeds

If something successfully compiles using make, but fails through makepkg, it is almost certainly because /etc/makepkg.conf sets an incompatible compilation variable. Try adding these flags to the PKGBUILD options array:

!buildflags, to prevent its default CPPFLAGS, CFLAGS, CXXFLAGS, and LDFLAGS.

!makeflags, to prevent its default MAKEFLAGS.

!debug, to prevent its default DEBUG_CFLAGS, and DEBUG_CXXFLAGS, in case the PKGBUILD is a debug build.

If any of these fix the problem, this could warrant an upstream bug report assuming the offending flag has been identified.

參閱