From 12d7c2f6e4eaab4f32a2ddba538641be4f45fb78 Mon Sep 17 00:00:00 2001 From: gwang-msft <62914304+gwang-msft@users.noreply.github.com> Date: Tue, 28 Apr 2020 17:09:31 -0700 Subject: [PATCH] iOS cross build on MacOS (#3699) * Enable iOS cross build on MacOS (step#1) * Changed parallel option * fixed style issues * Enable ios arm64 crossbuild on MacOS * Enable ios arm64 crossbuild on MacOS * Enable parallel build for xcode * Fix arm64 function not 4-byte aligned warning * Rename onnxruntime_ios.cmake to onnxruntime_ios.toolchain.cmake * change build.py to use the new ios toolchain file name --- cmake/onnxruntime_ios.toolchain.cmake | 5 + cmake/onnxruntime_mlas.cmake | 6 +- .../core/mlas/lib/aarch64/SgemmKernelNeon.S | 4 +- tools/ci_build/build.py | 151 +++++++++++++----- 4 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 cmake/onnxruntime_ios.toolchain.cmake diff --git a/cmake/onnxruntime_ios.toolchain.cmake b/cmake/onnxruntime_ios.toolchain.cmake new file mode 100644 index 0000000000..b181056ef4 --- /dev/null +++ b/cmake/onnxruntime_ios.toolchain.cmake @@ -0,0 +1,5 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +set(CMAKE_SYSTEM_NAME iOS) +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO) \ No newline at end of file diff --git a/cmake/onnxruntime_mlas.cmake b/cmake/onnxruntime_mlas.cmake index 9df48d93be..9d6ccc2d69 100644 --- a/cmake/onnxruntime_mlas.cmake +++ b/cmake/onnxruntime_mlas.cmake @@ -98,12 +98,16 @@ else() elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86") set(X86 TRUE) endif() - elseif(CMAKE_SYSTEM_NAME STREQUAL "iOSCross") + elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "iOSCross") set(IOS TRUE) if (CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") set(ARM64 TRUE) elseif (CMAKE_OSX_ARCHITECTURES STREQUAL "arm") set(ARM TRUE) + elseif (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64") + set(X86_64 TRUE) + elseif (CMAKE_OSX_ARCHITECTURES STREQUAL "i386") + set(X86 TRUE) endif() else() execute_process( diff --git a/onnxruntime/core/mlas/lib/aarch64/SgemmKernelNeon.S b/onnxruntime/core/mlas/lib/aarch64/SgemmKernelNeon.S index a856067420..f02ba34e23 100644 --- a/onnxruntime/core/mlas/lib/aarch64/SgemmKernelNeon.S +++ b/onnxruntime/core/mlas/lib/aarch64/SgemmKernelNeon.S @@ -19,6 +19,8 @@ Abstract: #include "asmmacro.h" .text + .p2align 2 + // // ClearRowAccumulators // @@ -431,7 +433,7 @@ Return Value: .globl C_UNDERSCORE(MlasSgemmKernel\Mode\()) #ifndef __APPLE__ .type C_UNDERSCORE(MlasSgemmKernel\Mode\()),%function -#endif +#endif C_UNDERSCORE(MlasSgemmKernel\Mode\()): stp d8,d9,[sp,#-32]! diff --git a/tools/ci_build/build.py b/tools/ci_build/build.py index 32de123586..b1833db77d 100755 --- a/tools/ci_build/build.py +++ b/tools/ci_build/build.py @@ -201,10 +201,27 @@ def parse_arguments(): parser.add_argument("--ios", action='store_true', help="build for ios") parser.add_argument( - "--ios_sysroot", default="", help="Path to ios sysroot") + "--ios_sysroot", default="", + help="Specify the location name of the macOS platform SDK to be used") parser.add_argument( "--ios_toolchain_dir", default="", help="Path to ios toolchain binaries") + parser.add_argument( + "--ios_toolchain_file", default="", + help="Path to ios toolchain file, " + "or cmake/onnxruntime_ios.toolchain.cmake will be used") + parser.add_argument( + "--use_xcode", action='store_true', + help="Use Xcode as cmake generator, this is only supported on MacOS.") + parser.add_argument( + "--osx_arch", type=str, + help="Specify the Target specific architectures for macOS and iOS" + "This is only supported on MacOS") + parser.add_argument( + "--apple_deploy_target", type=str, + help="Specify the minimum version of the target platform " + "(e.g. macOS or iOS)" + "This is only supported on MacOS") # Arguments needed by CI parser.add_argument( @@ -326,6 +343,10 @@ def is_windows(): return sys.platform.startswith("win") +def is_macOS(): + return sys.platform.startswith("darwin") + + def get_linux_distro(): try: with open('/etc/os-release', 'r') as f: @@ -496,7 +517,8 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home, "OFF" if args.skip_winml_tests else "ON"), "-Donnxruntime_GENERATE_TEST_REPORTS=ON", "-Donnxruntime_DEV_MODE=" + ( - "OFF" if args.android or args.use_acl else "ON"), + "OFF" if args.android or args.use_acl or + (args.ios and is_macOS()) else "ON"), "-DPYTHON_EXECUTABLE=" + sys.executable, "-Donnxruntime_USE_CUDA=" + ("ON" if args.use_cuda else "OFF"), "-Donnxruntime_CUDNN_HOME=" + (cudnn_home if args.use_cuda else ""), @@ -539,8 +561,10 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home, "ON" if args.use_openvino else "OFF"), "-Donnxruntime_USE_NNAPI=" + ("ON" if args.use_dnnlibrary else "OFF"), "-Donnxruntime_USE_OPENMP=" + ( - "ON" if args.use_openmp and not args.use_dnnlibrary and - not args.use_mklml and not args.use_ngraph and not args.android else "OFF"), + "ON" if args.use_openmp and not ( + args.use_dnnlibrary or args.use_mklml or args.use_ngraph or + args.android or (args.ios and is_macOS())) + else "OFF"), "-Donnxruntime_USE_TVM=" + ("ON" if args.use_tvm else "OFF"), "-Donnxruntime_USE_LLVM=" + ("ON" if args.use_llvm else "OFF"), "-Donnxruntime_ENABLE_MICROSOFT_INTERNAL=" + ( @@ -626,40 +650,83 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home, "-DANDROID_ABI=" + str(args.android_abi) ] + if is_macOS() and args.use_xcode: + cmake_args += ["-GXcode"] + if args.ios: - needed_args = [ - args.ios_sysroot, - args.arm64 or args.arm, - args.ios_toolchain_dir - ] - arg_names = [ - "--ios_sysroot ", - "--arm or --arm64", - "--ios_toolchain_dir " - ] - if not all(needed_args): - raise BuildError( - "iOS build canceled due to missing arguments: " + ', '.join( - val for val, cond in zip(arg_names, needed_args) - if not cond)) - compilers = sorted(glob.glob(args.ios_toolchain_dir + "/bin/*-clang*")) - os.environ["PATH"] = os.path.join( - args.ios_toolchain_dir, "bin") + os.pathsep + os.environ.get( - "PATH", "") - os.environ["LD_LIBRARY_PATH"] = os.path.join( - args.ios_toolchain_dir, "/lib") + os.pathsep + os.environ.get( - "LD_LIBRARY_PATH", "") - if len(compilers) != 2: - raise BuildError( - "error identifying compilers in ios_toolchain_dir") - cmake_args += [ - "-DCMAKE_OSX_ARCHITECTURES=" + ("arm64" if args.arm64 else "arm"), - "-DCMAKE_SYSTEM_NAME=iOSCross", - "-Donnxruntime_BUILD_UNIT_TESTS=OFF", - "-DCMAKE_OSX_SYSROOT=" + args.ios_sysroot, - "-DCMAKE_C_COMPILER=" + compilers[0], - "-DCMAKE_CXX_COMPILER=" + compilers[1] - ] + if is_macOS(): + needed_args = [ + args.use_xcode, + args.ios_sysroot, + args.osx_arch, + args.apple_deploy_target, + ] + arg_names = [ + "--use_xcode " + + "", + "--ios_sysroot " + + "", + "--osx_arch " + + "", + "--apple_deploy_target " + + "", + ] + if not all(needed_args): + raise BuildError( + "iOS build on MacOS canceled due to missing arguments: " + + ', '.join( + val for val, cond in zip(arg_names, needed_args) + if not cond)) + cmake_args += [ + "-DCMAKE_SYSTEM_NAME=iOS", + "-Donnxruntime_BUILD_UNIT_TESTS=OFF", + "-DCMAKE_OSX_SYSROOT=" + args.ios_sysroot, + "-DCMAKE_OSX_ARCHITECTURES=" + args.osx_arch, + "-DCMAKE_OSX_DEPLOYMENT_TARGET=" + args.apple_deploy_target, + # we do not need protoc binary for ios cross build + "-Dprotobuf_BUILD_PROTOC_BINARIES=OFF", + "-DCMAKE_TOOLCHAIN_FILE=" + ( + args.ios_toolchain_file if args.ios_toolchain_file + else "../cmake/onnxruntime_ios.toolchain.cmake") + ] + else: + # We are cross comppiling on linux + needed_args = [ + args.ios_sysroot, + args.arm64 or args.arm, + args.ios_toolchain_dir + ] + arg_names = [ + "--ios_sysroot ", + "--arm or --arm64", + "--ios_toolchain_dir " + ] + if not all(needed_args): + raise BuildError( + "iOS build canceled due to missing arguments: " + + ', '.join( + val for val, cond in zip(arg_names, needed_args) + if not cond)) + compilers = sorted( + glob.glob(args.ios_toolchain_dir + "/bin/*-clang*")) + os.environ["PATH"] = os.path.join( + args.ios_toolchain_dir, "bin") + os.pathsep + os.environ.get( + "PATH", "") + os.environ["LD_LIBRARY_PATH"] = os.path.join( + args.ios_toolchain_dir, "/lib") + os.pathsep + os.environ.get( + "LD_LIBRARY_PATH", "") + if len(compilers) != 2: + raise BuildError( + "error identifying compilers in ios_toolchain_dir") + cmake_args += [ + "-DCMAKE_OSX_ARCHITECTURES=" + + ("arm64" if args.arm64 else "arm"), + "-DCMAKE_SYSTEM_NAME=iOSCross", + "-Donnxruntime_BUILD_UNIT_TESTS=OFF", + "-DCMAKE_OSX_SYSROOT=" + args.ios_sysroot, + "-DCMAKE_C_COMPILER=" + compilers[0], + "-DCMAKE_CXX_COMPILER=" + compilers[1] + ] if path_to_protoc_exe: cmake_args += [ @@ -766,6 +833,9 @@ def build_targets(args, cmake_path, build_dir, configs, parallel): # if nodeReuse is true, msbuild processes will stay around for a bit after the build completes "/nodeReuse:False", ] + elif (is_macOS() and args.use_xcode): + # CMake will generate correct build tool args for Xcode + cmd_args += ["--parallel", num_cores] else: build_tool_args += ["-j" + num_cores] @@ -1320,6 +1390,9 @@ def build_protoc_for_host(cmake_path, source_dir, build_dir, args): if args.cmake_generator != 'Ninja': cmd_args += ['-T', 'host=x64'] cmd_args += ['-G', args.cmake_generator] + elif is_macOS() and args.use_xcode: + cmd_args += ['-G', 'Xcode'] + run_subprocess(cmd_args, cwd=protoc_build_dir) # Build step cmd_args = [cmake_path, @@ -1332,7 +1405,9 @@ def build_protoc_for_host(cmake_path, source_dir, build_dir, args): expected_protoc_path = ( os.path.join( protoc_build_dir, 'Release', 'protoc.exe') if is_windows() - else os.path.join(protoc_build_dir, 'protoc')) + else (os.path.join(protoc_build_dir, 'Release', 'protoc') + if is_macOS() and args.use_xcode + else os.path.join(protoc_build_dir, 'protoc'))) if not os.path.exists(expected_protoc_path): raise BuildError("Couldn't build protoc for host. Failing build.")