diff options
author | Simo Fält <simo.falt@qt.io> | 2021-11-25 16:08:21 +0200 |
---|---|---|
committer | Simo Fält <simo.falt@qt.io> | 2022-04-11 17:49:05 +0300 |
commit | 4187f1d7bfba5b519cfa0880fce6f793c0ffb6f1 (patch) | |
tree | 1f51bd82b9175a94b41b21514b353e08fc4db533 | |
parent | ed759eaa5665d3c9f134ffd75d41edc3fc22a462 (diff) |
Build macOS universal binary
Collection of bits and pieces to enable MacOS universal
wheel creation in Qt CI.
Change-Id: I0a889258ec4f89ca3a26c8bf2ee76f0d5c676a7a
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r-- | build_scripts/utils.py | 16 | ||||
-rw-r--r-- | coin/instructions/common_environment.yaml | 30 | ||||
-rw-r--r-- | coin/instructions/execute_build_instructions.yaml | 29 | ||||
-rw-r--r-- | coin/instructions/execute_test_instructions.yaml | 30 | ||||
-rw-r--r-- | coin/module_config.yaml | 12 | ||||
-rw-r--r-- | coin_build_instructions.py | 40 | ||||
-rw-r--r-- | coin_test_instructions.py | 32 |
7 files changed, 157 insertions, 32 deletions
diff --git a/build_scripts/utils.py b/build_scripts/utils.py index 5d62d4307..49839e2de 100644 --- a/build_scripts/utils.py +++ b/build_scripts/utils.py @@ -47,6 +47,7 @@ import subprocess import fnmatch import itertools import glob +from os.path import expanduser # There is no urllib.request in Python2 try: @@ -1157,7 +1158,7 @@ def install_pip_dependencies(env_pip, packages, upgrade=True): def get_qtci_virtualEnv(python_ver, host, hostArch, targetArch): - _pExe = "python" + _pExe = "python2" _env = "env{}".format(str(python_ver)) env_python = _env + "/bin/python" env_pip = _env + "/bin/pip" @@ -1229,3 +1230,16 @@ def get_ci_qmake_path(ci_install_dir, ci_host_os): return qmake_path + "\\bin\\qmake.exe" else: return qmake_path + "/bin/qmake" + + +def provisioning(): + home = expanduser("~") + file = "https://download.qt.io/development_releases/prebuilt/libclang/libclang-release_100-based-dyn-mac-universal.7z" + target = os.path.join(home, "libclang-dynlibs-10.0-universal") + try: + download_and_extract_7z(file, target) + except RuntimeError as e: + print("debug: Exception error: {}".format(e)) + file = file.replace("s://download","://master") + print("New url: {}".format(file)) + download_and_extract_7z(file, target)
\ No newline at end of file diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index 41ab0059c..cf391324e 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -119,6 +119,32 @@ instructions: variableName: LLVM_INSTALL_DIR variableValue: "{{.Env.LLVM_DYNAMIC_LIBS_100}}" disable_if: + condition: and + conditions: + - condition: property + property: target.arch + equals_value: X86_64-ARM64 # When target arch is universal binary, we can use the default libclang + - condition: property + property: host.os + equals_value: MacOS + - type: EnvironmentVariable + variableName: LLVM_INSTALL_DIR + variableValue: "/Users/qt/libclang-dynlibs-10.0-universal/libclang-dynlibs-10.0" + enable_if: + condition: and + conditions: + - condition: property + property: target.arch + equals_value: X86_64-ARM64 # When target arch is universal binary, we can use the default libclang + - condition: property + property: host.os + equals_value: MacOS + - type: PrependToEnvironmentVariable + variableName: PATH + variableValue: "/Library/Frameworks/Python.framework/Versions/3.9/bin:" + enable_if: condition: property - property: host.osVersion - equals_value: openSUSE_15_1 + property: host.os + equals_value: MacOS + + diff --git a/coin/instructions/execute_build_instructions.yaml b/coin/instructions/execute_build_instructions.yaml index e940e9250..ffd1ad5cc 100644 --- a/coin/instructions/execute_build_instructions.yaml +++ b/coin/instructions/execute_build_instructions.yaml @@ -1,13 +1,34 @@ type: Group instructions: - type: ExecuteCommand - command: "python -u coin_build_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=/Users/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch=X86_64 --targetArch={{.Env.CI_TARGET_ARCHITECTURE}} --phase=ALL" + command: "python -u coin_build_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=/Users/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch={{.Env.HOS_ARCH_COIN}} --targetArch={{.Env.TARGET_ARCH_COIN}} --phase=ALL" maxTimeInSeconds: 14400 maxTimeBetweenOutput: 1200 enable_if: - condition: property - property: host.os - equals_value: MacOS + condition: and + conditions: + - condition: property + property: target.arch + equals_value: X86_64 + - condition: property + property: host.os + equals_value: MacOS + userMessageOnFailure: > + Failed to execute build instructions on osx + + - type: ExecuteCommand + command: "python3 -u coin_build_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} {{.Env.CI_USE_SCCACHE}} --instdir=/Users/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch=={{.Env.HOST_ARCH_COIN}} --targetArch=X86_64-ARM64 --phase=ALL" + maxTimeInSeconds: 14400 + maxTimeBetweenOutput: 1200 + enable_if: + condition: and + conditions: + - condition: property + property: target.arch + equals_value: X86_64-ARM64 + - condition: property + property: host.os + equals_value: MacOS userMessageOnFailure: > Failed to execute build instructions on osx - type: ExecuteCommand diff --git a/coin/instructions/execute_test_instructions.yaml b/coin/instructions/execute_test_instructions.yaml index f5dd7aa50..b30ec2b92 100644 --- a/coin/instructions/execute_test_instructions.yaml +++ b/coin/instructions/execute_test_instructions.yaml @@ -8,15 +8,35 @@ instructions: variableName: QTEST_ENVIRONMENT variableValue: "ci" - type: ExecuteCommand - command: "python -u coin_test_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=/Users/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch=X86_64 --targetArch={{.Env.CI_TARGET_ARCHITECTURE}}" + command: "python -u coin_test_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=/Users/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch=X86_64 --targetArch={{.Env.TARGET_ARCH_COIN}}" maxTimeInSeconds: 14400 maxTimeBetweenOutput: 1200 enable_if: - condition: property - property: host.os - equals_value: MacOS + condition: and + conditions: + - condition: property + property: target.arch + equals_value: X86_64 + - condition: property + property: host.os + equals_value: MacOS + userMessageOnFailure: > + Failed to execute test instructions on osx + - type: ExecuteCommand + command: "python -u coin_test_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=/Users/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch=X86_64 --targetArch=X86_64-ARM64" + maxTimeInSeconds: 14400 + maxTimeBetweenOutput: 1200 + enable_if: + condition: and + conditions: + - condition: property + property: target.arch + equals_value: X86_64-ARM64 + - condition: property + property: host.os + equals_value: MacOS userMessageOnFailure: > - Failed to execute test instructions on osx + Failed to execute test instructions on osx - type: ExecuteCommand command: "python -u coin_test_instructions.py --os={{.Env.CI_OS}} {{.Env.CI_PACKAGING_FEATURE}} --instdir=/home/qt/work/install --targetOs={{.Env.CI_OS}} --hostArch=X86_64 --targetArch={{.Env.CI_TARGET_ARCHITECTURE}}" maxTimeInSeconds: 14400 diff --git a/coin/module_config.yaml b/coin/module_config.yaml index d736b2355..ce6b58a7d 100644 --- a/coin/module_config.yaml +++ b/coin/module_config.yaml @@ -18,10 +18,20 @@ accept_configuration: not_contains_value: -no-gui - condition: property # Following configs are not supported property: target.osVersion - not_in_values: [OPENSUSE_13_01, QEMU, WebAssembly, Ubuntu_18_04, SLES_12, SLES_15, MacOS_10_15, MacOS_11_00] + not_in_values: [openSUSE_15_1, OPENSUSE_13_01, QEMU, WebAssembly, Ubuntu_18_04, SLES_12, SLES_15, MacOS_10_15, MacOS_11_00, Windows_11_21H2] - condition: property # MibnGW and msvc2015 are not supported property: target.compiler not_in_values: [Mingw, MSVC2015] + + - condition: and + conditions: + - condition: property + property: target.osVersion + equals_value: Windows_11_21H2 + - condition: property + property: features + contains_value: Packaging + - condition: and conditions: - condition: property diff --git a/coin_build_instructions.py b/coin_build_instructions.py index 6a4d5dfd7..663633bf0 100644 --- a/coin_build_instructions.py +++ b/coin_build_instructions.py @@ -44,6 +44,7 @@ from build_scripts.utils import run_instruction from build_scripts.utils import rmtree from build_scripts.utils import get_python_dict from build_scripts.utils import get_ci_qmake_path +from build_scripts.utils import provisioning import os import datetime import calendar @@ -125,10 +126,18 @@ def call_setup(python_ver, phase): v_env = "virtualenv" run_instruction([v_env, "-p", _pExe, _env], "Failed to create virtualenv") # When the 'python_ver' variable is empty, we are using Python 2 - # Pip is always upgraded when CI template is provisioned, upgrading it in later phase may cause perm issue + try: + print("Upgrade pip") + run_instruction([env_python, "--m", "pip", "install", "--upgrade", "pip"]) + except Exception as e: + print("Failed to upgrade pip") + pass + run_instruction([env_pip, "install", "-r", "requirements.txt"], "Failed to install dependencies") if sys.platform == "win32": run_instruction([env_pip, "install", "numpy==1.19.3"], "Failed to install numpy 1.19.3") + elif os.environ.get("HOST_OSVERSION_COIN") == "macos_10_13" and python_ver == "3": + run_instruction([env_pip, "install", "numpy==1.19.4"], "Failed to install numpy") else: run_instruction([env_pip, "install", "numpy"], "Failed to install numpy") @@ -141,6 +150,12 @@ def call_setup(python_ver, phase): cmd += ["--build-tests", "--parallel=4", "--verbose-build"] + + if CI_TARGET_ARCH == "X86_64-ARM64": + cmd += ["--macos-arch='x86_64;arm64'"] + if CI_HOST_ARCH != "arm64": + cmd += ["--macos-deployment-target=10.14"] + if python_ver == "3": cmd += ["--limited-api=yes"] else: @@ -165,19 +180,28 @@ def call_setup(python_ver, phase): def run_build_instructions(phase): - # Uses default python, hopefully we have python2 installed on all hosts - # Skip building using Python 2 on Windows, because of different MSVC C runtimes (VS2008 vs VS2015+) - if CI_HOST_OS != "Windows": - call_setup("", phase) - # In case of packaging build, we have to build also python3 wheel - - if CI_RELEASE_CONF and CI_HOST_OS_VER not in ["RHEL_6_6"]: + if CI_TARGET_ARCH == "X86_64-ARM64": + # For universal wheels there will be only python3 wheel call_setup("3", phase) + else: + # Uses default python, hopefully we have python2 installed on all hosts + # Skip building using Python 2 on Windows, because of different MSVC C runtimes (VS2008 vs VS2015+) + if CI_HOST_OS != "Windows": + call_setup("2", phase) + # In case of packaging build, we have to build also python3 wheel + + if CI_RELEASE_CONF and CI_HOST_OS_VER not in ["RHEL_6_6"]: + call_setup("3", phase) + if __name__ == "__main__": # Remove some environment variables that impact cmake arch = '32' if CI_TARGET_ARCH and CI_TARGET_ARCH == 'X86' else '64' + # With 5.15.9 we are missing correct libclang so we need to install it for mac + # to create universal binaries. + if CI_HOST_OS == "MacOS" and CI_TARGET_ARCH == "X86_64-ARM64": + provisioning() expand_clang_variables(arch) for env_var in ['CC', 'CXX']: if os.environ.get(env_var): diff --git a/coin_test_instructions.py b/coin_test_instructions.py index 4ba5ac9ff..abb465223 100644 --- a/coin_test_instructions.py +++ b/coin_test_instructions.py @@ -43,6 +43,8 @@ from build_scripts.utils import get_qtci_virtualEnv from build_scripts.utils import run_instruction from build_scripts.utils import rmtree from build_scripts.utils import get_ci_qmake_path +from build_scripts.utils import provisioning + import os import site import sys @@ -85,6 +87,8 @@ def call_testrunner(python_ver, buildnro): run_instruction([env_pip, "install", "-r", "requirements.txt"], "Failed to install dependencies") if sys.platform == "win32": run_instruction([env_pip, "install", "numpy==1.19.3"], "Failed to install numpy 1.19.3") + elif os.environ.get("HOST_OSVERSION_COIN") == "macos_10_13" and python_ver == "3": + run_instruction([env_pip, "install", "numpy==1.19.4"], "Failed to install numpy") else: run_instruction([env_pip, "install", "numpy"], "Failed to install numpy") @@ -96,7 +100,7 @@ def call_testrunner(python_ver, buildnro): qmake_path = get_ci_qmake_path(CI_ENV_INSTALL_DIR, CI_HOST_OS) # Try to install built wheels, and build some buildable examples. - if CI_RELEASE_CONF: + if CI_RELEASE_CONF and CI_HOST_OS != "MacOS": wheel_tester_path = os.path.join("testing", "wheel_tester.py") cmd = [env_python, wheel_tester_path, qmake_path] run_instruction(cmd, "Error while running wheel_tester.py") @@ -104,6 +108,12 @@ def call_testrunner(python_ver, buildnro): def run_test_instructions(): # Remove some environment variables that impact cmake arch = '32' if CI_TARGET_ARCH and CI_TARGET_ARCH == 'X86' else '64' + + if CI_TARGET_ARCH == "X86_64-ARM64": + print("Install Libclang supporting universal binary") + provisioning() + else: + print("Using preinstalled libclang. While target arch was:" + str(CI_TARGET_ARCH)) expand_clang_variables(arch) for env_var in ['CC', 'CXX']: if os.environ.get(env_var): @@ -111,18 +121,18 @@ def run_test_instructions(): os.chdir(CI_ENV_AGENT_DIR) testRun = 0 - # We didn't build for Python 2 in win - if CI_HOST_OS != "Windows": + # In win machines, there are additional python versions to test with + if CI_HOST_OS == "Windows": + call_testrunner("3.6.1", str(testRun)) + call_testrunner("3.8.1", str(testRun)) + elif CI_HOST_OS == "MacOS" and CI_TARGET_ARCH=="X86_64-ARM64": + call_testrunner("3", str(testRun)) + else: call_testrunner("", str(testRun)) testRun =+ 1 - # We know that second build was with python3 - if CI_RELEASE_CONF: - # In win machines, there are additional python versions to test with - if CI_HOST_OS == "Windows": - call_testrunner("3.6.1", str(testRun)) - call_testrunner("3.8.1", str(testRun)) - else: - call_testrunner("3", str(testRun)) + call_testrunner("3", str(testRun)) if __name__ == "__main__": + print("HOST OS " + str(CI_HOST_OS)) + print("TARGET ARCH " + str(CI_TARGET_ARCH)) run_test_instructions() |