Source release 17.1.0
This commit is contained in:
276
build.py
276
build.py
@@ -1,7 +1,11 @@
|
||||
#!/usr/bin/python3 -B
|
||||
# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
# source code may only be used and distributed under the Widevine Master
|
||||
# License Agreement.
|
||||
# source code may only be used and distributed under the Widevine License
|
||||
# Agreement.
|
||||
|
||||
# b/230527132: Even though this usually uses Python3, we still need to support
|
||||
# Python2 for Cobalt builds.
|
||||
|
||||
"""Generates build files and builds the CDM source release."""
|
||||
|
||||
# Lint as: python2, python3
|
||||
@@ -13,44 +17,20 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# pylint: disable=C6204
|
||||
import build_utils
|
||||
|
||||
# Absolute path to Widevine CDM project repository.
|
||||
CDM_TOP_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||
COBALT_TOP_PATH = os.path.join(CDM_TOP_PATH, '..', '..')
|
||||
|
||||
# If gyp has been installed locally in third_party, this will find it.
|
||||
# Irrelevant if gyp has been installed globally.
|
||||
sys.path.insert(1, os.path.join(CDM_TOP_PATH, 'third_party'))
|
||||
import gyp
|
||||
# pylint: enable=C6204
|
||||
|
||||
PLATFORMS_DIR_PATH = os.path.join(CDM_TOP_PATH, 'platforms')
|
||||
OEMCRYPTO_FUZZTEST_DIR_PATH = os.path.join(CDM_TOP_PATH, 'oemcrypto', 'test',
|
||||
'fuzz_tests')
|
||||
# NOTE: Use relative paths for most of this because the Xcode generator tends
|
||||
# to ignore the output directory if you use absolute paths.
|
||||
PLATFORMS_DIR_PATH = 'platforms'
|
||||
|
||||
# Exit status for script if failure arises.
|
||||
EXIT_FAILURE = 1
|
||||
|
||||
|
||||
def LoadFields(path):
|
||||
"""Loads variables from an external python script.
|
||||
|
||||
Attempts to load the specified python fields from the source file
|
||||
specified at the given |path|.
|
||||
|
||||
Args:
|
||||
path: The path (absolute to relative) to the source file containing module
|
||||
to be loaded.
|
||||
|
||||
Returns:
|
||||
The fields dictionary if it is successfully loaded. Otherwise
|
||||
returns None
|
||||
"""
|
||||
fields = {}
|
||||
with open(path) as f:
|
||||
exec(f.read(), fields, fields) # pylint: disable=W0122
|
||||
return fields
|
||||
|
||||
|
||||
def IsNinjaInstalled():
|
||||
"""Determine if ninja is installed."""
|
||||
try:
|
||||
@@ -84,7 +64,7 @@ def PlatformExists(platform, print_details=False):
|
||||
True if the there exists configuration files for the specified |platform|,
|
||||
False otherwise.
|
||||
"""
|
||||
target_path = os.path.join(PLATFORMS_DIR_PATH, platform)
|
||||
target_path = os.path.join(CDM_TOP_PATH, PLATFORMS_DIR_PATH, platform)
|
||||
platform_gypi_path = os.path.join(target_path, 'settings.gypi')
|
||||
platform_environment_path = os.path.join(target_path, 'environment.py')
|
||||
|
||||
@@ -114,13 +94,14 @@ def RetrieveListOfPlatforms():
|
||||
Returns:
|
||||
A list of strings containing the name of the platform
|
||||
"""
|
||||
if not os.path.isdir(PLATFORMS_DIR_PATH):
|
||||
path = os.path.join(CDM_TOP_PATH, PLATFORMS_DIR_PATH)
|
||||
if not os.path.isdir(path):
|
||||
print(
|
||||
'Cannot find platforms directory: expected_path = {}'.format(
|
||||
PLATFORMS_DIR_PATH),
|
||||
path),
|
||||
file=sys.stderr)
|
||||
return []
|
||||
return sorted(filter(PlatformExists, os.listdir(PLATFORMS_DIR_PATH)))
|
||||
return sorted(filter(PlatformExists, os.listdir(path)))
|
||||
|
||||
|
||||
def VerboseSubprocess(args):
|
||||
@@ -129,47 +110,88 @@ def VerboseSubprocess(args):
|
||||
return subprocess.call(args)
|
||||
|
||||
|
||||
def RunMake(unused_output_path, build_config, job_limit, verbose):
|
||||
def RunMake(unused_output_path, options):
|
||||
"""Run Make as build system."""
|
||||
os.environ['BUILDTYPE'] = build_config
|
||||
os.environ['BUILDTYPE'] = options.build_config
|
||||
|
||||
if job_limit is not None:
|
||||
if math.isinf(job_limit):
|
||||
if options.jobs is not None:
|
||||
if math.isinf(options.jobs):
|
||||
job_args = ['-j']
|
||||
else:
|
||||
job_args = ['-j', str(job_limit)]
|
||||
job_args = ['-j', str(options.jobs)]
|
||||
else:
|
||||
job_args = []
|
||||
|
||||
if verbose:
|
||||
if options.verbose:
|
||||
job_args.append('-v')
|
||||
job_args.extend(['all', 'widevine_ce_cdm_shared'])
|
||||
job_args += options.target
|
||||
return VerboseSubprocess(['make', '-C', CDM_TOP_PATH] + job_args)
|
||||
|
||||
|
||||
def RunNinja(output_path, build_config, job_limit, verbose):
|
||||
def RunNinja(output_path, options):
|
||||
"""Run Ninja as build system."""
|
||||
build_path = os.path.join(output_path, build_config)
|
||||
build_path = os.path.join(output_path, options.build_config)
|
||||
|
||||
if job_limit is not None:
|
||||
if math.isinf(job_limit):
|
||||
if options.jobs is not None:
|
||||
if math.isinf(options.jobs):
|
||||
print('Ninja cannot run an infinite number of jobs', file=sys.stderr)
|
||||
print('Running at most 1000 jobs')
|
||||
job_limit = 1000
|
||||
job_args = ['-j', str(job_limit)]
|
||||
options.jobs = 1000
|
||||
job_args = ['-j', str(options.jobs)]
|
||||
else:
|
||||
job_args = []
|
||||
|
||||
if verbose:
|
||||
if options.verbose:
|
||||
job_args += ['-v']
|
||||
job_args += ['all', 'widevine_ce_cdm_shared']
|
||||
job_args += options.target
|
||||
return VerboseSubprocess(['ninja', '-C', build_path] + job_args)
|
||||
|
||||
|
||||
def RunXcode(output_path, options):
|
||||
"""Run Xcode as a build system."""
|
||||
if 'all' in options.target:
|
||||
scheme = 'All'
|
||||
elif len(options.target) == 1:
|
||||
scheme = options.target[0]
|
||||
else:
|
||||
raise ValueError('Can only specify one target on Xcode')
|
||||
|
||||
cmd = [
|
||||
'xcodebuild', 'test' if options.xcode_test else 'build',
|
||||
'-project', os.path.join(output_path, 'cdm', 'cdm_unittests.xcodeproj'),
|
||||
'-scheme', scheme,
|
||||
'-configuration', options.build_config,
|
||||
'-derivedDataPath', os.path.join(output_path, 'DerivedData'),
|
||||
]
|
||||
if options.xcode_test:
|
||||
cmd += ['-only-testing:' + scheme]
|
||||
if options.ios_device_name:
|
||||
if options.ios:
|
||||
cmd += ['-destination', 'platform=iOS,name=' + options.ios_device_name]
|
||||
else:
|
||||
cmd += [
|
||||
'-destination',
|
||||
'platform=iOS Simulator,name=' + options.ios_device_name,
|
||||
]
|
||||
elif options.ios:
|
||||
cmd += ['-destination', 'generic/platform=iOS']
|
||||
elif options.ios_sim:
|
||||
cmd += ['-destination', 'generic/platform=iOS Simulator']
|
||||
else:
|
||||
cmd += ['-destination', 'platform=macOS,arch=x86_64']
|
||||
|
||||
if options.jobs is not None:
|
||||
cmd += ['-jobs', str(options.jobs)]
|
||||
if not options.verbose:
|
||||
cmd += ['-quiet']
|
||||
return VerboseSubprocess(cmd)
|
||||
|
||||
|
||||
# Map from generator name to generator invocation function.
|
||||
BUILDERS = {
|
||||
'make': RunMake,
|
||||
'ninja': RunNinja,
|
||||
'xcode': RunXcode,
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +199,7 @@ def GetBuilder(generator):
|
||||
return BUILDERS.get(generator)
|
||||
|
||||
|
||||
def ImportPlatform(platform, gyp_args, build_fuzz_tests):
|
||||
def ImportPlatform(platform, is_cobalt, skip_deps, gyp_args):
|
||||
"""Handles platform-specific setup for the named platform.
|
||||
|
||||
Computes platform-specific paths, sets gyp arguments for platform-specific
|
||||
@@ -186,8 +208,8 @@ def ImportPlatform(platform, gyp_args, build_fuzz_tests):
|
||||
|
||||
Args:
|
||||
platform: The name of the platform.
|
||||
skip_deps: Whether to skip updating submodules.
|
||||
gyp_args: An array of gyp arguments to which this function will append.
|
||||
build_fuzz_tests: True when we are building OEMCrypto fuzz tests.
|
||||
|
||||
Returns:
|
||||
The path to the root of the build output.
|
||||
@@ -196,34 +218,54 @@ def ImportPlatform(platform, gyp_args, build_fuzz_tests):
|
||||
print(' Target Platform: ' + platform)
|
||||
assert PlatformExists(platform)
|
||||
|
||||
target_path = os.path.join(PLATFORMS_DIR_PATH, platform)
|
||||
target_path = os.path.join(CDM_TOP_PATH, PLATFORMS_DIR_PATH, platform)
|
||||
platform_gypi_path = os.path.join(target_path, 'settings.gypi')
|
||||
platform_environment_path = os.path.join(target_path, 'environment.py')
|
||||
output_path = os.path.join(CDM_TOP_PATH, 'out', platform)
|
||||
# Use an absolute path so the Ninja generator finds the correct path; this
|
||||
# still works with the Xcode generator, which doesn't like absolute paths.
|
||||
if is_cobalt:
|
||||
output_path = os.path.join('out')
|
||||
else:
|
||||
output_path = os.path.join(CDM_TOP_PATH, 'out', platform)
|
||||
gyp_args.append('--generator-output=' + output_path)
|
||||
|
||||
gyp_args.append('--include=' + platform_gypi_path)
|
||||
if build_fuzz_tests:
|
||||
fuzzer_settings_path = os.path.join(OEMCRYPTO_FUZZTEST_DIR_PATH,
|
||||
'platforms/x86-64')
|
||||
fuzzer_settings_gypi_path = os.path.join(fuzzer_settings_path,
|
||||
'fuzzer_settings.gypi')
|
||||
gyp_args.append('--include=' + fuzzer_settings_gypi_path)
|
||||
gyp_args.append('-Goutput_dir=' + output_path)
|
||||
|
||||
platform_environment_path = os.path.join(target_path, 'environment.py')
|
||||
target = LoadFields(platform_environment_path)
|
||||
target = build_utils.LoadPlatform(platform)
|
||||
|
||||
if not skip_deps and 'submodules' in target:
|
||||
for path in target['submodules']:
|
||||
print(' Updating submodule:', path)
|
||||
if subprocess.call(['git', '-C', CDM_TOP_PATH, 'submodule', 'update',
|
||||
'--init', path]) != 0:
|
||||
return None
|
||||
|
||||
if 'gyp_args' in target:
|
||||
gyp_args.extend(target['gyp_args'])
|
||||
|
||||
if 'export_variables' in target:
|
||||
for variable, value in target['export_variables'].items():
|
||||
if not os.environ.get(variable):
|
||||
existing_value = os.environ.get(variable)
|
||||
if not existing_value:
|
||||
if '/' in value or '\\' in value:
|
||||
# Use absolute paths since the output directory will be different. If
|
||||
# "value" is already absolute, os.path.join will only use that part.
|
||||
value = os.path.normpath(os.path.join(CDM_TOP_PATH, target_path,
|
||||
value))
|
||||
os.environ[variable] = value
|
||||
print(' set {} to {}'.format(variable, value))
|
||||
print('* Set {} to "{}"'.format(variable, value))
|
||||
else:
|
||||
print('* Did not set {} to "{}"'.format(variable, value))
|
||||
print(' {} is already set to "{}"'.format(variable, existing_value))
|
||||
|
||||
return output_path
|
||||
|
||||
|
||||
def main(args):
|
||||
if IsNinjaInstalled():
|
||||
if sys.platform == 'darwin':
|
||||
print('Host platform is Mac - use xcode for default generator')
|
||||
default_generator = 'xcode'
|
||||
elif IsNinjaInstalled():
|
||||
print('ninja is installed - use ninja for default generator')
|
||||
default_generator = 'ninja'
|
||||
else:
|
||||
@@ -233,6 +275,7 @@ def main(args):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'platform',
|
||||
nargs='?',
|
||||
help=('The platform to target. To add a new platform, create a new '
|
||||
'platform directory with "environment.py" and "settings.gypi" '
|
||||
'files under platforms/.'),
|
||||
@@ -260,6 +303,16 @@ def main(args):
|
||||
help=('Select a build configuration to use. Any configuration defined in '
|
||||
'the chosen platform\'s "settings.gypi" file may be used.'))
|
||||
|
||||
ios_group = parser.add_mutually_exclusive_group()
|
||||
ios_group.add_argument(
|
||||
'--ios',
|
||||
action='store_true',
|
||||
help=('On Mac, build for iOS device instead.'))
|
||||
ios_group.add_argument(
|
||||
'--ios_sim',
|
||||
action='store_true',
|
||||
help=('On Mac, build for iOS simulator instead.'))
|
||||
|
||||
parser.add_argument(
|
||||
'-g',
|
||||
'--generator',
|
||||
@@ -267,6 +320,12 @@ def main(args):
|
||||
help='Which build system to use. Defaults to {}.'.format(
|
||||
default_generator),
|
||||
choices=BUILDERS.keys())
|
||||
parser.add_argument(
|
||||
'-t',
|
||||
'--target',
|
||||
nargs='+',
|
||||
default=['all', 'widevine_ce_cdm_shared'],
|
||||
help='Which target(s) to build. Can specify multiple values.')
|
||||
parser.add_argument(
|
||||
'-j',
|
||||
'--jobs',
|
||||
@@ -291,19 +350,53 @@ def main(args):
|
||||
help=('External GYP file that is processed after the standard GYP files. '
|
||||
'(May be specified multiple times.)'))
|
||||
parser.add_argument(
|
||||
'-ft',
|
||||
'--fuzz_tests',
|
||||
'--xcode_test',
|
||||
action='store_true',
|
||||
help='Set this flag if you want to build fuzz tests.')
|
||||
help='When using Xcode, run tests in addition to building.')
|
||||
parser.add_argument(
|
||||
'--ios_device_name',
|
||||
help='Use the given iOS device name for builds/tests.')
|
||||
parser.add_argument(
|
||||
'-v',
|
||||
'--verbose',
|
||||
action='store_true',
|
||||
help=('Print verbose build output, including verbose output from the '
|
||||
'generator.'))
|
||||
parser.add_argument(
|
||||
'--skip-deps',
|
||||
action='store_true',
|
||||
help="Don't download/update submodules.")
|
||||
parser.add_argument(
|
||||
'--cobalt',
|
||||
metavar='CONFIG',
|
||||
help=('Build using Cobalt tools using the given Cobalt config; project '
|
||||
'must be checked out within the Cobalt source tree.'))
|
||||
|
||||
options = parser.parse_args(args)
|
||||
|
||||
if options.cobalt:
|
||||
if sys.version_info.major != 2:
|
||||
parser.error('Must use python2 with --cobalt')
|
||||
if options.ios or options.ios_sim:
|
||||
parser.error('Cannot use --cobalt with --ios/--ios_sim')
|
||||
if not options.platform:
|
||||
options.platform = 'cobalt'
|
||||
if not options.platform:
|
||||
parser.error('Must specify platform or use --cobalt')
|
||||
|
||||
# pylint: disable=C6204
|
||||
# If gyp has been installed locally in third_party, this will find it.
|
||||
# Irrelevant if gyp has been installed globally.
|
||||
if options.cobalt:
|
||||
os.chdir(COBALT_TOP_PATH)
|
||||
sys.path.insert(1, os.path.join(COBALT_TOP_PATH, 'tools', 'gyp', 'pylib'))
|
||||
sys.path.append(COBALT_TOP_PATH)
|
||||
else:
|
||||
os.chdir(CDM_TOP_PATH)
|
||||
sys.path.insert(1, os.path.join(CDM_TOP_PATH, 'third_party'))
|
||||
import gyp
|
||||
# pylint: enable=C6204
|
||||
|
||||
if not PlatformExists(options.platform, print_details=True):
|
||||
platforms = RetrieveListOfPlatforms()
|
||||
if platforms:
|
||||
@@ -311,22 +404,44 @@ def main(args):
|
||||
return EXIT_FAILURE
|
||||
|
||||
gyp_args = [
|
||||
'--format=' + options.generator,
|
||||
'--depth=' + CDM_TOP_PATH,
|
||||
'-D', 'generator=' + options.generator,
|
||||
# On iOS, we can't easily pass environment variables, so we define a
|
||||
# compiler flag to store the filter.
|
||||
'-D', 'gtest_filter=' + os.environ.get('GTEST_FILTER', '*'),
|
||||
'--depth', '.',
|
||||
]
|
||||
if options.fuzz_tests:
|
||||
gyp_args.append(
|
||||
os.path.join(OEMCRYPTO_FUZZTEST_DIR_PATH, 'oemcrypto_fuzztests.gyp'))
|
||||
if options.cobalt:
|
||||
os.environ['COBALT_CONFIG'] = options.cobalt
|
||||
options.build_config = options.cobalt + '_' + options.build_config
|
||||
gyp_args += [
|
||||
'-f', options.generator + '-' + options.cobalt,
|
||||
'--toplevel-dir=.',
|
||||
'-DOS=starboard',
|
||||
'-Gconfig=' + options.build_config,
|
||||
]
|
||||
else:
|
||||
gyp_args.append(os.path.join(CDM_TOP_PATH, 'cdm', 'cdm_unittests.gyp'))
|
||||
gyp_args += [
|
||||
'-f', options.generator,
|
||||
]
|
||||
|
||||
if options.ios or options.ios_sim:
|
||||
gyp_args += ['-DOS=ios']
|
||||
for var in options.define:
|
||||
gyp_args.append('-D' + var)
|
||||
|
||||
for var in options.extra_gyp:
|
||||
gyp_args.append(var)
|
||||
|
||||
for var in options.define:
|
||||
gyp_args.append('-D' + var)
|
||||
output_path = ImportPlatform(options.platform, options.cobalt,
|
||||
options.skip_deps, gyp_args)
|
||||
if not output_path:
|
||||
return 1
|
||||
|
||||
output_path = ImportPlatform(options.platform, gyp_args, options.fuzz_tests)
|
||||
if options.cobalt:
|
||||
gyp_args.append(os.path.join('third_party', 'cdm', 'cdm',
|
||||
'cdm_unittests.gyp'))
|
||||
else:
|
||||
gyp_args.append(os.path.join('cdm', 'cdm_unittests.gyp'))
|
||||
|
||||
print(' Running: {}'.format(' '.join(['gyp'] + gyp_args)))
|
||||
retval = gyp.main(gyp_args)
|
||||
@@ -341,8 +456,7 @@ def main(args):
|
||||
print(' Cannot automatically build with this generator', file=sys.stderr)
|
||||
print(' Please start the build manually', file=sys.stderr)
|
||||
return EXIT_FAILURE
|
||||
return builder(output_path, options.build_config, options.jobs,
|
||||
options.verbose)
|
||||
return builder(output_path, options)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user