From 37dc4b95b520f128cf41e0731f2e259faa1e8200 Mon Sep 17 00:00:00 2001 From: fangting Date: Thu, 23 Nov 2023 19:29:08 +0800 Subject: [PATCH] add mac standalone build Signed-off-by: fangting --- BUILD.gn | 43 +-- OAT.xml | 51 ++- build/compile_script/ark.py | 12 +- build/config/BUILD.gn | 12 + build/config/BUILDCONFIG.gn | 55 ++- build/config/compiler/BUILD.gn | 24 +- build/config/mac/BUILD.gn | 110 ++++++ build/config/mac/mac_sdk.gni | 109 ++++++ build/config/mac/mac_sdk_overrides.gni | 22 ++ build/config/mac/sdk_info.py | 106 ++++++ build/config/mac/symbols.gni | 29 ++ build/config/mac/xcrun.py | 29 ++ build/config/posix/BUILD.gn | 2 +- build/config/sanitizers/sanitizers.gni | 4 + build/config/sysroot.gni | 3 + build/core/gn/BUILD.gn | 24 +- build/misc/mac/check_return_value.py | 18 + build/misc/mac/find_sdk.py | 117 ++++++ build/misc/overrides/build.gni | 19 + .../prebuilts_download/prebuilts_download.sh | 3 +- .../prebuilts_download_config.json | 41 ++- build/scripts/check_mac_system_and_cpu.py | 63 ++++ build/templates/cxx/cxx.gni | 17 +- build/toolchain/BUILD.gn | 24 ++ build/toolchain/ark/BUILD.gn | 0 build/toolchain/ark/ark_toolchain.gni | 0 build/toolchain/cc_wrapper.gni | 0 build/toolchain/clang_static_analyzer.gni | 11 + .../clang_static_analyzer_wrapper.py | 72 ++++ build/toolchain/concurrent_links.gni | 53 +++ build/toolchain/gcc_toolchain.gni | 0 build/toolchain/get_concurrent_links.py | 91 +++++ build/toolchain/get_cpu_count.py | 24 ++ build/toolchain/linux/BUILD.gn | 0 build/toolchain/mac/BUILD.gn | 333 ++++++++++++++++++ build/toolchain/mac/filter_libtool.py | 55 +++ build/toolchain/mac/get_tool_mtime.py | 19 + build/toolchain/mac/linker_driver.py | 232 ++++++++++++ build/toolchain/mingw/BUILD.gn | 0 build/toolchain/toolchain.gni | 4 + tooling/BUILD.gn | 2 +- tooling/client/BUILD.gn | 1 + 42 files changed, 1781 insertions(+), 53 deletions(-) mode change 100644 => 100755 build/compile_script/ark.py create mode 100644 build/config/mac/BUILD.gn create mode 100644 build/config/mac/mac_sdk.gni create mode 100644 build/config/mac/mac_sdk_overrides.gni create mode 100755 build/config/mac/sdk_info.py create mode 100644 build/config/mac/symbols.gni create mode 100755 build/config/mac/xcrun.py create mode 100755 build/misc/mac/check_return_value.py create mode 100755 build/misc/mac/find_sdk.py create mode 100644 build/misc/overrides/build.gni create mode 100755 build/scripts/check_mac_system_and_cpu.py create mode 100644 build/toolchain/BUILD.gn mode change 100755 => 100644 build/toolchain/ark/BUILD.gn mode change 100755 => 100644 build/toolchain/ark/ark_toolchain.gni mode change 100755 => 100644 build/toolchain/cc_wrapper.gni create mode 100644 build/toolchain/clang_static_analyzer.gni create mode 100755 build/toolchain/clang_static_analyzer_wrapper.py create mode 100644 build/toolchain/concurrent_links.gni mode change 100755 => 100644 build/toolchain/gcc_toolchain.gni create mode 100755 build/toolchain/get_concurrent_links.py create mode 100755 build/toolchain/get_cpu_count.py mode change 100755 => 100644 build/toolchain/linux/BUILD.gn create mode 100644 build/toolchain/mac/BUILD.gn create mode 100755 build/toolchain/mac/filter_libtool.py create mode 100755 build/toolchain/mac/get_tool_mtime.py create mode 100755 build/toolchain/mac/linker_driver.py mode change 100755 => 100644 build/toolchain/mingw/BUILD.gn mode change 100755 => 100644 build/toolchain/toolchain.gni diff --git a/BUILD.gn b/BUILD.gn index 97aba4c4..3fcc6575 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -191,41 +191,36 @@ config("toolchain_test_config") { group("ark_toolchain_packages") { deps = [] - if (host_os != "mac") { - deps += [ - "./inspector:ark_debugger", - "./inspector:connectserver_debugger", - "./tooling:libark_ecma_debugger", - "./tooling/client:libark_client", - "./tooling/client/ark_cli:arkdb", - ] - } + deps += [ + "./inspector:ark_debugger", + "./inspector:connectserver_debugger", + "./tooling:libark_ecma_debugger", + "./tooling/client:libark_client", + "./tooling/client/ark_cli:arkdb", + ] } group("ark_toolchain_unittest") { testonly = true deps = [] - if (host_os != "mac") { - deps += [ - "//arkcompiler/toolchain/tooling/test:unittest", - "//arkcompiler/toolchain/websocket/test:unittest", - ] - if (is_ohos && is_standard_system) { - deps += [ "//arkcompiler/toolchain/test/fuzztest:fuzztest" ] - } + deps += [ + "./tooling/test:unittest", + "./websocket/test:unittest", + ] + if (is_ohos && is_standard_system) { + deps += [ "./test/fuzztest:fuzztest" ] } } group("ark_toolchain_host_unittest") { testonly = true deps = [] - if (host_os != "mac") { - # js unittest - deps += [ - "//arkcompiler/toolchain/tooling/test:host_unittest", - "//arkcompiler/toolchain/websocket/test:host_unittest", - ] - } + + # js unittest + deps += [ + "./tooling/test:host_unittest", + "./websocket/test:host_unittest", + ] } group("ark_js_host_unittest") { diff --git a/OAT.xml b/OAT.xml index 49b7c396..08cda0f1 100644 --- a/OAT.xml +++ b/OAT.xml @@ -53,9 +53,54 @@ Note:If the text contains special characters, please escape them according to th --> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/compile_script/ark.py b/build/compile_script/ark.py old mode 100644 new mode 100755 index 73c366f6..1b7d3140 --- a/build/compile_script/ark.py +++ b/build/compile_script/ark.py @@ -135,6 +135,14 @@ class ArkPy: "gn_args": ["target_os=\"ohos\"", "target_cpu=\"mipsel\""], "prefix_of_name_of_out_dir_of_second_level": "mipsel", }, + "mac_arm64": { + "flags": ["mac_arm64", "arm64"], + "description": + "Build for arkcompiler target of target-operating-system linux and " + "target-central-processing-unit arm64.", + "gn_args": ["target_os=\"mac\"", "target_cpu=\"arm64\""], + "prefix_of_name_of_out_dir_of_second_level": "mac_arm64", + }, }, "mode": { "release": { @@ -414,7 +422,7 @@ class ArkPy: self.build_for_gn_target( x64_out_path, ['target_os="linux"', 'target_cpu="x64"', 'is_debug=false'], self.ARG_DICT["target"]["test262"]["gn_targets_depend_on"], log_file_name) - + self.build_for_gn_target( out_path, gn_args, self.ARG_DICT["target"]["test262"]["gn_targets_depend_on"], log_file_name) test262_cmd = self.get_test262_cmd(gn_args, out_path, x64_out_path, aot_mode, run_pgo, args_to_test262_cmd) @@ -625,7 +633,7 @@ class ArkPy: return def start_for_matched_os_cpu_mode(self, os_cpu_key: str, mode_key: str, arg_list: list): - # get binary gn and ninja + # get binary gn and ninja self.get_binaries() # get out_path name_of_out_dir_of_second_level = \ diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 450838d8..1323361d 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn @@ -13,6 +13,7 @@ config("executable_config") { configs = [] + if (!is_mac) { if (!is_mingw) { cflags = [ "-fPIE" ] @@ -31,6 +32,17 @@ config("executable_config") { } else if (is_android) { configs += [ "$build_root/config/aosp:executable_config" ] } + } else if (is_mac) { + configs += [ "$build_root/config/mac:mac_dynamic_flags" ] + } +} + +# This config defines the configs applied to all shared libraries. +config("shared_library_config") { + configs = [] + + if (is_mac) { + configs += [ "$build_root/config/mac:mac_dynamic_flags" ] } } diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 9a4a8d2c..25c5d267 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -10,7 +10,6 @@ # 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. - declare_args() { ark_standalone_build = true use_musl = true @@ -20,8 +19,27 @@ declare_args() { enable_lto_O0 = false } +check_mac_system_and_cpu_script = + rebase_path("$build_root/scripts/check_mac_system_and_cpu.py") +check_darwin_system_result = + exec_script(check_mac_system_and_cpu_script, [ "system" ], "string") + +if (check_darwin_system_result != "") { + check_mac_host_cpu_result = + exec_script(check_mac_system_and_cpu_script, [ "cpu" ], "string") + if (check_mac_host_cpu_result != "") { + host_cpu = "arm64" + } +} + if (host_os == "linux") { host_platform_dir = "linux-x86_64" +} else if (host_os == "mac") { + if (host_cpu == "arm64") { + host_platform_dir = "darwin-arm64" + } else { + host_platform_dir = "darwin-x86_64" + } } else { assert(false, "Unsupported host_os: $host_os") } @@ -32,6 +50,20 @@ declare_args() { is_standard_system = false } +declare_args() { + # Enable mini debug info, it will add .gnu_debugdata + # section in each stripped sofile + + # Currently, we don't publish ohos-adapted python on m1 platform, + # So that we disable mini debug info on m1 platform until + # ohos-adapted python publishing on m1 platform + if (host_os == "mac") { + full_mini_debug = false + } else { + full_mini_debug = true + } +} + declare_args() { host_toolchain = "" custom_toolchain = "" @@ -70,6 +102,8 @@ if (host_toolchain == "") { } else { host_toolchain = "$build_root/toolchain/linux:$host_cpu" } + } else if (host_os == "mac") { + host_toolchain = "$build_root/toolchain/mac:clang_$host_cpu" } else { assert(false, "Unsupported host_os: $host_os") } @@ -88,6 +122,8 @@ if (target_os == "ohos") { _default_toolchain = "$build_root/toolchain/mingw:mingw_x86_64" } else if (target_os == "android" && target_cpu == "arm64") { _default_toolchain = "$build_root/toolchain/aosp:aosp_clang_arm64" +} else if (target_os == "mac" && target_cpu == "arm64") { + _default_toolchain = "$build_root/toolchain/mac:clang_arm64" } if (custom_toolchain != "") { set_default_toolchain(custom_toolchain) @@ -107,7 +143,19 @@ if (current_os == "") { # Variables like "is_..." are already used to represent for # "current_os == "..."" in most of the repositories. Thus, we need to make them # change with the change of current_os. -if (current_os == "ohos") { +if (current_os == "mac") { + is_aix = false + is_ohos = false + is_chromeos = false + is_linux = false + is_mac = true + is_nacl = false + is_posix = true + is_win = false + is_mingw = false + is_android = false + is_ios = false +} else if (current_os == "ohos") { is_ohos = true is_linux = false is_mac = false @@ -158,7 +206,8 @@ default_compiler_configs = [ default_static_library_configs = default_compiler_configs default_source_set_configs = default_compiler_configs -default_shared_library_configs = default_compiler_configs +default_shared_library_configs = + default_compiler_configs + [ "$build_root/config:shared_library_config" ] default_executable_configs = default_compiler_configs + [ "$build_root/config:executable_config" ] diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 37d29944..4613b124 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -22,14 +22,26 @@ declare_args() { treat_warnings_as_errors = true } +use_rtti = use_cfi_diag || is_ubsan_vptr || is_ubsan_security + config("rtti") { - cflags_cc = [ "-frtti" ] + if (is_win) { + cflags_cc = [ "/GR" ] + } else { + cflags_cc = [ "-frtti" ] + } } config("no_rtti") { # Some sanitizer configs may require RTTI to be left enabled globally - cflags_cc = [ "-fno-rtti" ] - cflags_objcc = cflags_cc + if (!use_rtti) { + if (is_win) { + cflags_cc = [ "/GR-" ] + } else { + cflags_cc = [ "-fno-rtti" ] + cflags_objcc = cflags_cc + } + } } config("exceptions") { @@ -246,6 +258,8 @@ config("compiler") { cflags += [ "-fno-stack-protector" ] } else if (is_ohos) { configs += [ "$build_root/config/ohos:compiler" ] + } else if (is_mac) { + configs += [ "$build_root/config/mac:compiler" ] } if (is_linux || is_ohos || is_android) { cflags += [ "-fPIC" ] @@ -450,6 +464,10 @@ config("runtime_config") { if (is_android) { configs += [ "$build_root/config/aosp:runtime_config" ] } + + if (is_mac) { + configs += [ "$build_root/config/mac:runtime_config" ] + } } config("ark_code") { diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn new file mode 100644 index 00000000..38f36d4a --- /dev/null +++ b/build/config/mac/BUILD.gn @@ -0,0 +1,110 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("$build_root/config/mac/mac_sdk.gni") +import("$build_root/config/mac/symbols.gni") +import("$build_root/config/sysroot.gni") + +# This is included by reference in the //build/config/compiler config that +# is applied to all targets. It is here to separate out the logic. +config("compiler") { + # These flags are shared between the C compiler and linker. + common_mac_flags = [] + + # CPU architecture. + if (current_cpu == "x64") { + common_mac_flags += [ + "-arch", + "x86_64", + ] + } else if (current_cpu == "x86") { + common_mac_flags += [ + "-arch", + "i386", + ] + } + + # This is here so that all files get recompiled after an Xcode update. + # (defines are passed via the command line, and build system rebuild things + # when their commandline changes). Nothing should ever read this define. + defines = [ "CR_XCODE_VERSION=$xcode_version" ] + + defines += [ + "_LIBCPP_CONFIG_SITE", + "_LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT=0", + ] + + asmflags = common_mac_flags + cflags = common_mac_flags + + # Without this, the constructors and destructors of a C++ object inside + # an Objective C struct won't be called, which is very bad. + cflags_objcc = [ "-fobjc-call-cxx-cdtors" ] + + ldflags = common_mac_flags + + # Create a new read-only segment for protected memory. The default segments + # (__TEXT and __DATA) are mapped read-execute and read-write by default. + ldflags += [ + "-segprot", + "PROTECTED_MEMORY", + "rw", + "r", + ] + + if (save_unstripped_output) { + ldflags += [ "-Wcrl,unstripped," + rebase_path(root_out_dir) ] + } +} + +# This is included by reference in the //build/config/compiler:runtime_library +# config that is applied to all targets. It is here to separate out the logic +# that is Mac-only. Please see that target for advice on what should go in +# :runtime_library vs. :compiler. +config("runtime_config") { + common_flags = [ + "-isysroot", + sysroot, + "-mmacosx-version-min=$mac_deployment_target", + ] + + asmflags = common_flags + cflags = common_flags + ldflags = common_flags + framework_dirs = [ sysroot ] + + # Prevent Mac OS X AssertMacros.h (included by system header) from defining + # macros that collide with common names, like 'check', 'require', and + # 'verify'. + # http://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/AssertMacros.h + defines = [ "__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORE=0" ] +} + +# On Mac, this is used for everything except static libraries. +config("mac_dynamic_flags") { + ldflags = [ "-Wl,-ObjC" ] # Always load Objective-C categories and classes. + + if (is_component_build) { + ldflags += [ + # Path for loading shared libraries for unbundled binaries. + "-Wl,-rpath,@loader_path/.", + + # Path for loading shared libraries for bundled binaries. Get back from + # Binary.app/Contents/MacOS. + "-Wl,-rpath,@loader_path/../../..", + ] + } +} + +# The ldflags referenced below are handled by +# //build/toolchain/mac/linker_driver.py. +# Remove this config if a target wishes to change the arguments passed to the +# strip command during linking. This config by default strips all symbols +# from a binary, but some targets may wish to specify an exports file to +# preserve specific symbols. +config("strip_all") { + if (enable_stripping) { + ldflags = [ "-Wcrl,strip,-x,-S" ] + } +} diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni new file mode 100644 index 00000000..1d89e433 --- /dev/null +++ b/build/config/mac/mac_sdk.gni @@ -0,0 +1,109 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("$build_root/config/mac/mac_sdk_overrides.gni") +import("$build_root/toolchain/toolchain.gni") + +declare_args() { + # The MACOSX_DEPLOYMENT_TARGET variable used when compiling. This partially + # controls the minimum supported version of macOS for Chromium by + # affecting the symbol availability rules. This may differ from + # mac_min_system_version when dropping support for older macOSes but where + # additional code changes are required to be compliant with the availability + # rules. + # Must be of the form x.x.x for Info.plist files. + mac_deployment_target = "10.13.0" + + # The value of the LSMinimumSystemVersion in Info.plist files. This partially + # controls the minimum supported version of macOS for Chromium by + # affecting the Info.plist. This may differ from mac_deployment_target when + # dropping support for older macOSes. This should be greater than or equal to + # the mac_deployment_target version. + # Must be of the form x.x.x for Info.plist files. + mac_min_system_version = "10.13.0" + + # Path to a specific version of the Mac SDK, not including a slash at the end. + # If empty, the path to the lowest version greater than or equal to + # mac_sdk_min is used. + mac_sdk_path = "" + + # The SDK name as accepted by xcodebuild. + mac_sdk_name = "macosx" +} + +# Check that the version of macOS SDK used is the one requested when building +# a version of Chrome shipped to the users. Disable the check if building for +# iOS as the version macOS SDK used is not relevant for the tool build for the +# host (they are not shipped) --- this is required as Chrome on iOS is usually +# build with the latest version of Xcode that may not ship with the version of +# the macOS SDK used to build Chrome on mac. +_verify_sdk = is_official_build && target_os != "ios" + +find_sdk_args = [ "--print_sdk_path" ] +if (!use_system_xcode) { + find_sdk_args += [ + "--developer_dir", + hermetic_xcode_path, + ] +} +if (_verify_sdk) { + find_sdk_args += [ + "--verify", + mac_sdk_min, + "--sdk_path=" + mac_sdk_path, + ] +} else { + find_sdk_args += [ mac_sdk_min ] +} + +# The tool will print the SDK path on the first line, and the version on the +# second line. +find_sdk_lines = + exec_script("$build_root/misc/mac/find_sdk.py", find_sdk_args, "list lines") + +mac_sdk_version = find_sdk_lines[1] +if (mac_sdk_path == "") { + mac_sdk_path = find_sdk_lines[0] +} + +script_name = "$build_root/config/mac/sdk_info.py" +sdk_info_args = [] +if (!use_system_xcode) { + sdk_info_args += [ + "--developer_dir", + hermetic_xcode_path, + ] +} +sdk_info_args += [ mac_sdk_name ] + +_mac_sdk_result = exec_script(script_name, sdk_info_args, "scope") +xcode_version = _mac_sdk_result.xcode_version +xcode_build = _mac_sdk_result.xcode_build +machine_os_build = _mac_sdk_result.machine_os_build +xcode_version_int = _mac_sdk_result.xcode_version_int + +if (mac_sdk_version != mac_sdk_min && + exec_script("$build_root/misc/mac/check_return_value.py", + [ + "test", + xcode_version, + "-ge", + "0730", + ], + "value") != 1) { + print( + "********************************************************************************") + print( + " WARNING: The Mac OS X SDK is incompatible with the version of Xcode. To fix,") + print( + " either upgrade Xcode to the latest version or install the Mac OS X") + print( + " $mac_sdk_min SDK. For more information, see https://crbug.com/620127.") + print() + print(" Current SDK Version: $mac_sdk_version") + print(" Current Xcode Version: $xcode_version ($xcode_build)") + print( + "********************************************************************************") + assert(false, "SDK is incompatible with Xcode") +} diff --git a/build/config/mac/mac_sdk_overrides.gni b/build/config/mac/mac_sdk_overrides.gni new file mode 100644 index 00000000..36326786 --- /dev/null +++ b/build/config/mac/mac_sdk_overrides.gni @@ -0,0 +1,22 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file contains arguments that subprojects may choose to override. It +# asserts that those overrides are used, to prevent unused args warnings. + +_sdk_min_from_env = getenv("FORCE_MAC_SDK_MIN") +declare_args() { + # Minimum supported version of the Mac SDK. + if (_sdk_min_from_env == "") { + mac_sdk_min = "10.12" + } else { + mac_sdk_min = _sdk_min_from_env + } +} + +# Always assert that mac_sdk_min is used on non-macOS platforms to prevent +# unused args warnings. +if (!is_mac) { + assert(mac_sdk_min == "10.12" || true) +} diff --git a/build/config/mac/sdk_info.py b/build/config/mac/sdk_info.py new file mode 100755 index 00000000..b032b8b6 --- /dev/null +++ b/build/config/mac/sdk_info.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import doctest +import itertools +import os +import subprocess +import sys + +# This script prints information about the build system, the operating +# system and the iOS or Mac SDK (depending on the platform "iphonesimulator", +# "iphoneos" or "macosx" generally). + + +def SplitVersion(version): + """Splits the Xcode version to 3 values. + + >>> list(SplitVersion('8.2.1.1')) + ['8', '2', '1'] + >>> list(SplitVersion('9.3')) + ['9', '3', '0'] + >>> list(SplitVersion('10.0')) + ['10', '0', '0'] + """ + if isinstance(version, bytes): + version = version.decode() + version = version.split('.') + return itertools.islice(itertools.chain(version, itertools.repeat('0')), 0, 3) + + +def FormatVersion(version): + """Converts Xcode version to a format required for DTXcode in Info.plist + + >>> FormatVersion('8.2.1') + '0821' + >>> FormatVersion('9.3') + '0930' + >>> FormatVersion('10.0') + '1000' + """ + major, minor, patch = SplitVersion(version) + return ('%2s%s%s' % (major, minor, patch)).replace(' ', '0') + + +def FillXcodeVersion(settings): + """Fills the Xcode version and build number into |settings|.""" + lines = subprocess.check_output(['xcodebuild', '-version']).splitlines() + settings['xcode_version'] = FormatVersion(lines[0].split()[-1]) + settings['xcode_version_int'] = int(settings['xcode_version'], 10) + settings['xcode_build'] = lines[-1].split()[-1] + + +def FillMachineOSBuild(settings): + """Fills OS build number into |settings|.""" + settings['machine_os_build'] = subprocess.check_output( + ['sw_vers', '-buildVersion']).strip() + + +def FillSDKPathAndVersion(settings, platform, xcode_version): + """Fills the SDK path and version for |platform| into |settings|.""" + settings['sdk_path'] = subprocess.check_output([ + 'xcrun', '-sdk', platform, '--show-sdk-path']).strip() + settings['sdk_version'] = subprocess.check_output([ + 'xcrun', '-sdk', platform, '--show-sdk-version']).strip() + settings['sdk_platform_path'] = subprocess.check_output([ + 'xcrun', '-sdk', platform, '--show-sdk-platform-path']).strip() + if xcode_version >= '0720': + settings['sdk_build'] = subprocess.check_output([ + 'xcrun', '-sdk', platform, '--show-sdk-build-version']).strip() + else: + settings['sdk_build'] = settings['sdk_version'] + + +if __name__ == '__main__': + doctest.testmod() + + parser = argparse.ArgumentParser() + parser.add_argument("--developer_dir", required=False) + args, unknownargs = parser.parse_known_args() + if args.developer_dir: + os.environ['DEVELOPER_DIR'] = args.developer_dir + + if len(unknownargs) != 1: + sys.stderr.write( + 'usage: %s [iphoneos|iphonesimulator|macosx]\n' % + os.path.basename(sys.argv[0])) + sys.exit(1) + + settings = {} + FillMachineOSBuild(settings) + FillXcodeVersion(settings) + FillSDKPathAndVersion(settings, unknownargs[0], settings['xcode_version']) + + for key in sorted(settings): + value = settings[key] + if isinstance(value, bytes): + value = value.decode() + if key != 'xcode_version_int': + value = '"%s"' % value + print('%s=%s' % (key, value)) + else: + print('%s=%d' % (key, value)) diff --git a/build/config/mac/symbols.gni b/build/config/mac/symbols.gni new file mode 100644 index 00000000..a510dc3a --- /dev/null +++ b/build/config/mac/symbols.gni @@ -0,0 +1,29 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("$build_root/config/sanitizers/sanitizers.gni") + +# This file declares arguments and configs that control whether dSYM debug +# info is produced and whether build products are stripped. + +declare_args() { + # Produce dSYM files for targets that are configured to do so. dSYM + # generation is controlled globally as it is a linker output (produced via + # the //build/toolchain/mac/linker_driver.py. Enabling this will result in + # all shared library, loadable module, and executable targets having a dSYM + # generated. + enable_dsyms = is_official_build || using_sanitizer + + # Strip symbols from linked targets by default. If this is enabled, the + # //build/config/mac:strip_all config will be applied to all linked targets. + # If custom stripping parameters are required, remove that config from a + # linked target and apply custom -Wcrl,strip flags. See + # //build/toolchain/mac/linker_driver.py for more information. + enable_stripping = is_official_build +} + +# Save unstripped copies of targets with a ".unstripped" suffix. This is +# useful to preserve the original output when enable_stripping=true but +# we're not actually generating real dSYMs. +save_unstripped_output = enable_stripping && !enable_dsyms diff --git a/build/config/mac/xcrun.py b/build/config/mac/xcrun.py new file mode 100755 index 00000000..1d82296a --- /dev/null +++ b/build/config/mac/xcrun.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import subprocess +import sys + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description='A script to execute a command via xcrun.') + parser.add_argument('--stamp', action='store', type=str, + help='Write a stamp file to this path on success.') + parser.add_argument('--developer_dir', required=False, + help='Path to Xcode.') + args, unknown_args = parser.parse_known_args() + + if args.developer_dir: + os.environ['DEVELOPER_DIR'] = args.developer_dir + + rv = subprocess.check_call(['xcrun'] + unknown_args) + if rv == 0 and args.stamp: + if os.path.exists(args.stamp): + os.unlink(args.stamp) + with open(args.stamp, 'w+') as fp: + sys.exit(rv) diff --git a/build/config/posix/BUILD.gn b/build/config/posix/BUILD.gn index 3c069149..b8c7da7e 100644 --- a/build/config/posix/BUILD.gn +++ b/build/config/posix/BUILD.gn @@ -24,7 +24,7 @@ config("runtime_config") { cflags = [] asmflags = [] - if (!is_mac && sysroot != "") { + if (sysroot != "") { # Pass the sysroot to all C compiler variants, the assembler, and linker. sysroot_flags = [ "--sysroot=" + rebase_path(sysroot, root_build_dir) ] diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 98159bab..effba924 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni @@ -25,4 +25,8 @@ declare_args() { is_ubsan_security = false using_sanitizer = false + + use_sanitizer_coverage = false + + use_fuzzing_engine = false } diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni index 9f0e0932..a6520ff3 100644 --- a/build/config/sysroot.gni +++ b/build/config/sysroot.gni @@ -18,6 +18,9 @@ if (is_ohos) { } else if (is_android) { import("$build_root/config/aosp/config.gni") sysroot = "$aosp_ndk_root/sysroot" +} else if (is_mac) { + import("$build_root/config/mac/mac_sdk.gni") + sysroot = mac_sdk_path } link_sysroot = sysroot diff --git a/build/core/gn/BUILD.gn b/build/core/gn/BUILD.gn index 940894ec..493a1651 100644 --- a/build/core/gn/BUILD.gn +++ b/build/core/gn/BUILD.gn @@ -28,21 +28,17 @@ print("target_os=$target_os, target_cpu=$target_cpu") print() group("default") { - if (host_os != "mac") { - deps = [ - ":ets_frontend", - ":ets_runtime", - ":runtime_core", - ":toolchain", - ] - } + deps = [ + ":ets_frontend", + ":ets_runtime", + ":runtime_core", + ":toolchain", + ] } group("unittest_packages") { testonly = true - if (host_os != "mac") { - deps = [ "$toolchain_root:ark_js_host_unittest" ] - } + deps = [ "$toolchain_root:ark_js_host_unittest" ] } group("ets_runtime") { @@ -52,7 +48,8 @@ group("ets_runtime") { "$js_root/ecmascript/quick_fix:quick_fix", ] if ((target_os == "linux" && target_cpu == "x64") || - (target_cpu == "arm64" && target_os == "ohos")) { + (target_cpu == "arm64" && target_os == "ohos") || + (target_cpu == "arm64" && target_os == "mac")) { deps += [ "$js_root/ecmascript/compiler:ark_aot_compiler", "$js_root/ecmascript/compiler:ark_stub_compiler", @@ -62,7 +59,8 @@ group("ets_runtime") { } group("ets_frontend") { - if ((target_os == "linux" && target_cpu == "x64") || target_os == "mingw") { + if ((target_os == "linux" && target_cpu == "x64") || target_os == "mingw" || + target_os == "mac") { deps = [ "$ets_frontend_root/es2panda:es2panda", "$ets_frontend_root/merge_abc:merge_abc", diff --git a/build/misc/mac/check_return_value.py b/build/misc/mac/check_return_value.py new file mode 100755 index 00000000..1bbb5966 --- /dev/null +++ b/build/misc/mac/check_return_value.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""This program wraps an arbitrary command and prints "1" if the command ran +successfully.""" + +import os +import subprocess +import sys + +with open(os.devnull, 'wb') as devnull: + if not subprocess.call(sys.argv[1:], stdout=devnull, stderr=devnull): + print(1) + else: + print(0) diff --git a/build/misc/mac/find_sdk.py b/build/misc/mac/find_sdk.py new file mode 100755 index 00000000..a0212c20 --- /dev/null +++ b/build/misc/mac/find_sdk.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Prints the lowest locally available SDK version greater than or equal to a +given minimum sdk version to standard output. If --developer_dir is passed, then +the script will use the Xcode toolchain located at DEVELOPER_DIR. + +Usage: + python find_sdk.py [--developer_dir DEVELOPER_DIR] 10.6 # Ignores SDKs < 10.6 +""" + +import os +import re +import subprocess +import sys + +from optparse import OptionParser + + +class SdkError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + + +def parse_version(version_str): + """'10.6' => [10, 6]""" + return map(int, re.findall(r'(\d+)', version_str)) + + +def main(): + parser = OptionParser() + parser.add_option("--verify", + action="store_true", dest="verify", default=False, + help="return the sdk argument and warn if it doesn't exist") + parser.add_option("--sdk_path", + action="store", type="string", dest="sdk_path", + default="", + help="user-specified SDK path; bypasses verification") + parser.add_option("--print_sdk_path", + action="store_true", dest="print_sdk_path", default=False, + help="Additionally print the path the SDK (appears first).") + parser.add_option("--developer_dir", help='Path to Xcode.') + options, args = parser.parse_args() + if len(args) != 1: + parser.error('Please specify a minimum SDK version') + min_sdk_version = args[0] + + if options.developer_dir: + os.environ['DEVELOPER_DIR'] = options.developer_dir + + job = subprocess.Popen(['xcode-select', '-print-path'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, err = job.communicate() + if job.returncode != 0: + print(out, file=sys.stderr) + print(err, file=sys.stderr) + raise Exception('Error %d running xcode-select' % job.returncode) + sdk_dir = os.path.join( + str(out.rstrip(), encoding="utf-8"), + 'Platforms/MacOSX.platform/Developer/SDKs') + # Xcode must be installed, its license agreement must be accepted, and its + # command-line tools must be installed. Stand-alone installations (in + # /Library/Developer/CommandLineTools) are not supported. + # https://bugs.chromium.org/p/chromium/issues/detail?id=729990#c1 + file_path = os.path.relpath("/path/to/Xcode.app") + if not os.path.isdir(sdk_dir) or not '.app/Contents/Developer' in sdk_dir: + raise SdkError('Install Xcode, launch it, accept the license ' + + 'agreement, and run `sudo xcode-select -s %s` ' % file_path + + 'to continue.') + sdks = [re.findall('^MacOSX(1[0,1,2,3,4]\.\d+)\.sdk$', s) for s in + os.listdir(sdk_dir)] + sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6'] + sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6'] + if list(parse_version(s)) >= list(parse_version(min_sdk_version))] + + if not sdks: + raise Exception('No %s+ SDK found' % min_sdk_version) + best_sdk = sorted(sdks)[0] + + if options.verify and best_sdk != min_sdk_version and not options.sdk_path: + print('', file=sys.stderr) + print(' vvvvvvv', + file=sys.stderr) + print('', file=sys.stderr) + print( + 'This build requires the %s SDK, but it was not found on your system.' \ + % min_sdk_version, file=sys.stderr) + print( + 'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.', + file=sys.stderr) + print('', file=sys.stderr) + print(' ^^^^^^^', + file=sys.stderr) + print('', file=sys.stderr) + sys.exit(1) + + if options.print_sdk_path: + _sdk_path = subprocess.check_output( + ['xcrun', '-sdk', 'macosx' + best_sdk, '--show-sdk-path']).strip() + if isinstance(_sdk_path, bytes): + _sdk_path = _sdk_path.decode() + print(_sdk_path) + return best_sdk + + +if __name__ == '__main__': + if sys.platform != 'darwin': + raise Exception("This script only runs on Mac") + print(main()) + sys.exit(0) diff --git a/build/misc/overrides/build.gni b/build/misc/overrides/build.gni new file mode 100644 index 00000000..f7162e9f --- /dev/null +++ b/build/misc/overrides/build.gni @@ -0,0 +1,19 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Variable that can be used to support multiple build scenarios, like having +# Chromium specific targets in a client project's GN file etc. +build_with_chromium = false + +# Some non-Chromium builds don't support building java targets. +enable_java_templates = true + +# Some non-Chromium builds don't use Chromium's third_party/binutils. +linux_use_bundled_binutils_override = true + +# Skip assertions about 4GiB file size limit. +ignore_elf32_limitations = true + +# Use the system install of Xcode for tools like ibtool, libtool, etc. +use_system_xcode = true diff --git a/build/prebuilts_download/prebuilts_download.sh b/build/prebuilts_download/prebuilts_download.sh index 3d0844f9..1bb06a37 100755 --- a/build/prebuilts_download/prebuilts_download.sh +++ b/build/prebuilts_download/prebuilts_download.sh @@ -101,7 +101,8 @@ fi if [ ! -z "$PYPI_URL" ];then pypi_url=$PYPI_URL else - pypi_url='http://repo.huaweicloud.com/repository/pypi/simple' +# pypi_url='http://repo.huaweicloud.com/repository/pypi/simple' + pypi_url='https://pypi.tuna.tsinghua.edu.cn/simple' fi cpu="--host-cpu $host_cpu" diff --git a/build/prebuilts_download/prebuilts_download_config.json b/build/prebuilts_download/prebuilts_download_config.json index 846fc83b..c127d17f 100644 --- a/build/prebuilts_download/prebuilts_download_config.json +++ b/build/prebuilts_download/prebuilts_download_config.json @@ -6,8 +6,48 @@ "dest": "/prebuilts/clang/ohos/linux-x86_64/llvm", "symlink_src": "/lib/clang/15.0.4", "symlink_dest": "/lib/clang/current" + }, + { + "src": "/prebuilts/clang/ohos/darwin-arm64/clang_darwin-arm64-fe7ee8-20230930", + "dest": "/prebuilts/clang/ohos/darwin-arm64/llvm", + "rename": "true", + "symlink_src": "/lib/clang/15.0.4", + "symlink_dest": "/lib/clang/current" } ], + "darwin": { + "arm64": { + "copy_config": [ + { + "unzip_dir": "prebuilts/build-tools/darwin-arm64/bin", + "file_path": "/openharmony/compiler/gn/2024/darwin/gn-darwin-x86-20230425.tar.gz", + "unzip_filename": "gn" + }, + { + "unzip_dir": "prebuilts/build-tools/darwin-arm64/bin", + "file_path": "/openharmony/compiler/ninja/1.11.0/darwin/ninja-darwin-x86-1.11.0.tar.gz", + "unzip_filename": "ninja" + }, + { + "unzip_dir": "prebuilts/ark_tools", + "file_path": "/openharmony/compiler/llvm_prebuilt_libs/ark_js_prebuilts_darwin_arm64_20230209.tar.gz", + "unzip_filename": "ark_js_prebuilts" + } + ], + "darwin_copy_config": [ + { + "unzip_dir": "prebuilts/clang/ohos/darwin-arm64", + "file_path": "/openharmony/compiler/clang/15.0.4-fe7ee8/darwin/clang_darwin-arm64-fe7ee8-20230930.tar.bz2", + "unzip_filename": "llvm" + }, + { + "unzip_dir": "prebuilts/clang/ohos/darwin-arm64", + "file_path": "/openharmony/compiler/clang/15.0.4-fe7ee8/darwin/libcxx-ndk_darwin-arm64-fe7ee8-20230930.tar.bz2", + "unzip_filename": "libcxx-ndk" + } + ] + } + }, "linux": { "x86_64": { "copy_config": [ @@ -42,4 +82,3 @@ } } } - diff --git a/build/scripts/check_mac_system_and_cpu.py b/build/scripts/check_mac_system_and_cpu.py new file mode 100755 index 00000000..4b79b4dd --- /dev/null +++ b/build/scripts/check_mac_system_and_cpu.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed 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. + +import os +import sys +import subprocess + + +def run_cmd(cmd): + res = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + sout, serr = res.communicate() + + return res.pid, res.returncode, sout, serr + + +def check_darwin_system(): + check_system_cmd = "uname -s" + res = run_cmd(check_system_cmd) + if res[1] == 0 and res[2] != "": + if "Darwin" in res[2].strip().decode(): + print("system is darwin") + + return 0 + + +def check_m1_cpu(): + check_host_cpu_cmd = "sysctl machdep.cpu.brand_string" + res = run_cmd(check_host_cpu_cmd) + if res[1] == 0 and res[2] != "": + host_cpu = res[2].strip().decode().split("brand_string:")[-1] + if "M1" in host_cpu: + print("host cpu is m1") + elif "M2" in host_cpu: + print("host cpu is m2") + elif "M3" in host_cpu: + print("host_cpu is m3") + + return 0 + + +def main(): + if sys.argv[1] == "cpu": + check_m1_cpu() + elif sys.argv[1] == "system": + check_darwin_system() + else: + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/templates/cxx/cxx.gni b/build/templates/cxx/cxx.gni index bb80d567..7c597fa4 100755 --- a/build/templates/cxx/cxx.gni +++ b/build/templates/cxx/cxx.gni @@ -48,6 +48,7 @@ template("ohos_executable") { "unit_test", "external_deps", "stack_protector_ret", + "use_rtti", ]) output_dir = output_dir if (defined(invoker.configs)) { @@ -62,7 +63,9 @@ template("ohos_executable") { configs += [ "//arkcompiler/toolchain/build/config/compiler:exceptions" ] ldflags = [] } - + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//arkcompiler/toolchain/build/config/compiler:rtti" ] + } if (!defined(libs)) { libs = [] } @@ -143,6 +146,7 @@ template("ohos_static_library") { "use_exceptions", "external_deps", "stack_protector_ret", + "use_rtti", ]) if (defined(invoker.configs)) { configs += invoker.configs @@ -157,6 +161,9 @@ template("ohos_static_library") { ldflags = [] } + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//arkcompiler/toolchain/build/config/compiler:rtti" ] + } if (!defined(libs)) { libs = [] } @@ -217,6 +224,7 @@ template("ohos_shared_library") { "external_deps", "stack_protector_ret", "innerapi_tags", + "use_rtti", ]) output_dir = output_dir if (defined(invoker.configs)) { @@ -235,6 +243,9 @@ template("ohos_shared_library") { if (!defined(inputs)) { inputs = [] } + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//arkcompiler/toolchain/build/config/compiler:rtti" ] + } if (defined(version_script)) { _version_script = rebase_path(version_script, root_build_dir) @@ -318,10 +329,14 @@ template("ohos_source_set") { "subsystem_name", "part_name", "stack_protector_ret", + "use_rtti", ]) if (defined(invoker.configs)) { configs += invoker.configs } + if (defined(invoker.use_rtti) && invoker.use_rtti) { + configs += [ "//arkcompiler/toolchain/build/config/compiler:rtti" ] + } if (defined(invoker.remove_configs)) { configs -= invoker.remove_configs } diff --git a/build/toolchain/BUILD.gn b/build/toolchain/BUILD.gn new file mode 100644 index 00000000..26114b81 --- /dev/null +++ b/build/toolchain/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("$build_root/toolchain/concurrent_links.gni") + +declare_args() { + # Pool for non goma tasks. + action_pool_depth = -1 +} + +if (action_pool_depth == -1) { + action_pool_depth = exec_script("get_cpu_count.py", [], "value") +} + +if (current_toolchain == default_toolchain) { + pool("link_pool") { + depth = concurrent_links + } + + pool("action_pool") { + depth = action_pool_depth + } +} diff --git a/build/toolchain/ark/BUILD.gn b/build/toolchain/ark/BUILD.gn old mode 100755 new mode 100644 diff --git a/build/toolchain/ark/ark_toolchain.gni b/build/toolchain/ark/ark_toolchain.gni old mode 100755 new mode 100644 diff --git a/build/toolchain/cc_wrapper.gni b/build/toolchain/cc_wrapper.gni old mode 100755 new mode 100644 diff --git a/build/toolchain/clang_static_analyzer.gni b/build/toolchain/clang_static_analyzer.gni new file mode 100644 index 00000000..9cb79754 --- /dev/null +++ b/build/toolchain/clang_static_analyzer.gni @@ -0,0 +1,11 @@ +# Copyright (c) 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Defines the configuration of Clang static analysis tools. +# See docs/clang_static_analyzer.md for more information. + +declare_args() { + # Uses the Clang static analysis tools during compilation. + use_clang_static_analyzer = false +} diff --git a/build/toolchain/clang_static_analyzer_wrapper.py b/build/toolchain/clang_static_analyzer_wrapper.py new file mode 100755 index 00000000..49da59f7 --- /dev/null +++ b/build/toolchain/clang_static_analyzer_wrapper.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Adds an analysis build step to invocations of the Clang C/C++ compiler. + +Usage: clang_static_analyzer_wrapper.py [args...] +""" + +import argparse +import sys +import wrapper_utils + +# Flags used to enable analysis for Clang invocations. +analyzer_enable_flags = [ + '--analyze', +] + +# Flags used to configure the analyzer's behavior. +analyzer_option_flags = [ + '-fdiagnostics-show-option', + '-analyzer-checker=cplusplus', + '-analyzer-opt-analyze-nested-blocks', + '-analyzer-eagerly-assume', + '-analyzer-output=text', + '-analyzer-config', + 'suppress-c++-stdlib=true', + + # List of checkers to execute. + # The full list of checkers can be found at + # https://clang-analyzer.llvm.org/available_checks.html. + '-analyzer-checker=core', + '-analyzer-checker=unix', + '-analyzer-checker=deadcode', +] + + +# Prepends every element of a list |args| with |token|. +# e.g. ['-analyzer-foo', '-analyzer-bar'] => ['-Xanalyzer', '-analyzer-foo', +# '-Xanalyzer', '-analyzer-bar'] +def interleave_args(args, token): + return list(sum(zip([token] * len(args), args), ())) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--mode', + choices=['clang', 'cl'], + required=True, + help='Specifies the compiler argument convention ' + 'to use.') + parser.add_argument('args', nargs=argparse.REMAINDER) + parsed_args = parser.parse_args() + + prefix = '-Xclang' if parsed_args.mode == 'cl' else '-Xanalyzer' + cmd = parsed_args.args + analyzer_enable_flags + interleave_args( + analyzer_option_flags, prefix) + returncode, stderr = wrapper_utils.capture_command_stderr( + wrapper_utils.command_to_run(cmd)) + sys.stderr.write(stderr) + + return_code, stderr = wrapper_utils.capture_command_stderr( + wrapper_utils.command_to_run(parsed_args.args)) + sys.stderr.write(stderr) + + return return_code + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/toolchain/concurrent_links.gni b/build/toolchain/concurrent_links.gni new file mode 100644 index 00000000..7ba806c3 --- /dev/null +++ b/build/toolchain/concurrent_links.gni @@ -0,0 +1,53 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file should only be imported from files that define toolchains. +# There's no way to enforce this exactly, but all toolchains are processed +# in the context of the default_toolchain, so we can at least check for that. +assert(current_toolchain == default_toolchain) + +import("$build_root/config/compiler/compiler.gni") +import("$build_root/config/sanitizers/sanitizers.gni") +import("$build_root/toolchain/toolchain.gni") + +declare_args() { + # Limit the number of concurrent links; we often want to run fewer + # links at once than we do compiles, because linking is memory-intensive. + # The default to use varies by platform and by the amount of memory + # available, so we call out to a script to get the right value. + concurrent_links = -1 +} + +if (concurrent_links == -1) { + if (use_sanitizer_coverage || use_fuzzing_engine) { + # Sanitizer coverage instrumentation increases linker memory consumption + # significantly. + _args = [ "--mem_per_link_gb=16" ] + } else if (is_win && symbol_level == 1 && !is_debug) { + _args = [ "--mem_per_link_gb=3" ] + } else if (is_win) { + _args = [ "--mem_per_link_gb=5" ] + } else if (is_mac) { + _args = [ "--mem_per_link_gb=4" ] + } else if (is_ohos && !is_component_build && symbol_level == 2) { + # Full debug symbols require large memory for link. + _args = [ "--mem_per_link_gb=25" ] + } else if (is_ohos && !is_debug && !using_sanitizer && symbol_level < 2) { + # Increase the number of concurrent links for release bots. Debug builds + # make heavier use of ProGuard, and so should not be raised. Sanitizers also + # increase the memory overhead. + if (symbol_level == 1) { + _args = [ "--mem_per_link_gb=6" ] + } else { + _args = [ "--mem_per_link_gb=4" ] + } + } else if (is_linux) { + # Memory consumption on link without debug symbols is low on linux. + _args = [ "--mem_per_link_gb=3" ] + } else { + _args = [] + } + + concurrent_links = exec_script("get_concurrent_links.py", _args, "value") +} diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni old mode 100755 new mode 100644 diff --git a/build/toolchain/get_concurrent_links.py b/build/toolchain/get_concurrent_links.py new file mode 100755 index 00000000..4699d9b5 --- /dev/null +++ b/build/toolchain/get_concurrent_links.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This script computes the number of concurrent links we want to run +# in the build as a function of machine spec. It's based +# on GetDefaultConcurrentLinks in GYP. + +import multiprocessing +import optparse +import os +import re +import subprocess +import sys + + +def _get_total_memory_in_bytes(): + if sys.platform in ('win32', 'cygwin'): + import ctypes + + class MEMORYSTATUSEX(ctypes.Structure): + _fields_ = [ + ("dwLength", ctypes.c_ulong), + ("dwMemoryLoad", ctypes.c_ulong), + ("ullTotalPhys", ctypes.c_ulonglong), + ("ullAvailPhys", ctypes.c_ulonglong), + ("ullTotalPageFile", ctypes.c_ulonglong), + ("ullAvailPageFile", ctypes.c_ulonglong), + ("ullTotalVirtual", ctypes.c_ulonglong), + ("ullAvailVirtual", ctypes.c_ulonglong), + ("sullAvailExtendedVirtual", ctypes.c_ulonglong), + ] + + stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX)) + ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) + return stat.ullTotalPhys + elif sys.platform.startswith('linux'): + if os.path.exists("/proc/meminfo"): + with open("/proc/meminfo") as meminfo: + memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB') + for line in meminfo: + match = memtotal_re.match(line) + if not match: + continue + return float(match.group(1)) * 2**10 + elif sys.platform == 'darwin': + try: + return int(subprocess.check_output(['sysctl', '-n', 'hw.memsize'])) + except Exception: + return 0 + return 0 + + +def _get_default_concurrent_links(mem_per_link_gb, reserve_mem_gb): + mem_total_bytes = _get_total_memory_in_bytes() + mem_total_bytes = max(0, mem_total_bytes - reserve_mem_gb * 2**30) + num_concurrent_links = int( + max(1, mem_total_bytes / mem_per_link_gb / 2**30)) + hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32))) + + try: + cpu_cap = multiprocessing.cpu_count() + except: # noqa E722 + cpu_cap = 1 + + return min(num_concurrent_links, hard_cap, cpu_cap) + + +def main(): + parser = optparse.OptionParser() + parser.add_option('--mem_per_link_gb', + action="store", + type="int", + default=8) + parser.add_option('--reserve_mem_gb', + action="store", + type="int", + default=0) + parser.disable_interspersed_args() + options, _ = parser.parse_args() + + print( + _get_default_concurrent_links(options.mem_per_link_gb, + options.reserve_mem_gb)) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/toolchain/get_cpu_count.py b/build/toolchain/get_cpu_count.py new file mode 100755 index 00000000..a26b53af --- /dev/null +++ b/build/toolchain/get_cpu_count.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This script shows cpu count to specify capacity of action pool. + +import multiprocessing +import sys + + +def main(): + try: + cpu_count = multiprocessing.cpu_count() + except: # noqa E722 + cpu_count = 1 + + print(cpu_count) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn old mode 100755 new mode 100644 diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn new file mode 100644 index 00000000..6e102328 --- /dev/null +++ b/build/toolchain/mac/BUILD.gn @@ -0,0 +1,333 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("$build_root/config/clang/clang.gni") +import("$build_root/config/mac/mac_sdk.gni") +import("$build_root/config/mac/symbols.gni") + +assert(host_os == "mac") + +import("$build_root/toolchain/cc_wrapper.gni") +import("$build_root/toolchain/clang_static_analyzer.gni") +import("$build_root/toolchain/toolchain.gni") + +# When implementing tools using Python scripts, a TOOL_VERSION=N env +# variable is placed in front of the command. The N should be incremented +# whenever the script is changed, so that the build system rebuilds all +# edges that utilize the script. Ideally this should be changed to use +# proper input-dirty checking, but that could be expensive. Instead, use a +# script to get the tool scripts' modification time to use as the version. +# This won't cause a re-generation of GN files when the tool script changes +# but it will cause edges to be marked as dirty if the ninja files are +# regenerated. See https://crbug.com/619083 for details. A proper fix +# would be to have inputs to tools (https://crbug.com/621119). +tool_versions = + exec_script("get_tool_mtime.py", + rebase_path([ + "$build_root/toolchain/mac/filter_libtool.py", + "$build_root/toolchain/mac/linker_driver.py", + ], + root_build_dir), + "trim scope") + +# Shared toolchain definition. Invocations should set current_os to set the +# build args in this definition. +template("mac_toolchain") { + toolchain(target_name) { + if (use_system_xcode) { + env_wrapper = "" + } else { + env_wrapper = "export DEVELOPER_DIR=$hermetic_xcode_path; " + } + + # When invoking this toolchain not as the default one, these args will be + # passed to the build. They are ignored when this is the default toolchain. + assert(defined(invoker.toolchain_args), + "Toolchains must declare toolchain_args") + toolchain_args = { + # Populate toolchain args from the invoker. + forward_variables_from(invoker.toolchain_args, "*") + + # The host toolchain value computed by the default toolchain's setup + # needs to be passed through unchanged to all secondary toolchains to + # ensure that it's always the same, regardless of the values that may be + # set on those toolchains. + host_toolchain = host_toolchain + } + + # Supports building with the version of clang shipped with Xcode when + # targeting iOS by not respecting clang_base_path. + if (toolchain_args.current_os == "ios" && use_xcode_clang) { + prefix = "" + } else { + prefix = rebase_path("$clang_base_path/bin/", root_build_dir) + } + + _cc = "${prefix}clang" + _cxx = "${prefix}clang++" + _ar = "${prefix}llvm-ar" + + # When the invoker has explicitly overridden use_goma or cc_wrapper in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. + if (defined(toolchain_args.cc_wrapper)) { + toolchain_cc_wrapper = toolchain_args.cc_wrapper + } else { + toolchain_cc_wrapper = cc_wrapper + } + + # Compute the compiler prefix. + if (toolchain_cc_wrapper != "") { + compiler_prefix = toolchain_cc_wrapper + " " + } else { + compiler_prefix = "" + } + + cc = compiler_prefix + _cc + cxx = compiler_prefix + _cxx + ld = _cxx + + if (use_clang_static_analyzer) { + analyzer_wrapper = + rebase_path("$build_root/toolchain/clang_static_analyzer_wrapper.py", + root_build_dir) + " --mode=clang" + cc = analyzer_wrapper + " ${cc}" + cxx = analyzer_wrapper + " ${cxx}" + ld = cxx + } + + linker_driver = "TOOL_VERSION=${tool_versions.linker_driver} " + + rebase_path("$build_root/toolchain/mac/linker_driver.py", + root_build_dir) + + # On iOS, the final applications are assembled using lipo (to support fat + # builds). The correct flags are passed to the linker_driver.py script + # directly during the lipo call. + _save_unstripped_output = false + + # Make these apply to all tools below. + lib_switch = "-l" + lib_dir_switch = "-L" + + # Object files go in this directory. Use label_name instead of + # target_output_name since labels will generally have no spaces and will be + # unique in the directory. + object_subdir = "{{source_out_dir}}/{{label_name}}" + + if (_save_unstripped_output) { + _unstripped_output = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.unstripped" + } + + tool("cc") { + depfile = "{{output}}.d" + precompiled_header_type = "gcc" + command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CC {{output}}" + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + tool("cxx") { + depfile = "{{output}}.d" + precompiled_header_type = "gcc" + command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CXX {{output}}" + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + tool("asm") { + # For GCC we can just use the C compiler to compile assembly. + depfile = "{{output}}.d" + command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "ASM {{output}}" + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + tool("objc") { + depfile = "{{output}}.d" + precompiled_header_type = "gcc" + command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "OBJC {{output}}" + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + tool("objcxx") { + depfile = "{{output}}.d" + precompiled_header_type = "gcc" + command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "OBJCXX {{output}}" + outputs = [ "$object_subdir/{{source_name_part}}.o" ] + } + + tool("alink") { + rspfile = "{{output}}.rsp" + rspfile_content = "{{inputs}}" + command = "$_ar {{arflags}} -r -c -s -D {{output}} \"@$rspfile\"" + command = "rm -f {{output}} && $command" + description = "AR {{output}}" + outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] + default_output_dir = "{{target_out_dir}}" + default_output_extension = ".a" + output_prefix = "lib" + } + + tool("solink") { + dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}" # eg + # "./libfoo.dylib" + rspfile = dylib + ".rsp" + pool = "$build_root/toolchain:link_pool($default_toolchain)" + + # These variables are not built into GN but are helpers that implement + # (1) linking to produce a .dylib, (2) extracting the symbols from that + # file to a temporary file, (3) if the temporary file has differences from + # the existing .TOC file, overwrite it, otherwise, don't change it. + # + # As a special case, if the library reexports symbols from other dynamic + # libraries, we always update the .TOC and skip the temporary file and + # diffing steps, since that library always needs to be re-linked. + tocname = dylib + ".TOC" + temporary_tocname = dylib + ".tmp" + + does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB" + + link_command = "$linker_driver $ld -shared " + if (is_component_build) { + link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" " + } + link_command += "{{ldflags}} -o \"$dylib\" -Wl,-filelist,\"$rspfile\" {{libs}} {{solibs}} {{frameworks}}" + + replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\"" + extract_toc_command = "{ otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; nm -gP \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }" + + command = "$env_wrapper if $does_reexport_command ; then $link_command && $extract_toc_command > \"$tocname\"; else $link_command && $extract_toc_command > \"$temporary_tocname\" && $replace_command ; fi; fi" + + rspfile_content = "{{inputs_newline}}" + + description = "SOLINK {{output}}" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_dir = "{{root_out_dir}}" + default_output_extension = ".dylib" + + output_prefix = "lib" + + # Since the above commands only updates the .TOC file when it changes, ask + # Ninja to check if the timestamp actually changed to know if downstream + # dependencies should be recompiled. + restat = true + + # Tell GN about the output files. It will link to the dylib but use the + # tocname for dependency management. + outputs = [ + dylib, + tocname, + ] + link_output = dylib + depend_output = tocname + + if (_save_unstripped_output) { + outputs += [ _unstripped_output ] + } + } + + tool("solink_module") { + sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" # eg + # "./libfoo.so" + rspfile = sofile + ".rsp" + pool = "$build_root/toolchain:link_pool($default_toolchain)" + + link_command = "$env_wrapper $linker_driver $ld -bundle {{ldflags}} -o \"$sofile\" -Wl,-filelist,\"$rspfile\"" + if (is_component_build) { + link_command += " -Wl,-install_name,@rpath/{{target_output_name}}{{output_extension}}" + } + link_command += " {{solibs}} {{libs}}" + command = link_command + + rspfile_content = "{{inputs_newline}}" + + description = "SOLINK_MODULE {{output}}" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_dir = "{{root_out_dir}}" + default_output_extension = ".so" + + outputs = [ sofile ] + + if (_save_unstripped_output) { + outputs += [ _unstripped_output ] + } + } + + tool("link") { + outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" + rspfile = "$outfile.rsp" + pool = "$build_root/toolchain:link_pool($default_toolchain)" + + # Note about -filelist: Apple's linker reads the file list file and + # interprets each newline-separated chunk of text as a file name. It + # doesn't do the things one would expect from the shell like unescaping + # or handling quotes. In contrast, when Ninja finds a file name with + # spaces, it single-quotes them in $inputs_newline as it would normally + # do for command-line arguments. Thus any source names with spaces, or + # label names with spaces (which GN bases the output paths on) will be + # corrupted by this process. Don't use spaces for source files or labels. + command = "$env_wrapper $linker_driver $ld {{ldflags}} -o \"$outfile\" -Wl,-filelist,\"$rspfile\" {{solibs}} {{libs}} {{frameworks}}" + description = "LINK $outfile" + rspfile_content = "{{inputs_newline}}" + outputs = [ outfile ] + + if (_save_unstripped_output) { + outputs += [ _unstripped_output ] + } + + default_output_dir = "{{root_out_dir}}" + } + + # These two are really entirely generic, but have to be repeated in + # each toolchain because GN doesn't allow a template to be used here. + # See $build_root/toolchain/toolchain.gni for details. + tool("stamp") { + command = stamp_command + description = stamp_description + } + tool("copy") { + command = copy_command + description = copy_description + } + + tool("action") { + pool = "$build_root/toolchain:action_pool($default_toolchain)" + } + } +} + +mac_toolchain("clang_x64") { + toolchain_args = { + current_cpu = "x64" + current_os = "mac" + } +} + +mac_toolchain("clang_x86") { + toolchain_args = { + current_cpu = "x86" + current_os = "mac" + } +} + +mac_toolchain("clang_arm64") { + toolchain_args = { + current_cpu = "arm64" + current_os = "mac" + } +} diff --git a/build/toolchain/mac/filter_libtool.py b/build/toolchain/mac/filter_libtool.py new file mode 100755 index 00000000..d79f6648 --- /dev/null +++ b/build/toolchain/mac/filter_libtool.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import re +import subprocess +import sys + +# This script executes libtool and filters out logspam lines like: +# '/path/to/libtool: file: foo.o has no symbols' +BLOCKLIST_PATTERNS = map(re.compile, [ + r'^.*libtool: (?:for architecture: \S* )?file: .* has no symbols$', + r'^.*libtool: warning for library: .* the table of contents is empty ' + r'\(no object file members in the library define global symbols\)$', + r'^.*libtool: warning same member name \(\S*\) in output file used for ' + r'input files: \S* and: \S* \(due to use of basename, truncation, ' + r'blank padding or duplicate input files\)$', +]) + + +def is_blocklisted_line(line): + """Returns whether the line should be filtered out.""" + for pattern in BLOCKLIST_PATTERNS: + if isinstance(line, bytes): + line = line.decode() + if pattern.match(line): + return True + return False + + +def main(cmd_list): + env = os.environ.copy() + # The problem with this flag is that it resets the file mtime on the file + # to epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone. + env['ZERO_AR_DATE'] = '1' + libtoolout = subprocess.Popen(cmd_list, stderr=subprocess.PIPE, env=env) + _, err = libtoolout.communicate() + for line in err.splitlines(): + if not is_blocklisted_line(line): + print(line, file=sys.stderr) + # Unconditionally touch the output .a file on the command line if present + # and the command succeeded. A bit hacky. + if not libtoolout.returncode: + for i in range(len(cmd_list) - 1): + if cmd_list[i] == '-o' and cmd_list[i + 1].endswith('.a'): + os.utime(cmd_list[i + 1], None) + break + return libtoolout.returncode + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/build/toolchain/mac/get_tool_mtime.py b/build/toolchain/mac/get_tool_mtime.py new file mode 100755 index 00000000..4d819839 --- /dev/null +++ b/build/toolchain/mac/get_tool_mtime.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import sys + +# Usage: python get_tool_mtime.py path/to/file1.py path/to/file2.py +# +# Prints a GN scope with the variable name being the basename sans-extension +# and the value being the file modification time. A variable is emitted for +# each file argument on the command line. + +if __name__ == '__main__': + for f in sys.argv[1:]: + variable = os.path.splitext(os.path.basename(f))[0] + print('%s = %d' % (variable, os.path.getmtime(f))) diff --git a/build/toolchain/mac/linker_driver.py b/build/toolchain/mac/linker_driver.py new file mode 100755 index 00000000..e05a5694 --- /dev/null +++ b/build/toolchain/mac/linker_driver.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import os.path +import shutil +import subprocess +import sys + +""" +The linker_driver.py is responsible for forwarding a linker invocation to +the compiler driver, while processing special arguments itself. + +Usage: linker_driver.py clang++ main.o -L. -llib -o prog -Wcrl,dsym,out + +On Mac, the logical step of linking is handled by three discrete tools to +perform the image link, debug info link, and strip. The linker_driver.py +combines these three steps into a single tool. + +The command passed to the linker_driver.py should be the compiler driver +invocation for the linker. It is first invoked unaltered (except for the +removal of the special driver arguments, described below). Then the driver +performs additional actions, based on these arguments: + + -Wcrl,dsym, + After invoking the linker, this will run `dsymutil` on the linker's + output, producing a dSYM bundle, stored at dsym_path_prefix. As an + example, if the linker driver were invoked with: + "... -o out/gn/obj/foo/libbar.dylib ... -Wcrl,dsym,out/gn ..." + The resulting dSYM would be out/gn/libbar.dylib.dSYM/. + + -Wcrl,unstripped, + After invoking the linker, and before strip, this will save a copy of + the unstripped linker output in the directory unstripped_path_prefix. + + -Wcrl,strip, + After invoking the linker, and optionally dsymutil, this will run + the strip command on the linker's output. strip_arguments are + comma-separated arguments to be passed to the strip command. +""" + + +def main(args): + """main function for the linker driver. Separates out the arguments for + the main compiler driver and the linker driver, then invokes all the + required tools. + + Args: + args: list of string, Arguments to the script. + """ + + if len(args) < 2: + raise RuntimeError("Usage: linker_driver.py [linker-invocation]") + + for i in range(len(args)): + if args[i] != '--developer_dir': + continue + os.environ['DEVELOPER_DIR'] = args[i + 1] + del args[i:i + 2] + break + + # Collect arguments to the linker driver (this script) and remove them from + # the arguments being passed to the compiler driver. + linker_driver_actions = {} + compiler_driver_args = [] + for arg in args[1:]: + if arg.startswith(_LINKER_DRIVER_ARG_PREFIX): + # Convert driver actions into a map of name => lambda to invoke. + driver_action = process_linker_driver_arg(arg) + assert driver_action[0] not in linker_driver_actions + linker_driver_actions[driver_action[0]] = driver_action[1] + else: + compiler_driver_args.append(arg) + + linker_driver_outputs = [_find_linker_output(compiler_driver_args)] + + try: + # Run the linker by invoking the compiler driver. + subprocess.check_call(compiler_driver_args) + + # Run the linker driver actions, in the order specified by the actions list. + for action in _LINKER_DRIVER_ACTIONS: + name = action[0] + if name in linker_driver_actions: + linker_driver_outputs += linker_driver_actions[name](args) + except: + # If a linker driver action failed, remove all the outputs to make the + # build step atomic. + map(_remove_path, linker_driver_outputs) + + # Re-report the original failure. + raise + + +def process_linker_driver_arg(arg): + """Processes a linker driver argument and returns a tuple containing the + name and unary lambda to invoke for that linker driver action. + + Args: + arg: string, The linker driver argument. + + Returns: + A 2-tuple: + 0: The driver action name, as in _LINKER_DRIVER_ACTIONS. + 1: An 1-ary lambda that takes the full list of arguments passed to + main(). The lambda should call the linker driver action that + corresponds to the argument and return a list of outputs from the + action. + """ + if not arg.startswith(_LINKER_DRIVER_ARG_PREFIX): + raise ValueError('%s is not a linker driver argument' % (arg,)) + + sub_arg = arg[len(_LINKER_DRIVER_ARG_PREFIX):] + + for driver_action in _LINKER_DRIVER_ACTIONS: + (name, action) = driver_action + if sub_arg.startswith(name): + return (name, + lambda full_args: action(sub_arg[len(name):], full_args)) + + raise ValueError('Unknown linker driver argument: %s' % (arg,)) + + +def run_dsym_util(dsym_path_prefix, full_args): + """Linker driver action for -Wcrl,dsym,. Invokes dsymutil + on the linker's output and produces a dsym file at |dsym_file| path. + + Args: + dsym_path_prefix: string, The path at which the dsymutil output should be + located. + full_args: list of string, Full argument list for the linker driver. + + Returns: + list of string, Build step outputs. + """ + if not len(dsym_path_prefix): + raise ValueError('Unspecified dSYM output file') + + linker_out = _find_linker_output(full_args) + base = os.path.basename(linker_out) + dsym_out = os.path.join(dsym_path_prefix, base + '.dSYM') + + # Remove old dSYMs before invoking dsymutil. + _remove_path(dsym_out) + subprocess.check_call(['xcrun', 'dsymutil', '-o', dsym_out, linker_out]) + return [dsym_out] + + +def run_save_unstripped(unstripped_path_prefix, full_args): + """Linker driver action for -Wcrl,unstripped,. Copies + the linker output to |unstripped_path_prefix| before stripping. + + Args: + unstripped_path_prefix: string, The path at which the unstripped output + should be located. + full_args: list of string, Full argument list for the linker driver. + + Returns: + list of string, Build step outputs. + """ + if not len(unstripped_path_prefix): + raise ValueError('Unspecified unstripped output file') + + linker_out = _find_linker_output(full_args) + base = os.path.basename(linker_out) + unstripped_out = os.path.join(unstripped_path_prefix, base + '.unstripped') + + shutil.copyfile(linker_out, unstripped_out) + return [unstripped_out] + + +def run_strip(strip_args_string, full_args): + """Linker driver action for -Wcrl,strip,. + + Args: + strip_args_string: string, Comma-separated arguments for `strip`. + full_args: list of string, Full arguments for the linker driver. + + Returns: + list of string, Build step outputs. + """ + strip_command = ['xcrun', 'strip'] + if len(strip_args_string) > 0: + strip_command += strip_args_string.split(',') + strip_command.append(_find_linker_output(full_args)) + subprocess.check_call(strip_command) + return [] + + +def _find_linker_output(full_args): + """Finds the output of the linker by looking for the output flag in its + argument list. As this is a required linker argument, raises an error if it + cannot be found. + """ + # The linker_driver.py script may be used to wrap either the compiler linker + # (uses -o to configure the output) or lipo (uses -output to configure the + # output). Since wrapping the compiler linker is the most likely possibility + # use try/except and fallback to checking for -output if -o is not found. + try: + output_flag_index = full_args.index('-o') + except ValueError: + output_flag_index = full_args.index('-output') + return full_args[output_flag_index + 1] + + +def _remove_path(path): + """Removes the file or directory at |path| if it exists.""" + if os.path.exists(path): + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.unlink(path) + + +_LINKER_DRIVER_ARG_PREFIX = '-Wcrl,' + +"""List of linker driver actions. The sort order of this list affects the +order in which the actions are invoked. The first item in the tuple is the +argument's -Wcrl, and the second is the function to invoke. +""" +_LINKER_DRIVER_ACTIONS = [ + ('dsym,', run_dsym_util), + ('unstripped,', run_save_unstripped), + ('strip,', run_strip), +] + +if __name__ == '__main__': + main(sys.argv) + sys.exit(0) diff --git a/build/toolchain/mingw/BUILD.gn b/build/toolchain/mingw/BUILD.gn old mode 100755 new mode 100644 diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni old mode 100755 new mode 100644 index b6ecd4c4..208f26d6 --- a/build/toolchain/toolchain.gni +++ b/build/toolchain/toolchain.gni @@ -14,6 +14,8 @@ # Toolchain-related configuration that may be needed outside the context of the # toolchain() rules themselves. +import("$build_root/misc/overrides/build.gni") + declare_args() { # If this is set to true, or if LLVM_FORCE_HEAD_REVISION is set to 1 # in the environment, we use the revision in the llvm repo to determine @@ -54,6 +56,8 @@ assert(!use_xcode_clang || target_os == "ios", # Extension for shared library files (including leading dot). if (is_mac) { shlib_extension = ".dylib" + dylib_extension = ".dylib.so" + rlib_extension = ".rlib" } else if (is_ohos && is_component_build) { # By appending .z, we prevent name collisions with libraries already loaded by the ohos. shlib_extension = ".z.so" diff --git a/tooling/BUILD.gn b/tooling/BUILD.gn index e8dcf561..df744b8c 100644 --- a/tooling/BUILD.gn +++ b/tooling/BUILD.gn @@ -25,7 +25,7 @@ config("ark_ecma_debugger_config") { "//third_party/cJSON", "//third_party/libuv/include", ] - if (!is_mingw && !is_mac && target_os != "ios") { + if (!is_mingw && target_os != "ios") { include_dirs += [ "//third_party/libuv/include" ] } } diff --git a/tooling/client/BUILD.gn b/tooling/client/BUILD.gn index c01354cc..d5aae4d3 100644 --- a/tooling/client/BUILD.gn +++ b/tooling/client/BUILD.gn @@ -47,6 +47,7 @@ ohos_source_set("libark_client_set") { ] deps += [ + "$ark_third_party_root/cJSON:cjson_static", "$ark_third_party_root/libuv:uv", "$ark_third_party_root/openssl:libcrypto_shared", "..:libark_ecma_debugger", -- Gitee