TLPI 程式碼問答集
原文來源:https://man7.org/tlpi/code/faq.html
一般的錯誤與警告
問題一:Warning: "_XOPEN_SOURCE" redefined
當使用提供的 makefile 編譯程式時,某些範例程式的“書籍”版本會產生以下編譯警告:
要了解出現此警告的原因,需注意兩條有用的背景訊息:
本書中的所有原始碼範例都是寫出來的,因此它們預設會使用 GNU C 編譯器選項,或以下選項(對應於符合 SUSv3+C99 標準的編譯環境)進行編譯:
程式的 makefile 包含了啟用大多數可能警告的編譯器選項 (-pedantic -Wall -W)。
範例程式中使用的一些介面需要有定義 _XOPEN_SOURCE。如果使用這些介面的程式是用 -std=c99 -D_XOPEN_SOURCE=600 編譯的,那麼一切都很正常。但是,如果此類程式在編譯時沒有定義 _XOPEN_SOURCE ,但又如上所述那樣打開了警告選項,則會導致錯誤或警告(例如,諸如函數 “xxxxxx” 的隱含宣告之類的訊息)。
我為這些程式決定的解決方案是,包含一個預先處理器(preprocessor)#define 語句,它適當地定義了 _XOPEN_SOURCE。此解決方案的局限性在於,當使用 -D_XOPEN_SOURCE=600 編譯這些程式,並且原始檔案使用不同的值重新定義 _XOPEN_SOURCE 時,編譯器會發出有關重新定義的警告。
這兩個範例對於避免編譯器警告,示範了更完整的解決方案:
由於代碼緊湊的原因,此方法未在「書籍」版本的程式碼中採用,但在「distribution」版本中會採用。
也可以參考 TLPI 書籍的 3.6.1 節。
問題二:error: sys/acl.h: No such file or directory
如果您遇到錯誤 sys/acl.h: No such file or directory,那是因為您的系統上沒有安裝所需的 ACL套件。
在 Debian 或是 Ubuntu 系統,用如下的指令安裝應該會有用:
在使用 RPM 安裝套件的系統上,你會需要安裝 libacl-devel 套件。
問題三:error: sys/capability.h: No such file or directory
如果你看到錯誤訊息「error sys/capability.h: No such file or directory」
這是因為你的系統沒有安裝所需的套件。在 Debian 或 Ubuntu 系統,你可以用下面的指令安裝看看,應該會有用:
在使用 RPM 安裝套件的系統上,你會需要安裝 libcap-devel 套件。
問題四:error: selinux/selinux.h: No such file or directory
如果你看到這個錯誤訊息「selinux/selinux.h: No such file or directory」,這是因為你的系統又有套件沒有安裝。在 Debian 或 Ubuntu 系統,你可以用下面的指令安裝看看,應該會有用:
在使用 RPM 安裝套件的系統上,你會需要安裝 libselinux-devel 套件。
編譯單一個檔案遇到的錯誤與警告
lib/cap_functions.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
lib/userns_functions.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
acl/acl_update.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題二。
acl/acl_view.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題二。
cap/cap_launcher.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
cap/cap_text.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
cap/check_password_caps.c
有關編譯「書本」版本的程式碼時發生的「_XOPEN_SOURCE」重新定義警告的訊息,請參考問題一。
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
cap/demo_file_caps.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
cap/view_cap_xattr.c
如果你看到錯誤訊息「sys/capability.h: No such file or directory」,請參考問題三。
dirs_links/list_files_readdir_r.c
編譯此程式時,在使用 glibc 2.24 或更高版本編譯時,您可能會遇到警告 'readdir_r' is deprecated [-Wdeprecated-declarations]。 (我如何得知系統上的 glibc 版本呢?)這是因為自 glibc 2.24 以來 readdir_r() 已被棄用。有關詳細信息,請參閱第 357 頁的勘誤表。
filesys/t_mount.c
編譯此程式的「book」版本時,若保留各種MS_*常數為未宣告,可能會發生錯誤。如果系統上的 GNU C 函式庫比2.12版舊時,就會發生此錯誤,因為舊版的 glibc 並未定義某些必要的常數。(如何找出系統上有哪個版本的glibc?)
解決的方法是在使用較新的 glibc 版本的系統上編譯程式,或是編譯程式的「distribution」版本。
此程式的「distribution」版本不會發生問題,此版本包含的程式碼,可依據條件定義所需的常數(如果未在 glibc 表頭中定義)。請參考兩個程式版本的差異。
pgsjc/catch_SIGHUP.c
如需 "_XOPEN_SOURCE" 重新定義警告(編譯此程式的 "book" 版本時發生)的說明,請參閱此處。
pgsjc/t_setsid.c
如需 "_XOPEN_SOURCE" 重新定義警告(編譯此程式的 "book" 版本時發生)的說明,請參閱此處。
proc/setjmp_vars.c
變數 'rvar' 可能會被 'longjmp' 或 'vfork' 警告所阻擋,在編譯此程式時可預期出現該警告。GNU C 編譯器正是在準確診斷這個程式所示範的問題。請見這本書第137頁。
shlibs/dynload.c
如果您遇到函式內不允許的 #pragma GCC 診斷錯誤,這是因為您使用的是舊版的 GNU C 編譯器,它不支援使用 #pragma 語法,因而程式若使用了 #pragma,則會導致編譯器發出警告。
如果可以,請升級至 gcc 4.6(2011年3月)或更新的版本。否則,請編輯程式,移除所有以 #pragma 開頭的那行程式碼並重新編譯(此時您會看到先前隱藏的警告訊息)。
signals/nonatomic_uint64.c.c
如果發生錯誤 bits/wordsize.h:No such file or directory or sys/cdefs.h: No such file or directory。您執行 Linux 套裝版本 (例如Ubuntu或Debian)可能是需要安裝 gcc-multilib 套件,才能建置此程式的。類似下列的安裝動作應該能正常運作:
threads/thread_multijoin.c
在 64 位元的系統上編譯時,您會看到有關指標與不同大小的整數之間的型別轉換警告。我應該在這個程式中使用 intptr_r 型別。但是,由於第 649 頁勘誤表末尾所談的原因,我選擇不對程式碼或文字進行任何的更改。
sockets/scm_security_send.c
如果發生錯誤 selinux/selinux.h: No such file or directory, 請參考問題四。
time/strtime.c
在編譯此程式的書籍版本時,若出現警告重複定義 "_XOPEN_SOURCE", 請參考問題一。
time/t_stime.c
For an explanation of the "_XOPEN_SOURCE" redefined warning that occurs when compiling the "book" version of this program, look here.
users_groups/check_password.c
For an explanation of the "_XOPEN_SOURCE" redefined warning that occurs when compiling the "book" version of this program, look here.
General questions
Why are there "book" and "distribution" versions of the example source code?
The example source code is provided in two versions. The reasons for this are explained here.
Where is the file lib/ename.c.inc?
哈囉!感謝您的詢問。有些讀者指出,在 TLPI 的第 58 頁上顯示的 lib/ename.c.inc 檔案在從書籍網站下載的程式碼 tarball 中並不存在。這是因為當在 lib 目錄(或原始碼的根目錄)中執行 make(1) 時,此檔案會透過腳本自動建立。請參閱 lib/Makefile,其中呼叫 Build_ename.sh。之所以採用這種方式,是因為錯誤名稱集可以因核心和 glibc 版本以及硬體架構而異。
What version of the Linux kernel do I have on my system?
To determine the version of the Linux kernel running on your system, use the following command:
What version of glibc do I have on my system?
On a sufficiently recent system, you can determine the version of glibc running on your system using the following command:
If that command doesn't work (perhaps because you have an older system), then you can obtain the glibc version by executing the library shared object. On many systems, this is as simple as the following:
The first line of output of this command shows the glibc version on your system.
However, on some systems, glibc resides at a different path, so that the above command won't work. The following command obtains the pathname of the library by applying ldd to a dynamically linked executable at a known location, and then nests the resulting output inside command substitution to execute that pathname, producing the same results as the simpler command above.
Why do I get warnings "_BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE"?
You are compiling the code on a system that has glibc 2.20 or later installed. In glibc 2.20, the _BSD_SOURCE and _SVID_SOURCE feature test macros were deprecated. They continue to expose the definitions that they exposed in earlier glibc versions, but their use produces the warning noted above. Instead, the _DEFAULT_SOURCE macro should be used. The simplest fix for this problem is to download the latest code tarball, which fixes the problem by modifying the Makefile.inc file to add -D_DEFAULT_SOURCE to the definition of the IMPL_CFLAGS macro.
\
Last updated