1#! /usr/bin/env python3 2# Copyright 2024 Google Inc. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5"""Install script for ANGLE targets 6 71. Suppose this is your custom prefix: 8 `export CUSTOM_PREFIX=/custom/prefix 92. Configure the install prefix with gn: 10 `gn gen --args="install_prefix=\"$CUSTOM_PREFIX\"" out` 113. Then install ANGLE: 12 `ninja -C out install_angle` 13 14This will copy all needed include directories under $CUSTOM_PREFIX/include and the 15libraries will be copied to $CUSTOM_PREFIX/lib. A package config file is generated for 16each library under $CUSTOM_PREFIX/lib/pkgconfig, therefore ANGLE libraries can be 17discovered by package config making sure this path is listed in the PKG_CONFIG_PATH 18environment variable. 19``` 20export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$CUSTOM_PREFIX/lib/pkgconfig 21pkg-config --libs EGL 22pkg-config --cflags EGL 23``` 24""" 25 26import argparse 27import os 28import shutil 29import sys 30 31 32def install2(src_list: list, dst_dir: str): 33 """Installs a list of files or directories in `src_list` to `dst_dir`""" 34 os.makedirs(dst_dir, exist_ok=True) 35 for src in src_list: 36 if not os.path.exists(src): 37 raise FileNotFoundError("Failed to find {}".format(src)) 38 basename = os.path.basename(src) 39 dst = os.path.join(dst_dir, basename) 40 print("Installing {} to {}".format(src, dst)) 41 if os.path.isdir(src): 42 shutil.copytree(src, dst, dirs_exist_ok=True) 43 else: 44 shutil.copy2(src, dst) 45 46 47PC_TEMPLATE = """prefix={prefix} 48libdir=${{prefix}}/lib 49includedir=${{prefix}}/include 50 51Name: {name} 52Description: {description} 53Version: {version} 54Libs: -L${{libdir}} {link_libraries} 55Cflags: -I${{includedir}} 56""" 57 58 59def gen_link_libraries(libs: list): 60 """Generates a string that can be used for the `Libs:` entry of a pkgconfig file""" 61 link_libraries = "" 62 for lib in libs: 63 # Absolute paths to file names only -> libEGL.dylib 64 basename = os.path.basename(lib) 65 # lib name only -> libEGL 66 libname: str = os.path.splitext(basename)[0] 67 # name only -> EGL 68 name = libname.strip('lib') 69 link_libraries += '-l{}'.format(name) 70 return link_libraries 71 72 73def gen_pkgconfig(name: str, version: str, prefix: os.path.abspath, libs: list): 74 """Generates a pkgconfig file for the current target""" 75 # Remove lib from name -> EGL 76 no_lib_name = name.strip('lib') 77 description = "ANGLE's {}".format(no_lib_name) 78 name_lowercase = no_lib_name.lower() 79 link_libraries = gen_link_libraries(libs) 80 pc_content = PC_TEMPLATE.format( 81 name=name_lowercase, 82 prefix=prefix, 83 description=description, 84 version=version, 85 link_libraries=link_libraries) 86 87 lib_pkgconfig_path = os.path.join(prefix, 'lib/pkgconfig') 88 if not os.path.exists(lib_pkgconfig_path): 89 os.makedirs(lib_pkgconfig_path) 90 91 pc_path = os.path.join(lib_pkgconfig_path, '{}.pc'.format(name_lowercase)) 92 print("Generating {}".format(pc_path)) 93 with open(pc_path, 'w+') as pc_file: 94 pc_file.write(pc_content) 95 96 97def install(name, version, prefix: os.path.abspath, libs: list, includes: list): 98 """Installs under `prefix` 99 - the libraries in the `libs` list 100 - the include directories in the `includes` list 101 - the pkgconfig file for current target if name is set""" 102 install2(libs, os.path.join(prefix, "lib")) 103 104 for include in includes: 105 assert (os.path.isdir(include)) 106 incs = [inc.path for inc in os.scandir(include)] 107 install2(incs, os.path.join(prefix, "include")) 108 109 if name: 110 gen_pkgconfig(name, version, prefix, libs) 111 112 113def main(): 114 parser = argparse.ArgumentParser(description='Install script for ANGLE targets') 115 parser.add_argument( 116 '--name', 117 help='Name of the target (e.g., EGL or GLESv2). Set it to generate a pkgconfig file', 118 ) 119 parser.add_argument( 120 '--version', help='SemVer of the target (e.g., 0.1.0 or 2.1)', default='0.0.0') 121 parser.add_argument( 122 '--prefix', 123 help='Install prefix to use (e.g., out/install or /usr/local/)', 124 default='', 125 type=os.path.abspath) 126 parser.add_argument( 127 '--libs', 128 help='List of libraries to install (e.g., libEGL.dylib or libGLESv2.so)', 129 default=[], 130 nargs='+', 131 type=os.path.abspath) 132 parser.add_argument( 133 '-I', 134 '--includes', 135 help='List of include directories to install (e.g., include or ../include)', 136 default=[], 137 nargs='+', 138 type=os.path.abspath) 139 140 args = parser.parse_args() 141 install(args.name, args.version, args.prefix, args.libs, args.includes) 142 143 144if __name__ == '__main__': 145 sys.exit(main()) 146