#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Copyright (C) 2019 Apple Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # BaseGenerator is the base class for generating new .xcfilelist content. Most # of the implementation is provided in this base class. Subclasses are created # to provide project-specific information, such as the path to the project file # and valid platform and configuration information. # # Instances of this class are create for each project/platform/configuration # triple. For each triple, .xcfilelist content is generated and compared to the # file that ultimately will contain that information. Any new lines are # determined and remembered for later addition to that destination file. # # Instances of this class can operate in either of two contexts. First, it's # possible for Xcode projects to invoke this script in order to keep their # .xcfilelist files up-to-date. In that case, this script starts out running in # the context of Xcode and it can just go ahead and generate the new content. # Alternatively, it's possible for someone to invoke this script from the # command line. In that case, this script needs to sublaunch itself in order to # expose itself to the environment variables that Xcode establishes during # builds. This script thus starts out as a free-standing script, creates a # BaseGenerator for the .xcfilelist content it needs to create, sub-launches # itself, and then creates another BaseGenerator to do the actual generation. # When this inner instance of the script exits, it writes the results of the # BaseGenerators to a temporary file. When the outer instance of the script # resumes, it reads the information from that temporary file. That information # is actually just a serialized (pickled) BaseGenerator instance and is # restored as such. This restored BaseGenerator now replaces the original # BaseGenerator in the outer script that caused it to be created, since the # inner one is the one with all the xcfilelist information. from __future__ import print_function import itertools import os import pickle import re import tempfile import traceback import webkitpy.generate_xcfilelists_lib.util as util from webkitpy.xcode import xcode_hash_for_path from webkitpy.xcode.sdk import SDK from webkitpy.common.attribute_saver import AttributeSaver class BaseGenerator(object): __slots__ = ( "application", "project_tag", "platform", "configuration", "triple", "ex_type", "ex_value", "ex_traceback", "added_lines_input_derived", "added_lines_output_derived", "added_lines_input_unified", "added_lines_output_unified", "cached_build_dirs") VALID_PLATFORMS = None VALID_CONFIGURATIONS = None @util.LogEntryExit def __init__(self, application, project_tag, platform, configuration): self.application = application self.project_tag = project_tag self.platform = platform self.configuration = configuration self.triple = (project_tag, platform, configuration) self.ex_type = None self.ex_value = None self.ex_traceback = None self.added_lines_input_derived = None self.added_lines_output_derived = None self.added_lines_input_unified = None self.added_lines_output_unified = None self.cached_build_dirs = None def __str__(self): return "project_tag = {}, platform = {}, configuration = {}, ex_type = {}, ex_value = {}, ex_traceback = {}, added_lines_input_derived = {}, added_lines_output_derived = {}, added_lines_input_unified = {}, added_lines_output_unified = {}, cached_build_dirs = {}".format( self.project_tag, self.platform, self.configuration, self.ex_type, self.ex_value, self.ex_traceback, self.added_lines_input_derived, self.added_lines_output_derived, self.added_lines_input_unified, self.added_lines_output_unified, self.cached_build_dirs) # Generate new .xcfilist list contents and return any new lines. This # generation is performed by relaunching ourselves under Xcode so that we # can operate in the context of its environment variables. When we relaunch # ourselves, we do so in a way that invokes this class's generate() # method. Any results from generate are written to a temporary file that # we set up here. When the relaunched instance completes, we reads those # results from the temporary file. @util.LogEntryExit def set_environment_and_generate(self): with tempfile.NamedTemporaryFile() as pickle_file, tempfile.NamedTemporaryFile() as debug_file: sublaunch_args = [ "PATH=\"{}:${{PATH}}\"".format(self._getenv("PATH")), # Xcode will "sanitize" PATH, such that Python is no longer on it, so get /usr/bin back in PATH. "PYTHONPATH=\"{}\"".format(self._getenv("PYTHONPATH", "")), self.application.get_generate_xcfilelists_script_path(), "generate-inner", "--project", self.project_tag, "--platform", self.platform, "--configuration", self.configuration, "--pickle-file", pickle_file.name] if self.application.cmd_line_args.debug: sublaunch_args += [ "--debug", "--debug-file", debug_file.name] if self.application.cmd_line_args.quiet: sublaunch_args.append("--quiet") try: self._sublaunch_under_xcode(sublaunch_args) finally: # If xcodebuild returns an error, we want to at least display the # debugging information. if self.application.cmd_line_args.debug: for line in debug_file: util.debug_log("{}".format(line.rstrip())) generators = [] while True: try: generator = pickle.load(pickle_file) generator.application = self.application generators.append(generator) except EOFError: break return generators # Relaunch this script under Xcode. This is performed by launching Xcode, # pointing it to the project that we are processing as well as a build # target that will re-execute us as a custom build step. @util.LogEntryExit def _sublaunch_under_xcode(self, sublaunch_args): xcode_parameters = [ "xcodebuild", "-project", self._get_project_file_path(), "-sdk", SDK.get_preferred_sdk_for_platform(self.platform).as_xcode_specification(), "-configuration", self.configuration, "-target", "Apply Configuration to XCFileLists", "SYMROOT={}".format(self._get_sym_root()), "OBJROOT={}".format(self._get_obj_root()), "SHARED_PRECOMPS_DIR={}".format(self._get_shared_precomps_dir())] # TODO: sublaunch_args will contain the path to the script to # sublaunch. There might be a problem if there's a space in that path. util.subprocess_run(xcode_parameters, env={"WK_SUBLAUNCH_SCRIPT_PARAMETERS": " ".join(sublaunch_args)}) # Generate the .xcfilelist content. Save the results internally as sets of # new lines to be added to the .xcfilelist files. These new lines can be # merged into those files if the user specified a "generate" command, or # can be reported in a "check" command. @util.LogEntryExit def generate(self): self._generate_derived() self._generate_unified() # Merge any saved added lines to their ultimate destinations. @util.LogEntryExit def merge(self): self._merge_derived() self._merge_unified() @util.LogEntryExit def pickle_to_file(self, f): # We don't want to pickle the application reference # We can't seem to pickle ex_traceback: PicklingError: Can't pickle : it's not found as __builtin__.traceback with AttributeSaver(self, "application"), AttributeSaver(self, "ex_traceback"): pickle.dump(self, f, pickle.HIGHEST_PROTOCOL) # Return whether or not any new lines for any .xcfilelist files were # discovered. @util.LogEntryExit def has_action(self): return (self.added_lines_input_derived or self.added_lines_output_derived or self.added_lines_input_unified or self.added_lines_output_unified) # If any errors occur during the generation of .xcfilelist content, they # are remembered internally for later processing. This function returns # whether or not any such error occurred with this generator. @util.LogEntryExit def has_error(self): return self.ex_type # Return whether or not the combination of project, platform, and # configuration is valid (which is to say, if, for example, the given # project can be built for the given platform and configuration). @util.LogEntryExit def is_valid(self): return (self.platform in self.__class__.VALID_PLATFORMS and self.configuration in self.__class__.VALID_CONFIGURATIONS) # If an error/exception occurred and was recorded (that is, if has_error() # returns true), report that error to the console. @util.LogEntryExit def report_error(self): try: if self.ex_value: raise self.ex_value except KeyboardInterrupt: print("### Canceled") except util.CalledProcessError as e: print("### Error {} calling subprocess: {}".format(e.args[0], e.args[1])) if e.args[2]: print("### stdout = {}".format(e.args[2])) if e.args[3]: print("### stderr = {}".format(e.args[3])) except util.InvalidConfigurationError as e: print("### Invalid configuration: {}".format(e)) return os.EX_USAGE except BaseException: traceback.print_exception(self.ex_type, self.ex_value, self.ex_traceback) return os.EX_SOFTWARE # Generate .xcfilelist content for the "Generate Derived Sources" build # phase. @util.LogEntryExit def _generate_derived(self): script = self._get_generate_derived_sources_script() if not script: return with tempfile.NamedTemporaryFile(dir=self._get_temp_dir()) as input, \ tempfile.NamedTemporaryFile(dir=self._get_temp_dir()) as output: (stdout, stderr) = util.subprocess_run( [script, "NO_SUPPLEMENTAL_FILES=1", "--no-builtin-rules", "--dry-run", "--always-make", "--debug=abvijm", "all"]) stdout = stdout.encode() if isinstance(stdout, str) else stdout (stdout, stderr) = util.subprocess_run( [self.application.get_extract_dependencies_from_makefile_script(), "--input", input.name, "--output", output.name], input=stdout) # TODO: Make this generator-specific (there's no need to reference # WebCore, for example, when processing the JavaScriptCore # project). input_lines = self._get_file_lines(input.name) output_lines = self._get_file_lines(output.name) input_lines = self._replacePrefix(input_lines, "JavaScriptCore/", "$(PROJECT_DIR)/") input_lines = self._replacePrefix(input_lines, "JavaScriptCorePrivateHeaders/", "$(JAVASCRIPTCORE_PRIVATE_HEADERS_DIR)/") input_lines = self._replacePrefix(input_lines, "WebCore/", "$(PROJECT_DIR)/") input_lines = self._replacePrefix(input_lines, "WebKit2PrivateHeaders/", "$(WEBKIT2_PRIVATE_HEADERS_DIR)/") input_lines = self._unexpand(input_lines, "JAVASCRIPTCORE_PRIVATE_HEADERS_DIR") input_lines = self._unexpand(input_lines, "PROJECT_DIR") input_lines = self._unexpand(input_lines, "WEBCORE_PRIVATE_HEADERS_DIR") input_lines = self._unexpand(input_lines, "WEBKIT2_PRIVATE_HEADERS_DIR") input_lines = self._unexpand(input_lines, "WEBKITADDITIONS_HEADERS_FOLDER_PATH") input_lines = self._unexpand(input_lines, "BUILT_PRODUCTS_DIR") # Do this last, since it's a prefix of some other variables and will "intercept" them if executed earlier than them. output_lines = [self._get_derived_sources_dir() + "/" + line for line in output_lines] output_lines = self._unexpand(output_lines, "BUILT_PRODUCTS_DIR") self.added_lines_input_derived = self._find_added_lines(input_lines, self._get_input_derived_xcfilelist_project_path()) self.added_lines_output_derived = self._find_added_lines(output_lines, self._get_output_derived_xcfilelist_project_path()) @util.LogEntryExit def _merge_derived(self): self._merge_added_lines(self.added_lines_input_derived, self._get_input_derived_xcfilelist_project_path()) self._merge_added_lines(self.added_lines_output_derived, self._get_output_derived_xcfilelist_project_path()) # Generate .xcfilelist content for the "Generate Unified Sources" build # phase. @util.LogEntryExit def _generate_unified(self): script = self._get_generate_unified_sources_script() if not script: return with tempfile.NamedTemporaryFile(dir=self._get_temp_dir()) as output: # We need to define BUILD_SCRIPTS_DIR so that the bash script we're # invoking can find the ruby script that it invokes. If we don't # define BUILD_SCRIPTS_DIR, the bash script we're invoking with try # to define its own value for BUILD_SCRIPTS_DIR, but it will do so # incorrectly for our purposes, leading to dire results. env = os.environ.copy() env["BUILD_SCRIPTS_DIR"] = self.application.get_build_scripts_dir() util.subprocess_run( [script, "--generate-xcfilelists", "--output-xcfilelist-path", output.name], env=env) input_lines = None output_lines = self._get_file_lines(output.name) output_lines = self._unexpand(output_lines, "BUILT_PRODUCTS_DIR") self.added_lines_input_unified = self._find_added_lines(input_lines, self._get_input_unified_xcfilelist_project_path()) self.added_lines_output_unified = self._find_added_lines(output_lines, self._get_output_unified_xcfilelist_project_path()) @util.LogEntryExit def _merge_unified(self): self._merge_added_lines(self.added_lines_input_unified, self._get_input_unified_xcfilelist_project_path()) self._merge_added_lines(self.added_lines_output_unified, self._get_output_unified_xcfilelist_project_path()) # Utility for post-processing the initial .xcfilelist content. Used to # replace text in the file. def _replaceSinglePrefix(self, line, prefix, replace_with): if line.startswith(prefix): return replace_with + line[len(prefix):] return line @util.LogEntryExit def _replacePrefix(self, lines, to_replace, replace_with): return set([self._replaceSinglePrefix(line, to_replace, replace_with) for line in lines]) # Utility for post-processing the initial .xcfilelist content. Used to # replace file path segments with the variables that represent those path # segments. # # The way we approach this gets a little involved. The straightforward # approach would be to fetch the value (a file system path) of the given # environment variable, and then replace that path with the variable name # in each of the given lines if the particular line is prefixed with that # path. So, for instance, converting: # # /Volumes/Data/dev/webkit/OpenSource/WebKitBuild/Debug/DerivedSources/JavaScriptCore/ErrorPrototype.lut.h # # to: # # $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/ErrorPrototype.lut.h # # However, there are issues with symlinks messing up that prefix matching. # It's possible for the entries in "lines" to contain fully resolved paths, # while the variable contains a path that has components that are symlinks. # These symlinks need to be resolved before the prefix matching can be # performed. That is, if BUILT_PRODUCTS_DIR contained # "/Users/Me/webkit/OpenSource/WebKitBuild/Debug", we would need to first # resolve that to "/Volumes/Data/dev/webkit/OpenSource/WebKitBuild/Debug" # before trying to replace it in any lines that are prefixed with it. # # Further, it's not always the case that the entries in "lines" contain # fully-resolved paths. For instance, some of them may refer to something # like .PrivateHeaders, which may be a symlink in a non-shallow # framework. If an incoming replacement value referred to that # PrivateHeaders directory, after being resolved, it now refers to the # versioned location (that is, /Versions/A/PrivateHeaders), and # will no longer match a path expressed in terms of # .PrivateHeaders. This means that each entry in "lines" also # needs to be fully resolved. # # And, yet, there's still a wrinkle. Sometimes we *don't* want to expand # the paths in "lines". An example of this occurs in DumpRenderTree, where # we wanted to convert: # # /Volumes/Data/dev/webkit/OpenSource/Tools/DumpRenderTree/../TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl # # to: # # $(PROJECT_DIR)/../TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl # # If we merely resolved the path, it would have been turned into: # # /Volumes/Data/dev/webkit/OpenSource/Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl # # and it would no longer have a prefix that matched $PROJECT_DIR. So we # adopt an approach where we'll try both the raw and resolved paths in the # given environment variable, and the raw and resolved paths in each of the # entries in "lines". @util.LogEntryExit def _unexpand(self, lines, variable_name): prefix = self._getenv(variable_name) if not prefix: return lines def _expand_if_abs(path): return os.path.realpath(path) if os.path.isabs(path) else path def _variations(path): def _gen(path): yield path yield _expand_if_abs(path) return (x for x in _gen(path)) def _try_unexpand(prefix, line): new_line = self._replaceSinglePrefix(line, prefix + "/", "$({})/".format(variable_name)) return new_line != line, new_line def _do_unexpand(line): for a_prefix, a_line in itertools.product(_variations(prefix), _variations(line)): changed, new_line = _try_unexpand(a_prefix, a_line) if changed: break return new_line if changed else line return set(_do_unexpand(line) for line in lines) # Given a source file with new .xcfilelist content and a dest file that # contains the original/previous .xcfilelist content (that is, likely the # file that's checked into the repo), determine what, if any, new lines # there are in source that aren't in dest. @util.LogEntryExit def _find_added_lines(self, source, dest): if not source: return set() def get_lines(source): return source if isinstance(source, set) else set(source) if isinstance(source, list) else self._get_file_lines(source) source_lines = get_lines(source) dest_lines = get_lines(dest) delta_lines = source_lines - dest_lines return delta_lines # Bottleneck routine for taking a set of new lines of .xcfilelist content # and adding them to their ultimate file/destination. @util.LogEntryExit def _merge_added_lines(self, added_lines, dest): if not added_lines: return dest_lines = self._get_file_lines(dest) merged_lines = sorted(set(added_lines) | dest_lines) merged_lines = [line + "\n" for line in merged_lines if line and not line.startswith("#")] merged_lines[0:0] = ["# This file is generated by the generate-xcfilelists script.\n"] with open(dest, "w") as f: f.writelines(merged_lines) # Utility to read a file and results the contents as a set of lines with # EOLs removed. @util.LogEntryExit def _get_file_lines(self, file): try: with open(file, "r") as f: return set([line.strip() for line in f]) except: return set() # Wrapper to return environment variable values. @util.LogEntryExit def _getenv(self, variable_name, default=None): return os.environ.get(variable_name, default) # Return the path to the project file (the *.xcodeproj "file). @util.LogEntryExit def _get_project_file_path(self): assert False, """\ Override this to return full path to the project file (e.g., ".../Source/JavaScriptCore/JavaScriptCode.xcodeproj").""" # Return the path to the directory containing the project file and its # supporting files and directories (e.g., ".../Source/JavaScriptCore"). @util.LogEntryExit def _get_project_dir(self): return os.path.dirname(self._get_project_file_path()) # Return the project file name (e.g., "JavaScriptCore.xcodeproj"). @util.LogEntryExit def _get_project_file_name(self): return os.path.basename(self._get_project_file_path()) # Return the project name (e.g., "JavaScriptCore"). @util.LogEntryExit def _get_project_name(self): return os.path.splitext(self._get_project_file_name())[0] # Return the path to the build output directory to use when the user has # indicated that they are building from the command line. Be sure to # support default command-line users, command-line users that set # WEBKIT_OUTPUTDIR, default Xcode users, and people like Jeff Miller who # configure a custom build output location for Xcode. @util.LogEntryExit def _get_sym_root(self): return self._get_build_dirs()[0] @util.LogEntryExit def _get_obj_root(self): return self._get_build_dirs()[1] @util.LogEntryExit def _get_shared_precomps_dir(self): return os.path.join(self._get_build_dirs()[1], "PrecompiledHeaders") # From Xcode; # # export SYMROOT =/Users/keith/Library/Developer/Xcode/DerivedData/Safari-bmjhivzkbpxamlajyexvkivfjbmb/Build/Products # export OBJROOT =/Users/keith/Library/Developer/Xcode/DerivedData/Safari-bmjhivzkbpxamlajyexvkivfjbmb/Build/Intermediates.noindex # export SHARED_PRECOMPS_DIR=/Users/keith/Library/Developer/Xcode/DerivedData/Safari-bmjhivzkbpxamlajyexvkivfjbmb/Build/Intermediates.noindex/PrecompiledHeaders # # From command-line: # # export SYMROOT =/Volumes/Data/dev/webkit/OpenSource/WebKitBuild # export OBJROOT =/Volumes/Data/dev/webkit/OpenSource/WebKitBuild # export SHARED_PRECOMPS_DIR=/Volumes/Data/dev/webkit/OpenSource/WebKitBuild/PrecompiledHeaders @util.LogEntryExit def _get_build_dirs(self): def define_xcode_build_dirs(self): # Delete any spurious ~/Library/Preferences/xcodebuild.plist, as this # file will interfere with any preferences set in the IDE. This # .plist file shouldn't really ever exist, so nuking it doesn't # cause any problems. xcodebuild_plist = os.path.join(os.path.expanduser("~"), "Library", "Preferences", "xcodebuild.plist") try: os.unlink(xcodebuild_plist) except: pass def read_xcode_user_default(key): try: (stdout, stderr) = util.subprocess_run(["defaults", "read", "com.apple.dt.Xcode", key]) return stdout.strip() except util.CalledProcessError: return None # The following is based on the logic in determineBaseProductDir() # in webkitdirs.pm and https://pewpewthespells.com/blog/xcode_build_locations.html. # Get the base directory for the build output. This will be some # default location (e.g., ~/Library/Developer/Xcode/DerivedData), # an absolute path, or a project-relative path. ide_custom_derived_data_location = read_xcode_user_default("IDECustomDerivedDataLocation") # Path not specified; use the default. if not ide_custom_derived_data_location: base_dir = os.path.join(os.path.expanduser("~"), "Library", "Developer", "Xcode", "DerivedData") # An absolute path is specified; use it. elif os.path.isabs(ide_custom_derived_data_location): base_dir = ide_custom_derived_data_location # A relative path is specified; append it to the project path. else: base_dir = os.path.join(self._get_project_dir(), ide_custom_derived_data_location) # Get the specification for how the build output should be stored # withing that base directory. This will be some unique directory # based on the hash of the project file path (e.g., # "Safari-sdlfkhasalksdjfhsdfhlksf"), some shared directory (e.g., # "Build"), or even something that might be an absolute path. ide_build_location_style = read_xcode_user_default("IDEBuildLocationStyle") # Create a unique directory within the base directory based on # project name and hash of its full path. # # IDEBuildLocationStyle = Unique; # This is the default if not specified. if ide_build_location_style == "Unique" or not ide_build_location_style: workspace = os.path.abspath(self.application.cmd_line_args.xcode) build_dir = os.path.join( base_dir, os.path.splitext(os.path.basename(workspace))[0] + "-" + xcode_hash_for_path(workspace), "Build") products_dir = os.path.join(build_dir, "Products") intermediates_dir = os.path.join(build_dir, "Intermediates.noindex") # Use a shared subdirectory; use the specified directory name. # # IDEBuildLocationStyle = Shared; # IDESharedBuildFolderName = Build; # Relative to DerivedDataLocation elif ide_build_location_style == "Shared": build_dir = os.path.join(base_dir, read_xcode_user_default("IDESharedBuildFolderName")) products_dir = os.path.join(build_dir, "Products") intermediates_dir = os.path.join(build_dir, "Intermediates.noindex") # Use the saved products and intermediates paths and either use # them as relative to the DerivedData directory or the project # folder, or just use them as absolute addresses. # # IDEBuildLocationStyle = Custom; elif ide_build_location_style == "Custom": ide_build_location_type = read_xcode_user_default("IDECustomBuildLocationType") products_dir = read_xcode_user_default("IDECustomBuildProductsPath") intermediates_dir = read_xcode_user_default("IDECustomBuildIntermediatesPath") # IDECustomBuildLocationType = RelativeToDerivedData; # IDECustomBuildIntermediatesPath = "Build/Intermediates.noindex"; # IDECustomBuildProductsPath = "Build/Products"; # IDECustomIndexStorePath = "Index/DataStore"; if ide_build_location_type == "RelativeToDerivedData": products_dir = os.path.join(base_dir, products_dir) intermediates_dir = os.path.join(base_dir, intermediates_dir) # IDECustomBuildLocationType = RelativeToWorkspace; # IDECustomBuildIntermediatesPath = "Build/Intermediates.noindex"; # IDECustomBuildProductsPath = "Build/Products"; # IDECustomIndexStorePath = "Index/DataStore"; elif ide_build_location_type == "RelativeToWorkspace": base_dir = self._get_project_dir(), products_dir = os.path.join(base_dir, products_dir) intermediates_dir = os.path.join(base_dir, intermediates_dir) # IDECustomBuildLocationType = Absolute; # IDECustomBuildIntermediatesPath = "/Users/joedeveloper/Desktop/Build/Intermediates.noindex"; # IDECustomBuildProductsPath = "/Users/joedeveloper/Desktop/Build/Products"; # IDECustomIndexStorePath = "/Users/joedeveloper/Desktop/Index/DataStore"; # IDECustomDerivedDataLocation = "/Users/joedeveloper/Library/Developer/Xcode/DerivedData"; elif ide_build_location_type == "Absolute": pass else: assert False, "Unknown/unsupported location type" else: assert False, "Unknown/unsupported style" return (products_dir, intermediates_dir) def define_command_line_build_dirs(self): products_dir = self._getenv("WEBKIT_OUTPUTDIR") if not products_dir: products_dir = os.path.join(self.application.get_opensource_dir(), "WebKitBuild") return (products_dir, products_dir) if not self.cached_build_dirs and self.application.cmd_line_args.xcode: self.cached_build_dirs = define_xcode_build_dirs(self) if not self.cached_build_dirs: self.cached_build_dirs = define_command_line_build_dirs(self) return self.cached_build_dirs # Return the location of the DerivedSources directory. Conventionally, we # use $BUILT_PRODUCTS/DerivedSources/$PROJECT_NAME, but we may some day use # $DERIVED_FILE_DIR aka $DERIVED_FILES_DIR aka $DERIVED_SOURCES_DIR, when # the projects have been updated to use them. @util.LogEntryExit def _get_derived_sources_dir(self): return os.path.join(self.application.get_xcode_built_products_dir(), "DerivedSources", self._get_project_name()) # Return the location for the xcfilelists. @util.LogEntryExit def _get_xcfilelist_dir(self): return self._get_project_dir() # Return the paths to the actual xcfilelists. @util.LogEntryExit def _get_input_derived_xcfilelist_project_path(self): return os.path.join(self._get_xcfilelist_dir(), "DerivedSources-input.xcfilelist") @util.LogEntryExit def _get_output_derived_xcfilelist_project_path(self): return os.path.join(self._get_xcfilelist_dir(), "DerivedSources-output.xcfilelist") @util.LogEntryExit def _get_input_unified_xcfilelist_project_path(self): return os.path.join(self._get_xcfilelist_dir(), "UnifiedSources-input.xcfilelist") @util.LogEntryExit def _get_output_unified_xcfilelist_project_path(self): return os.path.join(self._get_xcfilelist_dir(), "UnifiedSources-output.xcfilelist") # Return the paths to the scripts that generate the derived sources. @util.LogEntryExit def _get_generate_derived_sources_script(self): return None @util.LogEntryExit def _get_generate_unified_sources_script(self): return None @util.LogEntryExit def _get_temp_dir(self): return self.application.get_xcode_project_temp_dir() class JavaScriptCoreGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", "iphoneos", "iphonesimulator", "watchos", "watchsimulator", "appletvos", "appletvsimulator") VALID_CONFIGURATIONS = ("Debug", "Release", "Production", "Profiling") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Source", "JavaScriptCore", "JavaScriptCore.xcodeproj") @util.LogEntryExit def _get_generate_derived_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-derived-sources.sh") @util.LogEntryExit def _get_generate_unified_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-unified-sources.sh") class WebCoreGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", "iphoneos", "iphonesimulator", "watchos", "watchsimulator", "appletvos", "appletvsimulator") VALID_CONFIGURATIONS = ("Debug", "Release", "Production") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Source", "WebCore", "WebCore.xcodeproj") @util.LogEntryExit def _get_generate_derived_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-derived-sources.sh") @util.LogEntryExit def _get_generate_unified_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-unified-sources.sh") class WebKitGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", "iphoneos", "iphonesimulator", "watchos", "watchsimulator", "appletvos", "appletvsimulator") VALID_CONFIGURATIONS = ("Debug", "Release", "Production") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Source", "WebKit", "WebKit.xcodeproj") @util.LogEntryExit def _get_derived_sources_dir(self): return os.path.join(self.application.get_xcode_built_products_dir(), "DerivedSources", "WebKit") @util.LogEntryExit def _get_generate_derived_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-derived-sources.sh") @util.LogEntryExit def _get_generate_unified_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-unified-sources.sh") class WebKitLegacyGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", "iphoneos", "iphonesimulator", "watchos", "watchsimulator", "appletvos", "appletvsimulator") VALID_CONFIGURATIONS = ("Debug", "Release", "Production") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Source", "WebKitLegacy", "WebKitLegacy.xcodeproj") @util.LogEntryExit def _get_generate_unified_sources_script(self): return os.path.join(self._get_project_dir(), "scripts", "generate-unified-sources.sh") class DumpRenderTreeGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", ) VALID_CONFIGURATIONS = ("Debug", "Release", "Production") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Tools", "DumpRenderTree", "DumpRenderTree.xcodeproj") @util.LogEntryExit def _get_generate_derived_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-derived-sources.sh") class WebKitTestRunnerGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", ) VALID_CONFIGURATIONS = ("Debug", "Release", "Production") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Tools", "WebKitTestRunner", "WebKitTestRunner.xcodeproj") @util.LogEntryExit def _get_generate_derived_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-derived-sources.sh") class TestWebKitAPIGenerator(BaseGenerator): VALID_PLATFORMS = ("macosx", "iphoneos", "iphonesimulator", "watchos", "watchsimulator", "appletvos", "appletvsimulator") VALID_CONFIGURATIONS = ("Debug", "Release", "Production") @util.LogEntryExit def _get_project_file_path(self): return os.path.join(self.application.get_opensource_dir(), "Tools", "TestWebKitAPI", "TestWebKitAPI.xcodeproj") @util.LogEntryExit def _get_generate_unified_sources_script(self): return os.path.join(self._get_project_dir(), "Scripts", "generate-unified-sources.sh")