
At 11:28 AM 8/17/2004, Carlo Wood wrote:
At several places in the code we find something like:
// BOOST_POSIX or BOOST_WINDOWS specify which API to use. # if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX ) # if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) # define BOOST_WINDOWS # else # define BOOST_POSIX # endif # endif
(As in for example boost/libs/filesystem/src/path_posix_windows.cpp)
This sets BOOST_WINDOWS explicitely, as default, for cygwin - which is a POSIX operating system with a single root.
That's not really the full story. Programs compiled with the Cygwin tools (gcc compiler, libraries, etc.) are useful (and commonly used) in two different environments: * Plain Windows (such as from the Windows command line). * Cygwin's Linux/POSIX emulator (such as from the bash command line). Both uses have to be supported by the filesystem library. Originally only the emulator usage was supported; we quickly heard from users that this wasn't acceptable.
This breaks a lot of code - if not all - of boost::filesystem. For example, the following code:
#include <iostream> #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp>
int main() { boost::filesystem::path p = "/usr"; if (!boost::filesystem::exists(p)) std::cerr << p.string() << " doesn't exist according to boost::filesystem" << std::endl; }
indeed causes boost::filesystem::exists to return 'false' on cygwin while "/usr" definitely exists.
The reason for that is obvious and looks like a clear bug: The code of boost::filesystem::exists is as follows:
BOOST_FILESYSTEM_DECL bool exists( const path & ph ) { # ifdef BOOST_POSIX struct stat path_stat; if(::stat( ph.string().c_str(), &path_stat ) != 0) { if((errno == ENOENT) || (errno == ENOTDIR)) return false; // stat failed because the path does not exist // for any other error we assume the file does exist and fall through, // this may not be the best policy though... (JM 20040330) } return true; # else if(::GetFileAttributesA( ph.string().c_str() ) == 0xFFFFFFFF) { UINT err = ::GetLastError(); if((err == ERROR_FILE_NOT_FOUND) || (err ==
ERROR_PATH_NOT_FOUND)
|| (err == ERROR_INVALID_NAME)) return false; // GetFileAttributes failed because the path does not exist // for any other error we assume the file does exist and fall through, // this may not be the best policy though... (JM 20040330) return true; } return true; # endif }
Therefore, with BOOST_POSIX undefined, "/usr" is passed directly to ::GetFileAttributesA() and that can obviously not work.
My question is therefore: shouldn't BOOST_POSIX be forced to be defined on cygwin?
Yes, if you want the Cygwin emulator behavior, No, if you want the Windows behavior. There isn't any way for the compiler to know which the user prefers. To make that clearer, a "Note for Cygwin users" was added to the docs several months ago. See below. --Beman Note for Cygwin users The library's implementation code automatically detects the current platform, and compiles the POSIX or Windows implementation code accordingly. Automatic platform detection during object library compilation can be overridden by defining BOOST_POSIX or BOOST_WINDOWS macros. With the exception of the Cygwin environment, there is usually no reason to define one of the macros, as the software development kits supplied with most compilers only support a single platform. The Cygwin package of tools supports traditional Windows usage, but also provides an emulation layer and other tools which can be used to make Windows act as Linux (and thus POSIX), and provide the Linux look-and-feel. GCC is usually the compiler of choice in this environment, as it can be installed via the Cygwin install process. Other compilers can also use the Cygwin emulation of POSIX, at least in theory. Those wishing to use the Cygwin POSIX emulation layer should define the BOOST_POSIX macro when compiling the Boost Filesystem Library's object-library. The macro does not need to be defined (and will have no effect if defined) for Boost Filesystem Library user programs.