mirror of
https://github.com/mollyim/ringrtc.git
synced 2025-05-14 06:10:38 +01:00

This saves binary size for features we're not using. Also, skip building WebRTC tools. This just saves build time.
451 lines
17 KiB
Python
Executable file
451 lines
17 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
#
|
|
# Copyright 2019-2021 Signal Messenger, LLC
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
#
|
|
|
|
"""
|
|
This script generates libringrtc.aar for distribution
|
|
"""
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#
|
|
# Imports
|
|
#
|
|
|
|
try:
|
|
import argparse
|
|
import logging
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
import zipfile
|
|
import shutil
|
|
|
|
except ImportError as e:
|
|
raise ImportError(str(e) + "- required module not found")
|
|
|
|
|
|
DEFAULT_ARCHS = ['arm', 'arm64', 'x86', 'x64']
|
|
NINJA_TARGETS = ['ringrtc']
|
|
JAR_FILES = [
|
|
'lib.java/ringrtc/libringrtc.jar',
|
|
'lib.java/sdk/android/libwebrtc.jar',
|
|
]
|
|
SO_LIBS = [
|
|
'libringrtc_rffi.so',
|
|
'libringrtc.so',
|
|
]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
#
|
|
# Main
|
|
#
|
|
def ParseArgs():
|
|
parser = argparse.ArgumentParser(
|
|
description='Build and package libringrtc.aar')
|
|
parser.add_argument('-v', '--verbose',
|
|
action='store_true',
|
|
help='Verbose output')
|
|
parser.add_argument('-q', '--quiet',
|
|
action='store_true',
|
|
help='Quiet output')
|
|
parser.add_argument('-b', '--build-dir',
|
|
required=True,
|
|
help='Build directory')
|
|
parser.add_argument('-w', '--webrtc-src-dir',
|
|
required=True,
|
|
help='WebRTC source root directory')
|
|
parser.add_argument('-o', '--output',
|
|
default = 'libringrtc.aar',
|
|
help='Output AAR file name')
|
|
parser.add_argument('-d', '--debug-build',
|
|
action='store_true',
|
|
help='Build a debug version of the AAR. Default is both')
|
|
parser.add_argument('-r', '--release-build',
|
|
action='store_true',
|
|
help='Build a release version of the AAR. Default is both')
|
|
parser.add_argument('-a', '--arch',
|
|
default=DEFAULT_ARCHS,
|
|
choices=DEFAULT_ARCHS,
|
|
nargs='*',
|
|
help='CPU architectures to build. Defaults: %(default)s.')
|
|
parser.add_argument('-g', '--extra-gn-args',
|
|
nargs='*', default=[],
|
|
help='''Additional GN arguments, passed via `gn --args` switch.
|
|
These args override anything set internally by this script.''')
|
|
parser.add_argument('-n', '--extra-ninja-flags',
|
|
nargs='*', default=[],
|
|
help='''Additional Ninja flags, overriding anything set internally
|
|
by this script.''')
|
|
parser.add_argument('-f', '--extra-gn-flags',
|
|
nargs='*', default=[],
|
|
help='''Additional GN flags, overriding anything set internally
|
|
by this script.''')
|
|
parser.add_argument('-j', '--jobs',
|
|
default=32,
|
|
help='Number of parallel ninja jobs to run.')
|
|
parser.add_argument('--gradle-dir',
|
|
required=True,
|
|
help='Android gradle directory')
|
|
parser.add_argument('--publish-version',
|
|
required=True,
|
|
help='Library version to publish')
|
|
parser.add_argument('--extra-gradle-args',
|
|
nargs='*', default=[],
|
|
help='Additional gradle arguments')
|
|
parser.add_argument('--install-local',
|
|
action='store_true',
|
|
help='Install to local maven repo')
|
|
parser.add_argument('--install-dir',
|
|
help='Install to local directory')
|
|
parser.add_argument('--upload-sonatype-repo',
|
|
help='Upload to remote sonatype repo')
|
|
parser.add_argument('--upload-sonatype-user',
|
|
help='Upload to remote sonatype repo as user')
|
|
parser.add_argument('--upload-sonatype-password',
|
|
help='Upload to remote sonatype repo using password')
|
|
parser.add_argument('--signing-keyid',
|
|
help='''GPG keyId for signing key (8 character short form).
|
|
See https://docs.gradle.org/current/userguide/signing_plugin.html''')
|
|
parser.add_argument('--signing-password',
|
|
help='''GPG passphrase for signing key.
|
|
See https://docs.gradle.org/current/userguide/signing_plugin.html''')
|
|
parser.add_argument('--signing-secret-keyring',
|
|
help='''Absolute path to the secret key ring file containing signing key.
|
|
See https://docs.gradle.org/current/userguide/signing_plugin.html''')
|
|
parser.add_argument('--dry-run',
|
|
action='store_true',
|
|
help='Dry Run: print what would happen, but do not actually do anything')
|
|
parser.add_argument('-u', '--unstripped',
|
|
action='store_true',
|
|
help='Store the unstripped libraries in the .aar. Default is false')
|
|
parser.add_argument('-c', '--compile-only',
|
|
action='store_true',
|
|
help='Only compile the code, do not build the .aar. Default is false')
|
|
parser.add_argument('--clean',
|
|
action='store_true',
|
|
help='Remove all the build products. Default is false')
|
|
|
|
return parser.parse_args()
|
|
|
|
def RunSdkmanagerLicenses(dry_run):
|
|
executable = os.path.join('third_party', 'android_sdk', 'public',
|
|
'cmdline-tools', 'latest', 'bin', 'sdkmanager')
|
|
cmd = [ executable, '--licenses' ]
|
|
logging.debug('Running: {}'.format(cmd))
|
|
if dry_run is False:
|
|
subprocess.check_call(cmd)
|
|
|
|
def RunGn(dry_run, args):
|
|
cmd = [ 'gn' ] + args
|
|
logging.debug('Running: {}'.format(cmd))
|
|
if dry_run is False:
|
|
subprocess.check_call(cmd)
|
|
|
|
def RunNinja(dry_run, args):
|
|
cmd = [ 'ninja' ] + args
|
|
logging.debug('Running: {}'.format(cmd))
|
|
if dry_run is False:
|
|
subprocess.check_call(cmd)
|
|
|
|
def GetArchBuildRoot(build_dir, arch):
|
|
return os.path.join(build_dir, 'android-{}'.format(arch))
|
|
|
|
def GetArchBuildDir(build_dir, arch, debug_build):
|
|
if debug_build is True:
|
|
build_type = 'debug'
|
|
else:
|
|
build_type = 'release'
|
|
|
|
return os.path.join(GetArchBuildRoot(build_dir, arch), '{}'.format(build_type))
|
|
|
|
def GetOutputDir(build_dir, debug_build):
|
|
if debug_build is True:
|
|
build_type = 'debug'
|
|
else:
|
|
build_type = 'release'
|
|
|
|
return os.path.join(build_dir, '{}'.format(build_type))
|
|
|
|
def GetGradleBuildDir(build_dir):
|
|
return os.path.join(build_dir, 'gradle')
|
|
|
|
def BuildArch(dry_run, build_dir, arch, debug_build, extra_gn_args,
|
|
extra_gn_flags, extra_ninja_flags, jobs):
|
|
|
|
logging.info('Building: {} ...'.format(arch))
|
|
|
|
output_dir = GetArchBuildDir(build_dir, arch, debug_build)
|
|
gn_args = {
|
|
'target_os' : '"android"',
|
|
'target_cpu' : '"{}"'.format(arch),
|
|
'is_debug' : 'false',
|
|
'rtc_include_tests' : 'false',
|
|
'rtc_build_examples' : 'false',
|
|
'rtc_build_tools' : 'false',
|
|
'rtc_enable_protobuf' : 'false',
|
|
'rtc_enable_sctp' : 'false',
|
|
'rtc_libvpx_build_vp9': 'false',
|
|
'rtc_include_ilbc' : 'false',
|
|
}
|
|
if debug_build is True:
|
|
gn_args['is_debug'] = 'true'
|
|
gn_args['symbol_level'] = '2'
|
|
|
|
gn_args_string = '--args=' + ' '.join(
|
|
[k + '=' + v for k, v in gn_args.items()] + extra_gn_args)
|
|
|
|
gn_total_args = [ 'gen', output_dir, gn_args_string ] + extra_gn_flags
|
|
RunGn(dry_run, gn_total_args)
|
|
|
|
ninja_args = [ '-C', output_dir ] + NINJA_TARGETS + [ '-j', jobs ] + extra_ninja_flags
|
|
RunNinja(dry_run, ninja_args)
|
|
|
|
def GetABI(arch):
|
|
if arch == 'arm':
|
|
return 'armeabi-v7a'
|
|
elif arch == 'arm64':
|
|
return 'arm64-v8a'
|
|
elif arch == 'x86':
|
|
return 'x86'
|
|
elif arch == 'x64':
|
|
return 'x86_64'
|
|
else:
|
|
raise Exception('Unknown architecture: ' + arch)
|
|
|
|
def CreateLibs(dry_run, build_dir, archs, output, debug_build, unstripped,
|
|
extra_gn_args, extra_gn_flags, extra_ninja_flags, jobs,
|
|
compile_only):
|
|
|
|
for arch in archs:
|
|
BuildArch(dry_run, build_dir, arch, debug_build, extra_gn_args,
|
|
extra_gn_flags, extra_ninja_flags, jobs)
|
|
|
|
if compile_only is True:
|
|
return
|
|
|
|
output_dir = os.path.join(GetOutputDir(build_dir, debug_build),
|
|
'libs')
|
|
output_file = os.path.join(output_dir, output)
|
|
if dry_run is True:
|
|
return
|
|
|
|
shutil.rmtree(GetOutputDir(build_dir, debug_build), ignore_errors=True)
|
|
os.makedirs(output_dir)
|
|
|
|
for jar in JAR_FILES:
|
|
logging.debug(' Adding jar: {} ...'.format(jar))
|
|
output_arch_dir = GetArchBuildDir(build_dir, archs[0], debug_build)
|
|
shutil.copyfile(os.path.join(output_arch_dir, jar),
|
|
os.path.join(output_dir, os.path.basename(jar)))
|
|
|
|
for arch in archs:
|
|
for lib in SO_LIBS:
|
|
output_arch_dir = GetArchBuildDir(build_dir, arch, debug_build)
|
|
if unstripped is True:
|
|
# package the unstripped libraries
|
|
lib_file = os.path.join("lib.unstripped", lib)
|
|
else:
|
|
lib_file = lib
|
|
target_dir = os.path.join(output_dir, GetABI(arch))
|
|
logging.debug(' Adding lib: {}/{} to {}...'.format(GetABI(arch), lib_file, target_dir))
|
|
os.makedirs(target_dir, exist_ok=True)
|
|
shutil.copyfile(os.path.join(output_arch_dir, lib_file),
|
|
os.path.join(target_dir,
|
|
os.path.basename(lib)))
|
|
|
|
def RunGradle(dry_run, args):
|
|
cmd = [ './gradlew' ] + args
|
|
logging.debug('Running: {}'.format(cmd))
|
|
if dry_run is False:
|
|
subprocess.check_call(cmd)
|
|
|
|
def CreateAar(dry_run, extra_gradle_args, version, gradle_dir,
|
|
sonatype_repo, sonatype_user, sonatype_password,
|
|
signing_keyid, signing_password, signing_secret_keyring,
|
|
compile_only,
|
|
install_local, install_dir, build_dir, archs,
|
|
output, debug_build, release_build, unstripped,
|
|
extra_gn_args, extra_gn_flags, extra_ninja_flags, jobs):
|
|
|
|
build_types = []
|
|
if not (debug_build or release_build):
|
|
# build both
|
|
build_types = ['debug', 'release']
|
|
else:
|
|
if debug_build:
|
|
build_types = ['debug']
|
|
if release_build:
|
|
build_types = build_types + ['release']
|
|
|
|
gradle_build_dir = GetGradleBuildDir(build_dir)
|
|
shutil.rmtree(gradle_build_dir, ignore_errors=True)
|
|
gradle_args = [
|
|
'-PringrtcVersion={}'.format(version),
|
|
'-PbuildDir={}'.format(gradle_build_dir),
|
|
]
|
|
|
|
if sonatype_repo is not None:
|
|
sonatype_args = [
|
|
'-PsonatypeRepo={}'.format(sonatype_repo),
|
|
'-PsignalSonatypeUsername={}'.format(sonatype_user),
|
|
'-PsignalSonatypePassword={}'.format(sonatype_password),
|
|
]
|
|
gradle_args.extend(sonatype_args)
|
|
|
|
if signing_keyid is not None:
|
|
gradle_args.append(
|
|
'-Psigning.keyId={}'.format(signing_keyid))
|
|
|
|
if signing_password is not None:
|
|
gradle_args.append(
|
|
'-Psigning.password={}'.format(signing_password))
|
|
|
|
if signing_secret_keyring is not None:
|
|
gradle_args.append(
|
|
'-Psigning.secretKeyRingFile={}'.format(signing_secret_keyring))
|
|
|
|
for build_type in build_types:
|
|
if build_type == 'debug':
|
|
build_debug = True
|
|
output_dir = GetOutputDir(build_dir, build_debug)
|
|
lib_dir = os.path.join(output_dir, 'libs')
|
|
gradle_args = gradle_args + [
|
|
"-PdebugRingrtcLibDirs=['{}']".format(lib_dir),
|
|
"-PdebugOutputDir={}".format(output_dir),
|
|
]
|
|
else:
|
|
build_debug = False
|
|
output_dir = GetOutputDir(build_dir, build_debug)
|
|
lib_dir = os.path.join(output_dir, 'libs')
|
|
gradle_args = gradle_args + [
|
|
"-PreleaseRingrtcLibDirs=['{}']".format(lib_dir),
|
|
"-PreleaseOutputDir={}".format(output_dir),
|
|
]
|
|
CreateLibs(dry_run, build_dir, archs, output, build_debug, unstripped,
|
|
extra_gn_args, extra_gn_flags, extra_ninja_flags, jobs,
|
|
compile_only)
|
|
|
|
if compile_only is True:
|
|
return
|
|
|
|
gradle_args.append('assemble')
|
|
|
|
if install_local is True:
|
|
gradle_args.append('installArchives')
|
|
|
|
if sonatype_repo is not None:
|
|
gradle_args.append('uploadArchives')
|
|
|
|
gradle_args.extend(extra_gradle_args)
|
|
|
|
# Run gradle
|
|
os.chdir(os.path.abspath(gradle_dir))
|
|
RunGradle(dry_run, gradle_args)
|
|
|
|
if install_dir is not None:
|
|
for build_type in build_types:
|
|
if build_type == 'debug':
|
|
build_debug = True
|
|
output_dir = GetOutputDir(build_dir, build_debug)
|
|
dest_dir = os.path.join(install_dir, version, 'android', 'debug')
|
|
else:
|
|
build_debug = False
|
|
output_dir = GetOutputDir(build_dir, build_debug)
|
|
dest_dir = os.path.join(install_dir, version, 'android', 'release')
|
|
|
|
logging.info('Installing locally to: {}'.format(dest_dir))
|
|
if dry_run is False:
|
|
shutil.rmtree(dest_dir, ignore_errors=True)
|
|
os.makedirs(os.path.dirname(dest_dir), exist_ok=True)
|
|
shutil.copytree(output_dir, dest_dir)
|
|
|
|
def clean_dir(directory, dry_run):
|
|
logging.info('Removing: {}'.format(directory))
|
|
if dry_run is False:
|
|
shutil.rmtree(directory, ignore_errors=True)
|
|
|
|
def main():
|
|
|
|
args = ParseArgs()
|
|
|
|
if args.dry_run is True:
|
|
args.verbose = True
|
|
|
|
if args.verbose is True:
|
|
log_level = logging.DEBUG
|
|
else:
|
|
log_level = logging.INFO
|
|
|
|
logging.basicConfig(level=log_level, format='%(levelname).1s:%(message)s')
|
|
|
|
if args.quiet is True:
|
|
logging.disable(logging.CRITICAL)
|
|
|
|
build_dir = os.path.abspath(args.build_dir)
|
|
logging.debug('Using build directory: {}'.format(build_dir))
|
|
|
|
if args.verbose is True:
|
|
args.extra_ninja_flags = args.extra_ninja_flags + ['-v']
|
|
|
|
gradle_dir = os.path.abspath(args.gradle_dir)
|
|
logging.debug('Using gradle directory: {}'.format(gradle_dir))
|
|
|
|
if args.clean is True:
|
|
for arch in DEFAULT_ARCHS:
|
|
rm_dir = GetArchBuildRoot(build_dir, arch)
|
|
clean_dir(GetArchBuildRoot(build_dir, arch), args.dry_run)
|
|
clean_dir(GetGradleBuildDir(build_dir), args.dry_run)
|
|
for dir in ('debug', 'release', 'javadoc', 'rustdoc', 'rust-lint'):
|
|
clean_dir(os.path.join(build_dir, dir), args.dry_run)
|
|
return 0
|
|
|
|
os.chdir(os.path.abspath(args.webrtc_src_dir))
|
|
RunSdkmanagerLicenses(args.dry_run)
|
|
|
|
if args.upload_sonatype_repo is not None:
|
|
if args.debug_build is True or args.release_build is True:
|
|
print('ERROR: When uploading, must upload complete release and debug builds')
|
|
print('ERROR: You cannot specifiy either --release or --debug while uploading')
|
|
return 1
|
|
|
|
if args.upload_sonatype_user is None or args.upload_sonatype_password is None:
|
|
print('ERROR: If --upload-sonatype-repo argument set, then both --upload-sonatype-user and --upload-sonatype-password must also be set.')
|
|
return 1
|
|
|
|
if args.signing_keyid is None or \
|
|
args.signing_password is None or \
|
|
args.signing_secret_keyring is None:
|
|
print('ERROR: If --upload-sonatype-repo argument set, then all of --signing-keyid, --signing-password, and --signing-secret-keyring must also be set.')
|
|
return 1
|
|
|
|
CreateAar(args.dry_run, args.extra_gradle_args, args.publish_version, args.gradle_dir,
|
|
args.upload_sonatype_repo, args.upload_sonatype_user, args.upload_sonatype_password,
|
|
args.signing_keyid, args.signing_password, args.signing_secret_keyring,
|
|
args.compile_only,
|
|
args.install_local, args.install_dir,
|
|
build_dir, args.arch, args.output,
|
|
args.debug_build, args.release_build, args.unstripped, args.extra_gn_args,
|
|
args.extra_gn_flags, args.extra_ninja_flags, str(args.jobs))
|
|
|
|
logging.info('''
|
|
Version : {}
|
|
Architectures : {}
|
|
Debug Build : {}
|
|
Release Build : {}
|
|
Build Directory : {}
|
|
Stripped Libraries: {}
|
|
'''.format(args.publish_version, args.arch, args.debug_build,
|
|
args.release_build, args.build_dir, not args.unstripped))
|
|
|
|
return 0
|
|
|
|
|
|
# --------------------
|
|
#
|
|
# execution check
|
|
#
|
|
if __name__ == '__main__':
|
|
exit(main())
|