334 lines
11 KiB
Python
Executable File
334 lines
11 KiB
Python
Executable File
#!/usr/bin/env vpython3
|
|
#
|
|
# Copyright 2022 The ANGLE Project Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
#
|
|
# mesa_build.py:
|
|
# Helper script for building Mesa in an ANGLE checkout.
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
ANGLE_DIR = os.path.dirname(os.path.dirname(SCRIPT_DIR))
|
|
DEFAULT_LOG_LEVEL = 'info'
|
|
EXIT_SUCCESS = 0
|
|
EXIT_FAILURE = 1
|
|
MESON = os.path.join(ANGLE_DIR, 'third_party', 'meson', 'meson.py')
|
|
MESA_SOURCE_DIR = os.path.join(ANGLE_DIR, 'third_party', 'mesa', 'src')
|
|
LIBDRM_SOURCE_DIR = os.path.join(ANGLE_DIR, 'third_party', 'libdrm')
|
|
LIBDRM_BUILD_DIR = os.path.join(ANGLE_DIR, 'out', 'libdrm-build')
|
|
MESA_STAMP = 'mesa.stamp'
|
|
LIBDRM_STAMP = 'libdrm.stamp'
|
|
|
|
MESA_OPTIONS = [
|
|
'-Dzstd=disabled',
|
|
'-Dplatforms=x11',
|
|
'-Dgallium-drivers=zink',
|
|
'-Dvulkan-drivers=',
|
|
'-Dvalgrind=disabled',
|
|
]
|
|
LIBDRM_OPTIONS = [
|
|
'-Dtests=false',
|
|
'-Dintel=disabled',
|
|
'-Dnouveau=disabled',
|
|
'-Damdgpu=disabled',
|
|
'-Dradeon=disabled',
|
|
'-Dvmwgfx=disabled',
|
|
'-Dvalgrind=disabled',
|
|
'-Dman-pages=disabled',
|
|
]
|
|
|
|
|
|
def main(raw_args):
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'-l',
|
|
'--log',
|
|
'--log-level',
|
|
help='Logging level. Default is %s.' % DEFAULT_LOG_LEVEL,
|
|
default=DEFAULT_LOG_LEVEL)
|
|
|
|
subparser = parser.add_subparsers(dest='command')
|
|
|
|
mesa = subparser.add_parser('mesa')
|
|
mesa.add_argument('build_dir', help='Target build directory.')
|
|
mesa.add_argument('-j', '--jobs', help='Compile jobs.')
|
|
|
|
compile_parser = subparser.add_parser('compile')
|
|
compile_parser.add_argument('-j', '--jobs', help='Compile jobs.')
|
|
compile_parser.add_argument('build_dir', help='Target build directory.')
|
|
|
|
gni = subparser.add_parser('gni')
|
|
gni.add_argument('output', help='Output location for gni file.')
|
|
gni.add_argument('mesa_build_dir', help='Target Mesa build directory.')
|
|
gni.add_argument('libdrm_build_dir', help='Target libdrm build directory.')
|
|
|
|
libdrm = subparser.add_parser('libdrm')
|
|
|
|
runhook_parser = subparser.add_parser('runhook')
|
|
runhook_parser.add_argument(
|
|
'-o', '--output', help='Output location for stamp sha1 file.', default=MESA_STAMP)
|
|
|
|
setup_parser = subparser.add_parser('setup')
|
|
setup_parser.add_argument('target', help='Project: mesa or libdrm.')
|
|
setup_parser.add_argument('build_dir', help='Target build directory.')
|
|
setup_parser.add_argument('-w', '--wipe', help='Wipe output directory.', action='store_true')
|
|
|
|
args, extra_args = parser.parse_known_args(raw_args)
|
|
|
|
logging.basicConfig(level=args.log.upper())
|
|
|
|
assert os.path.exists(MESON), 'Could not find meson.py: %s' % MESON
|
|
|
|
if args.command == 'mesa':
|
|
SetupBuild(args.build_dir, MESA_SOURCE_DIR, MESA_OPTIONS)
|
|
Compile(args, args.build_dir)
|
|
elif args.command == 'compile':
|
|
Compile(args, args.build_dir)
|
|
elif args.command == 'gni':
|
|
GenerateGni(args)
|
|
elif args.command == 'libdrm':
|
|
SetupBuild(args.build_dir, LIBDRM_SOURCE_DIR, LIBDRM_OPTIONS)
|
|
Compile(args, args.build_dir)
|
|
elif args.command == 'runhook':
|
|
RunHook(args)
|
|
elif args.command == 'setup':
|
|
LazySetup(args, args.build_dir)
|
|
|
|
return EXIT_SUCCESS
|
|
|
|
|
|
def SetupBuild(build_dir, source_dir, options, pkg_config_paths=[]):
|
|
if not os.path.exists(build_dir):
|
|
os.mkdir(build_dir)
|
|
|
|
sysroot_dir = os.path.join(ANGLE_DIR, 'build', 'linux', 'debian_bullseye_amd64-sysroot')
|
|
|
|
cflags = ' '.join([
|
|
'--sysroot=%s' % sysroot_dir,
|
|
'-Wno-constant-conversion',
|
|
'-Wno-deprecated-builtins',
|
|
'-Wno-deprecated-declarations',
|
|
'-Wno-deprecated-non-prototype',
|
|
'-Wno-enum-compare-conditional',
|
|
'-Wno-enum-conversion',
|
|
'-Wno-implicit-const-int-float-conversion',
|
|
'-Wno-implicit-function-declaration',
|
|
'-Wno-initializer-overrides',
|
|
'-Wno-sometimes-uninitialized',
|
|
'-Wno-unused-but-set-variable',
|
|
'-Wno-unused-function',
|
|
])
|
|
|
|
pkg_config_paths += [
|
|
'%s/usr/share/pkgconfig' % sysroot_dir,
|
|
'%s/usr/lib/pkgconfig' % sysroot_dir
|
|
]
|
|
|
|
extra_env = {
|
|
'CC': 'clang',
|
|
'CC_LD': 'lld',
|
|
'CXX': 'clang++',
|
|
'CXX_LD': 'lld',
|
|
'CFLAGS': cflags,
|
|
'CXXFLAGS': cflags,
|
|
'PKG_CONFIG_PATH': ':'.join(pkg_config_paths),
|
|
}
|
|
|
|
args = [source_dir, build_dir, '--cross-file',
|
|
os.path.join(SCRIPT_DIR, 'angle_cross.ini')] + options
|
|
if os.path.isdir(os.path.join(build_dir, 'meson-info')):
|
|
args += ['--wipe']
|
|
|
|
return Meson(build_dir, 'setup', args, extra_env)
|
|
|
|
|
|
def Compile(args, build_dir):
|
|
return Meson(build_dir, 'compile', ['-C', build_dir])
|
|
|
|
|
|
def MakeEnv():
|
|
clang_dir = os.path.join(ANGLE_DIR, 'third_party', 'llvm-build', 'Release+Asserts', 'bin')
|
|
flex_bison_dir = os.path.join(ANGLE_DIR, 'tools', 'flex-bison')
|
|
|
|
# TODO: Windows
|
|
flex_bison_platform = 'linux'
|
|
flex_bison_bin_dir = os.path.join(flex_bison_dir, flex_bison_platform)
|
|
|
|
depot_tools_dir = os.path.join(ANGLE_DIR, 'third_party', 'depot_tools')
|
|
|
|
env = os.environ.copy()
|
|
paths = [clang_dir, flex_bison_bin_dir, depot_tools_dir, env['PATH']]
|
|
env['PATH'] = ':'.join(paths)
|
|
env['BISON_PKGDATADIR'] = os.path.join(flex_bison_dir, 'third_party')
|
|
return env
|
|
|
|
|
|
GNI_TEMPLATE = """\
|
|
# GENERATED FILE - DO NOT EDIT.
|
|
# Generated by {script_name}
|
|
#
|
|
# Copyright 2022 The ANGLE Project Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
#
|
|
# {filename}: ANGLE build information for Mesa.
|
|
|
|
angle_mesa_outputs = [
|
|
{angle_mesa_outputs}]
|
|
|
|
angle_mesa_sources = [
|
|
{angle_mesa_sources}]
|
|
|
|
angle_libdrm_outputs = [
|
|
{angle_libdrm_outputs}]
|
|
|
|
angle_libdrm_sources = [
|
|
{angle_libdrm_sources}]
|
|
"""
|
|
|
|
|
|
def GenerateGni(args):
|
|
mesa_sources_filter = lambda target: target['type'] != 'shared library'
|
|
mesa_outputs_filter = lambda target: target['type'] == 'shared library'
|
|
mesa_sources, mesa_outputs = GetMesonSourcesAndOutputs(args.mesa_build_dir,
|
|
mesa_sources_filter,
|
|
mesa_outputs_filter)
|
|
|
|
libdrm_sources_filter = lambda target: True
|
|
libdrm_outputs_filter = lambda target: target['type'] == 'shared library'
|
|
libdrm_sources, libdrm_outputs = GetMesonSourcesAndOutputs(args.libdrm_build_dir,
|
|
libdrm_sources_filter,
|
|
libdrm_outputs_filter)
|
|
|
|
fmt_list = lambda l, rp: ''.join(
|
|
sorted(list(set([' "%s",\n' % os.path.relpath(li, rp) for li in l]))))
|
|
|
|
format_args = {
|
|
'script_name': os.path.basename(__file__),
|
|
'filename': os.path.basename(args.output),
|
|
'angle_mesa_outputs': fmt_list(mesa_outputs, args.mesa_build_dir),
|
|
'angle_mesa_sources': fmt_list(mesa_sources, MESA_SOURCE_DIR),
|
|
'angle_libdrm_outputs': fmt_list(libdrm_outputs, args.libdrm_build_dir),
|
|
'angle_libdrm_sources': fmt_list(libdrm_sources, LIBDRM_SOURCE_DIR),
|
|
}
|
|
|
|
gni_text = GNI_TEMPLATE.format(**format_args)
|
|
|
|
with open(args.output, 'w') as outf:
|
|
outf.write(gni_text)
|
|
outf.close()
|
|
logging.info('Saved GNI data to %s' % args.output)
|
|
|
|
|
|
def GetMesonSourcesAndOutputs(build_dir, sources_filter, output_filter):
|
|
text_data = Meson(build_dir, 'introspect', [build_dir, '--targets'], stdout=subprocess.PIPE)
|
|
json_data = json.loads(text_data)
|
|
outputs = []
|
|
all_sources = []
|
|
generated = []
|
|
for target in json_data:
|
|
generated += target['filename']
|
|
if output_filter(target):
|
|
outputs += target['filename']
|
|
if sources_filter(target):
|
|
for target_source in target['target_sources']:
|
|
all_sources += target_source['sources']
|
|
|
|
sources = list(filter(lambda s: (s not in generated), all_sources))
|
|
|
|
for source in sources:
|
|
assert os.path.exists(source), '%s does not exist' % source
|
|
|
|
return sources, outputs
|
|
|
|
|
|
def Meson(build_dir, command, args, extra_env={}, stdout=None):
|
|
meson_cmd = [MESON, command] + args
|
|
env = MakeEnv()
|
|
for k, v in extra_env.items():
|
|
env[k] = v
|
|
# TODO: Remove when crbug.com/1373441 is fixed.
|
|
env['VPYTHON_DEFAULT_SPEC'] = os.path.join(ANGLE_DIR, '.vpython3')
|
|
logging.info(' '.join(['%s=%s' % (k, v) for (k, v) in extra_env.items()] + meson_cmd))
|
|
completed = subprocess.run(meson_cmd, env=env, stdout=stdout)
|
|
if completed.returncode != EXIT_SUCCESS:
|
|
logging.fatal('Got error from meson:')
|
|
with open(os.path.join(build_dir, 'meson-logs', 'meson-log.txt')) as logf:
|
|
lines = logf.readlines()
|
|
for line in lines[-10:]:
|
|
logging.fatal(' %s' % line.strip())
|
|
sys.exit(EXIT_FAILURE)
|
|
if stdout:
|
|
return completed.stdout
|
|
|
|
|
|
def RunHook(args):
|
|
output = os.path.join(SCRIPT_DIR, args.output)
|
|
Stamp(args, MESA_SOURCE_DIR, output)
|
|
libdrm_out = os.path.join(SCRIPT_DIR, LIBDRM_STAMP)
|
|
Stamp(args, LIBDRM_SOURCE_DIR, libdrm_out)
|
|
|
|
|
|
def Stamp(args, source_dir, output):
|
|
commit_id = GrabOutput('git rev-parse HEAD', source_dir)
|
|
with open(output, 'w') as outf:
|
|
outf.write(commit_id)
|
|
outf.close()
|
|
logging.info('Saved git hash data to %s' % output)
|
|
|
|
|
|
def GrabOutput(command, cwd):
|
|
return subprocess.Popen(
|
|
command, stdout=subprocess.PIPE, shell=True, cwd=cwd).communicate()[0].strip().decode()
|
|
|
|
|
|
def LazySetup(args, build_dir):
|
|
stamp = args.target + '.stamp'
|
|
in_stamp = os.path.join(SCRIPT_DIR, stamp)
|
|
out_stamp = os.path.join(build_dir, args.target, stamp)
|
|
if not args.wipe and SameStamps(in_stamp, out_stamp):
|
|
logging.info('%s setup up-to-date.' % args.target)
|
|
sys.exit(EXIT_SUCCESS)
|
|
|
|
if args.target == 'mesa':
|
|
source_dir = MESA_SOURCE_DIR
|
|
options = MESA_OPTIONS
|
|
pkg_config_paths = [os.path.join(build_dir, 'libdrm', 'meson-uninstalled')]
|
|
else:
|
|
assert (args.target == 'libdrm')
|
|
source_dir = LIBDRM_SOURCE_DIR
|
|
options = LIBDRM_OPTIONS
|
|
pkg_config_paths = []
|
|
|
|
SetupBuild(os.path.join(build_dir, args.target), source_dir, options, pkg_config_paths)
|
|
shutil.copyfile(in_stamp, out_stamp)
|
|
logging.info('Finished setup and updated %s.' % out_stamp)
|
|
|
|
|
|
def SameStamps(in_stamp, out_stamp):
|
|
assert os.path.exists(in_stamp)
|
|
if not os.path.exists(out_stamp):
|
|
return False
|
|
in_data = ReadFile(in_stamp)
|
|
out_data = ReadFile(out_stamp)
|
|
return in_data == out_data
|
|
|
|
|
|
def ReadFile(path):
|
|
with open(path, 'rt') as inf:
|
|
all_data = inf.read()
|
|
inf.close()
|
|
return all_data
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv[1:]))
|