Skip to content

Commit ad7edc0

Browse files
committed
Add tests for c++ standards, add using MACOSX_DEPLOYMENT_TARGET, fix names of macos wheels
1 parent 13f1bda commit ad7edc0

File tree

16 files changed

+315
-19
lines changed

16 files changed

+315
-19
lines changed

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ All being well, you should get wheels delivered to you in a few minutes.
225225
| | `CIBW_MANYLINUX1_I686_IMAGE` | Specify an alternative manylinux1 i686 docker image |
226226
| **Tests** | `CIBW_TEST_COMMAND` | Execute a shell command to test all built wheels |
227227
| | `CIBW_TEST_REQUIRES` | Install Python dependencies before running the tests |
228+
| | `CIBW_TEST_EXTRAS` | Install Python dependencies before running the tests using ``extras_require``|
228229
229230
A more detailed description of the options, the allowed values, and some examples can be found in the [Options](#options) section.
230231
@@ -235,6 +236,25 @@ Linux wheels are built in the [`manylinux1` docker images](https://github.com/py
235236
- The project directory is mounted in the running Docker instance as `/project`, the output directory for the wheels as `/output`. In general, this is handled transparently by `cibuildwheel`. For a more finegrained level of control however, the root of the host file system is mounted as `/host`, allowing for example to access shared files, caches, etc. on the host file system. Note that this is not available on CircleCI due to their Docker policies.
236237
- Alternative dockers images can be specified with the `CIBW_MANYLINUX1_X86_64_IMAGE` and `CIBW_MANYLINUX1_I686_IMAGE` options to allow for a custom, preconfigured build environment for the Linux builds. See [below](#options) for more details.
237238
239+
Moden C++ standards
240+
-------------------
241+
Python 2.7 use `register` keyword which is prohibited in c++17 standard.
242+
243+
Linux
244+
=====
245+
For `manulinux1` images only c++11 standards is supported. c++14 and c++17 will be supported with manylinux2010 image
246+
247+
MacOS
248+
=====
249+
To get c++11 and c++14 upport need to set `MACOSX_DEPLOYMENT_TARGET` variable to `10.9` value
250+
251+
To get c++17 support need to set `MACOSX_DEPLOYMENT_TARGET` variable to `10.13` or `10.14` value. `10.13` supports c++17 partialy, eg. filesystem header is in experimental: `#include<filesystem> -> #include<experimental/filesystem>`
252+
253+
Windows
254+
=======
255+
Visual C++ for Python 2.7 do not support modern standards of c++.
256+
Also MSVC 10.0
257+
238258
239259
Options
240260
-------
@@ -412,6 +432,25 @@ Example: `nose==1.3.7 moto==0.4.31`
412432
Platform-specific variants also available:
413433
`CIBW_TEST_REQUIRES_MACOS` | `CIBW_TEST_REQUIRES_WINDOWS` | `CIBW_TEST_REQUIRES_LINUX`
414434
435+
***
436+
437+
| Environment variable: `CIBW_TEST_EXTRAS`
438+
| ---
439+
440+
Optional.
441+
442+
Comma-separated list of
443+
[extras_require](https://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-extras-optional-features-with-their-own-dependencies)
444+
options that should be included when installing the wheel prior to running the
445+
tests. This can be used to avoid having to redefine test dependencies in
446+
``CIBW_TEST_REQUIRES`` if they are already defined in ``setup.py`` or
447+
``setup.cfg``.
448+
449+
Example: `test,qt` (will cause the wheel to be installed with ``pip install <wheel_file>[test,qt])
450+
451+
452+
Platform-specific variants also available:
453+
`CIBW_TEST_EXTRAS_MACOS` | `CIBW_TEST_EXTRAS_WINDOWS` | `CIBW_TEST_EXTRAS_LINUX`
415454
416455
### Example YML syntax
417456

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
python ./bin/run_tests.py
99
1010
- job: macos
11-
pool: {vmImage: 'macOS-10.13'}
11+
pool: {vmImage: 'macOS-10.14'}
1212
steps:
1313
- task: UsePythonVersion@0
1414
- bash: |

cibuildwheel/__main__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,16 @@ def main():
9191
output_dir = args.output_dir
9292
test_command = get_option_from_environment('CIBW_TEST_COMMAND', platform=platform)
9393
test_requires = get_option_from_environment('CIBW_TEST_REQUIRES', platform=platform, default='').split()
94+
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
9495
project_dir = args.project_dir
9596
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
9697
build_verbosity = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
9798
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
9899
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
99100

101+
if test_extras:
102+
test_extras = '[{0}]'.format(test_extras)
103+
100104
try:
101105
build_verbosity = min(3, max(-3, int(build_verbosity)))
102106
except ValueError:
@@ -129,6 +133,7 @@ def main():
129133
output_dir=output_dir,
130134
test_command=test_command,
131135
test_requires=test_requires,
136+
test_extras=test_extras,
132137
before_build=before_build,
133138
build_verbosity=build_verbosity,
134139
build_selector=build_selector,

cibuildwheel/linux.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def get_python_configurations(build_selector):
3030
return [c for c in python_configurations if build_selector(c.identifier)]
3131

3232

33-
def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment, manylinux1_images):
33+
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment, manylinux1_images):
3434
try:
3535
subprocess.check_call(['docker', '--version'])
3636
except:
@@ -86,7 +86,7 @@ def build(project_dir, output_dir, test_command, test_requires, before_build, bu
8686
delocated_wheel=(/tmp/delocated_wheel/*.whl)
8787
8888
# Install the wheel we just built
89-
"$PYBIN/pip" install "$delocated_wheel"
89+
"$PYBIN/pip" install "$delocated_wheel"{test_extras}
9090
9191
# Install any requirements to run the tests
9292
if [ ! -z "{test_requires}" ]; then
@@ -107,6 +107,7 @@ def build(project_dir, output_dir, test_command, test_requires, before_build, bu
107107
'''.format(
108108
pybin_paths=' '.join(c.path+'/bin' for c in platform_configs),
109109
test_requires=' '.join(test_requires),
110+
test_extras=test_extras,
110111
test_command=shlex_quote(
111112
prepare_command(test_command, project='/project') if test_command else ''
112113
),

cibuildwheel/macos.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
def get_python_configurations(build_selector):
1414
PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url'])
1515
python_configurations = [
16-
PythonConfiguration(version='2.7', identifier='cp27-macosx_10_9_x86_64', url='https://www.python.org/ftp/python/2.7.16/python-2.7.16-macosx10.9.pkg'),
16+
PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.16/python-2.7.16-macosx10.6.pkg'),
1717
PythonConfiguration(version='3.4', identifier='cp34-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.4.4/python-3.4.4-macosx10.6.pkg'),
1818
PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'),
19-
PythonConfiguration(version='3.6', identifier='cp36-macosx_10_9_x86_64', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg'),
20-
PythonConfiguration(version='3.7', identifier='cp37-macosx_10_9_x86_64', url='https://www.python.org/ftp/python/3.7.4/python-3.7.4-macosx10.9.pkg'),
19+
PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.6.pkg'),
20+
PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.7.4/python-3.7.4-macosx10.6.pkg'),
2121
]
2222

2323
# skip builds as required
2424
return [c for c in python_configurations if build_selector(c.identifier)]
25-
2625

27-
def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment):
26+
27+
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment):
2828
python_configurations = get_python_configurations(build_selector)
2929
get_pip_url = 'https://bootstrap.pypa.io/get-pip.py'
3030
get_pip_script = '/tmp/get-pip.py'
@@ -81,6 +81,8 @@ def call(args, env=None, cwd=None, shell=False):
8181
env['PATH'],
8282
])
8383
env = environment.as_dictionary(prev_environment=env)
84+
if "MACOSX_DEPLOYMENT_TARGET" not in env:
85+
env["MACOSX_DEPLOYMENT_TARGET"] = "10.9"
8486

8587
# check what version we're on
8688
call(['which', 'python'], env=env)
@@ -107,7 +109,8 @@ def call(args, env=None, cwd=None, shell=False):
107109
call(before_build_prepared, env=env, shell=True)
108110

109111
# build the wheel
110-
call(['pip', 'wheel', abs_project_dir, '-w', '/tmp/built_wheel', '--no-deps'] + get_build_verbosity_extra_flags(build_verbosity), env=env)
112+
call(['pip', 'wheel', '--global-option', 'bdist_wheel', '--global-option', "-p", "--global-option", "macosx_" + env["MACOSX_DEPLOYMENT_TARGET"] + "_intel",
113+
abs_project_dir, '-w', '/tmp/built_wheel', '--no-deps', ] + get_build_verbosity_extra_flags(build_verbosity), env=env)
111114
built_wheel = glob('/tmp/built_wheel/*.whl')[0]
112115

113116
if built_wheel.endswith('none-any.whl'):
@@ -121,7 +124,7 @@ def call(args, env=None, cwd=None, shell=False):
121124
delocated_wheel = glob('/tmp/delocated_wheel/*.whl')[0]
122125

123126
# install the wheel
124-
call(['pip', 'install', delocated_wheel], env=env)
127+
call(['pip', 'install', delocated_wheel + test_extras], env=env)
125128

126129
# test the wheel
127130
if test_requires:

cibuildwheel/windows.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def get_python_configurations(build_selector):
5656
return [c for c in python_configurations if build_selector(c.identifier)]
5757

5858

59-
def build(project_dir, output_dir, test_command, test_requires, before_build, build_verbosity, build_selector, environment):
59+
def build(project_dir, output_dir, test_command, test_requires, test_extras, before_build, build_verbosity, build_selector, environment):
6060
if IS_RUNNING_ON_AZURE:
6161
def shell(args, env=None, cwd=None):
6262
print('+ ' + ' '.join(args))
@@ -122,7 +122,7 @@ def shell(args, env=None, cwd=None):
122122
built_wheel = glob(built_wheel_dir+'/*.whl')[0]
123123

124124
# install the wheel
125-
shell(['pip', 'install', built_wheel], env=env)
125+
shell(['pip', 'install', built_wheel + test_extras], env=env)
126126

127127
# test the wheel
128128
if test_requires:

test/02_test/cibuildwheel_test.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,25 @@ def test():
1212
'CIBW_TEST_COMMAND': 'false || nosetests {project}/test',
1313
'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {project}/test',
1414
})
15-
15+
16+
# also check that we got the right wheels
17+
expected_wheels = utils.expected_wheels('spam', '0.1.0')
18+
actual_wheels = os.listdir('wheelhouse')
19+
assert set(actual_wheels) == set(expected_wheels)
20+
21+
22+
def test_extras_require():
23+
project_dir = os.path.dirname(__file__)
24+
25+
# build and test the wheels
26+
utils.cibuildwheel_run(project_dir, add_env={
27+
'CIBW_TEST_EXTRAS': 'test',
28+
# the 'false ||' bit is to ensure this command runs in a shell on
29+
# mac/linux.
30+
'CIBW_TEST_COMMAND': 'false || nosetests {project}/test',
31+
'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {project}/test',
32+
})
33+
1634
# also check that we got the right wheels
1735
expected_wheels = utils.expected_wheels('spam', '0.1.0')
1836
actual_wheels = os.listdir('wheelhouse')

test/02_test/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
setup(
44
name="spam",
55
ext_modules=[Extension('spam', sources=['spam.c'])],
6+
extras_require={'test': ['nose']},
67
version="0.1.0",
78
)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import os
2+
import utils
3+
import sys
4+
5+
def test_cpp11():
6+
add_env = {"CIBW_SKIP": "cp27-win* cp34-win*"}
7+
# VC for python 2.7 do not support modern standards
8+
if utils.platform == "macos":
9+
add_env["MACOSX_DEPLOYMENT_TARGET"] = "10.9"
10+
project_dir = os.path.join(os.path.dirname(__file__), "cpp11")
11+
# this test checks if c++11 standard is supported.
12+
13+
utils.cibuildwheel_run(project_dir, add_env=add_env)
14+
15+
16+
def test_cpp14():
17+
add_env = {"CIBW_SKIP": "cp27-win* cp34-win* cp35-win* *manylinux1*"}
18+
# VC for python 2.7 do not support modern standards
19+
# manylinux1 docker image do not support compilers with standards newer than c++11
20+
# python 3.4 and 3.5 are compiled with MSVC 10. which not support c++14
21+
if utils.platform == "macos":
22+
add_env["MACOSX_DEPLOYMENT_TARGET"] = "10.9"
23+
project_dir = os.path.join(os.path.dirname(__file__), "cpp14")
24+
# this test checks if c++14 standard is supported.
25+
26+
utils.cibuildwheel_run(project_dir, add_env=add_env)
27+
28+
def test_cpp17():
29+
# python 2.7 use `register` keyword which is forbidden in c++17 standard
30+
# manylinux1 docker image do not support compilers with standards newer than c++11
31+
# python 3.4 and 3.5 are compiled with MSVC 10. which not support c++17
32+
add_env = {"CIBW_SKIP": "cp27* cp34-win* cp35-win* *manylinux1*"}
33+
if utils.platform == "macos":
34+
add_env["MACOSX_DEPLOYMENT_TARGET"] = "10.13"
35+
36+
project_dir = os.path.join(os.path.dirname(__file__), "cpp17")
37+
# this test checks if c++17 standard is supported.
38+
39+
utils.cibuildwheel_run(project_dir, add_env=add_env)
40+

test/08_cpp_standards/cpp11/setup.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import os, sys
2+
3+
from setuptools import setup, Extension
4+
5+
setup(
6+
name="spam11",
7+
ext_modules=[Extension('spam11', sources=['spam11.cpp'], language="c++", extra_compile_args=["-std=c++11"])],
8+
version="0.1.0",
9+
)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <Python.h>
2+
#include <array>
3+
4+
static PyObject *
5+
spam_system(PyObject *self, PyObject *args)
6+
{
7+
const char *command;
8+
int sts;
9+
10+
if (!PyArg_ParseTuple(args, "s", &command))
11+
return NULL;
12+
sts = system(command);
13+
return PyLong_FromLong(sts);
14+
}
15+
16+
/* Module initialization */
17+
18+
#if PY_MAJOR_VERSION >= 3
19+
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
20+
#define MOD_DEF(m, name, doc, methods, module_state_size) \
21+
static struct PyModuleDef moduledef = { \
22+
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
23+
m = PyModule_Create(&moduledef);
24+
#define MOD_RETURN(m) return m;
25+
#else
26+
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
27+
#define MOD_DEF(m, name, doc, methods, module_state_size) \
28+
m = Py_InitModule3(name, methods, doc);
29+
#define MOD_RETURN(m) return;
30+
#endif
31+
32+
static PyMethodDef module_methods[] = {
33+
{"system", (PyCFunction)spam_system, METH_VARARGS,
34+
"Execute a shell command."},
35+
{NULL} /* Sentinel */
36+
};
37+
38+
MOD_INIT(spam11)
39+
{
40+
PyObject* m;
41+
42+
MOD_DEF(m,
43+
"spam11",
44+
"Example module",
45+
module_methods,
46+
-1)
47+
48+
MOD_RETURN(m)
49+
}

test/08_cpp_standards/cpp14/setup.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import os, sys
2+
3+
from setuptools import setup, Extension
4+
5+
setup(
6+
name="spam14",
7+
ext_modules=[Extension('spam14', sources=['spam14.cpp'], language="c++", extra_compile_args=["-std=c++14"])],
8+
version="0.1.0",
9+
)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <Python.h>
2+
#include <array>
3+
4+
int a = 100'000;
5+
6+
static PyObject *
7+
spam_system(PyObject *self, PyObject *args)
8+
{
9+
const char *command;
10+
int sts;
11+
12+
if (!PyArg_ParseTuple(args, "s", &command))
13+
return NULL;
14+
sts = system(command);
15+
return PyLong_FromLong(sts);
16+
}
17+
18+
/* Module initialization */
19+
20+
#if PY_MAJOR_VERSION >= 3
21+
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
22+
#define MOD_DEF(m, name, doc, methods, module_state_size) \
23+
static struct PyModuleDef moduledef = { \
24+
PyModuleDef_HEAD_INIT, name, doc, module_state_size, methods, }; \
25+
m = PyModule_Create(&moduledef);
26+
#define MOD_RETURN(m) return m;
27+
#else
28+
#define MOD_INIT(name) PyMODINIT_FUNC init##name(void)
29+
#define MOD_DEF(m, name, doc, methods, module_state_size) \
30+
m = Py_InitModule3(name, methods, doc);
31+
#define MOD_RETURN(m) return;
32+
#endif
33+
34+
static PyMethodDef module_methods[] = {
35+
{"system", (PyCFunction)spam_system, METH_VARARGS,
36+
"Execute a shell command."},
37+
{NULL} /* Sentinel */
38+
};
39+
40+
MOD_INIT(spam14)
41+
{
42+
PyObject* m;
43+
44+
MOD_DEF(m,
45+
"spam14",
46+
"Example module",
47+
module_methods,
48+
-1)
49+
50+
MOD_RETURN(m)
51+
}

0 commit comments

Comments
 (0)