#!/usr/bin/env python3 # # Copyright 2019 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Creates config files for building dav1d.""" from __future__ import print_function import os import re import shlex import shutil import subprocess import sys import tempfile BASE_DIR = os.path.abspath(os.path.dirname(__file__)) CHROMIUM_ROOT_DIR = os.path.abspath(os.path.join(BASE_DIR, '..', '..')) sys.path.append(os.path.join(CHROMIUM_ROOT_DIR, 'build')) import gn_helpers MESON = ['meson.py'] DEFAULT_BUILD_ARGS = [ '-Denable_tools=false', '-Denable_tests=false', '-Ddefault_library=static', '--buildtype', 'release' ] WINDOWS_BUILD_ARGS = ['-Dc_winlibs='] def PrintAndCheckCall(argv, *args, **kwargs): print('\n-------------------------------------------------\nRunning %s' % ' '.join(argv)) c = subprocess.check_call(argv, *args, **kwargs) def RewriteFile(path, search_replace): with open(path) as f: contents = f.read() with open(path, 'w') as f: for search, replace in search_replace: contents = re.sub(search, replace, contents) # Cleanup trailing newlines. f.write(contents.strip() + '\n') def SetupWindowsCrossCompileToolchain(target_arch): # First retrieve various MSVC and Windows SDK paths. output = subprocess.check_output([ 'python3', os.path.join(CHROMIUM_ROOT_DIR, 'build', 'vs_toolchain.py'), 'get_toolchain_dir' ], universal_newlines=True) # Turn this into a dictionary. win_dirs = gn_helpers.FromGNArgs(output) # Use those paths with a second script which will tell us the proper include # and lib paths to specify for cflags and ldflags respectively. output = subprocess.check_output([ 'python3', os.path.join(CHROMIUM_ROOT_DIR, 'build', 'toolchain', 'win', 'setup_toolchain.py'), win_dirs['vs_path'], win_dirs['sdk_path'], win_dirs['runtime_dirs'], 'win', target_arch, 'none' ], universal_newlines=True) flags = gn_helpers.FromGNArgs(output) cwd = os.getcwd() target_env = os.environ # Each path is of the form: # "/I../depot_tools/win_toolchain/vs_files/20d5f2553f/Windows Kits/10/Include/10.0.19041.0/winrt" # # Since there's a space in the include path, inputs are quoted in |flags|, we # can helpfully use shlex to split on spaces while preserving quoted strings. include_paths = [] for include_path in shlex.split(flags['include_flags_I']): # Apparently setup_toolchain prefers relative include paths, which # may work for chrome, but it does not work for dav1d, so let's make # them asbolute again. include_path = os.path.abspath(os.path.join(cwd, include_path[2:])) include_paths.append(include_path) SYSROOT_PREFIX = '/winsysroot:' for k in flags: if SYSROOT_PREFIX in flags[k]: target_env['WINSYSROOT'] = os.path.abspath( os.path.join(cwd, flags[k][len(SYSROOT_PREFIX):])) break target_env = os.environ target_env['INCLUDE'] = ';'.join(include_paths) return target_env def CopyConfigs(src_dir, dest_dir): if not os.path.exists(dest_dir): os.makedirs(dest_dir) shutil.copy(os.path.join(src_dir, 'config.h'), dest_dir) # The .asm file will not be present for all configurations. asm_file = os.path.join(src_dir, 'config.asm') if os.path.exists(asm_file): shutil.copy(asm_file, dest_dir) def GenerateConfig(config_dir, env, special_args=[]): temp_dir = tempfile.mkdtemp() PrintAndCheckCall(MESON + DEFAULT_BUILD_ARGS + special_args + [temp_dir], cwd='libdav1d', env=env) RewriteFile( os.path.join(temp_dir, 'config.h'), [ # We don't want non-visible log strings polluting the official binary. (r'(#define CONFIG_LOG .*)', r'// \1 -- Logging is controlled by Chromium'), # The Chromium build system already defines this. (r'(#define _WIN32_WINNT .*)', r'// \1 -- Windows version is controlled by Chromium'), # Clang LTO doesn't respect stack alignment, so we must use the # platform's default stack alignment; https://crbug.com/928743. (r'(#define STACK_ALIGNMENT \d{1,2})', r'// \1 -- Stack alignment is controlled by Chromium'), # Android doesn't have pthread_getaffinity_np. (r'(#define HAVE_PTHREAD_GETAFFINITY_NP \d{1,2})', r'// \1 -- Controlled by Chomium'), ]) config_asm_path = os.path.join(temp_dir, 'config.asm') if (os.path.exists(config_asm_path)): RewriteFile(config_asm_path, [(r'(%define STACK_ALIGNMENT \d{1,2})', r'; \1 -- Stack alignment is controlled by Chromium')]) CopyConfigs(temp_dir, config_dir) shutil.rmtree(temp_dir) def GenerateWindowsArm64Config(src_dir): win_arm64_dir = 'config/win/arm64' if not os.path.exists(win_arm64_dir): os.makedirs(win_arm64_dir) shutil.copy(os.path.join(src_dir, 'config.h'), win_arm64_dir) # Flip flags such that it looks like an arm64 configuration. RewriteFile(os.path.join(win_arm64_dir, 'config.h'), [(r'#define ARCH_X86 1', r'#define ARCH_X86 0'), (r'#define ARCH_X86_64 1', r'#define ARCH_X86_64 0'), (r'#define ARCH_AARCH64 0', r'#define ARCH_AARCH64 1')]) def GenerateGenericConfig(src_dir): generic_dir = 'config/linux-noasm/generic' if not os.path.exists(generic_dir): os.makedirs(generic_dir) shutil.copy(os.path.join(src_dir, 'config.h'), generic_dir) # Mark architecture as unknown. RewriteFile(os.path.join(generic_dir, 'config.h'), [(r'#define ARCH_X86 1', r'#define ARCH_X86 0'), (r'#define ARCH_X86_64 1', r'#define ARCH_X86_64 0')]) def CopyVersions(src_dir, dest_dir): if not os.path.exists(dest_dir): os.makedirs(dest_dir) shutil.copy(os.path.join(src_dir, 'include', 'dav1d', 'version.h'), dest_dir) shutil.copy(os.path.join(src_dir, 'include', 'vcs_version.h'), dest_dir) def GenerateVersion(version_dir, env): temp_dir = tempfile.mkdtemp() PrintAndCheckCall(MESON + DEFAULT_BUILD_ARGS + [temp_dir], cwd='libdav1d', env=env) PrintAndCheckCall(['ninja', '-C', temp_dir, 'include/vcs_version.h'], cwd='libdav1d', env=env) CopyVersions(temp_dir, version_dir) shutil.rmtree(temp_dir) def main(): linux_env = os.environ linux_env['CC'] = 'clang' GenerateConfig('config/linux/x64', linux_env) noasm_dir = 'config/linux-noasm/x64' GenerateConfig(noasm_dir, linux_env, ['-Denable_asm=false']) GenerateGenericConfig(noasm_dir) GenerateConfig('config/linux/x86', linux_env, ['--cross-file', '../crossfiles/linux32.crossfile']) GenerateConfig('config/linux/arm', linux_env, ['--cross-file', '../crossfiles/arm.crossfile']) GenerateConfig('config/linux/arm64', linux_env, ['--cross-file', '../crossfiles/arm64.crossfile']) win_x86_env = SetupWindowsCrossCompileToolchain('x86') GenerateConfig('config/win/x86', win_x86_env, ['--cross-file', '../crossfiles/win32.crossfile'] + [ '-Dc_args=-m32 -fuse-ld=lld /winsysroot ' + win_x86_env['WINSYSROOT'] ] + WINDOWS_BUILD_ARGS) win_x64_dir = 'config/win/x64' win_x64_env = SetupWindowsCrossCompileToolchain('x64') GenerateConfig( win_x64_dir, win_x64_env, ['--cross-file', '../crossfiles/win64.crossfile'] + ['-Dc_args=-fuse-ld=lld /winsysroot ' + win_x64_env['WINSYSROOT']] + WINDOWS_BUILD_ARGS) # Sadly meson doesn't support arm64 + clang-cl, so we need to create the # Windows arm64 config from the Windows x64 config. GenerateWindowsArm64Config(win_x64_dir) GenerateVersion('version', linux_env) if __name__ == '__main__': main()