在使用GNU GCC 4.8.2在Cygwin(1.7.28-2,64位)下构建一些基于C++的代码的过程中,我遇到了以下错误:
...
SortDetails.cpp: In function ‘FILE* create_tmpfile(const char*, char**)’:
SortDetails.cpp:127:20: error: ‘mkstemp’ was not declared in this scope
fd = mkstemp(tmpl);
^
SortDetails.cpp:133:24: error: ‘fdopen’ was not declared in this scope
fp = fdopen(fd, "wb+");
...
Run Code Online (Sandbox Code Playgroud)
无法编译的特定代码块是:
FILE *
create_tmpfile(char const* path, char** fileName)
{
FILE* fp;
int fd;
char* tmpl;
if ( path == NULL )
{
fileName = NULL;
return tmpfile();
}
tmpl = (char*)malloc(1 + strlen(path) + L_tmpnam);
strcpy(tmpl, path);
strcpy(tmpl+strlen(path), "/sb.XXXXXX");
fd = mkstemp(tmpl); /* <----- here... */
if(fd == -1)
{
fprintf(stderr, "unable to create temp file!\n");
return NULL;
}
fp = fdopen(fd, "wb+"); /* <----- ...and here */
*fileName = (char*)malloc(strlen(tmpl) + 1);
strcpy(*fileName, tmpl);
free(tmpl);
return fp;
}
Run Code Online (Sandbox Code Playgroud)
(结果malloc是由于此代码位于更大的基于C++的项目中.)
回归
此代码在Linux主机上与GNU GCC 4.8.x成功编译并成功运行,在OS X下与Clang/++ 5.0一起成功运行.
环境
我使用的是以下版本的Cygwin:
$ uname -a
CYGWIN_NT-6.1 CygFoo-PC 1.7.28(0.271/5/3) 2014-02-09 21:06 x86_64 Cygwin
Run Code Online (Sandbox Code Playgroud)
这是我正在使用的GCC版本:
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-pc-cygwin/4.8.2/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /cygdrive/i/szsz/tmpp/cygwin64/gcc/gcc-4.8.2-2/src/gcc-4.8.2/configure --srcdir=/cygdrive/i/szsz/tmpp/cygwin64/gcc/gcc-4.8.2-2/src/gcc-4.8.2 --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/libexec --datadir=/usr/share --localstatedir=/var --sysconfdir=/etc --libdir=/usr/lib --datarootdir=/usr/share --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --disable-__cxa_atexit --with-dwarf2 --with-tune=generic --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --disable-libitm --enable-libquadmath --enable-math-support --enable-libssp --enable-libada --enable-libgcj-sublibs --disable-java-awt --disable-symvers --with-ecj-jar=/usr/share/java/ecj.jar --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib
Thread model: posix
gcc version 4.8.2 (GCC)
Run Code Online (Sandbox Code Playgroud)
问题
是否有支持mkstemp(),并fdopen()在GCC 4.8.2 Cygwin的?
如果没有,是否有我可以添加的包或我可以相对容易编译的库以添加对这些功能的支持?
如果不是,是否有替代品mkstemp(),并fdopen()说我可以利用在Cygwin下复制它们的功能?
可能的修复
这是此功能的修改版本:
FILE *
create_tmpfile(char const* path, char** fileName)
{
FILE* fp;
char* tmpl;
if ( path == NULL )
{
fileName = NULL;
return tmpfile();
}
#if defined(__CYGWIN__) && !defined(_WIN32)
const char *cygwinPrefix = "/sb.";
const char *cygwinTmpDir = "/tmp";
char *cygwinTmplSuffix = (char *)malloc(1 + L_tmpnam);
tmpnam(cygwinTmplSuffix);
tmpl = (char *)malloc(1 + strlen(path) + strlen(cygwinPrefix) + strlen(cygwinTmplSuffix + strlen(cygwinTmpDir) + 1));
strcpy(tmpl, path);
strcpy(tmpl+strlen(path), cygwinPrefix);
strcpy(tmpl+strlen(path)+strlen(cygwinPrefix), cygwinTmplSuffix + strlen(cygwinTmpDir) + 1);
fp = fopen(tmpl, "wbx+"); /* we add the 'x' extension to apply the O_EXCL flag, to avoid a security hole described in the GNU C library docs */
free(cygwinTmplSuffix);
#else
tmpl = (char*)malloc(1 + strlen(path) + L_tmpnam);
strcpy(tmpl, path);
strcpy(tmpl+strlen(path), "/sb.XXXXXX");
int fd = mkstemp(tmpl);
if(fd == -1)
{
fprintf(stderr, "unable to create temp file!\n");
return NULL;
}
fp = fdopen(fd, "wb+");
#endif
*fileName = (char*)malloc(strlen(tmpl) + 1);
strcpy(*fileName, tmpl);
free(tmpl);
return fp;
}
Run Code Online (Sandbox Code Playgroud)
这非常难看.如果有办法使用POSIX函数,我想使用它们,如果可以的话.谢谢你的建议.
g++在Cygwin上使用4.8.2进行编译时,我在三种情况下记录了宏的扩展:
$ g++ -std=c++11 -E -Dd foo.cpp > foo.log.c++11
$ g++ -ansi -E -Dd foo.cpp > foo.log.ansi
$ g++ -E -Dd foo.cpp > foo.log.noFlag
Run Code Online (Sandbox Code Playgroud)
比较日志很有用.在-std=c++11和-ansi案件中有"漏洞" ,而包含mkstemp()声明的块出现在"无标志"的情况下.这让我了解处理不同的标题部分.
在文件/usr/include/stdlib.h中,声明mkstemp()如果和其他一些功能被拒绝__STRICT_ANSI__的定义-比如当我们使用编译时标志-ansi和-std=c++11.
同样,在文件中/usr/include/stdio.h,fdopen()由于同样的原因,将跳过声明.
C++标头<cstdlib>和<cstdio>两者都包含stdlib.h和stdio.h这两个函数(以及其他函数)之前的标题和保留声明,直到这两个标题.因此,如果我们使用-ansi和/或-std=c++11那么这两个函数将不会被声明,我们会得到编译错误.
似乎适用于玩具代码示例的解决方案是__STRICT_ANSI__在编译之前取消定义:
$ g++ -std=c++11 -U__STRICT_ANSI__ foo.cpp
Run Code Online (Sandbox Code Playgroud)
目前尚不清楚这会产生什么样的副作用,但是从谷歌搜索来看,这似乎是一个常见的问题,也是需要针对Cygwin的其他开发者应用的常见修复.
| 归档时间: |
|
| 查看次数: |
2168 次 |
| 最近记录: |