osx_utils.sh 18.5 KB
Newer Older
Matthew Brett's avatar
Matthew Brett committed
1
2
3
4
#!/bin/bash
# Use with ``source osx_utils.sh``
set -e

5
6
7
8
# Get our own location on this filesystem, load common utils
MULTIBUILD_DIR=$(dirname "${BASH_SOURCE[0]}")
source $MULTIBUILD_DIR/common_utils.sh

Matthew Brett's avatar
Matthew Brett committed
9
10
11
12
MACPYTHON_URL=https://www.python.org/ftp/python
MACPYTHON_PY_PREFIX=/Library/Frameworks/Python.framework/Versions
WORKING_SDIR=working

Andrew Murray's avatar
Andrew Murray committed
13
# As of 3 Oct 2023 - latest Python of each version with binary download
Matthew Brett's avatar
Matthew Brett committed
14
# available.
Andrew Murray's avatar
Andrew Murray committed
15
# See: https://www.python.org/downloads/macos/
robbuckley's avatar
robbuckley committed
16
LATEST_2p7=2.7.18
Andrew Murray's avatar
Andrew Murray committed
17
LATEST_3p5=3.5.4
Andrew Murray's avatar
Andrew Murray committed
18
LATEST_3p6=3.6.8
Andrew Murray's avatar
Andrew Murray committed
19
LATEST_3p7=3.7.9
Andrew Murray's avatar
Andrew Murray committed
20
LATEST_3p8=3.8.10
Andrew Murray's avatar
Andrew Murray committed
21
LATEST_3p9=3.9.13
Andrew Murray's avatar
Andrew Murray committed
22
LATEST_3p10=3.10.11
Andrew Murray's avatar
Andrew Murray committed
23
24
LATEST_3p11=3.11.6
LATEST_3p12=3.12.0
Matthew Brett's avatar
Matthew Brett committed
25

Matthew Brett's avatar
Matthew Brett committed
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

function check_python {
    if [ -z "$PYTHON_EXE" ]; then
        echo "PYTHON_EXE variable not defined"
        exit 1
    fi
}

function check_pip {
    if [ -z "$PIP_CMD" ]; then
        echo "PIP_CMD variable not defined"
        exit 1
    fi
}

function check_var {
    if [ -z "$1" ]; then
        echo "required variable not defined"
        exit 1
    fi
}

function get_py_digit {
    check_python
    $PYTHON_EXE -c "import sys; print(sys.version_info[0])"
}

function get_py_mm {
    check_python
    $PYTHON_EXE -c "import sys; print('{0}.{1}'.format(*sys.version_info[0:2]))"
}

function get_py_mm_nodot {
    check_python
    $PYTHON_EXE -c "import sys; print('{0}{1}'.format(*sys.version_info[0:2]))"
}

function get_py_prefix {
    check_python
    $PYTHON_EXE -c "import sys; print(sys.prefix)"
}

function fill_pyver {
    # Convert major or major.minor format to major.minor.micro
    #
    # Hence:
    # 2 -> 2.7.11  (depending on LATEST_2p7 value)
    # 2.7 -> 2.7.11  (depending on LATEST_2p7 value)
    local ver=$1
    check_var $ver
    if [[ $ver =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
        # Major.minor.micro format already
        echo $ver
    elif [ $ver == 2 ] || [ $ver == "2.7" ]; then
        echo $LATEST_2p7
Andrew Murray's avatar
Andrew Murray committed
81
    elif [ $ver == 3 ] || [ $ver == "3.12" ]; then
Andrew Murray's avatar
Andrew Murray committed
82
        echo $LATEST_3p12
Andrew Murray's avatar
Andrew Murray committed
83
84
    elif [ $ver == "3.11" ]; then
        echo $LATEST_3p11
Andrew Murray's avatar
Andrew Murray committed
85
86
    elif [ $ver == "3.10" ]; then
        echo $LATEST_3p10
Andrew Murray's avatar
Andrew Murray committed
87
    elif [ $ver == "3.9" ]; then
Andrew Murray's avatar
Andrew Murray committed
88
89
        echo $LATEST_3p9
    elif [ $ver == "3.8" ]; then
90
91
        echo $LATEST_3p8
    elif [ $ver == "3.7" ]; then
Andrew Murray's avatar
Andrew Murray committed
92
93
        echo $LATEST_3p7
    elif [ $ver == "3.6" ]; then
Matthew Brett's avatar
Matthew Brett committed
94
95
        echo $LATEST_3p6
    elif [ $ver == "3.5" ]; then
Matthew Brett's avatar
Matthew Brett committed
96
97
        echo $LATEST_3p5
    else
98
        echo "Can't fill version $ver" 1>&2
Matthew Brett's avatar
Matthew Brett committed
99
100
101
102
        exit 1
    fi
}

103
104
105
106
107
108
109
110
111
112
113
function macpython_sdk_list_for_version {
    # return a list of SDK targets supported for a given CPython version
    # Parameters
    #   $py_version (python version in major.minor.extra format)
    # eg
    #  macpython_sdks_for_version 2.7.15
    #  >> 10.6 10.9
    local _ver=$(fill_pyver $1)
    local _major=${_ver%%.*}
    local _return

114
    if [ "$(uname -m)" = "arm64" ]; then
115
116
        _return="11.0"
    elif [ "$_major" -eq "2" ]; then
robbuckley's avatar
robbuckley committed
117
        [ $(lex_ver $_ver) -lt $(lex_ver 2.7.18) ] && _return="10.6"
118
119
120
121
122
123
124
125
126
127
128
129
130
        [ $(lex_ver $_ver) -ge $(lex_ver 2.7.15) ] && _return="$_return 10.9"
    elif [ "$_major" -eq "3" ]; then
        [ $(lex_ver $_ver) -lt $(lex_ver 3.8)    ] && _return="10.6"
        [ $(lex_ver $_ver) -ge $(lex_ver 3.6.5)  ] && _return="$_return 10.9"
    else
        echo "Error version=${_ver}, expecting 2.x or 3.x" 1>&2
        exit 1
    fi
    echo $_return
}

function macpython_sdk_for_version {
    # assumes the output of macpython_sdk_list_for_version is a list
Andrew Murray's avatar
Andrew Murray committed
131
    # of SDK versions XX.Y in sorted order, eg "10.6 10.9" or "10.9"
132
133
134
    echo $(macpython_sdk_list_for_version $1) | awk -F' ' '{print $NF}'
}

Matthew Brett's avatar
Matthew Brett committed
135
136
137
138
139
140
141
142
function pyinst_ext_for_version {
    # echo "pkg" or "dmg" depending on the passed Python version
    # Parameters
    #   $py_version (python version in major.minor.extra format)
    #
    # Earlier Python installers are .dmg, later are .pkg.
    local py_version=$1
    check_var $py_version
143
    py_version=$(fill_pyver $py_version)
Matthew Brett's avatar
Matthew Brett committed
144
145
    local py_0=${py_version:0:1}
    if [ $py_0 -eq 2 ]; then
146
        if [ "$(lex_ver $py_version)" -ge "$(lex_ver 2.7.9)" ]; then
Matthew Brett's avatar
Matthew Brett committed
147
148
149
150
151
            echo "pkg"
        else
            echo "dmg"
        fi
    elif [ $py_0 -ge 3 ]; then
Andrew Murray's avatar
Andrew Murray committed
152
		echo "pkg"
Matthew Brett's avatar
Matthew Brett committed
153
154
155
    fi
}

156
function pyinst_fname_for_version {
157
    # echo filename for OSX installer file given Python and minimum
158
    # macOS versions
159
    # Parameters
160
    #   $py_version (Python version in major.minor.extra format)
161
    #   $py_osx_ver: {major.minor | not defined}
162
163
164
    #       if defined, the minimum macOS SDK version that Python is
    #       built for, eg: "10.6" or "10.9", if not defined, infers
    #       this from $py_version using macpython_sdk_for_version
165
166
    local py_version=$1
    local inst_ext=$(pyinst_ext_for_version $py_version)
Isuru Fernando's avatar
Isuru Fernando committed
167
168
169
    # Use the universal2 installer if we are on arm64
    # universal2 installer for python 3.8 needs macos 11.0 to run on
    # and therefore x86_64 builds use the intel only installer.
170
171
172
173
    # Note that intel only installer can create universal2 wheels, but
    # creates intel only wheels by default. When PLAT=universal2
    # we set the env variable _PYTHON_HOST_PLATFORM to change this
    # default.
174
    if [ "$(uname -m)" == "arm64" ] || [ $(lex_ver $py_version) -ge $(lex_ver 3.10.0) ]; then
Isuru Fernando's avatar
Isuru Fernando committed
175
176
177
178
179
      if [ "$py_version" == "3.9.1" ]; then
        echo "python-${py_version}-macos11.0.${inst_ext}"
      else
        echo "python-${py_version}-macos11.${inst_ext}"
      fi
180
    else
181
      local py_osx_ver=${2:-$(macpython_sdk_for_version $py_version)}
182
183
      echo "python-${py_version}-macosx${py_osx_ver}.${inst_ext}"
    fi
184
185
}

186
function get_macpython_arch {
robbuckley's avatar
robbuckley committed
187
188
189
190
191
192
    # echo arch (e.g. intel or x86_64), extracted from the distutils platform tag
    # Parameters
    #   $distutils_plat   PEP425 style platform tag, or if not provided, calls
    #                       the function get_distutils_platform, provided by
    #                       common_utils.sh. Fails if this is not a mac platform
    #
Andrew Murray's avatar
Andrew Murray committed
193
    # Note: MUST only be called after the version of Python used to build the
robbuckley's avatar
robbuckley committed
194
195
    # target wheel has been installed and is on the path
    local distutils_plat=${1:-$(get_distutils_platform)}
Isuru Fernando's avatar
Isuru Fernando committed
196
    if [[ $distutils_plat =~ macosx-(1[0-9]\.[0-9]+)-(.*) ]]; then
197
198
        echo ${BASH_REMATCH[2]}
    else
robbuckley's avatar
robbuckley committed
199
        echo "Error parsing macOS distutils platform '$distutils_plat'"
200
201
202
203
204
        exit 1
    fi
}

function get_macpython_osx_ver {
robbuckley's avatar
robbuckley committed
205
206
207
208
209
210
    # echo minimum macOS version (e.g. 10.9) from the distutils platform tag
    # Parameters
    #   $distutils_plat   PEP425 style platform tag, or if not provided, calls
    #                       the function get_distutils_platform, provided by
    #                       common_utils.sh. Fails if this is not a mac platform
    #
Andrew Murray's avatar
Andrew Murray committed
211
    # Note: MUST only be called after the version of Python used to build the
robbuckley's avatar
robbuckley committed
212
213
    # target wheel has been installed and is on the path
    local distutils_plat=${1:-$(get_distutils_platform)}
Isuru Fernando's avatar
Isuru Fernando committed
214
    if [[ $distutils_plat =~ macosx-(1[0-9]\.[0-9]+)-(.*) ]]; then
215
216
        echo ${BASH_REMATCH[1]}
    else
robbuckley's avatar
robbuckley committed
217
        echo "Error parsing macOS distutils platform '$distutils_plat'"
218
219
220
        exit 1
    fi
}
221

222
function macpython_arch_for_version {
223
224
    # echo arch (intel or x86_64) that a version of Python is expected
    # to be built for
225
    # Parameters
226
227
    #   $py_ver     Python version, in the format (major.minor.patch) for
    #               CPython, or pypy-(major.minor) for PyPy
228
    #   $py_osx_ver minimum macOS version the target Python is built for
229
    #               (major.minor)
230
231
232
233
234
235
236
237
238
    local py_ver=$1
    local py_osx_ver=${2:-$MB_PYTHON_OSX_VER}
    check_var $1
    if [[ $(macpython_impl_for_version $py_ver) == "cp" ]]; then
        if [[ "$py_osx_ver" == "10.6" ]]; then
            echo "intel"
        elif [[ "$py_osx_ver" == "10.9" ]]; then
            echo "x86_64"
        else
239
            echo "Unexpected CPython macOS version: ${py_osx_ver}, supported values: 10.6 and 10.9"
240
241
242
            exit 1
        fi
    else
Rob Buckley's avatar
Rob Buckley committed
243
        echo "x86_64"
244
245
246
247
248
249
    fi
}

function macpython_impl_for_version {
    # echo Python implementation (cp for CPython, pp for PyPy) given a
    # suitably formatted version string
250
251
    # Parameters:
    #     $version : [implementation-]major[.minor[.patch]]
252
253
    #         Python implementation, e.g. "3.6" for CPython or
    #         "pypy-5.4" for PyPy
254
    local version=$1
255
    check_var $1
mattip's avatar
mattip committed
256
    if [[ "$version" =~ ^pypy ]]; then
257
        echo pp
258
    elif [[ "$version" =~ ([0-9\.]+) ]]; then
259
        echo cp
Kyle Stewart's avatar
Kyle Stewart committed
260
    else
Matt Bachmann's avatar
Matt Bachmann committed
261
        echo "config error: Issue parsing this implementation in install_python:"
262
        echo "    version=$version"
Kyle Stewart's avatar
Kyle Stewart committed
263
264
265
266
        exit 1
    fi
}

267
function strip_macpython_ver_prefix {
268
    # strip any implementation prefix from a Python version string
269
270
271
272
273
274
275
276
277
278
279
    # Parameters:
    #     $version : [implementation-]major[.minor[.patch]]
    #         Python implementation, e.g. "3.6" for CPython or
    #         "pypy-5.4" for PyPy
    local version=$1
    check_var $1
    if [[ "$version" =~ (pypy-)?([0-9\.]+) ]]; then
        echo ${BASH_REMATCH[2]}
    fi
}

280
281
282
283
function install_macpython {
    # Install Python and set $PYTHON_EXE to the installed executable
    # Parameters:
    #     $version : [implementation-]major[.minor[.patch]]
mattip's avatar
mattip committed
284
    #         The Python implementation to install, e.g. "3.6", "pypy-5.4" or "pypy3.6-7.2"
285
    #     $py_osx_ver: {major.minor | not defined}
286
287
    #       if defined, the macOS version that CPython is built for, e.g.
    #       "10.6" or "10.9". Ignored for PyPy
288
    local version=$1
289
    local py_osx_ver=$2
290
291
    local impl=$(macpython_impl_for_version $version)
    if [[ "$impl" == "pp" ]]; then
mattip's avatar
mattip committed
292
        install_pypy $version
293
    elif [[ "$impl" == "cp" ]]; then
294
        local stripped_ver=$(strip_macpython_ver_prefix $version)
295
        install_mac_cpython $stripped_ver $py_osx_ver
Kyle Stewart's avatar
Kyle Stewart committed
296
    else
297
        echo "Unexpected Python impl: ${impl}"
Kyle Stewart's avatar
Kyle Stewart committed
298
299
300
301
        exit 1
    fi
}

302
function install_mac_cpython {
Matthew Brett's avatar
Matthew Brett committed
303
    # Installs Python.org Python
304
305
306
    # Parameters
    #   $py_version
    #       Version given in major or major.minor or major.minor.micro e.g
Andrew Murray's avatar
Andrew Murray committed
307
    #       "3" or "3.7" or "3.7.1".
308
    #   $py_osx_ver
309
    #       {major.minor | not defined}
310
    #       if defined, the macOS version that Python is built for, e.g.
311
    #        "10.6" or "10.9"
312
    # sets $PYTHON_EXE variable to Python executable
Matthew Brett's avatar
Matthew Brett committed
313
    local py_version=$(fill_pyver $1)
Rob Buckley's avatar
Rob Buckley committed
314
    local py_osx_ver=$2
315
    local py_stripped=$(strip_ver_suffix $py_version)
316
    local py_inst=$(pyinst_fname_for_version $py_version $py_osx_ver)
Matthew Brett's avatar
Matthew Brett committed
317
    local inst_path=$DOWNLOADS_SDIR/$py_inst
robbuckley's avatar
robbuckley committed
318
    local retval=""
Matthew Brett's avatar
Matthew Brett committed
319
    mkdir -p $DOWNLOADS_SDIR
robbuckley's avatar
robbuckley committed
320
    # exit early on curl errors, but don't let it exit the shell
robbuckley's avatar
robbuckley committed
321
322
323
324
325
326
    cmd_notexit curl -f $MACPYTHON_URL/$py_stripped/${py_inst} > $inst_path || retval=$?
    if [ ${retval:-0} -ne 0 ]; then
      echo "Python download failed! Check ${py_inst} exists on the server."
      exit $retval
    fi

327
    if [ "${py_inst: -3}" == "dmg" ]; then
Matthew Brett's avatar
Matthew Brett committed
328
329
330
331
        hdiutil attach $inst_path -mountpoint /Volumes/Python
        inst_path=/Volumes/Python/Python.mpkg
    fi
    sudo installer -pkg $inst_path -target /
332
    local py_mm=${py_version%.*}
Matthew Brett's avatar
Matthew Brett committed
333
    PYTHON_EXE=$MACPYTHON_PY_PREFIX/$py_mm/bin/python$py_mm
334
335
336
337
338
    # Install certificates for Python 3.6
    local inst_cmd="/Applications/Python ${py_mm}/Install Certificates.command"
    if [ -e "$inst_cmd" ]; then
        sh "$inst_cmd"
    fi
Matthew Brett's avatar
Matthew Brett committed
339
340
341
342
343
344
345
346
347
348
349
}

function install_virtualenv {
    # Generic install of virtualenv
    # Installs virtualenv into python given by $PYTHON_EXE
    # Assumes virtualenv will be installed into same directory as $PYTHON_EXE
    check_pip
    # Travis VMS install virtualenv for system python by default - force
    # install even if installed already
    $PIP_CMD install virtualenv --ignore-installed
    check_python
350
    VIRTUALENV_CMD="$(dirname $PYTHON_EXE)/virtualenv"
Matthew Brett's avatar
Matthew Brett committed
351
352
353
354
355
356
357
358
359
360
361
362
363
}

function make_workon_venv {
    # Make a virtualenv in given directory ('venv' default)
    # Set $PYTHON_EXE, $PIP_CMD to virtualenv versions
    # Parameter $venv_dir
    #    directory for virtualenv
    local venv_dir=$1
    if [ -z "$venv_dir" ]; then
        venv_dir="venv"
    fi
    venv_dir=`abspath $venv_dir`
    check_python
xoviat's avatar
xoviat committed
364
    $PYTHON_EXE -m virtualenv $venv_dir
Matthew Brett's avatar
Matthew Brett committed
365
366
367
368
369
370
    PYTHON_EXE=$venv_dir/bin/python
    PIP_CMD=$venv_dir/bin/pip
}

function remove_travis_ve_pip {
    # Remove travis installs of virtualenv and pip
xoviat's avatar
xoviat committed
371
372
    # FIXME: What if virtualenv is installed but pip is not?
    if [ "$(sudo which virtualenv)" == /usr/local/bin/virtualenv ] && [ "$(sudo which pip)" == /usr/local/bin/pip ]; then
Matthew Brett's avatar
Matthew Brett committed
373
374
375
376
377
378
379
380
        sudo pip uninstall -y virtualenv;
    fi
    if [ "$(sudo which pip)" == /usr/local/bin/pip ]; then
        sudo pip uninstall -y pip;
    fi
}

function set_py_vars {
381
    # Used by terryfy project; left here for back-compatibility
Matthew Brett's avatar
Matthew Brett committed
382
383
384
385
    export PATH="`dirname $PYTHON_EXE`:$PATH"
    export PYTHON_EXE PIP_CMD
}

386
function get_macpython_environment {
Matthew Brett's avatar
Matthew Brett committed
387
388
    # Set up MacPython environment
    # Parameters:
389
390
    #     $version : [implementation-]major[.minor[.patch]]
    #         The Python implementation to install, e.g. "3.6" or "pypy-5.4"
Matthew Brett's avatar
Matthew Brett committed
391
392
393
    #     $venv_dir : {directory_name|not defined}
    #         If defined - make virtualenv in this directory, set python / pip
    #         commands accordingly
394
    #     $py_osx_ver: {major.minor | not defined}
395
396
    #         if defined, the macOS version that Python is built for, e.g.
    #         "10.6" or "10.9", if not defined, use the version from MB_PYTHON_OSX_VER
Matthew Brett's avatar
Matthew Brett committed
397
398
399
400
401
402
    #
    # Installs Python
    # Sets $PYTHON_EXE to path to Python executable
    # Sets $PIP_CMD to full command for pip (including sudo if necessary)
    # If $venv_dir defined, Sets $VIRTUALENV_CMD to virtualenv executable
    # Puts directory of $PYTHON_EXE on $PATH
403
404
    local version=$1
    local venv_dir=$2
405
    local py_osx_ver=${3:-$MB_PYTHON_OSX_VER}
xoviat's avatar
xoviat committed
406
407
408
409

    if [ "$USE_CCACHE" == "1" ]; then
        activate_ccache
    fi
410

Matthew Brett's avatar
Matthew Brett committed
411
    remove_travis_ve_pip
412
    install_macpython $version $py_osx_ver
Matthew Brett's avatar
Matthew Brett committed
413
    PIP_CMD="$PYTHON_EXE -m pip"
Matthew Brett's avatar
Matthew Brett committed
414
415
416
    # Python 3.5 no longer compatible with latest pip
    if [ "$(get_py_mm)" == "3.5" ]; then
        # https://stackoverflow.com/a/29751768/1939576
417
        curl -LO https://bootstrap.pypa.io/pip/3.5/get-pip.py
Matthew Brett's avatar
Matthew Brett committed
418
419
420
421
422
423
        $PYTHON_EXE get-pip.py
        rm get-pip.py
    else
        $PYTHON_EXE -m ensurepip
        $PIP_CMD install --upgrade pip
    fi
xoviat's avatar
xoviat committed
424

Matthew Brett's avatar
Matthew Brett committed
425
426
427
    if [ -n "$venv_dir" ]; then
        install_virtualenv
        make_workon_venv $venv_dir
428
429
430
        source $venv_dir/bin/activate
    else
        export PATH="`dirname $PYTHON_EXE`:$PATH"
Matthew Brett's avatar
Matthew Brett committed
431
    fi
432
    export PYTHON_EXE PIP_CMD
Matthew Brett's avatar
Matthew Brett committed
433
}
434

435
function install_delocate {
436
437
    check_pip
    $PIP_CMD install delocate
438
439
440
441
442
}

function repair_wheelhouse {
    local wheelhouse=$1
    install_delocate
443
444
    delocate-wheel $wheelhouse/*.whl # copies library dependencies into wheel
}
445
446
447
448

function install_pkg_config {
    # Install pkg-config avoiding error from homebrew
    # See :
Hugo van Kemenade's avatar
Hugo van Kemenade committed
449
    # https://github.com/multi-build/multibuild/issues/24#issue-221951587
450
451
    command -v pkg-config > /dev/null 2>&1 || brew install pkg-config
}
xoviat's avatar
xoviat committed
452
453

function activate_ccache {
xoviat's avatar
xoviat committed
454

xoviat's avatar
xoviat committed
455
456
457
458
459
    brew install ccache
    export PATH=/usr/local/opt/ccache/libexec:$PATH
    export CCACHE_CPP2=1

    # Prove to the developer that ccache is activated
xoviat's avatar
xoviat committed
460
    echo "Using C compiler: $(which clang)"
xoviat's avatar
xoviat committed
461
}
462

463
function macos_intel_native_build_setup {
Isuru Fernando's avatar
Isuru Fernando committed
464
    # Setup native build for single arch x86_64 wheels
465
    export PLAT="x86_64"
466
    export _PYTHON_HOST_PLATFORM="macosx-${MB_PYTHON_OSX_VER}-x86_64"
467
468
    export CFLAGS+=" -arch x86_64"
    export CXXFLAGS+=" -arch x86_64"
469
    [[ $ARCHFLAGS =~ "-arch x86_64" ]] || export ARCHFLAGS+=" -arch x86_64"
470
471
472
473
    export CPPFLAGS+=" -arch x86_64"
    export LDFLAGS+=" -arch x86_64"
}

474
function macos_intel_cross_build_setup {
Isuru Fernando's avatar
Isuru Fernando committed
475
    echo "universal2 builds on arm64 are not supported yet."
476
477
478
479
480
    exit 1
}

function macos_arm64_cross_build_setup {
    # Setup cross build for single arch arm_64 wheels
481
482
    export PLAT="arm64"
    export BUILD_PREFIX=/opt/arm64-builds
483
    sudo mkdir -p $BUILD_PREFIX/lib $BUILD_PREFIX/include
484
485
486
487
488
489
    sudo chown -R $USER $BUILD_PREFIX
    update_env_for_build_prefix
    export _PYTHON_HOST_PLATFORM="macosx-11.0-arm64"
    export CFLAGS+=" -arch arm64"
    export CXXFLAGS+=" -arch arm64"
    export CPPFLAGS+=" -arch arm64"
490
    [[ $ARCHFLAGS =~ "-arch arm64" ]] || export ARCHFLAGS+=" -arch arm64"
491
492
    export FCFLAGS+=" -arch arm64"
    export FC=$FC_ARM64
493
494
    export F90=${F90_ARM64:-${FC}}
    export F77=${F77_ARM64:-${FC}}
495
    export MACOSX_DEPLOYMENT_TARGET="11.0"
496
    export CROSS_COMPILING=1
497
498
499
500
501
    export LDFLAGS+=" -arch arm64 -L$BUILD_PREFIX/lib -Wl,-rpath,$BUILD_PREFIX/lib ${FC_ARM64_LDFLAGS:-}"
    # This would automatically let autoconf know that we are cross compiling for arm64 darwin
    export host_alias="aarch64-apple-darwin20.0.0"
}

502
503
504
function macos_arm64_native_build_setup {
    # Setup native build for single arch arm_64 wheels
    export PLAT="arm64"
Isuru Fernando's avatar
Isuru Fernando committed
505
    # We don't want universal2 builds and only want an arm64 build
506
    export _PYTHON_HOST_PLATFORM="macosx-11.0-arm64"
507
    export ARCHFLAGS+=" -arch arm64"
508
509
510
    $@
}

511
512
function fuse_macos_intel_arm64 {
    local wheelhouse=$(abspath ${WHEEL_SDIR:-wheelhouse})
513
    local py_osx_ver=$(echo ${MACOSX_DEPLOYMENT_TARGET} | sed "s/\./_/g")
Isuru Fernando's avatar
Isuru Fernando committed
514
    mkdir -p tmp_fused_wheelhouse
515
    for whl in $wheelhouse/*.whl; do
Isuru Fernando's avatar
Isuru Fernando committed
516
       if [[ "$whl" == *macosx_${py_osx_ver}_x86_64.whl ]]; then
517
           whl_base=$(sed "s/macosx_${py_osx_ver}_x86_64.whl//" <<< $whl)
518
           if [[ -f "${whl_base}macosx_11_0_arm64.whl" ]]; then
Isuru Fernando's avatar
Isuru Fernando committed
519
               delocate-fuse $whl "${whl_base}macosx_11_0_arm64.whl" -w tmp_fused_wheelhouse
Isuru Fernando's avatar
Isuru Fernando committed
520
               mv tmp_fused_wheelhouse/$(basename $whl) $wheelhouse/$(basename ${whl_base})macosx_${py_osx_ver}_universal2.whl
521
               # Since we want one wheel that's installable for testing we are deleting the *_x86_64 wheel.
522
523
524
525
526
527
528
529
530
531
               # We are not deleting arm64 wheel because the size is lower and homebrew/conda-forge python
               # will use them by default
               rm $whl
           fi
       fi
    done
}

function wrap_wheel_builder {
    if [[ "${PLAT:-}" == "universal2" ]]; then
532
533
534
535
536
537
538
539
540
        if [[ "$(uname -m)" == "arm64" ]]; then
            (macos_intel_cross_build_setup && $@)
            rm -rf *-stamp
            (macos_arm64_native_build_setup && $@)
        else
            (macos_intel_native_build_setup && $@)
            rm -rf *-stamp
            (macos_arm64_cross_build_setup && $@)
        fi
541
        fuse_macos_intel_arm64
542
543
544
545
546
547
    elif [[ "${PLAT:-}" == "arm64" ]]; then
        if [[ "$(uname -m)" == "arm64" ]]; then
            (macos_arm64_native_build_setup && $@)
        else
            (macos_arm64_cross_build_setup && $@)
        fi
Isuru Fernando's avatar
Isuru Fernando committed
548
    elif [[ "${PLAT:-}" == "x86_64" ]]; then
549
550
551
552
553
        if [[ "$(uname -m)" == "x86_64" ]]; then
            (macos_intel_native_build_setup && $@)
        else
            (macos_intel_cross_build_setup && $@)
        fi
Isuru Fernando's avatar
Isuru Fernando committed
554
555
    else
        $@
556
557
    fi
}