2

让我先声明我几乎是一个编程新手,在 C 或 GNU 环境中都没有受过良好的训练。另外,我真的无法提供可重现的示例,因为我没有编写此代码,我只是在尝试构建它。我已经自学足以编译一些程序,给定一个良好的预先存在的makefile,并多次使用Rtools为Windows编译R。

我一直在尝试使用 GCC 4.8.4 为 Windows(7 64 位)编译 R(Rtools 仍然存在于 4.6.3 预发行版中,并且 4.9 中的链接时间优化已经复活了一些 错误),并且可以这样做问题。在其中一个文件(准确地说是/src/extra/trio/compat.c)中包含 stdio.h 和 and 的sprintf定义vsprintf。因此,构建崩溃并出现以下错误:

In file included from compat.c:3:0:
F:/MinGW64/x86_64-w64-mingw32/include/stdio.h:553:5: note: previous
definition of 'snprintf' was here
 int snprintf (char * __restrict__ __stream, size_t __n, const char *
__restrict__ __format, ...)
     ^
compat.c:75:5: error: redefinition of 'vsnprintf'
 int vsnprintf(char *buffer, size_t bufferSize, const char *format,
va_list args)
     ^
In file included from compat.c:3:0:
F:/MinGW64/x86_64-w64-mingw32/include/stdio.h:543:7: note: previous
definition of 'vsnprintf' was here
   int vsnprintf (char * __restrict__ __stream, size_t __n, const char
* __restrict__ __format, va_list __local_argv)
       ^
../../gnuwin32/MkRules:218: recipe for target 'compat.o' failed
make[4]: *** [compat.o] Error 1
Makefile:120: recipe for target 'rlibs' failed
make[3]: *** [rlibs] Error 1
Makefile:179: recipe for target '../../bin/x64/R.dll' failed
make[2]: *** [../../bin/x64/R.dll] Error 2
Makefile:104: recipe for target 'rbuild' failed
make[1]: *** [rbuild] Error 2
Makefile:14: recipe for target 'all' failed
make: *** [all] Error 2

compat.c 中的行是 65–79 中的行:

int snprintf(char *buffer, size_t max, const char *format, ...)
{
    int res;
    va_list(ap);
    va_start(ap, format);
    res = trio_vsnprintf(buffer, max, format, ap);
    va_end(ap);
    return res;
}

int vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args)
{
    return trio_vsnprintf(buffer, bufferSize, format, args);
}

如果我删除这些行,构建完成,但是 R 输出具有三位十进制科学记数法指数而不是两位数(例如“3.11e-004”而不是“3.11e-04”),这会导致各种检查崩溃。我被告知这是标准的 Windows 方法,所以我删除本地 R 版本几乎肯定会导致这个问题。

我的问题是,有什么方法可以继续将 stdio.h 包含在 compat.c 文件中,但在 compat.c 中将snpritfvsnprintf重新定义为本地文件?

谢谢你。

失败的尝试 1

我尝试添加直接#undef声明以及

#ifdef snprintf
#undef snprintf
#endif

vsnprintf以及compat.c 中的对应 for ,但都不起作用。由于“重新定义”,我得到相同的构建错误崩溃停止。

失败的尝试 2

将 compat.c 中的代码更改为:

#ifdef snprintf
#undef snprintf
int snprintf(char *buffer, size_t max, const char *format, ...)
{
    int res;
    va_list(ap);
    va_start(ap, format);
    res = trio_vsnprintf(buffer, max, format, ap);
    va_end(ap);
    return res;
}
#endif

允许程序编译,但它有相同的符号错误,这意味着它在功能上等同于删除这些行。

根据评论请求更新

  1. 安装一些 Mingw-64 的味道并将 \bin 放在 PATH 的头部
  2. 安装 MSYS2:基本安装,然后添加 tar、make、zlib、zip、unzip 和 rsync,并将其 bin 作为路径中的第二个
  3. Untar R-3.1.2.tar.gz (两次,第一次使用 MSYS2 的 tar 1.28 返回 simlink 错误。使用 Rtolls 的已修补的 tar 1.2.1 不会返回错误)
  4. 将 Tcl 和 bitmapdll 子目录从 R64 (Rtools) 复制到适当的位置
  5. 修改 MkRules.dist 以强制执行 64 位、Windows 64 平台、HTML 帮助以及 Cairo、Inno 和 qpdf 的正确目录,并将其保存为 MkRules.local。对于这些测试,我没有使用基于 OpenBLAS 的 Rblas,除了增加-pipe速度之外,没有对 EOPTS 进行任何特定于处理器的调用
  6. make all

我已经使用 Rtools 中的二进制文件构建了很多次 R,包括使用 OpenBLAS(愚弄 R 认为它是 ATLAS)。我注意到但不明白的是,stdio.h在 GCC 4.7(以及 4.6)和 4.8 及后续版本之间发生了变化。包含错误中抛出的行号的新版本snprintf直接定义vsnprintf。4.6.3 的版本没有。我复制了以下部分:

来自 GCC 4.6.3 第 494-514 行的 stdio.h:

#if !defined (__USE_MINGW_ANSI_STDIO) || __USE_MINGW_ANSI_STDIO == 0
/* this is here to deal with software defining
 * vsnprintf as _vsnprintf, eg. libxml2.  */
#pragma push_macro("snprintf")
#pragma push_macro("vsnprintf")
# undef snprintf
# undef vsnprintf
  int __cdecl vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
    __MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;

#ifndef __NO_ISOCEXT
  int __cdecl snprintf(char * __restrict__ s, size_t n, const char * __restrict__  format, ...);
#ifndef __CRT__NO_INLINE
  __CRT_INLINE int __cdecl vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
  {
    return _vsnprintf (d, n, format, arg);
  }
#endif /* !__CRT__NO_INLINE */
#endif /* !__NO_ISOCEXT */
#pragma pop_macro ("vsnprintf")
#pragma pop_macro ("snprintf")
#endif

来自 GCC 4.9.2 的 stdio.h(与 4.8.4 中的相同)第 531-565 行:

#if !defined (__USE_MINGW_ANSI_STDIO) || __USE_MINGW_ANSI_STDIO == 0
/* this is here to deal with software defining
 * vsnprintf as _vsnprintf, eg. libxml2.  */
#pragma push_macro("snprintf")
#pragma push_macro("vsnprintf")
# undef snprintf
# undef vsnprintf
  int __cdecl __ms_vsnprintf(char * __restrict__ d,size_t n,const char * __restrict__ format,va_list arg)
    __MINGW_ATTRIB_DEPRECATED_MSVC2005 __MINGW_ATTRIB_DEPRECATED_SEC_WARN;

  __mingw_ovr
  __MINGW_ATTRIB_NONNULL(3)
  int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
  {
    return __ms_vsnprintf (__stream, __n, __format, __local_argv);
  }

  int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__  format, ...);

#ifndef __NO_ISOCEXT
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
  register int __retval;
  __builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
  __retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
  __builtin_va_end( __local_argv );
  return __retval;
}
#endif /* !__NO_ISOCEXT */

#pragma pop_macro ("vsnprintf")
#pragma pop_macro ("snprintf")
#endif
4

1 回答 1

4

As you have observed, the compile errors in compat.c introduced with MinGW GCC 4.7 are caused by the new inclusion of inline definitions for vsprintf and snprintf (among others) in stdio.h. This breaks prior code, like compat.c that declines the Standard Library's formerly external definitions and supplies its own.

You can effect a restoration of the status quo ante, per problem function, that is conditional upon the definition of a preprocessor macro, i.e. only client code for which the macro is suitably defined will compile that function under the status quo ante; other code will compile it under the status quo.

To do this you must do a little preprocessor hacking of the problem header F:/MinGW64/x86_64-w64-mingw32/include/stdio.h.

Replace the lines [541-560], i.e.:

  __mingw_ovr
  __MINGW_ATTRIB_NONNULL(3)
  int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
  {
    return __ms_vsnprintf (__stream, __n, __format, __local_argv);
  }

  int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__  format, ...);

#ifndef __NO_ISOCEXT
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
  register int __retval;
  __builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
  __retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
  __builtin_va_end( __local_argv );
  return __retval;
} 

with:

#if NO_INLINE_VSNPRINTF == 0
  __mingw_ovr
  __MINGW_ATTRIB_NONNULL(3)
  int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv)
  {
    return __ms_vsnprintf (__stream, __n, __format, __local_argv);
  }
#else
  extern int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv);
#endif`

  int __cdecl __ms_snprintf(char * __restrict__ s, size_t n, const char * __restrict__  format, ...);

#ifndef __NO_ISOCEXT
#if NO_INLINE_SNPRINTF == 0
__mingw_ovr
__MINGW_ATTRIB_NONNULL(3)
int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...)
{
  register int __retval;
  __builtin_va_list __local_argv; __builtin_va_start( __local_argv, __format );
  __retval = __ms_vsnprintf (__stream, __n, __format, __local_argv);
  __builtin_va_end( __local_argv );
  return __retval;
}
#else
extern int snprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, ...);
#endif

(Take care to retain the #endif, originally on line 561, immediately following the one that concludes this hack.)

Then, edit compat.c and at the top, right before:

#include <stdio.h>

add the lines:

#define NO_INLINE_VSNPRINTF 1
#define NO_INLINE_SNPRINTF 1

(These two macros have no conventional meaning. I've just coined them.)

With these changes saved, compat.c will compile without errors. At least it does for me.

I haven't gone to the trouble of a full Windows build of R so you may encounter further breakages. If any are of the same ilk, the pattern of solution is this: If a header file header.h that is #include-ed by foo.c provides an inline function definition of the form:

__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
    ....
}

then in header.h replace it like:

#if NO_INLINE_FUNC_NAME == 0
__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
    ....
}
#else
extern some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...]);
#endif

and in foo.c, right before #include <header.h> insert:

#define NO_INLINE_FUNC_NAME 1
于 2015-01-13T18:42:38.460 回答