summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/pkg.configure
blob: 6b460ae174eedb028fa3cdffd4a079a6d8f94125 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.


@depends(toolchain_prefix, when=compile_environment)
def pkg_config(prefixes):
    return tuple("{}pkg-config".format(p) for p in (prefixes or ()) + ("",))


pkg_config = check_prog(
    "PKG_CONFIG",
    pkg_config,
    bootstrap=depends(when=target_sysroot.bootstrapped)(lambda: "pkgconf"),
    allow_missing=True,
    when=compile_environment
    & depends(target.os)(lambda os: os not in ("WINNT", "OSX", "Android")),
)


@depends_if(pkg_config)
@checking("for pkg-config version")
def pkg_config_version(pkg_config):
    return Version(check_cmd_output(pkg_config, "--version").rstrip())


@depends_if(pkg_config)
@checking("whether pkg-config is pkgconf")
def is_pkgconf(pkg_config):
    return "pkgconf " in check_cmd_output(pkg_config, "--about", onerror=lambda: "")


@depends(is_pkgconf, pkg_config_version, target_sysroot.bootstrapped, when=pkg_config)
def pkg_config_base_flags(is_pkgconf, pkg_config_version, target_sysroot_bootstrapped):
    # pkgconf 1.7.4 changed the default on Windows to use --static, but
    # that doesn't work for us.
    # Note: the --shared flag is not available before pkgconf 1.7
    flags = []
    if is_pkgconf and pkg_config_version >= "1.7.4":
        flags.append("--shared")
    # When pkg-config is in /usr things work fine by default, but when
    # it is not, it defines prefix to be something else than /usr, which
    # won't match what the .pc files actually say, and won't work in
    # sysroots.
    if target_sysroot_bootstrapped and (
        (is_pkgconf and pkg_config_version >= "1.2.0")
        or (not is_pkgconf and pkg_config_version >= "0.29.0")
    ):
        flags.append("--dont-define-prefix")
    return tuple(flags)


@depends(target, target_sysroot.path, target_multiarch_dir, when=pkg_config)
@imports(_from="os", _import="environ")
@imports(_from="os", _import="pathsep")
def pkg_config_vars(target, sysroot_path, multiarch_dir):
    if sysroot_path and target.kernel != "Darwin":
        return namespace(
            PKG_CONFIG_PATH="",
            PKG_CONFIG_SYSROOT_DIR=sysroot_path,
            PKG_CONFIG_LIBDIR=pathsep.join(
                os.path.join(sysroot_path, d)
                for d in (
                    "usr/lib/pkgconfig",
                    "usr/lib/{}/pkgconfig".format(multiarch_dir),
                    "usr/share/pkgconfig",
                )
            ),
        )


@depends(pkg_config_vars)
@imports(_from="os", _import="environ")
def pkg_config_env(vars):
    if vars:
        env = dict(environ)
        env["PKG_CONFIG_PATH"] = vars.PKG_CONFIG_PATH
        env["PKG_CONFIG_SYSROOT_DIR"] = vars.PKG_CONFIG_SYSROOT_DIR
        env["PKG_CONFIG_LIBDIR"] = vars.PKG_CONFIG_LIBDIR
        return env


set_config("PKG_CONFIG_PATH", pkg_config_vars.PKG_CONFIG_PATH)
set_config("PKG_CONFIG_SYSROOT_DIR", pkg_config_vars.PKG_CONFIG_SYSROOT_DIR)
set_config("PKG_CONFIG_LIBDIR", pkg_config_vars.PKG_CONFIG_LIBDIR)


# Locates the given module using pkg-config.
# - `var` determines the name of variables to set when the package is found.
#   <var>_CFLAGS and <var>_LIBS are set with corresponding values.
# - `package_desc` package name and version requirement string, list of
#   strings describing packages to locate, or depends function that will
#   resolve to such a string or list of strings.
# - `when` a depends function that will determine whether to perform
#   any checks (default is to always perform checks).
# - `allow_missing` If set, failure to fulfill the package description
#   will not result in an error or logged message, and any error message
#   will be returned to the caller.
#   Returns `True` when the package description is fulfilled.
@template
def pkg_check_modules(
    var, package_desc, when=always, allow_missing=False, config=True, cflags_only=False
):
    @depends(dependable(package_desc), when=when)
    def package_desc(desc):
        if isinstance(desc, str):
            desc = [desc]
        if not isinstance(desc, (tuple, list)):
            configure_error(
                "package_desc must be a string or a tuple or list of strings"
            )

        return " ".join(desc)

    allow_missing = dependable(allow_missing)

    @depends(when, "--enable-compile-environment")
    def when_and_compile_environment(when, compile_environment):
        return when and compile_environment

    @depends(pkg_config, pkg_config_version, when=when_and_compile_environment)
    def check_pkg_config(pkg_config, version):
        min_version = "0.9.0"
        if pkg_config is None:
            die(
                "*** The pkg-config script could not be found. Make sure it is\n"
                "*** in your path, or set the PKG_CONFIG environment variable\n"
                "*** to the full path to pkg-config."
            )
        if version < min_version:
            die(
                "*** Your version of pkg-config is too old. You need version %s or newer.",
                min_version,
            )

    @depends(
        pkg_config,
        pkg_config_env,
        package_desc,
        allow_missing,
        when=when_and_compile_environment,
    )
    @imports("sys")
    @imports(_from="mozbuild.configure.util", _import="LineIO")
    def package(pkg_config, env, package_desc, allow_missing):
        # package_desc may start as a depends function, so we can't use
        # @checking here.
        log.info("checking for %s... " % package_desc)
        retcode, stdout, stderr = get_cmd_output(
            pkg_config,
            "--errors-to-stdout",
            "--print-errors",
            package_desc,
            env=env,
        )
        if retcode == 0:
            log.info("yes")
            return True
        log.info("no")
        log_writer = log.warning if allow_missing else log.error
        with LineIO(lambda l: log_writer(l)) as o:
            o.write(stdout)
        if not allow_missing:
            sys.exit(1)

    @depends(
        pkg_config, pkg_config_env, package_desc, pkg_config_base_flags, when=package
    )
    @checking("%s_CFLAGS" % var, callback=lambda t: " ".join(t))
    def pkg_cflags(pkg_config, env, package_desc, base_flags):
        args = list(base_flags) + ["--cflags", package_desc]
        flags = check_cmd_output(pkg_config, *args, env=env)
        return tuple(flags.split())

    if cflags_only:

        @depends(pkg_cflags, when=package)
        def pkg_info(cflags):
            return namespace(cflags=cflags)

    else:

        @depends(
            pkg_config,
            pkg_config_env,
            package_desc,
            pkg_config_base_flags,
            when=package,
        )
        @checking("%s_LIBS" % var, callback=lambda t: " ".join(t))
        def pkg_libs(pkg_config, env, package_desc, base_flags):
            args = list(base_flags) + ["--libs", package_desc]
            libs = check_cmd_output(pkg_config, *args, env=env)
            # Remove evil flags like -Wl,--export-dynamic
            return tuple(libs.replace("-Wl,--export-dynamic", "").split())

        @depends(pkg_cflags, pkg_libs, when=package)
        def pkg_info(cflags, libs):
            return namespace(cflags=cflags, libs=libs)

    if config:
        set_config("%s_CFLAGS" % var, pkg_cflags)
        if not cflags_only:
            set_config("%s_LIBS" % var, pkg_libs)

    return pkg_info