Skip to content

Commit

Permalink
Add option to build x86_64 only on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
mayeut committed Nov 20, 2019
1 parent 09e7280 commit bfbc981
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 10 deletions.
2 changes: 1 addition & 1 deletion cibuildwheel/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
30 changes: 21 additions & 9 deletions cibuildwheel/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
]

Expand All @@ -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'

Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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]

Expand Down
17 changes: 17 additions & 0 deletions test/09_macos_x86_64/cibuildwheel_test.py
Original file line number Diff line number Diff line change
@@ -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)
12 changes: 12 additions & 0 deletions test/09_macos_x86_64/setup.py
Original file line number Diff line number Diff line change
@@ -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",
)
48 changes: 48 additions & 0 deletions test/09_macos_x86_64/spam.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <Python.h>

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)
}

0 comments on commit bfbc981

Please sign in to comment.