我正在尝试交叉编译一些代码(argtable-2.13,我无法更改)。
export cc_path="/usr"
export CFLAGS="-I${cc_path}/i686-w64-mingw32/include"
./configure --host=i686-w64-mingw32 --prefix=${cc_path}/i686-w64-mingw32
make CC=${cc_path}/bin/i686-w64-mingw32-gcc AR=${cc_path}/bin/i686-w64-mingw32-ar PREFIX=${cc_path}/i686-w64-mingw32 RANLIB=${cc_path}/bin/i686-w64-mingw32-ranlib LD={cc_path}/bin/i686-w64-mingw32-ld STRIP=${cc_path}/bin/i686-w64-mingw32-strip CXX=${cc_path}/bin/i686-w64-mingw32-g++
当我尝试在 Ubuntu 20.04(版本 i686-w64-mingw32-gcc (GCC) 9.3-win32 20200320)上使用 mingw-w64 编译此代码时,它编译得很好。但是当我在 Ubuntu 23.10(版本 i686-w64-mingw32-gcc (GCC) 12-win32)上尝试使用 mingw-w64 进行相同操作时,它会抛出错误。
/bin/i686-w64-mingw32-gcc -DHAVE_CONFIG_H -I. -I/i686-w64-mingw32/include -MT arg_int.lo -MD -MP -MF .deps/arg_int.Tpo -c arg_int.c -DDLL_EXPORT -DPIC -o .libs/arg_int.o
In file included from /usr/lib/gcc/i686-w64-mingw32/12-win32/include/mm_malloc.h:29,
from /usr/share/mingw-w64/include/malloc.h:84,
from /usr/share/mingw-w64/include/stdlib.h:770,
from arg_int.c:28:
arg_int.c:35:37: error: expected identifier before numeric constant
35 | enum {EMINCOUNT=1,EMAXCOUNT,EBADINT,EOVERFLOW};
| ^~~~~~~~~
arg_int.c: In function ‘strtol0X’:
arg_int.c:60:12: warning: implicit declaration of function ‘isspace’ [-Wimplicit-function-declaration]
60 | while (isspace(*ptr))
| ^~~~~~~
arg_int.c:33:1: note: include ‘<ctype.h>’ or provide a declaration of ‘isspace’
32 | #include <limits.h>
+++ |+#include <ctype.h>
33 |
arg_int.c:89:8: warning: implicit declaration of function ‘toupper’ [-Wimplicit-function-declaration]
89 | if (toupper(*ptr++)!=toupper(X))
| ^~~~~~~
arg_int.c:89:8: note: include ‘<ctype.h>’ or provide a declaration of ‘toupper’
make[2]: *** [Makefile:359: arg_int.lo] Error 1
我知道为什么它会抛出错误,因为枚举不能具有相同的名称,并且与 mingw-w64 v12 的某个地方发生冲突,但我无法更改代码。它包括定义了枚举
/usr/i686-w64-mingw32/include/errno.h
的文件 EOVERFLOW
,但 v 9.3 似乎并没有抱怨 v12 有问题。
我尝试添加
-std=c89
作为选项,但没有什么区别。
如何让 mingw-w64 版本 12 在这方面表现得像 mingw-w64 版本 9.3?
这对我来说是新闻,但似乎
errno.h
可以在整个标准命名空间中喷出以E
开头的自定义标识符,作为实现定义的功能。
C23 7.5:
以 E 和数字或 E 和大写字母开头的其他宏定义也可以由实现指定。
“未来的图书馆方向”中也提到了这一点。因此,该库的某些版本可能会将
EOVERFLOW
之类的内容定义为实现定义的功能。
通常添加像
-std=c11 -pedantic-errors
这样的编译器选项会从标准头中去除非标准标识符,但在这里它没有什么区别,因为标准 C 允许这些标识符存在。
但值得注意的是,这也意味着
errno.h
的这种实现不能在严格符合要求的程序中使用。
最好的解决方法是根本不使用
errno.h
- 它始终是一个过时且设计不良的标头,就像在多线程发明之前很久使用全局错误结果变量始终是糟糕的设计一样。但遗憾的是,许多标准函数都依赖于 errno
,所以也许这不是一个选择。
如果您无法重命名枚举,一个可能的解决方法就是执行
#undef EOVERFLOW
。
至于为什么不同的编译器版本会得到不同的结果,可能是Mingw一路切换了标准库。他们曾经使用微软的“CRT”标准库,但我认为(?)他们在某个地方换掉了那个。