-
Notifications
You must be signed in to change notification settings - Fork 253
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #156 from Czaki/master
upgrade macos version for support c++11
- Loading branch information
Showing
9 changed files
with
207 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
--- | ||
title: Modern C++ standards | ||
--- | ||
|
||
Building Python wheels with modern C++ standards (C++11 and later) requires a few tricks. | ||
|
||
|
||
## Python 2.7 and C++17 | ||
|
||
The Python 2.7 header files use the `register` keyword, which is [reserved and unused from C+17 onwards](https://en.cppreference.com/w/cpp/keyword/register). Compiling a wheel for Python 2.7 with the C++17 standard is still possible to allow usage of `register` using proper flag `-Wno-register` for gcc/clang and `/wd5033` for MSVC. | ||
|
||
## manylinux1 and C++14 | ||
The default `manylinux1` image (based on CentOS 5) contains a version of GCC and libstdc++ that only supports C++11 and earlier standards. There are however ways to compile wheels with the C++14 standard (and later): https://github.com/pypa/manylinux/issues/118 | ||
|
||
`manylinux2010` and `manylinux2014` are newer and support all C++ standards (up to C++17). | ||
|
||
## macOS and deployment target versions | ||
|
||
OS X/macOS allows you to specify a so-called "deployment target" version that will ensure backwards compatibility with older versions of macOS. One way to do this is by setting the `MACOSX_DEPLOYMENT_TARGET` environment variable. If not set, Python will set this variable to the version the Python distribution itself was compiled on (10.6 or 10.9, for the python.org packages), when creating the wheel. | ||
|
||
However, to enable modern C++ standards, the deploment target needs to be set high enough (since older OS X/macOS versions did not have the necessary modern C++ standard library). | ||
|
||
To get C++11 and C++14 support, set `MACOSX_DEPLOYMENT_TARGET` to (at least) `"10.9"`. | ||
|
||
To get C++17 support, set `MACOSX_DEPLOYMENT_TARGET` to (at least) `"10.13"` or `"10.14"` (macOS 10.13 offers partial C++17 support; e.g., the filesystem header is in experimental, offering `#include <experimental/filesystem>` instead of `#include <filesystem>`; macOS 10.14 has full C++17 support). | ||
|
||
For more details see https://en.cppreference.com/w/cpp/compiler_support and https://xcodereleases.com/: Xcode 10 needs macOS 10.13 and Xcode 11 needs macOS 10.14. | ||
|
||
## Windows and Python 2.7 | ||
|
||
Visual C++ for Python 2.7 does not support modern standards of C++. When building on Appveyor, you will need to either use the "Visual Studio 2017" or "Visual Studio 2019" image, but Python 2.7 is not supported on these images - skip it by setting `CIBW_SKIP=cp27-win*`. | ||
|
||
There is an optional workaround for this, though: the pybind11 project argues and shows that it is [possible to compile Python 2.7 extension with a newer compiler](https://pybind11.readthedocs.io/en/stable/faq.html#working-with-ancient-visual-studio-2008-builds-on-windows) and has an example project showing how to do this: https://github.com/pybind/python_example. The main catch is that a user might need to install a newer "Microsoft Visual C++ Redistributable", since the newer C++ standard libraries are not included by default with the Python 2.7 installation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ nav: | |
- setup.md | ||
- options.md | ||
- deliver-to-pypi.md | ||
- cpp_standards.md | ||
- faq.md | ||
- contributing.md | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import os | ||
import sys | ||
|
||
import pytest | ||
|
||
import utils | ||
|
||
|
||
project_dir = os.path.dirname(__file__) | ||
|
||
def test_cpp11(tmp_path): | ||
# This test checks that the C++11 standard is supported | ||
|
||
add_env = {'CIBW_SKIP': 'cp27-win*', 'CIBW_ENVIRONMENT': 'STANDARD=11'} | ||
# VC++ for Python 2.7 does not support modern standards | ||
if utils.platform == 'macos': | ||
add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.9' | ||
|
||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) | ||
expected_wheels = [x for x in utils.expected_wheels( | ||
'spam', '0.1.0', macosx_deployment_target='10.9') | ||
if 'cp27-cp27m-win' not in x] | ||
assert set(actual_wheels) == set(expected_wheels) | ||
|
||
|
||
def test_cpp14(): | ||
# This test checks that the C++14 standard is supported | ||
|
||
add_env = {'CIBW_SKIP': 'cp27-win* cp35-win*', 'CIBW_ENVIRONMENT': 'STANDARD=14'} | ||
# VC++ for Python 2.7 does not support modern standards | ||
# The manylinux1 docker image does not have a compiler which supports C++11 | ||
# Python 3.4 and 3.5 are compiled with MSVC 10, which does not support C++14 | ||
if utils.platform == 'macos': | ||
add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.9' | ||
|
||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) | ||
expected_wheels = [x for x in utils.expected_wheels( | ||
'spam', '0.1.0', macosx_deployment_target='10.9') | ||
if 'cp27-cp27m-win' not in x and 'cp35-cp35m-win' not in x] | ||
assert set(actual_wheels) == set(expected_wheels) | ||
|
||
|
||
def test_cpp17(): | ||
# This test checks that the C++17 standard is supported | ||
|
||
# Python 2.7 uses the `register` keyword which is forbidden in the C++17 standard | ||
# The manylinux1 docker image does not have a compiler which supports C++11 | ||
# Python 3.4 and 3.5 are compiled with MSVC 10, which does not support C++17 | ||
if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015': | ||
pytest.skip('Visual Studio 2015 does not support C++17') | ||
|
||
add_env = {'CIBW_SKIP': 'cp27-win* cp35-win*', 'CIBW_ENVIRONMENT': 'STANDARD=17'} | ||
if utils.platform == 'macos': | ||
add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.13' | ||
|
||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env) | ||
expected_wheels = [x for x in utils.expected_wheels( | ||
'spam', '0.1.0', macosx_deployment_target='10.13') | ||
if 'cp27-cp27m-win' not in x and 'cp35-cp35m-win' not in x] | ||
assert set(actual_wheels) == set(expected_wheels) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import os, sys | ||
from setuptools import setup, Extension | ||
import platform | ||
|
||
standard = os.environ["STANDARD"] | ||
|
||
language_standard = "/std:c++" + standard if platform.system() == "Windows" else "-std=c++" + standard | ||
|
||
extra_compile_args = [language_standard, "-DSTANDARD=" + standard] | ||
|
||
if standard == "17": | ||
if platform.system() == "Windows": | ||
extra_compile_args.append("/wd5033") | ||
else: | ||
extra_compile_args.append("-Wno-register") | ||
|
||
setup( | ||
name="spam", | ||
ext_modules=[Extension('spam', sources=['spam.cpp'], language="c++", extra_compile_args=extra_compile_args)], | ||
version="0.1.0", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include <Python.h> | ||
#include <string> | ||
|
||
// Depending on the requested standard, use a modern C++ feature | ||
// that was introduced in that standard. | ||
#if STANDARD == 11 | ||
#include <array> | ||
#elif STANDARD == 14 | ||
int a = 100'000; | ||
#elif STANDARD == 17 | ||
#include <utility> | ||
auto a = std::pair(5.0, false); | ||
#else | ||
#error Standard needed | ||
#endif | ||
|
||
static PyObject * | ||
spam_system(PyObject *self, PyObject *args) | ||
{ | ||
const char *command; | ||
int sts; | ||
|
||
if (!PyArg_ParseTuple(args, "s", &command)) | ||
return NULL; | ||
sts = system(command); | ||
return PyLong_FromLong(sts); | ||
} | ||
|
||
/* Module initialization */ | ||
|
||
#if PY_MAJOR_VERSION >= 3 | ||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) | ||
#define MOD_DEF(m, name, doc, methods, module_state_size) \ | ||
static struct PyModuleDef moduledef = { \ | ||
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \ | ||
m = PyModule_Create(&moduledef); | ||
#define MOD_RETURN(m) return m; | ||
#else | ||
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void) | ||
#define MOD_DEF(m, name, doc, methods, module_state_size) \ | ||
m = Py_InitModule3(name, methods, doc); | ||
#define MOD_RETURN(m) return; | ||
#endif | ||
|
||
static PyMethodDef module_methods[] = { | ||
{"system", (PyCFunction)spam_system, METH_VARARGS, | ||
"Execute a shell command."}, | ||
{NULL} /* Sentinel */ | ||
}; | ||
|
||
MOD_INIT(spam) | ||
{ | ||
PyObject* m; | ||
|
||
MOD_DEF(m, | ||
"spam", | ||
"Example module", | ||
module_methods, | ||
-1) | ||
|
||
MOD_RETURN(m) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters