2014-02-27 34 views
3

我試圖編寫一個程序,可以在Linux/glibc和FreeBSD上使用定製的stdio流,爲此,我試圖編寫一個autoconf腳本,它可以正確檢測這些腳本並打開必要的編譯器標誌支持他們。如何使autoconf有條件地使用系統擴展?

在glibc上,我需要定義_GNU_SOURCE才能訪問fopencookiecookie_io_functions_t。 Autoconf整齊地支持打開這個AC_USE_SYSTEM_EXTENSIONS,但我似乎無法弄清楚如何在必要時做到這一點。目前,我試圖做這樣的:

HAS_FOPENCOOKIE=yes 
AC_CHECK_FUNC(fopencookie, [AC_USE_SYSTEM_EXTENSIONS], [HAS_FOPENCOOKIE=no]) 
AC_CHECK_MEMBER([cookie_io_functions_t.read], [], [HAS_FOPENCOOKIE=no]) 

工作本身,而是大聲autoconf的抱怨時,我嘗試生成配置腳本,好幾次,那AC_COMPILE_IFELSE was called before AC_USE_SYSTEM_EXTENSIONS。顯然,它認爲在打開系統擴展之前實際進行任何測試是非常糟糕的做法。

該怎麼辦?只是忽略警告?手動進行必要的AC_DEFINE? (後者似乎很難看,因爲我需要定義一個AH_TEMPLATE以及所有這些。)只需打開我可能或可能不會使用的所有擴展,無條件地在文件的頂部?完全不同的東西?

回答

3

我在Autoconf郵件列表上與好人交談過。他們的意見似乎是,因爲我不是想與POSIX或ANSI C這樣的東西嚴格兼容,反正我應該使用AC_USE_SYSTEM_EXTENSIONS;並且這樣做應該沒有什麼壞處,因爲我實際上使用了系統擴展,無論該擴展實際上是否是默認編譯環境的一部分。

我承認我不確定我完全理解默認編譯環境和「擴展」環境之間的區別,但是因爲這是他們對自己的工具的看法,所以我會購買它並讓它成爲權威的答案。

1

無條件開啓系統擴展,或者編寫自己的AC_DEFINE(帶模板等)。我會做前者。

3

(事先已久的答案道歉,但我不希望冒險留下太多的細節了。)

你應該使用AH_VERBATIM創建模板有條件定義_GNU_SOURCEAC_DEFINE定義它的值,而如果您只想爲Glibc完成此操作,則會禁用其他系統的擴展功能。否則,你最好使用默認的系統擴展。請參閱以下代碼的前幾行,以獲得我想要的AH_VERBATIM的示例。

您可以省去AC_CHECK_ *調用的if/else部分,並使用shell代碼來測試$ac_cv_func_fopencookie$ac_cv_member_cookie_io_functions_t_read是否都是。如果它們都是,請將_GNU_SOURCE定義爲1.請注意,這可能會影響編譯器的其他測試,因此除非您有充分理由不這樣做,否則您應該在執行此檢查並定義_GNU_SOURCE之前運行其他任何其他測試編譯測試(例如AC_CHECK_FUNC)。

請注意,在這種情況下,如果您絕對拒絕使用系統擴展,那麼編寫自己的測試可能會更好。除非我使用AC_USE_SYSTEM_EXTENSIONS或先前定義的_GNU_SOURCE,否則cookie_io_functions_t是未定義的類型。檢查這種類型還需要_GNU_SOURCE,自然一旦定義,你顯然無法取消定義它。

這是我如何做的一個例子。它說明爲什麼你應該使用AC_USE_SYSTEM_EXTENSIONS,因爲它只能處理_GNU_SOURCE

AC_DEFUN([ck_FUNC_FOPENCOOKIE], 
[AH_VERBATIM(
    [_GNU_SOURCE], 
    [/* Enable GNU extensions for fopencookie functionality to work 
    where required. */ 
#ifndef _GNU_SOURCE 
#undef _GNU_SOURCE 
#endif]) 

AC_CACHE_CHECK(
    [whether fopencookie works without _GNU_SOURCE being defined], 
    [ck_cv_libc_fopencookie], 
    [AC_LINK_IFELSE(
     [AC_LANG_SOURCE(
      [#undef _GNU_SOURCE 
#include <stdio.h> 

cookie_read_function_t *ck_read = (cookie_read_function_t *)foo_read; 
cookie_write_function_t *ck_write = (cookie_write_function_t *)ck_read; 
cookie_seek_function_t *ck_seek = (cookie_seek_function_t *)ck_read; 
cookie_close_function_t *ck_close = (cookie_close_function_t *)fclose; 

size_t foo_read(void *cookie, char *buf, size_t size) 
{ 
    cookie = buf; 
    buf = cookie; 
    return (ssize_t)size; 
} 

int main(void) 
{ 
    cookie_io_functions_t x; 
    x.read = ck_read; 
    x.write = ck_write; 
    x.seek = ck_seek; 
    x.close = ck_close; 
    fopencookie(NULL, NULL, x); 
    return 0; 
} 
])], [ck_cv_libc_fopencookie=yes], [ck_cv_libc_fopencookie=no])]) 
if test "x${ck_cv_libc_fopencookie}" = xno ; then 
    AC_CACHE_CHECK(
     [whether fopencookie works at all], 
     [ck_cv_libc_fopencookie_gnu], 
     [AC_LINK_IFELSE(
      [AC_LANG_SOURCE(
       [#ifndef _GNU_SOURCE 
#define _GNU_SOURCE 1 
#endif 
#include <stdio.h> 

cookie_read_function_t *ck_read = (cookie_read_function_t *)foo_read; 
cookie_write_function_t *ck_write = (cookie_write_function_t *)ck_read; 
cookie_seek_function_t *ck_seek = (cookie_seek_function_t *)ck_read; 
cookie_close_function_t *ck_close = (cookie_close_function_t *)fclose; 

size_t foo_read(void *cookie, char *buf, size_t size) 
{ 
    cookie = buf; 
    buf = cookie; 
    return (ssize_t)size; 
} 

int main(void) 
{ 
    cookie_io_functions_t x; 
    x.read = ck_read; 
    x.write = ck_write; 
    x.seek = ck_seek; 
    x.close = ck_close; 
    fopencookie(NULL, NULL, x); 
    return 0; 
} 
])], [ck_cv_libc_fopencookie_gnu=yes], [ck_cv_libc_fopencookie_gnu=no])]) 

    if test "x${ck_cv_libc_fopencookie_gnu}" = xyes ; then 
     AC_DEFINE([_GNU_SOURCE], [1]) 
     ck_cv_libc_fopencookie=yes 
    fi # test with _GNU_SOURCE succeeded 
fi # test without _GNU_SOURCE failed 

if test "x${ck_cv_libc_fopencookie}" = xyes ; then 
    AC_DEFINE(
     [HAVE_FOPENCOOKIE], [1], 
     [Define to 1 if fopencookie and related functionality is fully working.]) 
fi]) 

我把它包在一個名爲ck_FUNC_FOPENCOOKIE宏,所以你可以把它放在你打電話之前得到通過m4_include包括一個獨立的m4文件中宏。這將防止你的配置腳本變得非常混亂,並且很容易添加和測試(以及刪除)。

上面的代碼的行爲摘要:

  • 沒有編譯/聯fopencookie的功能或類型不是預期:
    • ck_cv_libc_fopencookie =沒有
    • ck_cv_libc_fopencookie_gnu =無
    • _GNU_SOURCE(AC_DEFINE)= undefined
    • HAVE_FOPENCOOKIE = undefined
  • fopencookie的作品,_GNU_SOURCE不需要:
    • ck_cv_libc_fopencookie =是
    • ck_cv_libc_fopencookie_gnu =未設置
    • _GNU_SOURCE(AC_DEFINE)=未定義
    • HAVE_FOPENCOOKIE = 1
  • fopencookie作品,_GNU_SOURCE要求:
    • ck_cv_libc_fopencookie =是
    • ck_cv_libc_fopencookie_gnu =是
    • _GNU_SOURCE(AC_DEFINE)= 1個
    • HAVE_FOPENCOOKIE = 1

正如你所看到的,是不是更給它_GNU_SOURCE定義或缺乏。但是,不需要_GNU_SOURCE的情況用於跨平臺兼容性。

基本上_GNU_SOURCE僅在需要時啓用(Glibc),並且如果fopencookie材料可用,您仍然可以獲得定義HAVE_FOPENCOOKIE。我使用了一個非常通用的測試,但您可以輕鬆編輯代碼以使其更適合。

但是,AC_CHECK_FUNC宏和上面的代碼之間的主要區別在於,我使用鏈接測試來確保C庫包含fopencookie函數的符號。如果沒有,那麼即使在位於不同庫中的另一個系統上有這樣的功能,它也將被視爲不可用。由於我對項目的目標一無所知,因此我只能評論以下事實:您需要保存LIBS變量,根據目標將其設置爲包含特定庫,然後調用AC_LINK_IFELSE宏並恢復兩個測試完成後的值爲LIBS。在調用上述宏之前,甚至可以在主代碼中完成此操作。

我想最簡單的方法是「檢查你的蛋糕和吃它」是否會使用調用AC_PREPROC_IFELSE來確定是否檢測到glibc,並檢查Glibc獨有的宏是否會被檢查以確定它是否被定義。如果是,則進行檢查以確保當前版本包含您需要的功能和成員。如果檢查成功,你會自動定義_GNU_SOURCE,一切都會很好。但是,您犧牲了跨平臺兼容性,這是GNU Autotools的一個重點,並且可以在不依賴Glibc的情況下進行相同的檢查。對於我沒有研究過的所有知識,uClibc可能具有相同的內容,儘管不是Glibc,也沒有任何Glibc特定的預處理器符號。

+0

我想給這個答案不止一個upvote,因爲它包含了很多關於Autoconf的有用信息,但是我覺得我從Autoconf郵件列表中得到的答案(我發佈在一個單獨的答案中,看哪個)應該被認爲是權威的答案。 – Dolda2000

+0

這就是說,但是,我不認爲有''fopencookie'可用時沒有定義'_GNU_SOURCE'的情況。 – Dolda2000