| #! /usr/bin/env python3 | |
| # Copyright 2024 Google Inc. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """Install script for ANGLE targets | |
| 1. Suppose this is your custom prefix: | |
| `export CUSTOM_PREFIX=/custom/prefix | |
| 2. Configure the install prefix with gn: | |
| `gn gen --args="install_prefix=\"$CUSTOM_PREFIX\"" out` | |
| 3. Then install ANGLE: | |
| `ninja -C out install_angle` | |
| This will copy all needed include directories under $CUSTOM_PREFIX/include and the | |
| libraries will be copied to $CUSTOM_PREFIX/lib. A package config file is generated for | |
| each library under $CUSTOM_PREFIX/lib/pkgconfig, therefore ANGLE libraries can be | |
| discovered by package config making sure this path is listed in the PKG_CONFIG_PATH | |
| environment variable. | |
| ``` | |
| export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$CUSTOM_PREFIX/lib/pkgconfig | |
| pkg-config --libs EGL | |
| pkg-config --cflags EGL | |
| ``` | |
| """ | |
| import argparse | |
| import os | |
| import shutil | |
| import sys | |
| def install2(src_list: list, dst_dir: str): | |
| """Installs a list of files or directories in `src_list` to `dst_dir`""" | |
| os.makedirs(dst_dir, exist_ok=True) | |
| for src in src_list: | |
| if not os.path.exists(src): | |
| raise FileNotFoundError("Failed to find {}".format(src)) | |
| basename = os.path.basename(src) | |
| dst = os.path.join(dst_dir, basename) | |
| print("Installing {} to {}".format(src, dst)) | |
| if os.path.isdir(src): | |
| shutil.copytree(src, dst, dirs_exist_ok=True) | |
| else: | |
| shutil.copy2(src, dst) | |
| PC_TEMPLATE = """prefix={prefix} | |
| libdir=${{prefix}}/lib | |
| includedir=${{prefix}}/include | |
| Name: {name} | |
| Description: {description} | |
| Version: {version} | |
| Libs: -L${{libdir}} {link_libraries} | |
| Cflags: -I${{includedir}} | |
| """ | |
| def gen_link_libraries(libs: list): | |
| """Generates a string that can be used for the `Libs:` entry of a pkgconfig file""" | |
| link_libraries = "" | |
| for lib in libs: | |
| # Absolute paths to file names only -> libEGL.dylib | |
| basename = os.path.basename(lib) | |
| # lib name only -> libEGL | |
| libname: str = os.path.splitext(basename)[0] | |
| # name only -> EGL | |
| name = libname.strip('lib') | |
| link_libraries += '-l{}'.format(name) | |
| return link_libraries | |
| def gen_pkgconfig(name: str, version: str, prefix: os.path.abspath, libs: list): | |
| """Generates a pkgconfig file for the current target""" | |
| # Remove lib from name -> EGL | |
| no_lib_name = name.strip('lib') | |
| description = "ANGLE's {}".format(no_lib_name) | |
| name_lowercase = no_lib_name.lower() | |
| link_libraries = gen_link_libraries(libs) | |
| pc_content = PC_TEMPLATE.format( | |
| name=name_lowercase, | |
| prefix=prefix, | |
| description=description, | |
| version=version, | |
| link_libraries=link_libraries) | |
| lib_pkgconfig_path = os.path.join(prefix, 'lib/pkgconfig') | |
| if not os.path.exists(lib_pkgconfig_path): | |
| os.makedirs(lib_pkgconfig_path) | |
| pc_path = os.path.join(lib_pkgconfig_path, '{}.pc'.format(name_lowercase)) | |
| print("Generating {}".format(pc_path)) | |
| with open(pc_path, 'w+') as pc_file: | |
| pc_file.write(pc_content) | |
| def install(name, version, prefix: os.path.abspath, libs: list, includes: list): | |
| """Installs under `prefix` | |
| - the libraries in the `libs` list | |
| - the include directories in the `includes` list | |
| - the pkgconfig file for current target if name is set""" | |
| install2(libs, os.path.join(prefix, "lib")) | |
| for include in includes: | |
| assert (os.path.isdir(include)) | |
| incs = [inc.path for inc in os.scandir(include)] | |
| install2(incs, os.path.join(prefix, "include")) | |
| if name: | |
| gen_pkgconfig(name, version, prefix, libs) | |
| def main(): | |
| parser = argparse.ArgumentParser(description='Install script for ANGLE targets') | |
| parser.add_argument( | |
| '--name', | |
| help='Name of the target (e.g., EGL or GLESv2). Set it to generate a pkgconfig file', | |
| ) | |
| parser.add_argument( | |
| '--version', help='SemVer of the target (e.g., 0.1.0 or 2.1)', default='0.0.0') | |
| parser.add_argument( | |
| '--prefix', | |
| help='Install prefix to use (e.g., out/install or /usr/local/)', | |
| default='', | |
| type=os.path.abspath) | |
| parser.add_argument( | |
| '--libs', | |
| help='List of libraries to install (e.g., libEGL.dylib or libGLESv2.so)', | |
| default=[], | |
| nargs='+', | |
| type=os.path.abspath) | |
| parser.add_argument( | |
| '-I', | |
| '--includes', | |
| help='List of include directories to install (e.g., include or ../include)', | |
| default=[], | |
| nargs='+', | |
| type=os.path.abspath) | |
| args = parser.parse_args() | |
| install(args.name, args.version, args.prefix, args.libs, args.includes) | |
| if __name__ == '__main__': | |
| sys.exit(main()) |