简体   繁体   English

mkstemp()和fdopen()在Cygwin 1.7.28中

[英]mkstemp() and fdopen() in Cygwin 1.7.28

In the course of building some C++-based code under Cygwin (1.7.28-2, 64-bit) with GNU GCC 4.8.2, I ran into the following errors: 在使用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+");
...

The specific chunk of code that fails to compile is: 无法编译的特定代码块是:

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;
}

(The results of malloc are being cast because this code is within a larger C++-based project.) (正在编译malloc的结果,因为此代码位于更大的基于C ++的项目中。)

Regression 回归

This code compiles and works successfully with GNU GCC 4.8.x on Linux hosts and with Clang/++ 5.0 under OS X. 此代码在Linux主机上与GNU GCC 4.8.x成功编译并成功运行,在OS X下与Clang / ++ 5.0一起成功运行。

Environment 环境

I am using the following version of Cygwin: 我使用的是以下版本的Cygwin:

$ uname -a
CYGWIN_NT-6.1 CygFoo-PC 1.7.28(0.271/5/3) 2014-02-09 21:06 x86_64 Cygwin

Here is the version of GCC I am using: 这是我正在使用的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)

Questions 问题

  1. Is there support for mkstemp() and fdopen() in GCC 4.8.2 for Cygwin? 对于Cygwin,是否支持GCC 4.8.2中的mkstemp()fdopen()

  2. If not, is there a package I can add or a library I can relatively easily compile to add support for these functions? 如果没有,是否有我可以添加的包或我可以相对容易编译的库以添加对这些功能的支持?

  3. If not, are there alternatives to mkstemp() and fdopen() that I can make use of to replicate their functionality under Cygwin? 如果没有,有没有替代mkstemp()fdopen() ,我可以利用它来复制他们在Cygwin下的功能?

Possible fix 可能的修复

Here's a modified version of this function: 这是此功能的修改版本:

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;
}

This is pretty ugly. 这非常难看。 If there is a way to use POSIX functions, I'd like to use them, if I can. 如果有办法使用POSIX函数,我想使用它们,如果可以的话。 Thanks for any advice. 谢谢你的建议。

When compiling with g++ 4.8.2 on Cygwin, I logged the expansion of macros in three cases: 在Cygwin上使用g++ 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

Comparing the logs was useful. 比较日志很有用。 There were "holes" in the -std=c++11 and -ansi cases, while a block containing the mkstemp() declaration shows up in the "flagless" case. -std=c++11-ansi情况下有“漏洞”,而包含mkstemp()声明的块在“无标记”情况下出现。 This let me zero in on the parts of the headers that were processed differently. 这让我了解处理不同的标题部分。

In the file /usr/include/stdlib.h , declarations of mkstemp() and some other functions are rejected if __STRICT_ANSI__ is defined — such as when we use the compile-time flags -ansi and -std=c++11 . 在文件/usr/include/stdlib.h ,如果定义了__STRICT_ANSI__则拒绝mkstemp()和其他一些函数的声明 - 例如当我们使用编译时标志-ansi-std=c++11

Likewise, in the file /usr/include/stdio.h , declarations of fdopen() will get skipped for the same reason. 同样,在文件/usr/include/stdio.h ,由于同样的原因,将跳过fdopen()声明。

The C++ headers <cstdlib> and <cstdio> both include the stdlib.h and stdio.h headers and leave declaration of those two functions (among others) up to those two headers. C ++头文件<cstdlib><cstdio>都包含stdlib.hstdio.h头文件,并将这两个函数(以及其他函数)的声明留给这两个头文件。 So if we use -ansi and/or -std=c++11 then those two functions will not be declared and we get the compile errors. 因此,如果我们使用-ansi和/或-std=c++11那么这两个函数将不会被声明,我们会得到编译错误。

The solution that seems to work for the toy code samples is to undefine __STRICT_ANSI__ before compiling: 似乎适用于玩具代码示例的解决方案是在编译之前__STRICT_ANSI__定义__STRICT_ANSI__

$ g++ -std=c++11 -U__STRICT_ANSI__ foo.cpp

It's not clear what the side effects of this will be, but from googling, it seems like this is a common problem and a common fix applied by other developers who need to target Cygwin. 目前尚不清楚这会产生什么样的副作用,但是从谷歌搜索来看,这似乎是一个常见的问题,也是需要针对Cygwin的其他开发者应用的常见修复。

Cygwin has a Linux-like set of Feature Test Macros . Cygwin有一套类似Linux的功能测试宏 However, on Linux with C++, _GNU_SOURCE is defined unconditionally, essentially negating all such guards. 但是,在使用C ++的Linux上, _GNU_SOURCE是无条件定义的,基本上否定了所有这些警卫。 On Cygwin, we do not do this, meaning you actually have to respect the meaning of the various flags on C++ as well. 在Cygwin上,我们这样做,这意味着你实际上也必须尊重C ++上各种标志的含义。

As noted, using any -std=c++* flag will define __STRICT_ANSI__ , which is recognized by the macros. 如上所述,使用任何-std=c++*标志将定义__STRICT_ANSI__ ,它由宏识别。 Undefining that on the command line is incorrect. 在命令行上取消定义是不正确的。 Instead, either define the correct documented flag(s) for the functions you wish to use (in this case, -D_POSIX_C_SOURCE=200809L should cover both), or use -std=gnu++* flags instead (which, btw, do not define _GNU_SOURCE ) to not declare ANSI compliance. 相反,要么为你想要使用的函数定义正确的文档标志(在这种情况下, -D_POSIX_C_SOURCE=200809L应该覆盖两者),或者使用-std=gnu++*标志(btw, 定义_GNU_SOURCE )不声明ANSI合规性。

My pal Vincent cooked up a simple version that works with Cygwin. 我的朋友文森特制作了一个与Cygwin合作的简单版本。 http://code.google.com/p/xpost/source/browse/src/lib/xpost_compat.c#113 http://code.google.com/p/xpost/source/browse/src/lib/xpost_compat.c#113

It might not cover all cases. 它可能无法涵盖所有​​情况。

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>

# include <windows.h>
# include <io.h>

int mkstemp(char *template)
{
    char *temp;

    temp = _mktemp(template);
    if (!temp)
        return -1;

    return _open(temp, _O_CREAT | _O_TEMPORARY | _O_EXCL | _O_RDWR, _S_IREAD | _S_IWRITE);
}

As for fdopen , I'm not sure. 至于fdopen ,我不确定。 I'll have to do some research/thinking. 我将不得不做一些研究/思考。

Recently I was compiling git-crypt and encountered the same problem. 最近我在编译git-crypt并遇到了同样的问题。 The solution from the answer above worked except that it had to be deployed via 'make' and not via 'g++', like this: 上面的答案的解决方案工作,除了它必须通过'make'而不是'g ++'部署,如下所示:

make CXXFLAGS="-U__STRICT_ANSI__ -std=c++11"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM