繁体   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