pkg.configure (7731B)
1 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- 2 # vim: set filetype=python: 3 # This Source Code Form is subject to the terms of the Mozilla Public 4 # License, v. 2.0. If a copy of the MPL was not distributed with this 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 8 @depends(toolchain_prefix, when=compile_environment) 9 def pkg_config(prefixes): 10 return tuple("{}pkg-config".format(p) for p in (prefixes or ()) + ("",)) 11 12 13 @depends(compile_environment, target) 14 def use_pkg_config(compile_environment, target): 15 return compile_environment and target.os not in ("WINNT", "OSX", "Android") 16 17 18 pkg_config = check_prog( 19 "PKG_CONFIG", 20 pkg_config, 21 bootstrap=depends(when=target_sysroot.bootstrapped)(lambda: "pkgconf"), 22 allow_missing=True, 23 when=use_pkg_config, 24 ) 25 26 27 @depends_if(pkg_config) 28 @checking("for pkg-config version") 29 def pkg_config_version(pkg_config): 30 return Version(check_cmd_output(pkg_config, "--version").rstrip()) 31 32 33 @depends_if(pkg_config) 34 @checking("whether pkg-config is pkgconf") 35 def is_pkgconf(pkg_config): 36 return "pkgconf " in check_cmd_output(pkg_config, "--about", onerror=lambda: "") 37 38 39 @depends(is_pkgconf, pkg_config_version, target_sysroot.bootstrapped, when=pkg_config) 40 def pkg_config_base_flags(is_pkgconf, pkg_config_version, target_sysroot_bootstrapped): 41 # pkgconf 1.7.4 changed the default on Windows to use --static, but 42 # that doesn't work for us. 43 # Note: the --shared flag is not available before pkgconf 1.7 44 flags = [] 45 if is_pkgconf and pkg_config_version >= "1.7.4": 46 flags.append("--shared") 47 # When pkg-config is in /usr things work fine by default, but when 48 # it is not, it defines prefix to be something else than /usr, which 49 # won't match what the .pc files actually say, and won't work in 50 # sysroots. 51 if target_sysroot_bootstrapped and ( 52 (is_pkgconf and pkg_config_version >= "1.2.0") 53 or (not is_pkgconf and pkg_config_version >= "0.29.0") 54 ): 55 flags.append("--dont-define-prefix") 56 return tuple(flags) 57 58 59 @depends(target, target_sysroot.path, target_multiarch_dir, when=pkg_config) 60 @imports(_from="os", _import="environ") 61 @imports(_from="os", _import="pathsep") 62 def pkg_config_vars(target, sysroot_path, multiarch_dir): 63 if sysroot_path and target.kernel != "Darwin": 64 pkgconfig_dirs = [ 65 "usr/lib/pkgconfig", 66 "usr/lib/{}/pkgconfig".format(multiarch_dir), 67 "usr/share/pkgconfig", 68 ] 69 if target.bitness == 64: 70 pkgconfig_dirs.insert(0, "usr/lib64/pkgconfig") 71 return namespace( 72 PKG_CONFIG_PATH="", 73 PKG_CONFIG_SYSROOT_DIR=sysroot_path, 74 PKG_CONFIG_LIBDIR=pathsep.join( 75 os.path.join(sysroot_path, d) for d in pkgconfig_dirs 76 ), 77 ) 78 79 80 @depends(pkg_config_vars) 81 @imports(_from="os", _import="environ") 82 def pkg_config_env(vars): 83 if vars: 84 env = dict(environ) 85 env["PKG_CONFIG_PATH"] = vars.PKG_CONFIG_PATH 86 env["PKG_CONFIG_SYSROOT_DIR"] = vars.PKG_CONFIG_SYSROOT_DIR 87 env["PKG_CONFIG_LIBDIR"] = vars.PKG_CONFIG_LIBDIR 88 return env 89 90 91 set_config("PKG_CONFIG_PATH", pkg_config_vars.PKG_CONFIG_PATH) 92 set_config("PKG_CONFIG_SYSROOT_DIR", pkg_config_vars.PKG_CONFIG_SYSROOT_DIR) 93 set_config("PKG_CONFIG_LIBDIR", pkg_config_vars.PKG_CONFIG_LIBDIR) 94 95 96 # Locates the given module using pkg-config. 97 # - `var` determines the name of variables to set when the package is found. 98 # <var>_CFLAGS and <var>_LIBS are set with corresponding values. 99 # - `package_desc` package name and version requirement string, list of 100 # strings describing packages to locate, or depends function that will 101 # resolve to such a string or list of strings. 102 # - `when` a depends function that will determine whether to perform 103 # any checks (default is to always perform checks). 104 # - `allow_missing` If set, failure to fulfill the package description 105 # will not result in an error or logged message, and any error message 106 # will be returned to the caller. 107 # Returns `True` when the package description is fulfilled. 108 @template 109 def pkg_check_modules( 110 var, 111 package_desc, 112 when=always, 113 allow_missing=False, 114 config=True, 115 cflags_only=False, 116 ): 117 @depends(dependable(package_desc), when=when) 118 def package_desc(desc): 119 if isinstance(desc, str): 120 desc = [desc] 121 if not isinstance(desc, (tuple, list)): 122 configure_error( 123 "package_desc must be a string or a tuple or list of strings" 124 ) 125 126 return " ".join(desc) 127 128 allow_missing = dependable(allow_missing) 129 130 @depends(when, when=use_pkg_config) 131 def when_and_use_pkg_config(when): 132 return when 133 134 @depends(pkg_config, pkg_config_version, when=when_and_use_pkg_config) 135 def check_pkg_config(pkg_config, version): 136 min_version = "0.9.0" 137 if pkg_config is None: 138 die( 139 "*** The pkg-config script could not be found. Make sure it is\n" 140 "*** in your path, or set the PKG_CONFIG environment variable\n" 141 "*** to the full path to pkg-config." 142 ) 143 if version < min_version: 144 die( 145 "*** Your version of pkg-config is too old. You need version %s or newer.", 146 min_version, 147 ) 148 149 @depends( 150 pkg_config, 151 pkg_config_env, 152 package_desc, 153 allow_missing, 154 when=when_and_use_pkg_config, 155 ) 156 @imports("sys") 157 @imports(_from="mozbuild.configure.util", _import="LineIO") 158 def package(pkg_config, env, package_desc, allow_missing): 159 # package_desc may start as a depends function, so we can't use 160 # @checking here. 161 log.info("checking for %s... " % package_desc) 162 retcode, stdout, stderr = get_cmd_output( 163 pkg_config, 164 "--errors-to-stdout", 165 "--print-errors", 166 package_desc, 167 env=env, 168 ) 169 if retcode == 0: 170 log.info("yes") 171 return True 172 log.info("no") 173 log_writer = log.warning if allow_missing else log.error 174 with LineIO(lambda l: log_writer(l)) as o: 175 o.write(stdout) 176 if not allow_missing: 177 sys.exit(1) 178 179 @depends( 180 pkg_config, pkg_config_env, package_desc, pkg_config_base_flags, when=package 181 ) 182 @checking("%s_CFLAGS" % var, callback=lambda t: " ".join(t)) 183 def pkg_cflags(pkg_config, env, package_desc, base_flags): 184 args = list(base_flags) + ["--cflags", package_desc] 185 flags = check_cmd_output(pkg_config, *args, env=env) 186 return tuple(flags.split()) 187 188 if cflags_only: 189 190 @depends(pkg_cflags, when=package) 191 def pkg_info(cflags): 192 return namespace(cflags=cflags) 193 194 else: 195 196 @depends( 197 pkg_config, 198 pkg_config_env, 199 package_desc, 200 pkg_config_base_flags, 201 when=package, 202 ) 203 @checking("%s_LIBS" % var, callback=lambda t: " ".join(t)) 204 def pkg_libs(pkg_config, env, package_desc, base_flags): 205 args = list(base_flags) + ["--libs", package_desc] 206 libs = check_cmd_output(pkg_config, *args, env=env) 207 # Remove evil flags like -Wl,--export-dynamic 208 return tuple(libs.replace("-Wl,--export-dynamic", "").split()) 209 210 @depends(pkg_cflags, pkg_libs, when=package) 211 def pkg_info(cflags, libs): 212 return namespace(cflags=cflags, libs=libs) 213 214 if config: 215 set_config("%s_CFLAGS" % var, pkg_cflags) 216 if not cflags_only: 217 set_config("%s_LIBS" % var, pkg_libs) 218 219 return pkg_info