歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> 更多Linux >> autoconf手冊(五)

autoconf手冊(五)

日期:2017/2/27 9:39:09   编辑:更多Linux

編寫測試   如果現有的特征測試不能完成你所需要的工作,你就必須編寫一個新的。這些宏是創建模塊。它們為其它宏提供了檢查各種特征是否存在並且報告結果的方式。     本章包括一些建議和一些關於現有的測試的為什麼要那樣編寫的原因。通過閱讀現有的測試,你還可以學到許多關於編寫 Autoconf測試的方法。如果在一個或多個Autoconf測試中出現了錯誤,這些信息可以幫助你理解它們意味著什麼,這有助於你找到最佳的解決問題的辦法。     這些宏檢查C編譯器系統的輸出。它們並不為未來的使用而緩存測試的結果(參見緩存結果),這是因為它們沒有足夠的信息以生成緩存變量名。基於同樣的原因,它們還不會輸出任何消息。對特殊的C的特征進行的測試調用這些宏並且緩存它們的結果、打印關於它們所進行的測試的消息。     當你編寫了一個可以適用於多於一個軟件包的特征測試時,最好的方式就是用一個新宏封裝它。關於如何封裝,參見 編寫宏。     檢驗聲明   宏AC_TRY_CPP用於檢測某個特定的頭文件是否存在。你可以一次檢查一個頭文件,或者如果你為了某些目的而希望多個頭文件都存在,也可以一次檢查多個頭文件。   宏: AC_TRY_CPP (includes, [action-if-true [, action-if-false]])   includes是C或C++的#include語句和聲明,對於它,將進行shell變量、反引用(backquote)、以及反斜線(backslash)替換。(實際上,它可以是任何C程序,但其它的語句可能沒有用。)如果預處理器在處理它的時候沒有報告錯誤,就運行shell命令action-if-true。否則運行shell命令action-if-false。     本宏使用CPPFLAGS,而不使用CFLAGS,這是因為`-g'、`-O'等選項對於許多C預處理器來說都是不合法的選項。   下面是如何確認在某個頭文件中是否包含一個特定的聲明,比如說typedef、結構、結構成員或者一個函數。使用 AC_EGREP_HEADER而不是對頭文件直接運行grep;在某些系統中,符號可能是在另一個你所檢查的 `#include'文件。   宏: AC_EGREP_HEADER (pattern, header-file, action-if-found [, action-if-not-found])   如果對系統頭文件header-file運行預處理器所產生的輸出與egrep常規表達式pattern相匹配,就執行shell命令action-if-found,否則執行action-if-not-found。     為了檢查由頭文件或者C預處理器預定義的C預處理器符號,使用AC_EGREP_CPP。下面是後者的一個例子:     AC_EGREP_CPP(yes,   [#ifdef _AIX   yes   #endif   ], is_aix=yes, is_aix=no)   宏: AC_EGREP_CPP (pattern, program, [action-if-found [, action-if-not-found]])   program是C或者C++的程序文本,對於它,將進行shell變量、反引號(backquote)以及反斜線(backslash)替換。如果對program運行預處理器產生的輸出與egrep常規表達式(regular eXPression)pattern 相匹配,就執行shell命令action-if-found,否則執行action-if-not-found。     如果宏還沒有調用AC_PROG_CPP或者AC_PROG_CXXCPP(根據當前語言來確定使用那個宏,參見對語言的選擇),本宏將調用它。   檢驗語法   為了檢查C、C++或者Fortran 77編譯器的語法特征,比如說它是否能夠識別某個關鍵字,就使用AC_TRY_COMPILE 來嘗試編譯一個小的使用該特征的程序。你還可以用它檢查不是所有系統都支持的結構和結構成員。   宏: AC_TRY_COMPILE (includes, function-body, [action-if-found [, action-if-not-found]])   創建一個C、C++或者Fortran 77測試程序(依賴於當前語言,參見對語言的選擇),來察看由function-body組成的函數是否可以被編譯。     對於C和C++,includes是所有function-body中的代碼需要的#include語句(如果當前選擇的語言是Fortran 77,includes將被忽略)。如果當前選擇的語言是C或者C++,本宏還將在編譯的時侯使用CFLAGS或者CXXFLAGS,以及CPPFLAGS。如果當前選擇的語言是Fortran 77,那麼就在編譯的時候使用FFLAGS。     如果文件被成功地編譯了,就運行shell命令action-if-found,否則運行action-if-not-found。     本宏並不試圖進行連接;如果你希望進行連接,使用AC_TRY_LINK (參見檢驗庫)。   檢驗庫   為了檢查一個庫、函數或者全局變量,Autoconf configure腳本試圖編譯並連接一個使用它的小程序。不像Metaconfig,它在缺省情況下對C庫使用nm或者ar以試圖確認可以使用那個函數。由於與函數相連接避免了處理nm和ar的各個變種的選項及輸出格式,而且不必處理標准庫的位置,所以與函數連接通常是更加可靠的辦法。如果需要,它還允許進行交叉配置或者檢查函數的運行是特征。另一方面,它比一次性掃描庫要慢一些。     少數系統的連接器在出現找不到的函數錯誤(unresolved functions)時不返回失敗的退出狀態。這個錯誤使得由Autoconf 生成的配置腳本不能在這樣的系統中使用。然而,有些這樣的連接器允許給出選項以便正確地返回錯誤狀態。 Autoconf目前還不能自動地處理這個問題。如果用戶遇到了這樣的問題,他們可能可以通過在環境中設置LDFLAGS 以把連接器所需要的選項(例如,`-Wl,-dn' on MIPS RISC/OS)傳遞給連接器,從而解決這個問題。     AC_TRY_LINK用於編譯測試程序,以測試函數和全局變量。AC_CHECK_LIB還用本宏把被測試的庫暫時地加入LIBS並試圖連接一個小程序,從而對庫進行檢查(參見庫文件)。   宏: AC_TRY_LINK (includes, function-body, [action-if-found [, action-if-not-found]])   根據當前語言(參見對語言的選擇),創建一個測試程序以察看一個函數體為function-body的函數是否可以被編譯和連接。     對C和C++來說,includes給出了所有function-body中的代碼需要的#include語句(如果當前選定的語言是Fortran 77,includes將被忽略)。如果當前語言是C或者C++,本宏在編譯時還將使用 CFLAGS或者CXXFLAGS,以及CPPFLAGS。如果當前選定的語言是Fortran 77,那麼在編譯時將使用FFLAGS。然而,在任何情況下,連接都將使用LDFLAGS和LIBS。     如果文件被成功地編譯和連接了,就運行shell命令action-if-found,否則就運行action-if-not-found。     宏: AC_TRY_LINK_FUNC (function, [action-if-found [, action-if-not-found]])   根據當前語言(參見對語言的選擇),創建一個測試程序以察看一個含有function 原型和對它的調用的程序是否可以被編譯和連接。     如果文件被成功地編譯和連接了,就運行shell命令action-if-found,否則就運行action-if-not-found。     宏: AC_TRY_LINK_FUNC (function, [action-if-found [, action-if-not-found]])   試圖編譯並且連接一個與function相連接的小程序。如果文件被成功地編譯和連接了,就運行shell命令 action-if-found,否則就運行action-if-not-found。   宏: AC_COMPILE_CHECK (echo-text, includes, function-body, action-if-found [, action-if-not-found])   本宏是AC_TRY_LINK的一個過時的版本。此外,如果echo-text不為空,它首先還要把 `checking for echo-text'打印到標准輸出。用AC_MSG_CHECKING 和AC_MSG_RESULT來代替本宏的打印消息的功能(參見打印消息)。     檢驗運行時的特征   有時候,你需要知道系統在運行時作了些什麼,比如說某個給定的函數是否具備某種能力或者是否含有錯誤。如果你能,你可以在你的程序初始化時自行檢查這類事件(比如說machine's endianness)。     如果你實在需要在配置時刻檢查運行時的特征,你可以編寫一個測試程序以確定結果,並且通過AC_TRY_RUN 來編譯和運行它。如果可能就避免運行測試程序,這是因為使用它們使得人們不能對你的包進行交叉編譯。     運行測試程序   如果你希望在配置的時候測試系統運行時的特征,就使用如下的宏。   宏: AC_TRY_RUN (program, [action-if-true [, action-if-false [, action-if-cross-compiling]]])   program是C程序的文本,將對該文本進行shell變量和反引用(backquote)替換。如果它被成功地編譯和連接了並且在執行的時候返回的退出狀態為0,就運行shell命令action-if-true。否則就運行shell命令action-if-false;程序的退出狀態可以通過shell變量`$?'得到。本宏在編譯時使用CFLAGS或者CXXFLAGS以及 CPPFLAGS、LDFLAGS和LIBS。     如果使用的C編譯器生成的不是在configure運行的系統上運行的可執行文件,那麼測試程序就不運行。如果給出了可選的shell命令action-if-cross-compiling,它們就代替生成的可執行文件執行。否則, configure打印一條錯誤消息並且退出。   當交叉編譯使運行時測試變得不可能的時候,就嘗試提供一個應急(pessimistic)的缺省值以供使用。你通過把可選的最後一個參數傳遞給AC_TRY_RUN來完成這個工作。在每次生成configure的過程中,每次遇到沒有提供 action-if-cross-compiling參數的AC_TRY_RUN調用時,autoconf都打印一條警告消息。雖然用戶將不能為交叉編譯你的包而進行配置,你仍可以忽略該警告。與Autoconf一同發行的少數宏產生該警告消息。     為了為交叉編譯進行配置,你還可以根據規范系統名(canonical system name)為這些參數選擇值(參見手工配置)。另一種方式是把測試緩存文件設置成目標系統的正確值(參見緩存結果)。     為了給嵌入到其它宏(包括少數與Autoconf一同發行的宏)中的,對AC_TRY_RUN的調用提供缺省值,你可以在它們運行之前調用AC_PROG_CC。那麼,如果shell變量cross_compiling被設置成 `yes',就使用另一種方法來獲取結果,而不是調用宏。   宏: AC_C_CROSS   本宏已經過時;它不作任何事情。     測試程序指南   測試程序不應該向標准輸出輸出任何信息。如果測試成功,它們應該返回0,否則返回非0,以便於把成功的執行從core dump或者其它失敗中區分出來;段沖突(segmentation violations)和其它失敗產生一個非0的退出狀態。測試程序應該從main中exit,而不是return,這是因為在某些系統中(至少在老式的Sun上),main的return的參數將被忽略。     測試程序可以使用#if或者#ifdef來檢查由已經執行了的測試定義的預處理器宏的值。例如,如果你調用AC_HEADER_STDC,那麼在`configure.in'的隨後部分,你可以使用一個有條件地引入標准C頭文件的測試程序:     #if STDC_HEADERS   # include   #endif     如果測試程序需要使用或者創建數據文件,其文件名應該以`conftest'開頭,例如`conftestdata'。在運行測試程序之後或者腳本被中斷時,configure將通過運行`rm -rf conftest*'來清除數據文件。     測試函數   在測試程序中的函數聲明應該條件地含有為C++提供的原型。雖然實際上測試程序很少需要帶參數的函數。     #ifdef __cplusplus   foo(int i)   #else   foo(i) int i;   #endif     測試程序聲明的函數也應該有條件地含有為C++提供的,需要`extern "C"'的原型。要確保不要引入任何包含沖突原型的頭文件。     #ifdef __cplusplus   extern "C" void *malloc(size_t);   #else   char *malloc();   #endif     如果測試程序以非法的參數調用函數(僅僅看它是否存在),就組織程序以確保它從不調用這個函數。你可以在另一個從不調用的函數中調用它。你不能把它放在對exit的調用之後,這是因為GCC第2版知道 exit永遠不會返回,並且把同一塊中該調用之後的所有代碼都優化掉。     如果你引入了任何頭文件,確保使用正確數量的參數調用與它們相關的函數,即使它們不帶參數也是如此,以避免原型造成的編譯錯誤。GCC第2版為有些它自動嵌入(inline)的函數設置了內置原型;例如, memcpy。為了在檢查它們時避免錯誤,既可以給它們正確數量的參數,也可以以不同的返回類型(例如char)重新聲明它們。     可移植的Shell編程   在編寫你自己的測試時,為了使你的代碼可以移植,你應該避免使用某些shell腳本編程技術。 Bourne shell和諸如Bash和Korn shell之類的向上兼容的shell已經發展了多年,但為了避免麻煩,不要利用在UNIX版本7,circa 1977之後添加的新特征。你不應該使用shell函數、別名、負字符集(negated character classes)或者其它不是在所有與Bourne兼容的shell中都能找到的特征;把你自己限制到最低的風險中去。(the lowest common denominator)。即使是unset都不能夠被所有的shell所支持!還有,像下面那樣在指定解釋器的驚歎號之後給出空格:     #! /usr/bin/perl     如果你忽略了路徑之前的空格,那麼基於4.2BSD的系統(比如說Sequent DYNIX)將忽略這一行,這是因為它們把 `#! /'看作一個四字節的魔數(magic number)。     你在configure腳本中運行的外部程序,應該是一個相當小的集合。關於可用的外部程序列表,參見 GNU編碼標准中的‘Makefile中的工具’一節。這個限制允許用戶在只擁有相當少的程序時進行配置和編譯,這避免了軟件包之間過多的依賴性。     此外,這些外部工具中的某些工具只有一部分特征是可移植的。例如,不要依賴ln支持`-f'選項,也不要依賴cat含有任何選項。sed腳本不應該含有注釋,也不應該使用長於8個字符的分支標記。不要使用`grep -s'來禁止(suppress)輸出。而要把grep的標准輸出和標准錯誤輸出(在文件不存在的情況下會輸出信息到標准錯誤輸出)重新定向到`/dev/null'中。檢查grep的退出狀態以確定它是否找到了一個匹配。     測試值和文件   configure腳本需要測試許多文件和字符串的屬性。下面是在進行這些測試的時候需要提防的一些移植性問題。     程序test是進行許多文件和字符串測試的方式。人們使用替代(alternate)名`['來調用它,但因為`['是一個m4的引用字符,在Autoconf代碼中使用`['將帶來麻煩。     如果你需要通過test創建多個檢查,就用shell操作符`&&'和`' 把它們組合起來,而不是使用test操作符`-a'和`-o'。在System V中, `-a'和`-o'相對於unary操作符的優先級是錯誤的;為此,POSIX並未給出它們,所以使用它們是不可移植的。如果你在同一個語句中組合使用了`&&'和`',要記住它們的優先級是相同的。     為了使得configure腳本可以支持交叉編譯,它們不能作任何測試主系統而不是測試目標系統的事。但你偶爾可以發現有必要檢查某些特定(arbitrary)文件的存在。為此,使用`test -f'或者`test -r'。不要使用`test -x',因為4.3BSD不支持它。     另一個不可移植的shell編程結構是     var=${var:-value}     它的目的是僅僅在沒有設定var的值的情況下,把var設置成value,但如果var已經含有值,即使是空字符串,也不修改var。老式BSD shell,包括 Ultrix sh,不接受這個冒號,並且給出錯誤並停止。一個可以移植的等價方式是     : ${var=value}     多種情況   有些操作是以幾種可能的方式完成的,它依賴於UNIX的變種。檢查它們通常需要一個"case 語句"。Autoconf不能直接提供該語句;然而,通過用一個shell變量來記錄是否采用了操作的某種已知的方式,可以容易地模擬該語句。     下面是用shell變量fstype記錄是否還有需要檢查的情況的例子。     AC_MSG_CHECKING(how to get filesystem type)   fstype=no   # The order of these tests is important.   AC_TRY_CPP([#include   #include ], AC_DEFINE(FSTYPE_STATVFS) fstype=SVR4)   if test $fstype = no; then   AC_TRY_CPP([#include   #include ], AC_DEFINE(FSTYPE_USG_STATFS) fstype=SVR3)   fi   if test $fstype = no; then   AC_TRY_CPP([#include   #include ], AC_DEFINE(FSTYPE_AIX_STATFS) fstype=AIX)   fi   # (more cases omitted here)   AC_MSG_RESULT($fstype)       對語言的選擇   既使用C又使用C++的包需要同時測試兩個編譯器。Autoconf生成的configure腳本在缺省情況下檢查C的特征。以下的宏決定在`configure.in'的隨後部分使用那個語言的編譯器。   宏: AC_LANG_C   使用CC和CPP進行編譯測試並且把`.c'作為測試程序的擴展名。如果已經運行過AC_PROG_CC,就把把shell變量cross_compiling的值設置成該宏計算的結果,否則就設置為空。   宏: AC_LANG_CPLUSPLUS   使用CXX和CXXPP進行編譯測試並且把`.C'作為測試程序的擴展名。如果已經運行過AC_PROG_CXX,就把把shell變量cross_compiling的值設置成該宏計算的結果,否則就設置為空。   宏: AC_LANG_FORTRAN77   使用F77進行編譯測試並且把`.f'作為測試程序的擴展名。如果已經運行過AC_PROG_F77,就把把shell變量cross_compiling的值設置成該宏計算的結果,否則就設置為空。   宏: AC_LANG_SAVE   在堆棧中記錄當前的語言(由AC_LANG_C、AC_LANG_CPLUSPLUS或者AC_LANG_FORTRAN77 所設定)。不改變當前使用的語言。在需要暫時地切換到其它特殊語言的宏之中使用本宏和AC_LANG_RESTORE。   宏: AC_LANG_RESTORE   選擇儲存在棧頂的,由AC_LANG_SAVE設置的語言,並且把它從棧頂刪除。本宏等價於運行在最後被調用的 AC_LANG_SAVE之前最近的AC_LANG_C、AC_LANG_CPLUSPLUS或者 AC_LANG_FORTRAN77。     調用本宏的次數不要多於調用AC_LANG_SAVE的次數。     宏: AC_REQUIRE_CPP   確認已經找到了當前用於測試的預處理器。本宏根據當前選擇的語言,以AC_PROG_CPP或者AC_PROG_CXXCPP 為參數調用AC_REQUIRE(參見首要的宏)。     測試的結果   一旦configure確定了某個特征是否存在,它將如何記錄這一信息?這裡有四種記錄方式:定義一個C預處理器符號、在輸出文件中設置一個變量、為將來運行configure而把結果儲存到一個緩存文件中,以及打印一條消息以便讓用戶知道測試的結果。     定義C預處理器符號   對一個特征的檢測的常見回應是定義一個表示測試結果的C預處理器符號。這是通過調用AC_DEFINE 或者AC_DEFINE_UNQUOTED來完成的。     在缺省狀態下,AC_OUTPUT把由這些宏定義的符號放置到輸出變量DEFS中,該變量為每個定義了的符號添加一個選項`-Dsymbol=value'。與Autoconf第1版不同,在運行時不定義DEFS變量。為了檢查Autoconf宏是否已經定義了某個C預處理器符號,就檢查適當的緩存變量的值,例子如下:     AC_CHECK_FUNC(vprintf, AC_DEFINE(HAVE_VPRINTF))   if test "$ac_cv_func_vprintf" != yes; then   AC_CHECK_FUNC(_doprnt, AC_DEFINE(HAVE_DOPRNT))   fi     如果已經調用了AC_CONFIG_HEADER,那麼就不是創建DEFS,而是由AC_OUTPUT 創建一個頭文件,這是通過在一個暫時文件中把正確的值替換到#define語句中來實現的。關於這種輸出的詳情,請參見配置頭文件。   宏: AC_DEFINE (variable [, value [, description]])   定義C預處理器變量variable。如果給出了value,就把variable設置成那個值(不加任何改變),否則的話就設置為1。value不應該含有新行,同時如果你沒有使用AC_CONFIG_HEADER,它就不應該含有任何`#'字符,這是因為make將刪除它們。為了使用shell變量(你需要使用該變量定義一個包含了 m4引用字符`['或者`]'的值),就使用AC_DEFINE_UNQUOTED。只有在你使用AC_CONFIG_HEADER的時候,description才有用。在這種情況下,description被作為注釋放置到生成的`config.h.in'的宏定義之前;不必在`acconfig.h'中提及該宏。下面的例子把 C預處理器變量EQUATION的值定義成常量字符串`"$a > $b"':   






Copyright © Linux教程網 All Rights Reserved