让我先说明这个问题,我说我几乎是一个编程新手,并且在C或GNU环境中都没有受过良好的训练。另外,我真的无法提供一个可重现的例子,因为我还没有编写这段代码,我只是想构建它。我已经足够自学了一些程序,给出了一个很好的预先存在的makefile,并且已经多次使用Rtools编译了R for Windows。
我一直在尝试使用GCC 4.8.4编译R for Windows(7 64位)(Rtools仍然存在于4.6.3预发布中,4.9中的链接时优化已经复活some {{3 }} old),并且可以解决一个问题。在其中一个文件中(确切地说bugs)既包含stdio.h,也包含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")导致各种检查崩溃。 /src/extra/trio/compat.c这是标准的Windows方法,因此删除本地R版本几乎肯定会导致此问题。
我的问题是,有什么方法可以继续将compd.c包含在compat.c文件中,但是将snpritf
和vsnprintf
重新定义为compat.c中的本地文件。 ?
谢谢。
我尝试添加直接#undef
声明以及
#ifdef snprintf
#undef snprintf
#endif
和compat.c中的vsnprintf
对应,但都没有用。由于"重新定义"我得到了相同的构建错误而导致停止。
将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
允许程序编译,但它有相同的符号错误,这意味着它在功能上等同于删除那些行。
-pipe
之外没有任何特定于处理器的EOPTS调用make all
我使用Rtools中的二进制文件构建了R一次,包括使用OpenBLAS(将R哄骗到思考它的ATLAS中)。我所注意到的,但不明白的是,stdio.h
在GCC 4.7(以及4.6)和4.8及之后的版本之间发生了变化。包含错误中抛出的行号的新版本直接定义snprintf
和vsnprintf
。 4.6.3的版本没有。我复制了以下部分:
stdio.h来自GCC 4.6.3第494-514行:
#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
答案 0 :(得分:3)
正如您所观察到的,导致MinGW GCC 4.7引入的compat.c
中的编译错误
通过在vsprintf
中新添加snprintf
和stdio.h
(以及其他)的内联定义。
这会破坏之前的代码,例如拒绝标准库的compat.c
以前的外部定义并提供自己的定义。
根据预处理器的定义,您可以根据问题函数恢复现状的恢复 宏,即仅适当定义宏的客户端代码将在状态下编译该函数 quo ante ;其他代码将在现状下编译它。
要做到这一点,你必须对问题标题F:/MinGW64/x86_64-w64-mingw32/include/stdio.h
进行一些预处理黑客攻击。
替换[541-560]行,即:
__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;
}
使用:
#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
(注意保留最初在第561行的#endif
,紧跟结束此黑客的那个。{/ p>
然后,在之前编辑compat.c
并在顶部右侧:
#include <stdio.h>
添加以下行:
#define NO_INLINE_VSNPRINTF 1
#define NO_INLINE_SNPRINTF 1
(这两个宏没有传统意义。我只是创造了它们。)
保存这些更改后,compat.c
将无错误地编译。至少它对我有用。
我没有遇到过R的完整Windows版本的麻烦,所以你可能会遇到更多问题
破损。如果有任何相同的解决方案,解决方案的模式是:如果是标题
由header.h
编辑的#include
文件foo.c
提供内联函数定义
形式:
__some_decorator
[__maybe_some_more_decorators...]
some_return_type func_name(some arg_type arg0[,some_other_arg_type arg1...])
{
....
}
然后在header.h
中将其替换为:
#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
并在foo.c
中,恰好在#include <header.h>
插入之前:
#define NO_INLINE_FUNC_NAME 1