chromium/third_party/weston/generate_configs.py

#!/usr/bin/env python
#
# Copyright 2020 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 Weston."""

from __future__ import print_function

import os
import pathlib
import re
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, '..', '..'))

CLANG_DIR = os.path.join(CHROMIUM_ROOT_DIR, 'third_party', 'llvm-build', 'Release+Asserts', 'bin')

sys.path.append(os.path.join(CHROMIUM_ROOT_DIR, 'build'))

import gn_helpers

MESON = ['meson', 'setup']

DEFAULT_BUILD_ARGS = [
    '--buildtype', 'release',
    '-Dbackend-drm=false',
    '-Dbackend-drm-screencast-vaapi=false',
    '-Dbackend-pipewire=false',
    '-Dbackend-rdp=false',
    '-Dscreenshare=false',
    '-Dbackend-vnc=false',
    '-Dbackend-default=auto',
    '-Dxwayland=false',
    '-Dremoting=false',
    '-Dpipewire=false',
    '-Dshell-ivi=false',
    '-Dcolor-management-lcms=false',
    '-Dimage-jpeg=false',
    '-Dimage-webp=false',
    '-Ddemo-clients=false',
    '-Dsimple-clients=egl',
    '-Dwcap-decode=false',
]


def GetAbsPath(relative_path):
    return os.path.join(BASE_DIR, relative_path)


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 AddAttributeInConfig(path):
    with open(path) as f:
        contents = f.read()
    with open(path, 'w') as f:
        f.write(contents.strip() + '\n')
        f.write('\n' + '__attribute__((visibility("default"))) int main(int argc, char* argv[]);' + '\n')

def CopyConfigsAndCleanup(config_dir, dest_dir):
    if not os.path.exists(dest_dir):
        os.makedirs(dest_dir)

    shutil.copy(os.path.join(config_dir, 'config.h'), dest_dir)
    shutil.rmtree(config_dir)


def RewriteGitFile(path, data):
    with open(path, 'w') as f:
        contents = data

        # Cleanup trailing newlines.
        f.write(contents.strip() + '\n')


def CopyGitConfigsAndCleanup(config_dir, dest_dir):
    if not os.path.exists(dest_dir):
        os.makedirs(dest_dir)

    shutil.copy(os.path.join(config_dir, 'git-version.h'), dest_dir)
    shutil.rmtree(config_dir)


def GenerateGitConfig(config_dir, env, special_args=[]):
    temp_dir = tempfile.mkdtemp()
    PrintAndCheckCall(
        MESON + DEFAULT_BUILD_ARGS + special_args + [temp_dir],
        cwd=GetAbsPath('src'),
        env=env)

    label = subprocess.check_output(["git", "describe", "--always"]).strip()
    label = label.decode("utf-8")
    RewriteGitFile(
        os.path.join(temp_dir, 'git-version.h'),
        "#define BUILD_ID \"{label}\"".format(label=label))
    CopyGitConfigsAndCleanup(temp_dir, config_dir)


def GenerateConfig(config_dir, env, special_args=[]):
    temp_dir = tempfile.mkdtemp()
    PrintAndCheckCall(
        MESON + DEFAULT_BUILD_ARGS + special_args + [temp_dir],
        cwd=GetAbsPath('src'),
        env=env)

    CopyConfigsAndCleanup(temp_dir, config_dir)


def ChangeConfigPath():
    configfile = GetAbsPath("config/config.h")
    DIRS = ["BINDIR",
            "DATADIR",
            "LIBEXECDIR",
            "LIBWESTON_MODULEDIR",
            "MODULEDIR"]
    for dir in DIRS:
        pattern = "#define {dir} \"/[a-zA-Z0-9\\-_/]+\"".format(dir=dir)
        RewriteFile(configfile, [(pattern, "")])

    # Add attribute in config.h to suppress all undefined symbol(function) warnings
    AddAttributeInConfig(configfile)


def GenerateWestonVersion():
    dirname = GetAbsPath("version/libweston")
    if not os.path.exists(dirname):
        os.makedirs(dirname)
    version_op_file = GetAbsPath("version/libweston/version.h")
    configfile = GetAbsPath("config/config.h")
    version_in_file = GetAbsPath("src/include/libweston/version.h.in")
    version_number = "0.0.0"
    with open(configfile, 'r') as f:
        for line in f:
            if "PACKAGE_VERSION" in line:
                package_version_list = (line.strip("\n")).split(" ")
                version_number = package_version_list[-1]

    version_number_list = (version_number.strip('"\n"')).split(".")
    version_number_list.append(version_number.strip("\"\""))
    VERSIONS = ["@WESTON_VERSION_MAJOR@", "@WESTON_VERSION_MINOR@",
                "@WESTON_VERSION_MICRO@", "@WESTON_VERSION@"]
    with open(version_in_file) as f:
        contents = f.read()

    for version, version_number in zip(VERSIONS, version_number_list):
        pattern = version
        repl_string = version_number
        with open(version_op_file, 'w') as f:
            contents = re.sub(pattern, repl_string, contents)

            # Cleanup trailing newlines.
            f.write(contents.strip() + '\n')
    print("Created version.h file from version.h.in\n")


def RemoveUndesiredDefines():
    configfile = GetAbsPath('config/config.h')
    # Weston doesn't have a meson option to avoid using memfd_create() method that was
    # introduced in GLIBC 2.27. That results in weston failing to run on Xenial based bot as
    # it has GLIBC 2.23, because this config might be generated on a system that has newer
    # libc libraries that meson checks with has_function() method. Thus, explicitly rewrite
    # the config to disable usage of that method.
    RewriteFile(configfile, [("#define HAVE_MEMFD_CREATE .*", "")])


def main():
    env = os.environ
    env['CC'] = 'clang'
    env['PATH'] = ':'.join([CLANG_DIR, env['PATH']])
    GenerateGitConfig(GetAbsPath('version'), env)
    GenerateConfig(GetAbsPath('config'), env)
    ChangeConfigPath()
    RemoveUndesiredDefines()
    GenerateWestonVersion()

if __name__ == '__main__':
    main()