Mkstemp () and fdopen () in Cygwin 1.7.28

In the process of creating C ++ code under Cygwin (1.7.28-2, 64-bit) with GNU GCC 4.8.2, I encountered the following errors:

... 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+"); ... 

A specific piece of code that does not compile is as follows:

 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 malloc results are transmitted because this code is part of a larger C ++ project.)

regression

This code compiles and works with GNU GCC 4.8.x on Linux hosts and with Clang / ++ 5.0 under OS X.

Environment

I am using the following version of 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 -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

  • Is there any support for mkstemp() and fdopen() in GCC 4.8.2 for Cygwin?

  • If not, is there a package that I can add, or a library that I can relatively easily compile to add support for these functions?

  • If not, are there alternatives to mkstemp() and fdopen() that I can use to replicate their functions under Cygwin?

Possible fix

Here is 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 the POSIX functions, I would like to use them if possible. Thanks for any advice.

+6
source share
4 answers

When compiling with g++ 4.8.2 on Cygwin, I registered a macro extension in three cases:

 $ 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 

Compare logs was helpful. In the cases -std=c++11 and -ansi were “holes”, while the block containing the mkstemp() declaration is detected in the “fake” case. This allowed me to zero out parts of the headers that were handled differently.

In the /usr/include/stdlib.h file, mkstemp() declarations and some other functions are discarded if __STRICT_ANSI__ is defined - for example, when we use the compile-time flags -ansi and -std=c++11 .

Similarly, in the /usr/include/stdio.h file, fdopen() declarations will be skipped for the same reason.

The C ++ headers <cstdlib> and <cstdio> include the stdlib.h and stdio.h headers and leave the declaration of these two functions (among others) before the two headers. Therefore, if we use -ansi and / or -std=c++11 , then these two functions will not be declared, and we will get compilation errors.

A solution that seems to work for toy code samples is to define __STRICT_ANSI__ before compiling:

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

It's unclear what the side effects of this will be, but from googling it seems like a general problem and a general fix applied by other developers who need to configure Cygwin.

+6
source

Cygwin has a Linux-like set of functional test macros . However, on Linux with C ++, _GNU_SOURCE is defined unconditionally, essentially nullifying all such guards. At Cygwin, we do not do this, that is, you must respect the meaning of various flags in C ++.

As already noted, using any -std=c++* flag -std=c++* determine __STRICT_ANSI__ , which is recognized by macros. Determining what is wrong on the command line. Instead, either define the correct documented flag for the functions you want to use (in this case, -D_POSIX_C_SOURCE=200809L should cover both), or use the -std=gnu++* flags instead (which, by the way, do not define _GNU_SOURCE ) do not declare compliance ANSI

0
source

My buddy Vincent has prepared a simple version that works with Cygwin. http://code.google.com/p/xpost/source/browse/src/lib/xpost_compat.c#113

It may 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. I will need to do some research / reflection.

-1
source

I recently compiled git-crypt and ran into the same problem. The solution from the answer above worked, except that it had to be deployed through "make" and not through "g ++", for example like this:

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

All Articles