我是 QNAP 套件的開發者。如果我有問題或要回報錯誤,可以向 QNAP 的工程師尋求協助嗎?

致:QNAP員工

QNAP客服真的幫不上忙。:disappointed_face:

我要怎麼向真正懂行的QNAP開發人員取得協助?我知道他們一定有。

我真的很努力地繼續支持QNAP,但跟「客服」的互動就是讓人心力交瘁,而且這種情況太常見了。我都不敢想其他用戶會遇到什麼困難。

你有試過重開機嗎?

到目前為止,我所有 QNAP 支援的互動都是因為 10Gbit 網卡故障,不過照著「流程」處理其實還算簡單。

很驚訝 QNAP 居然沒有提供給開發者互動的頻道。

我認為他的問題不是出在支援應用程式和客服。問題在於一般的支援人員並不是開發人員,這根本不是他們受訓要做的工作。所以他們會從「使用者的系統有問題」的角度來處理,而不是從「這是開發上的問題」來思考。

我可以怎麼幫你?還是你的工單號碼是多少呢? :wink:
開玩笑啦。
不過認真的說,你的工單號碼是多少?讓我看看我能幫什麼忙,或者我們一起討論你需要什麼。

謝謝 Silas。:+1:

我正在尋找有關 QPKG 管理的技術問題支援管道。

有什麼建議嗎?如果我註冊成為 QNAP 開發者,你知道是否會有 QNAP 員工提供支援嗎?

如果您想詢問有關開發者套件的問題,核准成為我們的開發者後,您可以透過原申請單提出問題。或者,您也可以提交一張支援單 — 關於開發相關的問題,我們的支援團隊會協助轉交給相關部門進行說明。謝謝!

我不這麼認為。不過我對 QPKG 系統相當熟悉,可以幫你。

另外,對於任何正在開發應用或想要為 QNAP 開發任何東西的人,我會說(不知道該去哪裡說),但編譯任何給 QTS6+ 的東西其實非常容易:

1) QTS 6 和 QuTS hero 都是基於 Ubuntu 24.04 / glibc。

你可以自己在機器上檢查:ldd --version 就會印出 2.39。這完全就是 Ubuntu 24.04。所以你不需要
任何 SDK、交叉工具鏈或容器(針對 x86_64 型號)。只要裝一台純 Ubuntu 24.04 虛擬機,在那裡編譯,
然後把二進制拷過去就行了。(這對 QTS 5.x 不適用,因為它的 glibc 老很多。請先確認。)

2) 選一個在 /opt 之外的目的地目錄。

# /opt 是 Entware 的專用目錄。開啟或關閉 Entware 都會把你的 symlink 抹掉。
# 給你的 app 一個固定目錄,把所有東西都放進去:
MY_APP_DEST_DIR=/usr/bin/my_app

3) 只有一個規則真的很重要:依賴全部靜態,只有 glibc 動態。

你需要用到的每個 library 都以靜態 .a 編譯並連到你的二進制檔裡。只有 glibc 保持動態連結。

  • 千萬不要完全靜態連結(-static)。這會破壞 NSS,導致 getaddrinfo() 和用戶查詢在執行時失效。
  • 千萬不要把你自己的 .so 檔丟進 NAS 的 /usr/lib。你會和 QNAP 的 library 衝突,
    最後可能會弄壞不是你的東西。

4) 一個完整、真實的例子:ncurses(庫)+ htop(應用)。

SYSROOT=$HOME/build/sysroot          # library 的私人前綴,不會安裝到 NAS
MY_APP_DEST_DIR=/usr/bin/my_app      # 應用在 NAS 上的安裝目錄

# --- library:只編靜態 ncurses -------------------------------------
# --without-shared --with-normal:只編 .a,不編 .so
# --enable-widec:libncursesw,支援 UTF-8
# --with-fallbacks + --disable-db-install:將終端說明檔編到 library 裡,
# 這樣你不用額外提供 terminfo 資料庫,也能在裸 NAS 上運行
cd ncurses-6.6
./configure --prefix=$SYSROOT \
  --without-shared --with-normal --enable-widec \
  --enable-pc-files --with-pkg-config-libdir=$SYSROOT/lib/pkgconfig \
  --with-fallbacks=xterm,xterm-256color,screen,linux,vt100,dumb \
  --disable-db-install \
  --without-debug --without-ada --without-cxx-binding --without-tests --without-manpages \
  CFLAGS="-O2 -pipe -fPIC"
make -j3 && make install             # 結果會安裝在 $SYSROOT,不會裝到系統

# --- 應用:htop,連結靜態 ncurses ---------------------
# PKG_CONFIG="pkg-config --static":拉 Libs.private,也就是全部靜態依賴
# PKG_CONFIG_LIBDIR=...:只看 sysroot,不查主機 library
# --prefix:應用在 NAS 上的路徑
# -static-libgcc:C++ app 要加 -static-libstdc++
cd ../htop-3.3.0
PKG_CONFIG="pkg-config --static" \
PKG_CONFIG_LIBDIR="$SYSROOT/lib/pkgconfig" \
./configure --prefix=$MY_APP_DEST_DIR --enable-unicode \
  CFLAGS="-O2 -pipe" \
  CPPFLAGS="-I$SYSROOT/include -I$SYSROOT/include/ncursesw" \
  LDFLAGS="-L$SYSROOT/lib -static-libgcc"
make -j3
make install DESTDIR=$PWD/../out     # 暫時安裝;DESTDIR + prefix = 你要打包的目錄樹

--prefix 是二進制在 NAS 上的路徑,DESTDIR 是你在編譯機上暫存的地方。分開設置,不然你的 app 會找錯地方去讀設定。

5) 在拷給 NAS 之前一定要驗證。三個指令,每個二進制都驗一遍。

B=out/usr/bin/my_app/bin/htop

readelf -h $B | grep Machine
#   Advanced Micro Devices X86-64  <- 正確架構

readelf -d $B | grep NEEDED
#   libm.so.6, libc.so.6           <- 只剩 glibc。ncurses 已經進到二進制裡。

objdump -T $B | grep -oE 'GLIBC_[0-9.]+' | sort -uV | tail -1
#   GLIBC_2.38                     <- 務必 <= 2.39,不然 NAS 不會啟動

如果 NEEDED 有列任何不是 libc/libm/libpthread/libdl/librt/libresolv/ld-linux/libgcc_s,
表示你忘了把依賴靜態連進二進制。回去修 library,不要只修 app。

6) patchelf:唯一無法靜態連結的 library 處理方式。

在上述例子中,htop 還是從編譯主機抓到了 libcap.so.2。有兩個正統做法:

方案A,乾脆不要這個功能:./configure --disable-capabilities。這樣就不用帶額外檔案了。

方案B,把 library 放進你自己的目錄裡並告訴二進制去哪找。這就是 patchelf 的用途,
而 $ORIGIN 很重要:它代表「這支二進制所在的目錄」,在執行時解析,所以無論包裝移去哪都能正常運作。

mkdir -p out/usr/bin/my_app/lib
cp -L /lib/x86_64-linux-gnu/libcap.so.2 out/usr/bin/my_app/lib/
patchelf --set-rpath '$ORIGIN/../lib' out/usr/bin/my_app/bin/htop
#         ^ 單引號,讓 shell 不要展開 $ORIGIN。

readelf -d out/usr/bin/my_app/bin/htop | grep -E 'RUNPATH|NEEDED'
#   RUNPATH  [$ORIGIN/../lib]
ldd out/usr/bin/my_app/bin/htop | grep libcap
#   libcap.so.2 => .../my_app/bin/../lib/libcap.so.2  <- 這是你自己的複本,不是系統的

還有兩個 patchelf 技巧值得知道:

patchelf --remove-rpath  $B                       # 把編譯主機的絕對 RPATH 清掉
                                                  # libtool 很愛寫進去(/home/you/build/...)
patchelf --replace-needed libfoo.so.1 libfoo.so.2 $B   # 修改一個無法重建的二進制的依賴

記得 RUNPATH 只會解析你實際提供的 library。不要拿來借用 QNAP 的 library,
你也不該這麼做:那裡的 library 會隨著韌體版本變動。

7) ARM 型號。

同樣方法,多一步。Ubuntu 24.04 自帶交叉編譯器,安裝
gcc-aarch64-linux-gnu 或 gcc-arm-linux-gnueabihf,然後每個 ./configure 加 --host=aarch64-linux-gnu
(或 arm-linux-gnueabihf),另外匯出
CC/CXX/AR/RANLIB/STRIP 等帶前綴的編譯器。其他,包括三個驗證步驟,都一樣。對 armv7 有一點要注意:舊款 Marvell 沒有 NEON,自己寫的 NEON 組語要能偵測執行時或直接關掉。

以上所有步驟都用 Ubuntu 24.04 做過實測:ncurses 6.6 靜態,htop 3.3.0,GLIBC_2.38 最高,libcap 用 $ORIGIN/../lib 搬移,二進制可以啟動且正常印版本。


若你想完整了解 QNAP QPKG,只需裝 StorageDiag Workbench & Utiltities,用 CmdHelper 仔細看一下 start/stop 腳本的流程:

有需要可以問我,我都會盡量幫你解釋。

謝謝 Silas,那裡有一些很棒的資訊。我希望更多人能發帖分享這類操作方法。如果 QNAP 像這樣給力,我想可供安裝的 QPKG 會多很多。 :nerd:

我自己的套件則簡單得多。一般來說我不編譯,但我確實需要學會如何打包更新版的 glibc,因為這阻止了我分發其他一些應用程式。

libicu 也是我需要研究的另一個套件。

謝謝你,Steve。 :+1:

既然談到這個話題(作為合作夥伴開發者),我想這意味著我提交的 QPKG 必須由 QNAP 人員審核是否通過。我開發的 QPKG 通常包含一些 hack 式的解決方法,用來應對我這些年在不同 QTS 版本中遇到的問題。QNAP 方面會對這些作法有意見嗎?舉例來說:QPKG 簽署。

在 QTS 4.x 和 5.x 的舊時期,我直接把整個 glibc(從 Debian 虛擬機拿來的)和我要分發的應用程式一起打包,這就是我編譯應用程式時用的同一個 glibc。

舉個例子,TVHeadend QPKG 就是這樣做的。或許這種方式在「空間利用」上不是最有效率,但它確實管用 :grinning_face:

我喜歡這個! :grin:

你是怎麼讓應用程式用你那個特定的 glibc,而不是系統的呢?這部分我有點搞不清楚。

i got your point,
i would recommend you recompile instead going that way, because in such case you has to supply ld-library together and do some workaround…hmmm

# cat SoulseekCloud.sh
#!/bin/sh

NAME=SoulseekCloud
FRAMEWORK=QX11

export _DISPLAY=99

LOCK=/tmp/${NAME}.lock
_DEBUG=1

# Symbols
DOUBLE_LEFT_QUOTE_SYMBOL=$(echo -e "\xab")	; ASC_DLQ=$DOUBLE_LEFT_QUOTE_SYMBOL
DOUBLE_RIGHT_QUOTE_SYMBOL=$(echo -e "\xbb")	; ASC_DRQ=$DOUBLE_RIGHT_QUOTE_SYMBOL
GREATER_SYMBOL=$(echo -e "\x3e")		; ASC_GT=$GREATER_SYMBOL
LESS_SYMBOL=$(echo -e "\x3c")			; ASC_LT=$LESS_SYMBOL

# Normal Colors
black='\e[0;30m'        # Black
red='\e[0;31m'          # Red
green='\e[0;32m'        # Green
yellow='\e[0;33m'       # Yellow
blue='\e[0;34m'         # Blue
purple='\e[0;35m'       # Purple
cyan='\e[0;36m'         # Cyan
white='\e[0;37m'        # White

# Bold
bblack='\e[1;30m'       # Black
bred='\e[1;31m'         # Red
bgreen='\e[1;32m'       # Green
byellow='\e[1;33m'      # Yellow
bblue='\e[1;34m'        # Blue
bpurple='\e[1;35m'      # Purple
bcyan='\e[1;36m'        # Cyan
bwhite='\e[1;37m'       # White

# Background
on_black='\e[40m'       # Black
on_red='\e[41m'         # Red
on_green='\e[42m'       # Green
on_yellow='\e[43m'      # Yellow
on_blue='\e[44m'        # Blue
on_purple='\e[45m'      # Purple
on_cyan='\e[46m'        # Cyan
on_white='\e[47m'       # White

nc="\e[m"               # Color Reset

alert=${bwhite}${on_red} # Bold White on red background
warn=${black}${on_yellow} # Bold White on red background
notice=${black}${on_cyan} # Bold White on red background
info=${black}${on_green} # Bold White on red background

fd=0                    # stdin

DATE=`date +%Y-%m-%d`
NOW=`date +%Y%m%d_%H%M%S`

alias strip_esc='sed -r "s/\x1B[\[|\(]([0-9]{1,2}(;[0-9]{1,2})?)?[m|K|A|B|C|E|J|S|Z|H]//g"'

# interactive shell? then keep user attention on the err msg
if [ -t "$fd" ] || [ -p /dev/stdin ]; then
	echo -n ""
fi


function DEBUG()
{
	[ "$_DEBUG" == "1" ] && $@
}

_exit()
{
	echo -e "$*"
	echo

	# interactive shell? then keep user attention on the err msg
	if [ -t "$fd" ] || [ -p /dev/stdin ]; then
		echo -n "" ; sleep 1
		echo -n "" ; sleep 1
		echo -n "" ; sleep 1
		echo -n "" ; sleep 1
		echo -n "" ; sleep 1
	fi

	exit 1
}

available() {
	type -t "$1" >/dev/null && return 0
	return 1
}



# Message to terminal and system log
# ###########################################################################
_log() {
	local msg_type="info"
	local write_msg="/sbin/log_tool -t0 -u$NAME -p127.0.0.1 -mlocalhost -a"
	local message="$NAME: ${*:-"Unspecified Notice"}"

	[ "$_QUIET" != "1" ] && echo -e "(${green}$msg_type${nc}) $message"

#	message=`echo -e $message | strip_esc`

	# save to system Event Log only when in DEBUG mode
	[ "$_DEBUG" == "1" ] && $write_msg "($msg_type) $(echo -e $message | strip_esc)"
}

# Warning message to terminal and system log
# ###########################################################################
__warn() {
	local msg_type="warn"
	local message="$NAME: ${*:-"Unknown Warning"}"
	echo -e "(${red}$msg_type${nc}) "
}
_warn() {
	local msg_type="warn"
	local write_warn="/sbin/log_tool -t1 -u$NAME -p127.0.0.1 -mlocalhost -a"
	local message="$NAME: ${*:-"Unknown Warning"}" && $write_warn "($msg_type) $(echo -e $message | strip_esc)"

	echo -e "(${red}$msg_type${nc}) $message"
}

# Write error log message and exit
# ###########################################################################
__err(){
	local msg_type="err!"
	local message="$NAME: ${*:-"Unknown Error"}"

	_exit "(${alert}$msg_type${nc}) $message \n"
}
_err(){
	local msg_type="err!"
	local write_err="/sbin/log_tool -t2 -u$NAME -p127.0.0.1 -mlocalhost -a"
	local message="$NAME: ${*:-"Unknown Error"}" && $write_err "($msg_type) $(echo -e $message | strip_esc)"

	_exit "(${alert}$msg_type${nc}) $message \n"
}


function help()
{
	echo -e "------------------------------------------------------------------------------"
	echo -e " (${NAME}) PID: $$; (parent:${PPID})"
	echo -e "---------------------------------------------------------- || Hello World! ---"
	echo
	echo -e "  Usage:"
	echo -e "          ${white}$0${nc} (start|stop|restart)"
	echo
	echo -e "  Available options:"
	echo -e "    start/stop/restart        - start or stop chroot environment"
}


# Helper: Get script location
# ########################################
function _get_cwd()
{
	if [[ ${0:0:1} != "/" ]]; then
		CWD="$PWD"/$(dirname "$0")
	else
		CWD=$(dirname "$0")
	fi

	CWD=`cd "${CWD}" 2>/dev/null && pwd || echo "${CWD}"`
	ROOT="${CWD}"
}

_get_cwd
DEBUG echo Found current directory: "$CWD"
CWD=`getcfg -f /etc/config/qpkg.conf $NAME Install_Path`
DEBUG echo And app is installed in: "$CWD"
_PWD=`pwd`
cd "$CWD" 2>/dev/null 1>/dev/null

ROOTFS="${CWD}/rootfs"

SHARE_DOWNLOAD=/share/Download
SHARE_MULTIMEDIA=/share/Multimedia
$(cd "${SHARE_DOWNLOAD}" 2>/dev/null || _err Download share does not exist. Please enable multimedia functions or create it manually.)
$(cd "${SHARE_MULTIMEDIA}" 2>/dev/null || _err Multimedia share does not exist. Please enable multimedia functions or create it manually.)
SOULSEEK_DOWNLOAD_DIR="${SHARE_DOWNLOAD}/SoulseekCloud"
mkdir -p $SOULSEEK_DOWNLOAD_DIR 2>/dev/null 1>/dev/null
SOULSEEK_MULTIMEDIA_DIR="${SHARE_MULTIMEDIA}"


# Install my icons ...
# ###########################################################################
install_icons(){
	cp -af "$CWD/.qpkg_icon.gif" "/home/httpd/RSS/images/${NAME}.gif"		2>/dev/null
	cp -af "$CWD/.qpkg_icon_gray.gif" "/home/httpd/RSS/images/${NAME}_gray.gif"	2>/dev/null
	cp -af "$CWD/.qpkg_icon_80.gif" "/home/httpd/RSS/images/${NAME}_80.gif"		2>/dev/null
}
install_icons


RESULT=`/sbin/getcfg ${FRAMEWORK} Enable -u -d TRUE -f /etc/config/qpkg.conf`
if  [ "$RESULT" = "FALSE" ] ; then
	_err " ${FRAMEWORK} is disabled"
	exit 1
fi

RESULT=`/sbin/getcfg ${FRAMEWORK} Install_Path -d /null -f /etc/config/qpkg.conf`
QX11_PATH=${RESULT}/rootfs
if  [ ! -d "${QX11_PATH}" ] ; then
	_err " ${FRAMEWORK} is missing or not installed!. Please install ${FRAMEWORK} first! "
	exit 1
fi


case "$1" in
	"enable")
		/sbin/setcfg ${NAME} Enable TRUE -f /etc/config/qpkg.conf
	;;
	"disable")
		/sbin/setcfg ${NAME} Enable FALSE -f /etc/config/qpkg.conf
	;;
	"start")
		echo "- $NAME -- # QPKG Enable check"
		RESULT=`/sbin/getcfg ${NAME} Enable -u -d TRUE -f /etc/config/qpkg.conf`
		if  [ "$RESULT" = "FALSE" ] ; then
			echo " ${NAME} is disabled"
			exit 1
		fi

		echo "- $NAME -- # QPKG Running check"
		if [ -e ${LOCK} ] ; then
			echo " ${NAME} already Started $BASE "
			exit 1
		fi

		touch ${LOCK}

		[ -f "/etc/machine-id" ] || dbus-uuidgen > /etc/machine-id
		#locale-gen en_US.UTF-8

		SHARE_SOULSEEK=/share/Download/SoulseekCloud
		mkdir -p ${SHARE_SOULSEEK}/Music
		mkdir -p ${SHARE_SOULSEEK}/Soulseek\ Chat\ Logs
		mkdir -p ${SHARE_SOULSEEK}/Soulseek\ Downloads
		#[ -L /usr/share/novnc/logs ] || ln -s ${SHARE_SOULSEEK}/Soulseek\ Chat\ Logs /usr/share/novnc/logs
		#[ -L /usr/share/novnc/downloads ] || ln -s ${SHARE_SOULSEEK}/Soulseek\ Downloads /usr/share/novnc/downloads

		[ -d "${SHARE_SOULSEEK}/.SoulseekQt" ] || cp -af ${CWD}/config/default/.SoulseekQt "${SHARE_SOULSEEK}/"

		echo "- $NAME -- # QX11_framework_enable" ; /etc/init.d/QX11.sh enable
		echo "- $NAME -- # QX11_framework_start..." ; /etc/init.d/QX11.sh start
		/sbin/log_tool -t 0 -a "${NAME} in : Framework started on port 601${_DISPLAY} -> forwarded to 259${_DISPLAY}"

		#${CWD}/init.sh
		export pgid=1000
		export puid=1000
		export resize=scale
		export resolution=1920x1040

		export DISPLAY=":${_DISPLAY}"
		#[ -f /tmp/.X${_DISPLAY}-lock ] && rm /tmp/.${_DISPLAY}-lock 2>/dev/null 1>/dev/null

		export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
		export TEMP="/tmp"
		export TMP="/tmp"
		export TMPDIR="/tmp"
		export TERM="xterm"
		export EDITOR="/usr/bin/mcedit"
		export SHELL="/bin/sh"
		export LD_LIBRARY_PATH
		export LD_RUN_PATH
		export MC_HOME
		export MC_TMPDIR
		export WGETRC
		unset -v LD_LIBRARY_PATH
		unset -v LD_RUN_PATH
		unset -v MC_HOME
		unset -v MC_TMPDIR
		unset -v WGETRC


		export LANG=en_US.UTF-8
		export LANGUAGE=en_US:en
		export LC_ALL=en_US.UTF-8
		export XDG_RUNTIME_DIR=/share/Download/SoulseekCloud

		export FONTCONFIG_PATH="/usr/bin/QX11/etc/fonts/"

		export HOME="/share/Download/SoulseekCloud"
		export LD_RUN_PATH="${CWD}/app/lib"
		export LD_RUN="${CWD}/app/lib"
		export LD_LIBRARY_PATH="${CWD}/libc:${CWD}/app/lib:${QX11_PATH}/usr/lib/x86_64-linux-gnu/mesa:${QX11_PATH}/usr/lib/x86_64-linux-gnu:${QX11_PATH}/lib/x86_64-linux-gnu"
		#export LD_RUN_PATH=$LD_LIBRARY_PATH
		#echo $LD_LIBRARY_PATH

		#${CWD}/app/ld-2.19.so ${CWD}/app/SoulseekQt &
		${CWD}/app/ld-2.27.so ${CWD}/app/SoulseekQt &
		#${CWD}/app/ld-2.31.so ${CWD}/app/SoulseekQt &

		echo "app/SoulseekQt" > /var/run/QX11.SoulseekQt

		;;
	"stop")
		if [ ! -e ${LOCK} ] ; then
			echo " ( lock file not exist: ${LOCK} ) "
#			echo "Stop : Nothing to do ${POOL_NAME} not started."
#			exit 0
		fi

		kill `ps ax | grep SoulseekQt | grep -v grep | awk '{print $1}' 2>/dev/null`  2>/dev/null 1>/dev/null
		sleep 1
		sync
		kill -9 `ps ax | grep SoulseekQt | grep -v grep | awk '{print $1}' 2>/dev/null`  2>/dev/null 1>/dev/null
		sync

		rm ${LOCK} 2>/dev/null 1>/dev/null

		/sbin/log_tool -t 0 -a "${NAME} Stopped"
		;;
	"status")
		echo Process:
		ps ax | grep Soulseek | grep -v grep | grep -v container | grep -v "$(basename $0)"
		;;
	"restart")
		${CWD}/$0 stop
		/bin/sleep 2
		${CWD}/$0 start
		;;
	*)
		help
		echo
		echo Status
		${CWD}/$0 status
		exit 1
esac

# Parent process has died so we also better die.
exit 0

please look at start sequence
so i shipped my app together with own libc from other system


listen to me… this was for QTS <6.0
from now QTS is Ubuntu24 and you can compile anything you want and even just copy from Ubuntu24
if you wish me i can even writte some skills for claude/codex/copilot and others with instruction how to exactly compile and write compilation scripts if you want

the other way too do such things is native chroot and run app from chroot

but as i said - please avoid those two methods, are legacy from the moment when qts 6 goes out

謝啦,哥們。:nerd_face:

順便問一下:你有在 QTS 6 上測試過嗎?看起來現在還沒推出,連測試版都沒有。

請問你能回覆我在 forum.qnap.net.pl 上的私訊嗎?

不過針對你的問題回答一下:
QuTS hero 6 已經採用新版 glibc
所以我們可以預期 QTS 6 也會是新版的 :wink:

啊,抱歉啦,我平常沒有在那邊待,所以不知道你有發訊息給我。我剛剛才回覆了。

你現在也可以在這個論壇上私訊我了。 :nerd_face:

給正在跟進的朋友們,我今天有一點小成果。

我從我的 Debian Trixie 複製了 glibc(還有 linker),然後成功在 QTS 5.2.10 上運行了一個需要 QTS 沒有的 glibc 版本的小型二進位檔 :tada:

目前二進位檔運作良好。不過還需要進一步測試。

基本語法是:

/path/to/new/linker --library-path /path/to/custom/libs/ /path/to/executable

這樣看起來對嗎?

現在我用這個方法來指定多個函式庫位置:

LD_LIBRARY_PATH=/path/to/custom/libs/ /path/to/new/linker /path/to/executable

這一切都對,朋友。