• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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