# Copyright (c) 2024 The Brave Authors. All rights reserved. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at https://mozilla.org/MPL/2.0/. import argparse import inspect import os import shutil import sys from distutils.dir_util import copy_tree from brave_chromium_utils import wspath from lib.config import PLATFORM, enable_verbose_mode, is_verbose_mode from lib.util import execute_stdout from pathlib import Path def main(): if PLATFORM != 'darwin': # Only applicable to macOS sys.exit(0) args = parse_args() if args.verbose: enable_verbose_mode() create_required_spm_resources(force=args.force) generate_lldbinit(force=args.force) def parse_args(): parser = argparse.ArgumentParser(description='Bootstrap the iOS project') parser.add_argument('-v', '--verbose', action='store_true', help='Prints the output of the subprocesses') parser.add_argument('-f', '--force', action='store_true', help='Always rewrite the symlink/directory entirely') return parser.parse_args() def create_required_spm_resources(force=False): # Runs webpack on the JS files that are generated in iOS. This is so that # Package.swift/SPM resolves with the resources available execute_stdout(['npm', 'run', 'ios_pack_js']) # Creates the expected out/ios_current_link directory and places placeholder # xcframeworks inside to ensure Package.swift/SPM validates the manifest # correctly. ios_current_link = Path(wspath("//out/ios_current_link")) if ios_current_link.is_symlink(): # Check if the symlink is valid and unlink if its not, (or in the case # of --force, unlink anyways so it can be removed) if force or not os.path.exists(os.readlink(ios_current_link)): ios_current_link.unlink() if force and ios_current_link.exists(): # Remove the directory entirely shutil.rmtree(ios_current_link) ios_current_link.mkdir(parents=True, exist_ok=True) # Make xcframework placeholders for targets exported by the iOS GN target # These are essentially the bare-essential requirements for SPM to validate # the Package.swift manifest: The existence of the xcframework directory # itself, plus a valid Info.plist inside it. frameworks = ['BraveCore', 'MaterialComponents', 'NalaAssets'] for frmk in frameworks: framework_dir = os.path.join(ios_current_link, f'{frmk}.xcframework') if force and os.path.exists(framework_dir): shutil.rmtree(framework_dir) if not os.path.exists(framework_dir): Path(framework_dir).mkdir(parents=True) info_plist = wspath( "//brave/ios/brave-ios/BraveCore/placeholders/xcframework.plist" ) shutil.copyfile(info_plist, os.path.join(framework_dir, 'Info.plist')) # Creates an empty args.xcconfig due to a race in Xcode which seems to fail # to find the xcconfig after its generated during the build preaction script args_config_path = os.path.join(ios_current_link, 'args.xcconfig') if force or not os.path.exists(args_config_path): Path(args_config_path).touch() def generate_lldbinit(force=False): contents = inspect.cleandoc(f""" # This file is generated by ios_bootstrap.py # # This allows proper source mapping to builds made with the GN arg # strip_absolute_paths_from_debug_symbols set to true. settings set target.source-map "../.." "{wspath("//")}" """) lldbinit_file = wspath("//brave/ios/brave-ios/App/Configuration/LLDBInit") if force or not os.path.exists(lldbinit_file): with open(lldbinit_file, 'w') as f: f.write(contents) if __name__ == '__main__': main()