From bfbc9814d7b94cea46cab009130ace2cf88d0cfb Mon Sep 17 00:00:00 2001 From: mayeut Date: Tue, 19 Nov 2019 23:36:20 +0100 Subject: [PATCH] Add option to build `x86_64` only on macOS --- cibuildwheel/__main__.py | 2 +- cibuildwheel/macos.py | 30 +++++++++----- test/09_macos_x86_64/cibuildwheel_test.py | 17 ++++++++ test/09_macos_x86_64/setup.py | 12 ++++++ test/09_macos_x86_64/spam.c | 48 +++++++++++++++++++++++ 5 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 test/09_macos_x86_64/cibuildwheel_test.py create mode 100644 test/09_macos_x86_64/setup.py create mode 100644 test/09_macos_x86_64/spam.c diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 9b237f765..eab82ab27 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -92,7 +92,7 @@ def main(): if platform == 'linux': repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}' elif platform == 'macos': - repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel -w {dest_dir} {wheel}' + repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel --require-archs {machine} -w {dest_dir} {wheel}' else: repair_command_default = '' repair_command = get_option_from_environment('CIBW_REPAIR_WHEEL_COMMAND', platform=platform, default=repair_command_default) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 1344c9ffe..3a4b64960 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -11,13 +11,13 @@ from .util import prepare_command, get_build_verbosity_extra_flags -def get_python_configurations(build_selector): +def get_python_configurations(build_selector, machine='intel'): PythonConfiguration = namedtuple('PythonConfiguration', ['version', 'identifier', 'url']) python_configurations = [ - PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_intel', url='https://www.python.org/ftp/python/2.7.17/python-2.7.17-macosx10.6.pkg'), - 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'), - 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'), - PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_intel', url='https://www.python.org/ftp/python/3.7.5/python-3.7.5-macosx10.6.pkg'), + PythonConfiguration(version='2.7', identifier='cp27-macosx_10_6_' + machine, url='https://www.python.org/ftp/python/2.7.17/python-2.7.17-macosx10.6.pkg'), + PythonConfiguration(version='3.5', identifier='cp35-macosx_10_6_' + machine, url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'), + PythonConfiguration(version='3.6', identifier='cp36-macosx_10_6_' + machine, url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.6.pkg'), + PythonConfiguration(version='3.7', identifier='cp37-macosx_10_6_' + machine, url='https://www.python.org/ftp/python/3.7.5/python-3.7.5-macosx10.6.pkg'), PythonConfiguration(version='3.8', identifier='cp38-macosx_10_9_x86_64', url='https://www.python.org/ftp/python/3.8.0/python-3.8.0-macosx10.9.pkg'), ] @@ -31,7 +31,10 @@ def build(project_dir, output_dir, test_command, test_requires, test_extras, bef built_wheel_dir = os.path.join(temp_dir, 'built_wheel') repaired_wheel_dir = os.path.join(temp_dir, 'repaired_wheel') - python_configurations = get_python_configurations(build_selector) + machine = os.environ.get('CIBW_MACOS_MACHINE', 'intel') + assert machine in ['intel', 'x86_64'] + python_configurations = get_python_configurations(build_selector, machine) + get_pip_url = 'https://bootstrap.pypa.io/get-pip.py' get_pip_script = '/tmp/get-pip.py' @@ -50,14 +53,14 @@ def call(args, env=None, cwd=None, shell=False): return subprocess.check_call(args, env=env, cwd=cwd, shell=shell) # get latest pip once and for all - call(['curl', '-L', '-o', get_pip_script, get_pip_url]) + call(['curl', '-sSLo', get_pip_script, get_pip_url]) for config in python_configurations: # if this version of python isn't installed, get it from python.org and install python_package_identifier = 'org.python.Python.PythonFramework-%s' % config.version if python_package_identifier not in installed_system_packages: # download the pkg - call(['curl', '-L', '-o', '/tmp/Python.pkg', config.url]) + call(['curl', '-sSLo', '/tmp/Python.pkg', config.url]) # install call(['sudo', 'installer', '-pkg', '/tmp/Python.pkg', '-target', '/']) # patch open ssl @@ -97,6 +100,15 @@ def call(args, env=None, cwd=None, shell=False): call(['pip', '--version'], env=env) call(['pip', 'install', '--upgrade', 'setuptools', 'wheel', 'delocate'], env=env) + # setup target platform + current_platform = subprocess.check_output(['python', '-c', 'import distutils.util; print(distutils.util.get_platform())'], env=env) + if sys.version_info[0] >= 3: + current_platform = current_platform.decode('utf8') + current_platform = current_platform.strip() + if machine == 'x86_64' and current_platform.endswith('intel'): + env['_PYTHON_HOST_PLATFORM'] = current_platform.replace('intel', 'x86_64') # cross-compilation platform override + env['ARCHFLAGS'] = '-arch x86_64' # https://github.com/python/cpython/blob/a5ed2fe0eedefa1649aa93ee74a0bafc8e628a10/Lib/_osx_support.py#L260 + # run the before_build command if before_build: before_build_prepared = prepare_command(before_build, project=abs_project_dir) @@ -117,7 +129,7 @@ def call(args, env=None, cwd=None, shell=False): # pure Python wheel or empty repair command shutil.move(built_wheel, repaired_wheel_dir) else: - repair_command_prepared = prepare_command(repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir) + repair_command_prepared = prepare_command(repair_command, wheel=built_wheel, dest_dir=repaired_wheel_dir, machine=machine) call(repair_command_prepared, env=env, shell=True) repaired_wheel = glob(os.path.join(repaired_wheel_dir, '*.whl'))[0] diff --git a/test/09_macos_x86_64/cibuildwheel_test.py b/test/09_macos_x86_64/cibuildwheel_test.py new file mode 100644 index 000000000..5c6792a00 --- /dev/null +++ b/test/09_macos_x86_64/cibuildwheel_test.py @@ -0,0 +1,17 @@ +import os, pytest +import utils + + +pytestmark = pytest.mark.skipif(utils.platform != 'macos', 'these tests are only relevant to the macOS build') + +project_dir = os.path.dirname(__file__) + + +def test(): + # build the wheels + actual_wheels = utils.cibuildwheel_run(project_dir, add_env={ + 'CIBW_MACOS_MACHINE': 'x86_64', + }) + # also check that we got the right wheels + expected_wheels = [w.replace('intel', 'x86_64') for w in utils.expected_wheels('spam', '0.1.0')] + assert set(actual_wheels) == set(expected_wheels) diff --git a/test/09_macos_x86_64/setup.py b/test/09_macos_x86_64/setup.py new file mode 100644 index 000000000..48d7c00b7 --- /dev/null +++ b/test/09_macos_x86_64/setup.py @@ -0,0 +1,12 @@ +import os + +from setuptools import setup, Extension + +if os.environ.get('CIBUILDWHEEL', '0') != '1': + raise Exception('CIBUILDWHEEL environment variable is not set to 1') + +setup( + name="spam", + ext_modules=[Extension('spam', sources=['spam.c'])], + version="0.1.0", +) diff --git a/test/09_macos_x86_64/spam.c b/test/09_macos_x86_64/spam.c new file mode 100644 index 000000000..d1ab0f225 --- /dev/null +++ b/test/09_macos_x86_64/spam.c @@ -0,0 +1,48 @@ +#include + +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) +}