歡迎您光臨本站 註冊首頁

GNU 編碼標準 Part 3

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  使用C以外的語言
使用C以外的語言就好像使用非標準特徵:它將為用戶帶來麻煩。即使GCC能夠支持其它
語言,用戶也可能因為不得不安裝其它語言的編譯器以創建你的程序而感到不便。所以
請使用C語言。
這條規則有三個例外:
如果有些程序包括了特殊語言的解釋器,那麼就可以使用這種語言。
因此,GNU Emacs包含用Emacs Lisp寫的代碼就沒有問題,因為GNU Emacs包含了Lisp解
釋器。
如果一個工具就是為了某種語言而編寫的,那麼就可以使用那種語言。
這是因為那些需要創建這個工具的人必然是那些已經安裝了其它語言的人。
如果一個應用程序沒有被極端廣泛地關注,那麼應用程序的安裝不太方面就不是特別重
要。
格式化你的源代碼
把作為C函數的開頭的左花括弧放到第零列是十分重要的,並且避免把任何其它的左花括
號、左括弧或者左方括弧放到第零列。有些工具通過尋找在第零列的左花括弧來尋找C函
數的起點。這些工具將不能處理那些不按照這種方式排版的代碼。
對於函數定義來說,把函數名的起始字元放到第零列也同樣重要。這幫助任何尋找函數
定義,並且可能有助於幫助某些工具識別它們。因此,正確的格式應該是:
static char *
concat (s1, s2) /* Name starts in column zero here */
char *s1, *s2;
{ /* Open brace in column zero here */
...
}
或者,如果你希望使用標準C,定義的格式是:
static char *
concat (char *s1, char *s2)
{
...
}
在標準C中,如果參數不能夠被美觀地放在一行中,按照下面的方式把它們分開:
int
lots_of_args (int an_integer, long a_long, short a_short,
double a_double, float a_float)
...
對於函數體,我們希望它按照如下方式排版:
if (x < foo (y, z))
haha = bar[4] + 5;
else
{
while (z)
{
haha += foo (z, z);
z--;
}
return ++x + bar ();
}
我們發現如果在左括弧之前以及逗號之後添加空格將使程序更加容易閱讀。尤其是在逗
號之後添加空格。
當我們把一個表達式分成多行的時候,在操作符之前而不是之後分割。下面是正確的方
式:
if (foo_this_is_long && bar > win (x, y, z)
&& remaining_condition)
儘力避免讓兩個不同優先順序的操作符出現在相同的對齊方式中。例如,不要象下面那樣
寫:
mode = (inmode[j] == VOIDmode
|| GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j])
? outmode[j] : inmode[j]);
應該附加額外的括弧以使得文本縮進可以表示出這種嵌套:
mode = ((inmode[j] == VOIDmode
|| (GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j])))
? outmode[j] : inmode[j]);
插入額外的括弧以使得Emacs可以正確地對齊它們。例如,如果你手工完成縮進工作,那
么它們看起來不錯,但Emacs將把它們混在一起:
v = rup->ru_utime.tv_sec*1000 + rup->ru_utime.tv_usec/1000
+ rup->ru_stime.tv_sec*1000 + rup->ru_stime.tv_usec/1000;
但添加一組括弧解決了這個問題:
v = (rup->ru_utime.tv_sec*1000 + rup->ru_utime.tv_usec/1000
+ rup->ru_stime.tv_sec*1000 + rup->ru_stime.tv_usec/1000);
按照如下方式排版do-while語句:
do
{
a = foo (a);
}
while (a > 0);
請按照邏輯關係(而不是在函數中)使用走紙字元(control-L)以把程序劃分成頁。頁
有多長並不重要,因為它們不必被放在一個列印的頁中。走紙字元應該單獨地出現在一
行中。
為你的工作寫註釋
每個程序都應該以一段簡短地、說明其功能的註釋開頭。例如:`fmt - filter for si
mple filling of text'.
請為每個函數書寫註釋以說明函數做了些什麼,需要哪些種類的參數,參數可能值的含
義以及用途。如果按照常見的方式使用C語言類型,就沒有必要逐字重寫C參數聲明的含
義。如果它使用了任何非標準的東西(例如,一個類型為char *的參數實際上給出了一
個字元串的第二個字元,而不是第一個字元,的地址),或者是可能導致函數不能工作
的任何可能的值(例如,不能保證正確處理一個包含了新行的字元串),請確認對它們
進行了說明。
如果存在重要的返回值,也需要對其進行解釋。
請在你的註釋之後添加兩個空格,以便Emacs句子命名進行處理。還有,請書寫完整的句
子並且使頭一個單詞以大寫字母開頭。如果小寫字母組成的標識符出現在句子的開頭,
不要把它變成大寫的!修改拼寫就構成了不同的標識符。如果你不希望句子以小寫字母
開頭,可以寫下不同的句子(例如,「The identifier lower-case is ...」)。
如果你使用參數名來說明參數值,關於函數的註釋就會更清晰。變數名本身應該是小寫
的,但在你說到它的值而不是變數本身的時候就使用大寫字母。因此,「the inode nu
mber node_num」 比「an inode」要好。
通常在函數之前的註釋中沒有必要重新提到函數的名字,因為讀者可以自己看到它。一
種可能的例外是:註釋太長了,以至於函數本身被擠出了屏幕底端之外。
對於每個靜態變數,也象下面那樣應該提供註釋:
/* Nonzero means truncate lines in the display;
zero means continue them. */
int truncate_lines;
除非`#endif'是一個沒有嵌套而且很短(只有幾行)的條件,每個 `#endif'都應該含有
一個註釋。註釋應該說明它所結束的條件,包括它的含義。 `#else'應該含有一個說明
條件與隨後代碼的含義的註釋。例如:
#ifdef foo
...
#else /* not foo */
...
#endif /* not foo */
但相反,按照如下方式為`#ifndef'寫註釋:
#ifndef foo
...
#else /* foo */
...
#endif /* foo */
清晰地使用C語言成分
請顯式地聲明函數的所有參數。不要因為它們是整數就忽略它們。
對外部函數以即將隨後出現在源文件中的函數的聲明應該出現在靠近文件開頭(在第一
個函數定義之前的某個地方)的同一個地方。或者其它的聲明應該出現在頭文件中。不
要在函數中放置外部聲明。
在過去一種常見的做法是在同一個函數中把同一個局部變數(比如說名為tem的變數反覆
地用於不同的值。但現在,更好的方式是為每個不同的目的分別定義局部變數,並且給
它們以更有意義的名字。這不僅僅是程序更容易理解,它還會被好的編譯程序所優化。
你還可以把對局部變數的聲明放到包含對它的使用的最小範圍中。這可以把程序變得更
清晰。
不要使用可以遮蔽全局標識符的局部變數和參數。
不要在跨越了行的聲明中聲明多個變數。在每一行中都以一個新的聲明開頭。例如,不
應該:
int foo,
bar;
而應該:
int foo, bar;
或者:
int foo;
int bar;
(如果它們是全局變數,在它們之中的每一個之前都應該添加一條註釋。)
當你在一個if語句中嵌套了另一個if-else語句,總是用花括弧把if-else括起來。因此
,不要寫:
if (foo)
if (bar)
win ();
else
lose ();
而總是要寫:
if (foo)
{
if (bar)
win ();
else
lose ();
}
如果你在else語句中嵌套了一個if語句,即可以像下面那樣寫else if:
if (foo)
...
else if (bar)
...
按照與then那部分代碼相同的縮進方式縮進else if的then部分代碼,也可以在花括弧中
像下面那樣把if嵌套起來:
if (foo)
...
else
{
if (bar)
...
}
不要在同一個聲明中同時說明結構標識和變數或者結構標試和類型定義(typedef)。單
獨地說明結構標試,而後用它定義變數或者定義類型。
儘力避免在if的條件中進行賦值。例如,不要寫:
if ((foo = (char *) malloc (sizeof *foo)) == 0)
fatal ("virtual memory exhausted");
而要寫:
foo = (char *) malloc (sizeof *foo);
if (foo == 0)
fatal ("virtual memory exhausted");
不要為了通過lint的檢查而把程序修改得難看。請不要加入任何關於void的強制類型轉
換。沒有進行類型轉換的零作為空指針常量是很好的。
命名變數和函數
請在名字中使用下劃線以分隔單詞,以便Emacs單詞命令對它們來說有用。堅持使用小寫
;把大寫字母留給宏和枚舉常量,以及根據統一的慣例使用的前綴。
例如,你應該使用類似ignore_space_change_flag的名字;不要使用類似 iCantReadTh
is的名字。
用於標明一個命令行選項是否被給出的變數應該在選項含義的說明之後,而不是選項字
符之後,被命名。一條註釋即應該說明選項的精確含義,還應該說明選項的字母。例如

/* Ignore changes in horizontal whitespace (-b). */
int ignore_space_change_flag;
當你需要為常量整數值定義名字的時候,使用enum而不是`#define'。 GDB知道枚舉常量

使用14個字元或者少於14個字元的文件名,以避免無緣無故地在System V上導致問題。

使用非標準的特徵
許多現有的GNU工具在兼容Unix工具的基礎上提供了許多方便的擴展。在實現你的程序時
是否使用這些擴展是一個難以回答的問題。
一方面,使用擴展可以使程序變得清晰。但另一方面,除非人們可以得到其它的GNU工具
,人們就不能創建程序。這可能使得程序只能在較少類型的機器上工作。
對於某些擴展,可能可以很容易地應付上述兩種選擇。例如,你可以用「關鍵字」 INL
INE定義函數並且把INLINE定義成一個宏,在根據編譯器確定它是被擴展成inline或者擴
展成空。
一般地,如果你能夠在沒有它們的情況下直截了當地完成任務,可能最好的辦法是不使
用擴展,但如果擴展可以大大地改進你的工作,就使用擴展。
對這一規則的一個例外是那些運行在大量不同系統上的大規模、已經創建的程序(例如
Emacs)。使用GNU擴展將破壞這些程序。
另一個例外是那些作為編譯本身的一部分的程序:這包括必須用其它編譯器進行編譯以
構造GNU 編譯工具的任何東西。如果它們需要GNU編譯器,那麼沒有人可以在沒有安裝它
們的情況下編譯它們。這將是不好的。
由於大部分計算機系統還沒有實現標準C,使用標準C的特徵,所以使用標準C就相當於使
用 GNU擴展,所以前面的考慮也適用於它。(除了那些令我們失望的標準特徵,例如三
元組序列(trigraphs)--永遠不要使用它們。)
三元組序列是標準C中為了彌補某些終端上可用字元的不足而提供的、用三個字元組合代
替一個特殊字元的方法。所有可用的三元組為:「??=」轉換成「#」、「??/」轉換成「
\」、 「??'」轉換成「^」、「??(」轉換成「[」、「??)」轉換成「]」、「??!」轉換
成「|」、「??<」轉換成「{」、 「??>」轉換成「}」、「??-」轉換成「~」。
---- 譯者注
適用於所有程序的程序行為
通過動態地分配所有的數據結構來避免對任何數據結構,包括變數名、行、文件和符號
,的長度和數量施加任何限制。在大多數Unix工具中,「長行被沒有提示地截斷」了。
對於GNU工具來說,這是不可接受的。
讀入文件的工具不應該放棄NUL字元、或者任何不可列印的字元,包括那些大於0177的字
符。唯一明智的例外是那些為訪問與不能處理這些字元的特定類型的印表機的界面而設
計的工具。
為每個系統調用的返回值進行錯誤檢查,除非你知道你希望忽略錯誤。把那些系統錯誤
文字(來自於perror或者它的等價物)包括在每個有失敗的系統調用導致的錯誤消息中
,如果有的話還要包括文件名和工具名。僅僅給出「cannot open foo.c」或者「stat
failed」 是不夠的。
檢查每個對malloc或者realloc的調用以察看它是否返回0。即使在 realloc使塊變小的
時候,也要檢查它的返回值;在有些系統中總是把塊的大小擴大到2的冪次。如果你申請
更少的空間,realloc可能得到一個不同的塊。
在Unix中,如果realloc返回0,那麼它就可以破壞存儲塊。GNU realloc 沒有這個錯誤
:如果它失敗了,原來的塊不會被改變。放心地假定這個錯誤已經被修正了。如果你希
望在 Unix上運行你的程序,並且在這種情況下不希望失去內存塊,你可以使用GNU mal
loc。
你必須假定free將改變被釋放的塊的內容。任何你希望從塊中獲得的東西,你必須在調
用free之前拿到它。
使用getopt_long對參數進行解碼,除非參數的語法使得這樣做變得不合情理。
當靜態內存在程序執行的時候被寫入的情況下,顯式地使用C代碼來初始化它。保留對那
些不會被改變的數據的C初始化聲明。
儘力避免訪問晦澀的Unix數據結構的低級界面(例如文件目錄、utmp或者內核內存的分
布),因為它們通常會降低兼容性。如果你希望找到目錄中的所有文件,使用readdir或
者其它高級的界面。GNU兼容將地支持它們。
在預設狀態下,GNU系統將提供BSD的信號處理函數和POSIX的信號處理函數。因此GNU軟
件應該使用它們。
在錯誤中檢測到「不可能」的條件是,只要退出就行。沒有理由列印任何消息。這些檢
查表明有bug存在。任何希望修正錯誤的人都必須閱讀源代碼並且運行調試器。所以在源
代碼中通過註釋給出問題的解釋。相關的數據將儲存在變數中,這些變數很容易被調試
器檢測到,所以沒有理由把它們轉移的其它任何地方。
格式化錯誤信息
來自於編譯器的錯誤信息應該使用格式:
source-file-name:lineno: message
如果有適當的源文件存在,則來自於非互動式程序的錯誤信息應該使用格式:
program:source-file-name:lineno: message
或者,如果沒有相關的源文件,則應該使用格式:
program: message
在一個互動式程序(從終端讀入命令的程序)中,不把程序名包括在錯誤信息中更好一
些。指明程序正在運行的地方應該是提示符或者屏幕的布局。(當相同的程序在運行時
從源文件中,而不是從終端中讀取輸入,它就不是互動式的了,並且最好按照非交互方
式風格列印錯誤信息。)
在字元串message被放置在程序名和/或文件名之後時,它不應該以大寫字母開頭。此外
,它也不應該以句點結尾。
來自於互動式程序的錯誤信息,以及其它的諸如使用信息的信息,應該以大寫字母開頭
。但它們不應該以句點結尾。
庫的行為
試著使庫函數成為可再入的。如果它們需要進行動態內存分配,至少要試圖避免任何來
自 malloc本身的非可再入的方面。
這裡給出了一些庫的命名慣例,以避免名字的衝突。
為庫選擇一個多於兩個字元的命名前綴。所有的外部函數和變數名都應該以這個前綴開
頭。還有,在任何給定的庫成員中,僅僅應該含有一個函數或者變數。這通常意味著要
把每個函數和變數都放在單獨的源文件中。
一個例外是如果兩個符號總是在一起使用,而使得沒有任何合理的程序只需要使用其中
的一個而不使用另外一個;那麼它們可以被放在同一個文件中。
標示沒有在文檔中給予說明的調用點的外部符號的名字應該以`_'開頭。它們還要包括為
庫選擇的名字前綴,以防止與其它庫可能產生的衝突。如果你願意,它們可以和用戶調
用點放在同一個文件中。
你可以按照你的意願使用靜態函數和靜態變數並且它們不需要服從任何命名慣例。
適用於GNU的移植性
在Unix世界中,「移植性」往往指的是移植到不同的Unix版本中。對於GNU軟體來說是次
要的,這是因為它們的主要目的是運行在GNU內核上而且僅僅運行與其上,使用GNU C編
譯器編譯並且僅僅由它進行編譯。不同cpu上的各種GNU系統的變種數量將象不同cpu上的
Berkeley 4.3系統的變種一樣多。
今天所有的用戶都在非GNU系統上運行GNU軟體。所以有必要支持各種非GNU系統;但不是
特別重要。在合理範圍的系統上獲得可移植性的最簡單方式是使用Autoconf。由於大部
分程序需要知道的關於主機的知識已經由Autoconf寫下來了,所以你的程序不太可能需
要知道比Autoconf所能夠提供的知識的更多知識。
因為目前GNU內核還沒有被完成,所以還難以確定GNU內核將提供那些工具。因此,就假
定你可以使用你在4.3中可以使用的任何東西;只要避免使用有更高級的替代結構(rea
ddir)存在的半內部的數據結構(例如,directories)就可以了。
你可以自由地假設任何合理C語言標準工具、庫或者內核,因為我們將發現有必要在完整
的GNU系統中支持它們,而不論我們是否已經這樣做了。一些現有的內核或者C編譯器所
缺少的功能與GNU內核和 C編譯器對它們的支持沒有關係。
另外一個需要擔心的是cpy類型間的不同,例如位元組序(byte order)的不同和對齊限制
的不同。 16位的機器恐怕不會被GNU所支持,所以沒有必要花費任何時間去考慮整數少
於32位的可能性。
你可以假定所有的指針都具有相同的格式,而不論它們指向什麼,並且它們實際上都是
一個整數。在一些怪異的機器上不是這樣,但它們並不重要;不要為迎合它們而浪費時
間。此外,我們最終將把函數原型放到所有的GNU程序中,而那將可能使你的程序即使在
怪異的機器上也能夠工作。
因為一些重要的機器(包括68000)是高位開頭(big-endian),不能假定整數對象的地
址就是最低位位元組(least-significant)的地址是十分重要的。因此,不要犯如下的錯
誤:
int c;
...
while ((c = getchar()) != EOF)
write(file_descriptor, &c, 1);
你可以假定使用一兆內存是合理的。除非可以在那個層次可以做到,不要為減少內存的
使用而費力。如果你的程序創建了複雜的數據結構,就把它們存放在內核中,並且在ma
lloc返回0的時候給出一個致命錯誤就行了。
如果一個程序按照行工作並且可以被用於任何用戶提供的輸入文件,它就應該在內存中
僅僅保存一行,因為這並不十分困難並且用戶將需要能夠操作比內核一次能夠處理的文
件更大的輸入文件。
命令行界面標準
請不要讓工具的行為依賴於調用它的名字。有時需要把一個工具連接到不同的名字,並
且這將不會改變它的功能。
最為替代,可以在運行時使用選項或者編譯器選項,或者同時使用兩者來選擇不同的程
序行為。
服從POSIX關於程序的命令行選項的指導是一個好主意。這樣做的最簡單方式是使用get
opt 來分析選項。需要指出的是,除非使用了特殊參數`--',GNU版本的getopt 通常允
許選項出現在參數中的任何位置。這不是POSIX的規定;它是GNU的擴展。
請為Unix風格的單字元選項定義等價的長名字選項。我們希望以這種方式使GNU對用戶更
加友好。通過使用GNU函數getopt_long很容易做到這一點。
通常僅僅把最為普通參數給出的文件名當作輸入文件是一個好主意;所有輸出文件都應
該通過選項給出(使用`-o'更好)。即使你為了保持兼容性而允許把普通參數當作輸出
文件名,你仍然可以試圖為輸出文件名提供一個合適的選項。這將為GNU工具帶來更多的
一致性,以減少用戶需要記憶的特徵。
程序還應該支持一個用於輸出程序的版本號的選項`--version',以及支持一個用於輸出
選項用法信息的選項`--help'。
為程序製作文檔
為GNU程序製作文檔請使用Texinfo。參見Texinfo手冊,硬拷貝或者GNU Emacs Info子系
統中的版本都行。(C-h i)。作為例子,可以看看現有的GNU Texinfo文件(例如,在
GNU Emacs發布版本中`man/'目錄下的Texinfo文件)。
手冊的標題頁應該說明本手冊適用於程序的那個版本。手冊的頂節點也應該包含這個信
息。如果手冊比程序改變得還要快,後者與程序是無關的,請在上述兩個地方說明手冊
的版本號。
手冊應該說明所有的命令行參數和所有的命令。手冊應該給出使用它們的例子。但不要
把手冊組織成一個特徵的列表。相反,在手冊中按照把用戶需要理解的概念放在特徵之
前的方式組織文檔。說明用戶可能需要達到的目的,並且解釋如何完成它們。不要把Un
ix man手冊作為書寫GNU文檔的模式;它們不是值得模仿的好例子。
手冊應該有一個名為`program Invocation'或者 `program Invoke'或者`Invoking pro
gram' 的節點,其中program是該程序的程序名,也就是在shell中輸入以運行程序的那
個名字。該節點(如果它有子節點,也包括子節點)應該說明程序的命令行參數以及如
何運行它(也就是人們將在man手冊中看到的那一類信息)。以`@example'開頭包含一個
程序可以使用的所有選項和參數的模板。
另一種方式是,在某些菜單中添加一個名字元合上述模式之一的菜單項。它表明由菜單
項指出的節點就是為此而創建的,而不管這個節點的實際名字是什麼。
將會有一個自動的功能使得用戶可以給出程序名並且只需要快速地閱讀手冊的這個部分

如果一個手冊說明了多個程序,那麼手冊應該為每個它所說明的程序定義一個這樣的節
點。
除了程序包的手冊之外,包還應該包含一個名為`NEWS'的文件,它包含了一個對用戶來
說是可見的、並且值得一提的修改。在每個新的發行版本中,在文件的前面添加新的條
目並且指出適用於它們的版本。不要刪除原來的條目;把它們保留在新條目的後面。按
照這種方式,從以前的版本升級的用戶就可以看到有那些新的功能。
如果`NEWS'文件變得太長了,可以把一些陳舊的條目放到一個名為`ONEWS' 的文件中,
並且在`NEWS'文件的結尾加一個說明以告知用戶參考`ONEWS'。
如果你願意,你可以在提供Texinfo手冊的同時提供man手冊。但請記住維護man手冊需要
在每次程序改變的時候都付出努力。你花費在man手冊上的任何時間都消耗了你本來能夠
用在貢獻更有價值的東西上的時間。
因此,即使用戶自願提供man手冊,你可能會發現這個禮物太麻煩而不值得接受。除非你
手頭有時間,並且除非有志願者願意承擔維護它的全部責任--以至於你可以把它完整地
交給他,拒絕提供man手冊可能會更好一些。如果志願者停止維護man手冊,那麼也不必
感到有責任讓你自己承擔它;在其它的出現志願者維護它之前撤銷man手冊也許更好一些

另一種方式是,如果你希望man手冊的內容與實際情況區別很小而使得man手冊仍然有用
,可以在man 手冊的開頭給出顯著的聲明以說明你沒有維護它並且Texinfo手冊是更加權
威的,同時指出如何訪問 Texinfo文檔。
製作發行包
發行Foo的版本69.96的tar文件包的名字是`foo-69.96.tar'。它應該被解包到名為 `fo
o-69.96'的子目錄中。
對程序的創建和安裝不應該修改發布版本中的任何文件。這意味著以任何方式作為程序
的正式部分的所有文件都必須被分成源文件和非源文件兩類。源文件由人手工編寫並且
不會被自動改變;非源文件則在Makefile的控制下由程序從源文件生成。
自然地,所有源文件必須出現在發布版本中。只有在非源文件不是過時的並且與機器是
無關的情況下,從而在創建發布版本時將不會需要修改它們,才能把非源文件包含在發
布版本中。我們一般把由Bison、 Lex、TeX和Makeinfo生成的非源文件包括進去;這有
助於避免在我們的發布版本中引入不必要的依賴性,以使得用戶可以安裝他們需要安裝
的包。
永遠不要把實際上可能在程序的創建和安裝中被修改的非源文件包含在發布版本中。所
以如果你發布非源文件,在你作新的發布時,總是要確認它們沒有過時。
確保從發布包中解開的目錄(以及所有的子目錄)對於所有人來說都是可寫的(八進位
模式777)。這樣做是為了使那些保留從tar包中取出的文件的所有權(ownership)和許
可權(permissions)的老版本的 tar,即使在用戶沒有授權的情況下也能夠提取出所有
的文件。
確保在發布版本中的沒有多於14個字元的文件名。同樣地,由程序創建的文件都不含有
長於14個字元的文件名。這樣做的原因是有些系統堅持POSIX標準的愚蠢解釋,並且拒絕
打開長文件名,而不是象在過去那樣把文件名截短。
不要在發布版本本身包含任何符號連接。如果tar文件包括符號連接,那麼人們甚至不能
在那些不能支持符號連接的系統上打開包。還有,不要在不同的目錄中為一個文件使用
多個名字,因為某些文件系統不能處理它並且這使得包不能在這類文件系統上被打開。

試著確保所有的文件名在MS-DOG下都是唯一的。在MS-DOG下文件名由8個字元組成,後面
還可以附加一個點和至多三個字元。MS-DOG將截斷點之前和之後的多餘字元。因此,`f
oobarhacker.c'和 `foobarhacker.o'不會被混淆;它們被截斷成`foobarha.c'和`foob

arha.o' ,它們是截然不同的。
在你的發布版本中包含一個你用來測試列印所有`*.texinfo'文件的`texinfo.tex'的副
本。
同樣地,如果你的程序使用了諸如regex、getopt、obstack或者termcap之類的小GNU軟
件包,把它們包括在發布文件中。把它們排除在外將使發布文件小一些,其代價是給那
些不知道需要哪些額外文件的用戶帶來不便。


[火星人 ] GNU 編碼標準 Part 3已經有657次圍觀

http://coctec.com/docs/program/show-post-72230.html