1
+ load ("@bazel_tools//tools/cpp:cc_configure.bzl" , "cc_autoconf_impl" )
2
+
1
3
"""Rules for importing Nixpkgs packages."""
2
4
3
5
def _nixpkgs_git_repository_impl (repository_ctx ):
@@ -110,7 +112,9 @@ def _nixpkgs_package_impl(repository_ctx):
110
112
output_path = exec_result .stdout .splitlines ()[- 1 ]
111
113
# Build a forest of symlinks (like new_local_package() does) to the
112
114
# Nix store.
113
- _symlink_children (repository_ctx , output_path )
115
+ for target in _find_children (repository_ctx , output_path ):
116
+ basename = target .rpartition ("/" )[- 1 ]
117
+ repository_ctx .symlink (target , basename )
114
118
115
119
116
120
_nixpkgs_package = repository_rule (
@@ -128,6 +132,7 @@ _nixpkgs_package = repository_rule(
128
132
local = True ,
129
133
)
130
134
135
+
131
136
def nixpkgs_package (* args , ** kwargs ):
132
137
# Because of https://github.com/bazelbuild/bazel/issues/5356 we can't
133
138
# directly pass a dict from strings to labels to the rule (which we'd like
@@ -145,6 +150,70 @@ def nixpkgs_package(*args, **kwargs):
145
150
else :
146
151
_nixpkgs_package (* args , ** kwargs )
147
152
153
+
154
+ def _nixpkgs_cc_autoconf_impl (repository_ctx ):
155
+ # Calling repository_ctx.path() on anything but a regular file
156
+ # fails. So the roundabout way to do the same thing is to find
157
+ # a regular file we know is in the workspace (i.e. the WORKSPACE
158
+ # file itself) and then use dirname to get the path of the workspace
159
+ # root.
160
+ workspace_file_path = repository_ctx .path (
161
+ Label ("@nixpkgs_cc_toolchain//:WORKSPACE" )
162
+ )
163
+ workspace_root = _execute_or_fail (
164
+ repository_ctx ,
165
+ ["dirname" , workspace_file_path ],
166
+ ).stdout .rstrip ()
167
+
168
+ # Make a list of all available tools in the Nix derivation. Override
169
+ # the Bazel autoconfiguration with the tools we found.
170
+ bin_contents = _find_children (repository_ctx , workspace_root + "/bin" )
171
+ overriden_tools = {
172
+ tool : repository_ctx .path (Label ("@nixpkgs_cc_toolchain//:bin/" + tool ))
173
+ for entry in bin_contents
174
+ for tool in [entry .rpartition ("/" )[- 1 ]] # Compute basename
175
+ }
176
+ cc_autoconf_impl (repository_ctx , overriden_tools = overriden_tools )
177
+
178
+ _nixpkgs_cc_autoconf = repository_rule (
179
+ implementation = _nixpkgs_cc_autoconf_impl
180
+ )
181
+
182
+
183
+ def nixpkgs_cc_configure (
184
+ repository = None ,
185
+ repositories = None ,
186
+ nix_file_content = """
187
+ with import <nixpkgs> {}; buildEnv {
188
+ name = "bazel-cc-toolchain";
189
+ paths = [ gcc binutils ];
190
+ }
191
+ """ ):
192
+ """Use a CC toolchain from Nixpkgs.
193
+
194
+ By default, Bazel auto-configures a CC toolchain from commands (e.g.
195
+ `gcc`) available in the environment. To make builds more hermetic, use
196
+ this rule to specific explicitly which commands the toolchain should
197
+ use.
198
+ """
199
+ if repository and repositories or not repository and not repositories :
200
+ fail ("Specify one of repository or repositories (but not both)." )
201
+ elif repository :
202
+ repositories = {"nixpkgs" : repository }
203
+
204
+ nixpkgs_package (
205
+ name = "nixpkgs_cc_toolchain" ,
206
+ repositories = repositories ,
207
+ nix_file_content = nix_file_content ,
208
+ build_file_content = """exports_files(glob(["bin/*"]))""" ,
209
+ )
210
+ # Following lines should match
211
+ # https://github.com/bazelbuild/bazel/blob/master/tools/cpp/cc_configure.bzl#L93.
212
+ _nixpkgs_cc_autoconf (name = "local_config_cc" )
213
+ native .bind (name = "cc_toolchain" , actual = "@local_config_cc//:toolchain" )
214
+ native .register_toolchains ("@local_config_cc//:all" )
215
+
216
+
148
217
def _execute_or_fail (repository_ctx , arguments , failure_message = "" , * args , ** kwargs ):
149
218
"""Call repository_ctx.execute() and fail if non-zero return code."""
150
219
result = repository_ctx .execute (arguments , * args , ** kwargs )
@@ -165,11 +234,10 @@ Error output:
165
234
return result
166
235
167
236
168
- def _symlink_children (repository_ctx , target_dir ):
169
- """Create a symlink to all children of `target_dir` in the current
170
- build directory."""
237
+ def _find_children (repository_ctx , target_dir ):
171
238
find_args = [
172
239
_executable_path (repository_ctx , "find" ),
240
+ "-L" ,
173
241
target_dir ,
174
242
"-maxdepth" , "1" ,
175
243
# otherwise the directory is printed as well
@@ -178,10 +246,8 @@ def _symlink_children(repository_ctx, target_dir):
178
246
"-print0" ,
179
247
]
180
248
exec_result = _execute_or_fail (repository_ctx , find_args )
181
- for target in exec_result .stdout .rstrip ("\0 " ).split ("\0 " ):
182
- basename = target .rpartition ("/" )[- 1 ]
183
- repository_ctx .symlink (target , basename )
184
-
249
+ return exec_result .stdout .rstrip ("\0 " ).split ("\0 " )
250
+
185
251
186
252
def _executable_path (repository_ctx , exe_name , extra_msg = "" ):
187
253
"""Try to find the executable, fail with an error."""
0 commit comments