chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# pylint: disable=invalid-name
|
||||
# ruff: noqa: E501, RUF005
|
||||
"""Utility to invoke Xcode compiler toolchain"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from . import utils
|
||||
|
||||
|
||||
def xcrun(cmd):
|
||||
"""Run xcrun and return the output.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cmd : list of str
|
||||
The command sequence.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : str
|
||||
The output string.
|
||||
"""
|
||||
cmd = ["xcrun"] + cmd
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
(out, _) = proc.communicate()
|
||||
return out.strip()
|
||||
|
||||
|
||||
def __get_min_os_version(sdk):
|
||||
if sdk == "macosx":
|
||||
return None
|
||||
if sdk in ("iphoneos", "iphonesimulator"):
|
||||
return "13.0"
|
||||
raise RuntimeError(f"Unsupported sdk: {sdk}")
|
||||
|
||||
|
||||
def __get_min_os_version_cmd(sdk, min_os_version):
|
||||
if min_os_version is None:
|
||||
min_os_version = __get_min_os_version(sdk)
|
||||
if min_os_version is not None:
|
||||
return "-mios-version-min=" + min_os_version
|
||||
return ""
|
||||
|
||||
|
||||
def create_dylib(output, objects, arch, sdk="macosx", min_os_version=None):
|
||||
"""Create dynamic library.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
output : str
|
||||
The target shared library.
|
||||
|
||||
objects : list
|
||||
List of object files.
|
||||
|
||||
options : str
|
||||
The additional options.
|
||||
|
||||
arch : str
|
||||
Target major architectures
|
||||
|
||||
sdk : str
|
||||
The sdk to be used.
|
||||
"""
|
||||
clang = xcrun(["-sdk", sdk, "-find", "clang"])
|
||||
sdk_path = xcrun(["-sdk", sdk, "--show-sdk-path"])
|
||||
cmd = [clang]
|
||||
cmd += ["-dynamiclib"]
|
||||
cmd += ["-arch", arch]
|
||||
cmd += ["-isysroot", sdk_path]
|
||||
cmd += [__get_min_os_version_cmd(sdk, min_os_version)]
|
||||
cmd += ["-o", output]
|
||||
if isinstance(objects, str):
|
||||
cmd += [objects]
|
||||
else:
|
||||
cmd += objects
|
||||
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
(out, _) = proc.communicate()
|
||||
|
||||
if proc.returncode != 0:
|
||||
msg = "Compilation error:\n"
|
||||
msg += out.decode("utf-8", errors="replace")
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
||||
# assign so as default output format
|
||||
create_dylib.output_format = "dylib"
|
||||
|
||||
|
||||
def compile_metal(code, path_target=None, sdk="macosx", min_os_version=None):
|
||||
"""Compile Metal with CLI tool from env.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
code : str
|
||||
The Metal code.
|
||||
|
||||
path_target : str, optional
|
||||
Output file.
|
||||
|
||||
sdk : str, optional
|
||||
The target platform SDK.
|
||||
|
||||
Return
|
||||
------
|
||||
metallib : bytearray
|
||||
The bytearray of the metallib
|
||||
"""
|
||||
temp = utils.tempdir()
|
||||
temp_code = temp.relpath("my_lib.metal")
|
||||
temp_ir = temp.relpath("my_lib.air")
|
||||
temp_target = temp.relpath("my_lib.metallib")
|
||||
|
||||
with open(temp_code, "w") as out_file:
|
||||
out_file.write(code)
|
||||
file_target = path_target if path_target else temp_target
|
||||
|
||||
# See:
|
||||
# - https://developer.apple.com/documentation/metal/gpu_functions_libraries/building_a_library_with_metal_s_command-line_tools#overview # pylint: disable=line-too-long
|
||||
#
|
||||
# xcrun -sdk macosx metal -c MyLibrary.metal -o MyLibrary.air
|
||||
# xcrun -sdk macosx metallib MyLibrary.air -o MyLibrary.metallib
|
||||
min_target = __get_min_os_version_cmd(sdk, min_os_version)
|
||||
if sdk == "macosx":
|
||||
language_version = "-std=macos-metal2.3"
|
||||
elif sdk in ("iphoneos", "iphonesimulator"):
|
||||
language_version = "-std=ios-metal2.3"
|
||||
else:
|
||||
raise RuntimeError(f"Unsupported sdk: {sdk}")
|
||||
cmd1 = ["xcrun", "-sdk", sdk, "metal", language_version, min_target, "-O3"]
|
||||
cmd1 += ["-c", temp_code, "-o", temp_ir]
|
||||
cmd2 = ["xcrun", "-sdk", sdk, "metallib"]
|
||||
cmd2 += [temp_ir, "-o", file_target]
|
||||
proc = subprocess.Popen(
|
||||
" ".join(cmd1) + ";" + " ".join(cmd2),
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
(out, _) = proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
sys.stderr.write("Compilation error:\n")
|
||||
sys.stderr.write(out.decode("utf-8", errors="replace"))
|
||||
sys.stderr.flush()
|
||||
libbin = None
|
||||
else:
|
||||
libbin = bytearray(open(file_target, "rb").read())
|
||||
return libbin
|
||||
|
||||
|
||||
def compile_coreml(model, model_name="main", out_dir="."):
|
||||
"""Compile coreml model and return the compiled model path."""
|
||||
mlmodel_path = os.path.join(out_dir, model_name + ".mlmodel")
|
||||
mlmodelc_path = os.path.join(out_dir, model_name + ".mlmodelc")
|
||||
metadata = {"inputs": list(model.input_description), "outputs": list(model.output_description)}
|
||||
# Use the description field to send info to CoreML runtime
|
||||
model.short_description = json.dumps(metadata)
|
||||
model.save(mlmodel_path)
|
||||
|
||||
res = xcrun(["coremlcompiler", "compile", mlmodel_path, out_dir])
|
||||
if not os.path.isdir(mlmodelc_path):
|
||||
raise RuntimeError(f"Compile failed: {res}")
|
||||
|
||||
return mlmodelc_path
|
||||
Reference in New Issue
Block a user