makepkg 是一個軟體包自動化構建腳本,使用時需要一個具備構建條件的 Unix 環境和一個 PKGBUILD 文件。
makepkg 是由 pacman包 包提供的。
配置
全局配置位於 /etc/makepkg.conf
,還可以通過 $XDG_CONFIG_HOME/pacman/makepkg.conf
或 ~/.makepkg.conf
進行用戶特定配置。你還可以添加 /etc/makepkg.conf.d/makepkg.conf
文件進行系統全局配置更改。在構建軟體包前,建議先檢查 makepkg 配置。
/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
構建)
你還可以#在包目錄下使用相對路徑。
驗證簽名
如果簽名文件是以 .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 aPKGBUILD
may contain arbitrary commands, building as root is generally considered unsafe.[3] Users who have no access to a regular user account should runmakepkg
as the nobody user, e.g. using the commandrunuser -u nobody makepkg
.
要構建軟體包,用戶必須首先創建一個 PKGBUILD 文件或編譯腳本(在創建軟體包中有詳細描述),或者從 Arch 構建系統(ABS)、AUR 或其他來源獲取。獲取到 PKGBUILD
後,切換到該文件所在文件夾中,然後執行以下命令構建軟體包:
$ makepkg
如果需要的依賴不滿足,makepkg 會輸出一個警告然後失敗。想要編譯軟體包並自動安裝必須的依賴,只需添加 -s
/--syncdeps
參數:
$ makepkg --syncdeps
如果添加了 -r
/--rmdeps
選項,makepkg 會在結束後刪除不再需要的編譯依賴。如果需要持續編譯軟體包,請考慮定期刪除未使用軟體包。
- 這些依賴必須在已配置的軟體源之中存在,具體信息請參考 pacman#軟體倉庫。另外,用戶也可以在編譯前手動安裝需要的依賴:(
pacman -S --asdeps dep1 dep2
)。 - Only global values are used when installing dependencies, i.e any override done in a split package's packaging function will not be used.
在滿足所有依賴並成功編譯軟體包後,一個軟體包文件(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]。因此,用戶可以通過調整以下選項來適應本地環境,以獲得或多或少的收益。
性能相關修改
90bf367e 號提交(包含在2024 年 2 月的 pacman 6.0.2-9 版本)應用了兩個配置更改,對於本地軟體包構建性能可能有重大影響。因此,建議用戶對其進行審查:
- 啟用
debug
和lto
標誌:請參考 #禁用調試包和 LTO - 將 zstd 的默認壓縮等級修改為
--ultra -20
:請參考 #修改壓縮等級
更多信息請參考 archlinux/packaging/packages/pacman!1 和 archlinux/packaging/packages/pacman#23。
優化編譯結果
通過啟用針對主機的編譯器優化,可以提高打包後軟體的性能。缺點是,為特定處理器架構編譯的二進位文件無法在其他機器上正常運行。在 x86_64 機器上,重新構建官方軟體包通常不會有顯著的性能提升,因此不值得為此投入時間。
不過,使用 「非標準」 編譯器標誌很容易降低性能。許多編譯器優化僅在某些情況下有用,不應對軟體包隨意應用。除非有評測數據證明某項優化更快,否則很有可能會導致性能下降!Gentoo 的 GCC 優化和安全的 CFLAGS 文章提供了有關編譯器優化的更多信息。
傳遞到 C/C++ 編譯器(例如 gcc包 或 clang包)的選項是通過 CFLAGS
、CXXFLAGS
和 CPPFLAGS
環境變量傳入的。在使用 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
從 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
參數更改為 3
、s
或 z
。詳情請參見 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
臨時文件系統。
使用編譯緩存
ccache 可以將編譯結果緩存起來供下次編譯使用,減少編譯時間。
使用 mold 連結器
mold包 是 ld/lld 連結器的直接替代,據稱其速度稍微較快。
要使用 mold,需添加 -fuse-ld=mold
到 LDFLAGS
,例如:
/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 號提交默認啟用了 debug
和 lto
選項。
構建調試包能讓官方倉庫為用戶提供更多的問題排查工具(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 -)
lz4包 和 xz包 默認使用多線程,不需要對 /etc/makepkg.conf
進行修改。
pigz包 是 gzip包 的一個替代、並行實現,它默認使用所有可用的CPU核心(可以使用 -p
/--processes
標誌來使用較少的核心):
COMPRESSGZ=(pigz -c -f -n)
pbzip2包 是 bzip2包 的一個替代、並行實現,它也默認使用所有可用的CPU核心。可以使用 -p#
標誌來使用較少的核心(注意:-p
和核心數之間沒有空格):
COMPRESSBZ2=(pbzip2 -c -f)
lbzip2包 是 bzip2包 的另一個替代、並行實現,它也默認使用所有可用的CPU核心。可以使用 -n
標誌來使用較少的核心。
COMPRESSBZ2=(lbzip2 -c -f)
plzipAUR 是 lzip包 的一個多線程實現,它也默認使用所有可用的 CPU 核心。可以使用 -n
/--threads
標誌來使用較少的核心。
COMPRESSLZ=(plzip -c -f)
修改壓縮等級
有幾種壓縮算法(包括 zstd 和 xz)支持設定壓縮等級,以在速度、內存占用和壓縮效率間進行取捨。
小技巧
減少下載和解壓時間
設定源文件位置
特別是在編譯 VCS 軟體包時,使用 SRCDEST
可以縮短重新構建時獲取和解壓原始碼的時間。
生成新校驗和
安裝 pacman-contrib包,然後在 PKGBUILD 文件所在目錄中執行以下命令來生成新校驗和:
$ updpkgsums
updpkgsums
uses makepkg --geninteg
to generate the checksums. See this forum discussion for more details.
也可以用如 sha256sum
命令生成校驗和並手動加入到 sha256sums
數組中。
Build from local source files
If you want to make changes to the source code you can download the source code without building the package by using the -o, --nobuild Download and extract files only option.
$ makepkg -o
You can now make changes to the sources and then build the package by using the -e, --noextract Do not extract source files (use existing $srcdir/ dir) option. Use the -f option to overwrite already built and existing packages.
$ makepkg -ef
Show packages with specific packager
expac包 is a pacman database extraction utility. This command shows all packages installed on the system with the packager named packagername:
$ expac "%n %p" | grep "packagername" | column -t
This shows all packages installed on the system with the packager set in the /etc/makepkg
variable PACKAGER
. This shows only packages that are in a repository defined in /etc/pacman.conf
.
$ . /etc/makepkg.conf; grep -xvFf <(pacman -Qqm) <(expac "%n\t%p" | grep "$PACKAGER$" | cut -f1)
在 64 位系統上構建 32 位軟體包
參考32位軟體包打包準則。
Unattended package signing
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
orSCHED_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 $$
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.
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
中的字面字符串會進入到軟體包中的文件[9]。
可以在 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.