I added the ability to create a manylinux wheel for the nupic.core project 
(github.com/numenta/nupic.core). However, in testing, I found that some 
exception-handling logic that used to work is now failing when running the 
wheel on Ubuntu 16.04, which uses the gcc/g++ 5.4.0 toolchain. One example in 
particular is the failure to catch the exception std::ios::failure.

This makes it impractical to create manylinux wheels from legacy C++ code that 
also, as in the case of nupic.core, includes globs of additional 3rd party 
code. It's not practical because the incompatibilities may not be limited to 
just this one exception class and the actual failures are unreasonably 
difficult to simulate in testing, making it difficult, if not impossible, to 
find all occurrences in one's own code, not to mention 3rd party code that it 
links with.

It turns out that, among other things, "the C++11 standard mandated an ABI 
change for std::ios_base::failure, by giving it a std::system_error base class 
that wasn't present in C++03" (see 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66145). The 4.8.2 compiler 
toolchain on the manylinux docker image supports C++11 in spirit, but doesn't 
implement the new ABI (its std::ios_base::failure is derived from 
std::exception); however, the 5.4.0 toolchain on Ubuntu 16.04 implements the 
new ABI (derives from std::system_error, etc.), and its stdc++ library is 
compiled using the new toolchain. So, the signature of std::ios_base::failure 
compiled into the manylinux wheel doesn't match the signature of 
std::ios_base::failure that's raised by the stdc++ library on Ubuntu 16.04.

The following simple app demonstrates the issue:

```
#include <iostream>
#include <fstream>

int main() {

  try {
    std::ifstream input("notafile");
    input.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    input.get();
  } catch(const std::ios::failure &e) {
    std::cout << "caught a std::ios::failure: what=" << e.what()
      << '\n';
  }
}
```

First, we build and run it on the manylinux docker image:
$ docker run -it -v /home/vitaly/localbuilds/ios-base-failure:/ios-base-failure 
quay.io/pypa/manylinux1_x86_64 bash
[root@39eecd65e630 ios-base-failure]# g++ -std=c++11 test.cpp

[root@39eecd65e630 ios-base-failure]# ./a.out
caught a std::ios::failure: what=basic_ios::clear

As you can see above, running it on the manylinux container works correctly: it 
catches std::ios::failure and prints the expected message to stdout.

However, when we run the same executable on Ubuntu 16.04, we get a very 
different result below. We see that the exception wasn't caught.

g++ (Ubuntu 5.4.0-6ubuntu1~16.04.1) 5.4.0 20160609
('Ubuntu', '16.04', 'denial')

vitaly@ubuntuvm:~/localbuilds/ios-base-failure$ ./a.out
terminate called after throwing an instance of 
'std::ios_base::failure[abi:cxx11]'
  what():  basic_ios::clear: iostream error
Aborted (core dumped)

Vitaly

_______________________________________________
Wheel-builders mailing list
Wheel-builders@python.org
https://mail.python.org/mailman/listinfo/wheel-builders

Reply via email to