簡體   English   中英

如何使autoconf有條件地使用系統擴展?

[英]How to make autoconf conditionally use system extensions?

我正在嘗試編寫一個可以在Linux / glibc和FreeBSD上使用自定義stdio流的程序,為此,我正在嘗試編寫一個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以及所有這些。)只需打開我可能使用或不使用的所有擴展,無條件地在文件的頂部? 完全不同的東西?

(對於長期答案,請提前道歉,但我不想冒險留下太多細節。)

您應該使用AH_VERBATIM有條件地定義_GNU_SOURCE以創建模板,並使用AC_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_SOURCEcookie_io_functions_t是未定義的類型。 檢查該類型還需要_GNU_SOURCE ,並且自然一旦定義,您顯然無法_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文件中,該文件在調用宏之前通過m4_include包含在內。 這將阻止您的配置腳本變得非常混亂,並且很容易添加和測試(以及刪除)。

以上代碼的行為摘要:

  • 沒有可編譯/可鏈接的fopencookie函數或類型不是預期的:
    • ck_cv_libc_fopencookie =沒有
    • ck_cv_libc_fopencookie_gnu =沒有
    • _GNU_SOURCE(AC_DEFINE)=未定義
    • HAVE_FOPENCOOKIE =未定義
  • 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特定的預處理器符號。

我和Autoconf郵件列表上的好人談到了這一點。 他們的意見似乎是因為我並沒有試圖與POSIX或ANSI C這樣的東西嚴格兼容, AC_USE_SYSTEM_EXTENSIONS無論如何我應該使用AC_USE_SYSTEM_EXTENSIONS ; 因為我實際上正在使用系統擴展,所以這樣做應該沒有害處,無論該擴展是否實際上是默認編譯環境的一部分。

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM