| #!/usr/bin/env python3 |
| # |
| # Copyright 2022 The Fuchsia 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 performs a single 'make' build for a given profile and |
| # architecture. The included feature set is specified using 'configure' |
| # script command line options, which are provided in the profile file. |
| # Artifacts generated by the build are deposited in a temporary directory |
| # by profile name and architecture. |
| |
| import argparse |
| import multiprocessing |
| import os |
| import re |
| import shutil |
| import subprocess |
| import sys |
| |
| |
| def PrintAndCheckCall(argv, *args, **kwargs): |
| print("Running %s" % "\n ".join(argv)) |
| subprocess.check_call(argv, *args, **kwargs) |
| |
| |
| def GetDsoName(dso_name, dso_version): |
| return "lib%s.so.%s" % (dso_name, dso_version) |
| |
| |
| def RewriteFile(path, search, replace): |
| with open(path) as f: |
| contents = f.read() |
| with open(path, "w") as f: |
| f.write(re.sub(search, replace, contents)) |
| |
| |
| def BuildFFmpeg( |
| target_arch, |
| profile, |
| parallel_jobs, |
| config_only, |
| roll_dir, |
| ffmpeg_src_dir, |
| configure_flags, |
| ): |
| config_dir = os.path.join(roll_dir, profile, target_arch) |
| shutil.rmtree(config_dir, ignore_errors=True) |
| os.makedirs(os.path.join(config_dir, "out")) |
| |
| PrintAndCheckCall( |
| [os.path.join(ffmpeg_src_dir, "configure")] + configure_flags, cwd=config_dir |
| ) |
| |
| RewriteFile( |
| os.path.join(config_dir, "config.h"), |
| r"(#define HAVE_PRCTL [01])", |
| (r"#define HAVE_PRCTL 0"), |
| ) |
| |
| RewriteFile( |
| os.path.join(config_dir, "config.h"), |
| r"(#define HAVE_SYSCTL [01])", |
| (r"#define HAVE_SYSCTL 0"), |
| ) |
| |
| RewriteFile( |
| os.path.join(config_dir, "config.h"), |
| r"(#define HAVE_AS_FUNC [01])", |
| (r"#define HAVE_AS_FUNC 0"), |
| ) |
| |
| RewriteFile( |
| os.path.join(config_dir, "config.h"), |
| r"(#define HAVE_VALGRIND_VALGRIND_H [01])", |
| (r"#define HAVE_VALGRIND_VALGRIND_H 0"), |
| ) |
| |
| if config_only: |
| print("Skipping build step as requested.") |
| else: |
| libraries = [ |
| os.path.join("libavcodec", GetDsoName("avcodec", 59)), |
| os.path.join("libavformat", GetDsoName("avformat", 59)), |
| os.path.join("libavutil", GetDsoName("avutil", 57)), |
| ] |
| PrintAndCheckCall(["make", "-j%d" % parallel_jobs] + libraries, cwd=config_dir) |
| for lib in libraries: |
| shutil.copy(os.path.join(config_dir, lib), os.path.join(config_dir, "out")) |
| |
| if target_arch in ("arm64"): |
| RewriteFile( |
| os.path.join(config_dir, "config.h"), |
| r"(#define HAVE_VFP_ARGS [01])", |
| (r"/* \1 -- softfp/hardfp selection is done by the fuchsia build */"), |
| ) |
| |
| |
| def ProfileFromPath(path): |
| if not path.endswith("_args"): |
| exit(f"ERROR: Profile path {path} must be of the form <profile>_args.") |
| return os.path.basename(path)[: -len("_args")] |
| |
| |
| def main(argv): |
| parser = argparse.ArgumentParser( |
| epilog="Resulting binaries will be placed in: <roll_dir>/<profile>/<x64|arm64>/out/" |
| ) |
| |
| parser.add_argument( |
| "roll_dir", |
| metavar="<roll dir>", |
| help="directory for build output", |
| ) |
| |
| parser.add_argument( |
| "profile_file", |
| metavar="<profile file>", |
| help="profile file containing configure args", |
| ) |
| |
| parser.add_argument( |
| "target_arch", |
| metavar="<x64|arm64>", |
| help="target architecture", |
| ) |
| |
| parser.add_argument( |
| "--fuchsia-src-dir", |
| default="../../../..", |
| metavar="<path>", |
| help="directory containing Fuchsia source code", |
| ) |
| |
| parser.add_argument( |
| "--ffmpeg-src-dir", |
| default="../../../../third_party/ffmpeg/src", |
| metavar="<path>", |
| help="directory containing ffmpeg source code", |
| ) |
| |
| parser.add_argument( |
| "--config-only", action="store_true", help="skip the build step" |
| ) |
| |
| args = parser.parse_args(argv) |
| |
| profile_name = ProfileFromPath(args.profile_file) |
| |
| configure_file_args = [] |
| with open(args.profile_file, "r") as f: |
| configure_file_args = f.read().splitlines() |
| |
| parallel_jobs = multiprocessing.cpu_count() |
| |
| print( |
| "System information:\n" |
| "Profile : %s\n" |
| "Target arch : %s\n" |
| "Parallel jobs : %d\n" % (profile_name, args.target_arch, parallel_jobs) |
| ) |
| |
| configure_flags = [] |
| |
| # Note: --disable-everything does not in fact disable |
| # everything, just non-library components such as decoders and demuxers. |
| configure_flags.extend( |
| [ |
| "--disable-everything", |
| "--disable-all", |
| "--disable-doc", |
| "--disable-htmlpages", |
| "--disable-manpages", |
| "--disable-podpages", |
| "--disable-txtpages", |
| "--disable-static", |
| "--enable-avcodec", |
| "--enable-avformat", |
| "--enable-avutil", |
| "--enable-fft", |
| "--enable-rdft", |
| "--enable-shared", |
| "--enable-libopus", |
| # Disable features. |
| "--disable-debug", |
| "--disable-bzlib", |
| "--disable-iconv", |
| "--disable-network", |
| "--disable-schannel", |
| "--disable-sdl2", |
| "--disable-symver", |
| "--disable-xlib", |
| "--disable-zlib", |
| "--disable-securetransport", |
| "--disable-faan", |
| "--disable-alsa", |
| # Disable automatically detected external libraries. This prevents |
| # automatic inclusion of things like hardware decoders. Each roll should |
| # audit new [autodetect] configure options and add any desired options to |
| # this file. |
| "--disable-autodetect", |
| # Setup include path so Fuchsia's libopus can be used. |
| "--extra-cflags=-I" |
| + os.path.abspath( |
| os.path.join(args.fuchsia_src_dir, "third_party/opus/include") |
| ), |
| '--optflags="-O2"', |
| # Force usage of yasm |
| "--x86asmexe=yasm", |
| "--enable-pic", |
| "--enable-lto", |
| "--cc=clang", |
| "--cxx=clang++", |
| "--ld=clang", |
| ] |
| ) |
| |
| # TODO(dalesat): determine if we can use --enable-lto in x64 |
| |
| if args.target_arch == "x64": |
| configure_flags.extend( |
| [ |
| "--enable-cross-compile", |
| "--cross-prefix=/usr/bin/x86_64-linux-gnu-", |
| "--target-os=linux", |
| "--arch=x86_64", |
| "--enable-decoder=vp9", |
| "--enable-parser=vp9", |
| "--sysroot=" |
| + os.path.abspath( |
| os.path.join( |
| args.fuchsia_src_dir, |
| "prebuilt", |
| "third_party", |
| "sysroot", |
| "linux", |
| ) |
| ), |
| ] |
| ) |
| elif args.target_arch == "arm64": |
| configure_flags.extend( |
| [ |
| "--enable-cross-compile", |
| "--cross-prefix=/usr/bin/x86_64-linux-gnu-", |
| "--target-os=linux", |
| "--arch=aarch64", |
| "--enable-armv8", |
| "--extra-cflags=-march=armv8-a", |
| "--sysroot=" |
| + os.path.abspath( |
| os.path.join( |
| args.fuchsia_src_dir, |
| "prebuilt", |
| "third_party", |
| "sysroot", |
| "linux", |
| ) |
| ), |
| "--extra-cflags=--target=aarch64-linux-gnu", |
| "--extra-ldflags=--target=aarch64-linux-gnu", |
| "--disable-linux-perf", |
| ] |
| ) |
| else: |
| print("Error: Unknown target arch %r!" % (args.target_arch), file=sys.stderr) |
| return 1 |
| |
| BuildFFmpeg( |
| args.target_arch, |
| profile_name, |
| parallel_jobs, |
| args.config_only, |
| args.roll_dir, |
| os.path.abspath(args.ffmpeg_src_dir), |
| configure_flags + configure_file_args, |
| ) |
| |
| print("Build completed successfully.") |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main(sys.argv[1:])) |