blob: 9c45e2128ccc1ddea3ba12565816952ee2e6eba4 [file] [log] [blame]
#!/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:]))