[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / utils / bazel / terminfo.bzl
blob2505f76272398e2fa97831e3915bfbded19a1732
1 # This file is licensed under the Apache License v2.0 with LLVM Exceptions.
2 # See https://llvm.org/LICENSE.txt for license information.
3 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 """Repository rules to configure the terminfo used by LLVM.
7 Most users should pick one of the explicit rules to configure their use of terminfo
8 with LLVM:
9 - `llvm_terminfo_system` will detect and link against a terminfo-implementing
10   system library (non-hermetically).
11 - 'llvm_terminfo_disable` will disable terminfo completely.
13 If you would like to make your build configurable, you can use
14 `llvm_terminfo_from_env`. By default, this will disable terminfo, but will
15 inspect the environment variable (most easily set with a `--repo_env` flag to
16 the Bazel invocation) `BAZEL_LLVM_TERMINFO_STRATEGY`. If it is set to
17 `system` then it will behave the same as `llvm_terminfo_system`. Any other
18 setting will disable terminfo the same as not setting it at all.
19 """
21 def _llvm_terminfo_disable_impl(repository_ctx):
22     repository_ctx.template(
23         "BUILD",
24         repository_ctx.attr._disable_build_template,
25         executable = False,
26     )
28 _terminfo_disable_attrs = {
29     "_disable_build_template": attr.label(
30         default = Label("//utils/bazel/deps_impl:terminfo_disable.BUILD"),
31         allow_single_file = True,
32     ),
35 llvm_terminfo_disable = repository_rule(
36     implementation = _llvm_terminfo_disable_impl,
37     attrs = _terminfo_disable_attrs,
40 def _find_c_compiler(repository_ctx):
41     """Returns the path to a plausible C compiler.
43     This routine will only reliably work on roughly POSIX-y systems as it
44     ultimately falls back on the `cc` binary. Fortunately, the thing we are
45     trying to use it for (detecting if a trivial source file can compile and
46     link against a particular library) requires very little.
47     """
48     cc_env = repository_ctx.os.environ.get("CC")
49     cc = None
50     if cc_env:
51         if "/" in cc_env:
52             return repository_ctx.path(cc_env)
53         else:
54             return repository_ctx.which(cc_env)
56     # Look for Clang, GCC, and the POSIX / UNIX specified C compiler
57     # binaries.
58     for compiler in ["clang", "gcc", "c99", "c89", "cc"]:
59         cc = repository_ctx.which(compiler)
60         if cc:
61             return cc
63     return None
65 def _try_link(repository_ctx, cc, source, linker_flags):
66     """Returns `True` if able to link the source with the linker flag.
68     Given a source file that contains references to library routines, this
69     will check that when linked with the provided linker flag, those
70     references are successfully resolved. This routine assumes a generally
71     POSIX-y and GCC-ish compiler and environment and shouldn't be expected to
72     work outside of that.
73     """
74     cmd = [
75         cc,
76         # Force discard the linked executable.
77         "-o",
78         "/dev/null",
79         # Leave language detection to the compiler.
80         source,
81     ]
83     # The linker flag must be valid for a compiler invocation of the link step,
84     # so just append them to the command.
85     cmd += linker_flags
86     exec_result = repository_ctx.execute(cmd, timeout = 20)
87     return exec_result.return_code == 0
89 def _llvm_terminfo_system_impl(repository_ctx):
90     # LLVM doesn't need terminfo support on Windows, so just disable it.
91     if repository_ctx.os.name.lower().find("windows") != -1:
92         _llvm_terminfo_disable_impl(repository_ctx)
93         return
95     if len(repository_ctx.attr.system_linkopts) > 0:
96         linkopts = repository_ctx.attr.system_linkopts
97     else:
98         required = repository_ctx.attr.system_required
100         # Find a C compiler we can use to detect viable linkopts on this system.
101         cc = _find_c_compiler(repository_ctx)
102         if not cc:
103             if required:
104                 fail("Failed  to find a C compiler executable")
105             else:
106                 _llvm_terminfo_disable_impl(repository_ctx)
107                 return
109         # Get the source file we use to detect successful linking of terminfo.
110         source = repository_ctx.path(repository_ctx.attr._terminfo_test_source)
112         # Collect the candidate linkopts and wrap them into a list. Ideally,
113         # these would be provided as lists, but Bazel doesn't currently
114         # support that. See: https://github.com/bazelbuild/bazel/issues/12178
115         linkopts_candidates = [[x] for x in repository_ctx.attr.candidate_system_linkopts]
117         # For each candidate, try to use it to link our test source file.
118         for linkopts_candidate in linkopts_candidates:
119             if _try_link(repository_ctx, cc, source, linkopts_candidate):
120                 linkopts = linkopts_candidate
121                 break
123         # If we never found a viable linkopts candidate, either error or disable
124         # terminfo for LLVM.
125         if not linkopts:
126             if required:
127                 fail("Failed to detect which linkopt would successfully provide the " +
128                      "necessary terminfo functionality")
129             else:
130                 _llvm_terminfo_disable_impl(repository_ctx)
131                 return
133     repository_ctx.template(
134         "BUILD",
135         repository_ctx.attr._system_build_template,
136         substitutions = {
137             "{TERMINFO_LINKOPTS}": str(linkopts),
138         },
139         executable = False,
140     )
142 def _merge_attrs(attrs_list):
143     attrs = {}
144     for input_attrs in attrs_list:
145         attrs.update(input_attrs)
146     return attrs
148 _terminfo_system_attrs = _merge_attrs([_terminfo_disable_attrs, {
149     "_system_build_template": attr.label(
150         default = Label("//utils/bazel/deps_impl:terminfo_system.BUILD"),
151         allow_single_file = True,
152     ),
153     "_terminfo_test_source": attr.label(
154         default = Label("//utils/bazel/deps_impl:terminfo_test.c"),
155         allow_single_file = True,
156     ),
157     "candidate_system_linkopts": attr.string_list(
158         default = [
159             "-lterminfo",
160             "-ltinfo",
161             "-lcurses",
162             "-lncurses",
163             "-lncursesw",
164         ],
165         doc = "Candidate linkopts to test and see if they can link " +
166               "successfully.",
167     ),
168     "system_required": attr.bool(
169         default = False,
170         doc = "Require that one of the candidates is detected successfully on POSIX platforms where it is needed.",
171     ),
172     "system_linkopts": attr.string_list(
173         default = [],
174         doc = "If non-empty, a specific array of linkopts to use to " +
175               "successfully link against the terminfo library. No " +
176               "detection is performed if this option is provided, it " +
177               "directly forces the use of these link options. No test is " +
178               "run to determine if they are valid or work correctly either.",
179     ),
182 llvm_terminfo_system = repository_rule(
183     implementation = _llvm_terminfo_system_impl,
184     configure = True,
185     local = True,
186     attrs = _terminfo_system_attrs,
189 def _llvm_terminfo_from_env_impl(repository_ctx):
190     terminfo_strategy = repository_ctx.os.environ.get("BAZEL_LLVM_TERMINFO_STRATEGY")
191     if terminfo_strategy == "system":
192         _llvm_terminfo_system_impl(repository_ctx)
193     else:
194         _llvm_terminfo_disable_impl(repository_ctx)
196 llvm_terminfo_from_env = repository_rule(
197     implementation = _llvm_terminfo_from_env_impl,
198     configure = True,
199     local = True,
200     attrs = _merge_attrs([_terminfo_disable_attrs, _terminfo_system_attrs]),
201     environ = ["BAZEL_LLVM_TERMINFO_STRATEGY", "CC"],