blob: 4f62ba94c1a208749aba43d78c270c720cc76834 [file] [log] [blame]
Alan Donovan312d1a52017-10-02 10:10:28 -04001# Copyright 2014 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# (From https://github.com/bazelbuild/rules_go/blob/master/go/def.bzl@a6f9d0c)
16
17load("//go/private:repositories.bzl", "go_repositories")
18load("//go/private:go_repository.bzl", "go_repository", "new_go_repository")
19load("//go/private:go_prefix.bzl", "go_prefix")
20load("//go/private:json.bzl", "json_marshal")
21
22"""These are bare-bones Go rules.
23
24In order of priority:
25
26- BUILD file must be written by hand.
27
28- No support for SWIG
29
30- No test sharding or test XML.
31
32"""
33
34_DEFAULT_LIB = "go_default_library"
35
36_VENDOR_PREFIX = "/vendor/"
37
38go_filetype = FileType([
39 ".go",
40 ".s",
41 ".S",
42 ".h", # may be included by .s
43])
44
45# be consistent to cc_library.
46hdr_exts = [
47 ".h",
48 ".hh",
49 ".hpp",
50 ".hxx",
51 ".inc",
52]
53
54cc_hdr_filetype = FileType(hdr_exts)
55
56# Extensions of files we can build with the Go compiler or with cc_library.
57# This is a subset of the extensions recognized by go/build.
58cgo_filetype = FileType([
59 ".go",
60 ".c",
61 ".cc",
62 ".cxx",
63 ".cpp",
64 ".s",
65 ".S",
66 ".h",
67 ".hh",
68 ".hpp",
69 ".hxx",
70])
71
72################
73
74def go_environment_vars(ctx):
alandonovanf935de82021-01-22 14:46:13 -050075 """Return a map of environment variables for use with actions, based on
76 the arguments. Uses the ctx.fragments.cpp.cpu attribute, if present,
77 and picks a default of target_os="linux" and target_arch="amd64"
78 otherwise.
Alan Donovan312d1a52017-10-02 10:10:28 -040079
alandonovanf935de82021-01-22 14:46:13 -050080 Args:
81 The starlark Context.
Alan Donovan312d1a52017-10-02 10:10:28 -040082
alandonovanf935de82021-01-22 14:46:13 -050083 Returns:
84 A dict of environment variables for running Go tool commands that build for
85 the target OS and architecture.
86 """
87 default_toolchain = {"GOOS": "linux", "GOARCH": "amd64"}
88 bazel_to_go_toolchain = {
89 "k8": {"GOOS": "linux", "GOARCH": "amd64"},
90 "piii": {"GOOS": "linux", "GOARCH": "386"},
91 "darwin": {"GOOS": "darwin", "GOARCH": "amd64"},
92 "darwin_x86_64": {"GOOS": "darwin", "GOARCH": "amd64"},
93 "freebsd": {"GOOS": "freebsd", "GOARCH": "amd64"},
94 "armeabi-v7a": {"GOOS": "linux", "GOARCH": "arm"},
95 "arm": {"GOOS": "linux", "GOARCH": "arm"},
96 }
97 env = {}
98 if hasattr(ctx.file, "go_tool"):
99 env["GOROOT"] = ctx.file.go_tool.dirname + "/.."
100 env.update(bazel_to_go_toolchain.get(ctx.fragments.cpp.cpu, default_toolchain))
101 return env
Alan Donovan312d1a52017-10-02 10:10:28 -0400102
103def _is_darwin_cpu(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500104 cpu = ctx.fragments.cpp.cpu
105 return cpu == "darwin" or cpu == "darwin_x86_64"
Alan Donovan312d1a52017-10-02 10:10:28 -0400106
107def _emit_generate_params_action(cmds, ctx, fn):
alandonovanf935de82021-01-22 14:46:13 -0500108 cmds_all = [
109 # Use bash explicitly. /bin/sh is default, and it may be linked to a
110 # different shell, e.g., /bin/dash on Ubuntu.
111 "#!/bin/bash",
112 "set -e",
113 ]
114 cmds_all += cmds
115 cmds_all_str = "\n".join(cmds_all) + "\n"
116 f = ctx.new_file(ctx.configuration.bin_dir, fn)
117 ctx.file_action(
118 output = f,
119 content = cmds_all_str,
120 executable = True,
121 )
122 return f
Alan Donovan312d1a52017-10-02 10:10:28 -0400123
124def _emit_go_asm_action(ctx, source, hdrs, out_obj):
alandonovanf935de82021-01-22 14:46:13 -0500125 """Construct the command line for compiling Go Assembly code.
126 Constructs a symlink tree to accomodate for workspace name.
127 Args:
128 ctx: The starlark Context.
129 source: a source code artifact
130 hdrs: list of .h files that may be included
131 out_obj: the artifact (configured target?) that should be produced
132 """
133 params = {
134 "go_tool": ctx.file.go_tool.path,
135 "includes": [f.dirname for f in hdrs] + [ctx.file.go_include.path],
136 "source": source.path,
137 "out": out_obj.path,
138 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400139
alandonovanf935de82021-01-22 14:46:13 -0500140 inputs = hdrs + ctx.files.toolchain + [source]
141 ctx.action(
142 inputs = inputs,
143 outputs = [out_obj],
144 mnemonic = "GoAsmCompile",
145 executable = ctx.executable._asm,
146 arguments = [json_marshal(params)],
147 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400148
149def _go_importpath(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500150 """Returns the expected importpath of the go_library being built.
Alan Donovan312d1a52017-10-02 10:10:28 -0400151
alandonovanf935de82021-01-22 14:46:13 -0500152 Args:
153 ctx: The starlark Context
Alan Donovan312d1a52017-10-02 10:10:28 -0400154
alandonovanf935de82021-01-22 14:46:13 -0500155 Returns:
156 Go importpath of the library
157 """
158 path = ctx.attr.importpath
159 if path != "":
160 return path
161 path = ctx.attr.go_prefix.go_prefix
162 if path.endswith("/"):
163 path = path[:-1]
164 if ctx.label.package:
165 path += "/" + ctx.label.package
166 if ctx.label.name != _DEFAULT_LIB:
167 path += "/" + ctx.label.name
168 if path.rfind(_VENDOR_PREFIX) != -1:
169 path = path[len(_VENDOR_PREFIX) + path.rfind(_VENDOR_PREFIX):]
170 if path[0] == "/":
171 path = path[1:]
Alan Donovan312d1a52017-10-02 10:10:28 -0400172 return path
Alan Donovan312d1a52017-10-02 10:10:28 -0400173
174def _emit_go_compile_action(ctx, sources, deps, libpaths, out_object, gc_goopts):
alandonovanf935de82021-01-22 14:46:13 -0500175 """Construct the command line for compiling Go code.
Alan Donovan312d1a52017-10-02 10:10:28 -0400176
alandonovanf935de82021-01-22 14:46:13 -0500177 Args:
178 ctx: The starlark Context.
179 sources: an iterable of source code artifacts (or CTs? or labels?)
180 deps: an iterable of dependencies. Each dependency d should have an
181 artifact in d.transitive_go_libraries representing all imported libraries.
182 libpaths: the set of paths to search for imported libraries.
183 out_object: the object file that should be produced
184 gc_goopts: additional flags to pass to the compiler.
185 """
186 if ctx.coverage_instrumented():
187 sources = _emit_go_cover_action(ctx, sources)
Alan Donovan312d1a52017-10-02 10:10:28 -0400188
alandonovanf935de82021-01-22 14:46:13 -0500189 # Compile filtered files.
190 args = [
191 "-cgo",
192 ctx.file.go_tool.path,
193 "tool",
194 "compile",
195 "-o",
196 out_object.path,
197 "-trimpath",
198 "-abs-.",
199 "-I",
200 "-abs-.",
201 ]
202 inputs = depset(sources + ctx.files.toolchain)
203 for dep in deps:
204 inputs += dep.transitive_go_libraries
205 for path in libpaths:
206 args += ["-I", path]
207 args += gc_goopts + [("" if i.basename.startswith("_cgo") else "-filter-") + i.path for i in sources]
Alan Donovan312d1a52017-10-02 10:10:28 -0400208 ctx.action(
alandonovanf935de82021-01-22 14:46:13 -0500209 inputs = list(inputs),
210 outputs = [out_object],
211 mnemonic = "GoCompile",
212 executable = ctx.executable._filter_exec,
213 arguments = args,
Alan Donovan312d1a52017-10-02 10:10:28 -0400214 env = go_environment_vars(ctx),
215 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400216
alandonovanf935de82021-01-22 14:46:13 -0500217 return sources
218
219def _emit_go_pack_action(ctx, out_lib, objects):
220 """Construct the command line for packing objects together.
221
222 Args:
223 ctx: The starlark Context.
224 out_lib: the archive that should be produced
225 objects: an iterable of object files to be added to the output archive file.
226 """
227 ctx.action(
228 inputs = objects + ctx.files.toolchain,
229 outputs = [out_lib],
230 mnemonic = "GoPack",
231 executable = ctx.file.go_tool,
232 arguments = ["tool", "pack", "c", out_lib.path] + [a.path for a in objects],
233 env = go_environment_vars(ctx),
234 )
235
236def _emit_go_cover_action(ctx, sources):
237 """Construct the command line for test coverage instrument.
238
239 Args:
240 ctx: The starlark Context.
241 sources: an iterable of Go source files.
242
243 Returns:
244 A list of Go source code files which might be coverage instrumented.
245 """
246 outputs = []
247
248 # TODO(linuxerwang): make the mode configurable.
249 count = 0
250
251 for src in sources:
252 if not src.path.endswith(".go") or src.path.endswith("_test.go"):
253 outputs += [src]
254 continue
255
256 cover_var = "GoCover_%d" % count
257 out = ctx.new_file(src, src.basename[:-3] + "_" + cover_var + ".cover.go")
258 outputs += [out]
259 ctx.action(
260 inputs = [src] + ctx.files.toolchain,
261 outputs = [out],
262 mnemonic = "GoCover",
263 executable = ctx.file.go_tool,
264 arguments = ["tool", "cover", "--mode=set", "-var=%s" % cover_var, "-o", out.path, src.path],
265 env = go_environment_vars(ctx),
266 )
267 count += 1
268
269 return outputs
Alan Donovan312d1a52017-10-02 10:10:28 -0400270
271def go_library_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500272 """Implements the go_library() rule."""
Alan Donovan312d1a52017-10-02 10:10:28 -0400273
alandonovanf935de82021-01-22 14:46:13 -0500274 sources = depset(ctx.files.srcs)
275 go_srcs = depset([s for s in sources if s.basename.endswith(".go")])
276 asm_srcs = [s for s in sources if s.basename.endswith(".s") or s.basename.endswith(".S")]
277 asm_hdrs = [s for s in sources if s.basename.endswith(".h")]
278 deps = ctx.attr.deps
279 dep_runfiles = [d.data_runfiles for d in deps]
Alan Donovan312d1a52017-10-02 10:10:28 -0400280
alandonovanf935de82021-01-22 14:46:13 -0500281 cgo_object = None
282 if hasattr(ctx.attr, "cgo_object"):
283 cgo_object = ctx.attr.cgo_object
Alan Donovan312d1a52017-10-02 10:10:28 -0400284
alandonovanf935de82021-01-22 14:46:13 -0500285 if ctx.attr.library:
286 go_srcs += ctx.attr.library.go_sources
287 asm_srcs += ctx.attr.library.asm_sources
288 asm_hdrs += ctx.attr.library.asm_headers
289 deps += ctx.attr.library.direct_deps
290 dep_runfiles += [ctx.attr.library.data_runfiles]
291 if ctx.attr.library.cgo_object:
292 if cgo_object:
293 fail("go_library %s cannot have cgo_object because the package " +
294 "already has cgo_object in %s" % (
295 ctx.label.name,
296 ctx.attr.library.name,
297 ))
298 cgo_object = ctx.attr.library.cgo_object
299 if not go_srcs:
300 fail("may not be empty", "srcs")
Alan Donovan312d1a52017-10-02 10:10:28 -0400301
alandonovanf935de82021-01-22 14:46:13 -0500302 transitive_cgo_deps = depset([], order = "topological")
303 if cgo_object:
304 dep_runfiles += [cgo_object.data_runfiles]
305 transitive_cgo_deps += cgo_object.cgo_deps
Alan Donovan312d1a52017-10-02 10:10:28 -0400306
alandonovanf935de82021-01-22 14:46:13 -0500307 extra_objects = [cgo_object.cgo_obj] if cgo_object else []
308 for src in asm_srcs:
309 obj = ctx.new_file(src, "%s.dir/%s.o" % (ctx.label.name, src.basename[:-2]))
310 _emit_go_asm_action(ctx, src, asm_hdrs, obj)
311 extra_objects += [obj]
Alan Donovan312d1a52017-10-02 10:10:28 -0400312
alandonovanf935de82021-01-22 14:46:13 -0500313 lib_name = _go_importpath(ctx) + ".a"
314 out_lib = ctx.new_file(lib_name)
315 out_object = ctx.new_file(ctx.label.name + ".o")
316 search_path = out_lib.path[:-len(lib_name)]
317 gc_goopts = _gc_goopts(ctx)
318 transitive_go_libraries = depset([out_lib])
319 transitive_go_library_paths = depset([search_path])
320 for dep in deps:
321 transitive_go_libraries += dep.transitive_go_libraries
322 transitive_cgo_deps += dep.transitive_cgo_deps
323 transitive_go_library_paths += dep.transitive_go_library_paths
Alan Donovan312d1a52017-10-02 10:10:28 -0400324
alandonovanf935de82021-01-22 14:46:13 -0500325 go_srcs = _emit_go_compile_action(
326 ctx,
327 sources = go_srcs,
328 deps = deps,
329 libpaths = transitive_go_library_paths,
330 out_object = out_object,
331 gc_goopts = gc_goopts,
332 )
333 _emit_go_pack_action(ctx, out_lib, [out_object] + extra_objects)
Alan Donovan312d1a52017-10-02 10:10:28 -0400334
alandonovanf935de82021-01-22 14:46:13 -0500335 dylibs = []
336 if cgo_object:
337 dylibs += [d for d in cgo_object.cgo_deps if d.path.endswith(".so")]
Alan Donovan312d1a52017-10-02 10:10:28 -0400338
alandonovanf935de82021-01-22 14:46:13 -0500339 runfiles = ctx.runfiles(files = dylibs, collect_data = True)
340 for d in dep_runfiles:
341 runfiles = runfiles.merge(d)
Alan Donovan312d1a52017-10-02 10:10:28 -0400342
alandonovanf935de82021-01-22 14:46:13 -0500343 return struct(
344 label = ctx.label,
345 files = depset([out_lib]),
346 runfiles = runfiles,
347 go_sources = go_srcs,
348 asm_sources = asm_srcs,
349 asm_headers = asm_hdrs,
350 cgo_object = cgo_object,
351 direct_deps = ctx.attr.deps,
352 transitive_cgo_deps = transitive_cgo_deps,
353 transitive_go_libraries = transitive_go_libraries,
354 transitive_go_library_paths = transitive_go_library_paths,
355 gc_goopts = gc_goopts,
356 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400357
alandonovanf935de82021-01-22 14:46:13 -0500358def _c_linker_options(ctx, blocklist = []):
359 """Extracts flags to pass to $(CC) on link from the current context
Alan Donovan312d1a52017-10-02 10:10:28 -0400360
alandonovanf935de82021-01-22 14:46:13 -0500361 Args:
362 ctx: the current context
363 blocklist: Any flags starts with any of these prefixes are filtered out from
364 the return value.
Alan Donovan312d1a52017-10-02 10:10:28 -0400365
alandonovanf935de82021-01-22 14:46:13 -0500366 Returns:
367 A list of command line flags
368 """
369 cpp = ctx.fragments.cpp
370 features = ctx.features
371 options = cpp.compiler_options(features)
372 options += cpp.unfiltered_compiler_options(features)
373 options += cpp.link_options
374 options += cpp.mostly_static_link_options(ctx.features, False)
375 filtered = []
376 for opt in options:
377 if any([opt.startswith(prefix) for prefix in blocklist]):
378 continue
379 filtered.append(opt)
380 return filtered
Alan Donovan312d1a52017-10-02 10:10:28 -0400381
382def _gc_goopts(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500383 gc_goopts = [
384 ctx.expand_make_variables("gc_goopts", f, {})
385 for f in ctx.attr.gc_goopts
386 ]
387 if ctx.attr.library:
388 gc_goopts += ctx.attr.library.gc_goopts
389 return gc_goopts
Alan Donovan312d1a52017-10-02 10:10:28 -0400390
391def _gc_linkopts(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500392 gc_linkopts = [
393 ctx.expand_make_variables("gc_linkopts", f, {})
394 for f in ctx.attr.gc_linkopts
395 ]
396 for k, v in ctx.attr.x_defs.items():
397 gc_linkopts += ["-X", "%s='%s'" % (k, v)]
398 return gc_linkopts
Alan Donovan312d1a52017-10-02 10:10:28 -0400399
400def _extract_extldflags(gc_linkopts, extldflags):
alandonovanf935de82021-01-22 14:46:13 -0500401 """Extracts -extldflags from gc_linkopts and combines them into a single list.
Alan Donovan312d1a52017-10-02 10:10:28 -0400402
alandonovanf935de82021-01-22 14:46:13 -0500403 Args:
404 gc_linkopts: a list of flags passed in through the gc_linkopts attributes.
405 ctx.expand_make_variables should have already been applied.
406 extldflags: a list of flags to be passed to the external linker.
Alan Donovan312d1a52017-10-02 10:10:28 -0400407
alandonovanf935de82021-01-22 14:46:13 -0500408 Return:
409 A tuple containing the filtered gc_linkopts with external flags removed,
410 and a combined list of external flags.
411 """
412 filtered_gc_linkopts = []
413 is_extldflags = False
414 for opt in gc_linkopts:
415 if is_extldflags:
416 is_extldflags = False
417 extldflags += [opt]
418 elif opt == "-extldflags":
419 is_extldflags = True
420 else:
421 filtered_gc_linkopts += [opt]
422 return filtered_gc_linkopts, extldflags
Alan Donovan312d1a52017-10-02 10:10:28 -0400423
alandonovanf935de82021-01-22 14:46:13 -0500424def _emit_go_link_action(
425 ctx,
426 transitive_go_library_paths,
427 transitive_go_libraries,
428 cgo_deps,
429 libs,
430 executable,
431 gc_linkopts):
432 """Sets up a symlink tree to libraries to link together."""
433 config_strip = len(ctx.configuration.bin_dir.path) + 1
434 pkg_depth = executable.dirname[config_strip:].count("/") + 1
Alan Donovan312d1a52017-10-02 10:10:28 -0400435
alandonovanf935de82021-01-22 14:46:13 -0500436 ld = "%s" % ctx.fragments.cpp.compiler_executable
437 extldflags = _c_linker_options(ctx) + [
438 "-Wl,-rpath,$ORIGIN/" + ("../" * pkg_depth),
439 ]
440 for d in cgo_deps:
441 if d.basename.endswith(".so"):
442 short_dir = d.dirname[len(d.root.path):]
443 extldflags += ["-Wl,-rpath,$ORIGIN/" + ("../" * pkg_depth) + short_dir]
444 gc_linkopts, extldflags = _extract_extldflags(gc_linkopts, extldflags)
Alan Donovan312d1a52017-10-02 10:10:28 -0400445
alandonovanf935de82021-01-22 14:46:13 -0500446 link_cmd = [
447 ctx.file.go_tool.path,
448 "tool",
449 "link",
450 "-L",
451 ".",
452 ]
453 for path in transitive_go_library_paths:
454 link_cmd += ["-L", path]
455 link_cmd += [
456 "-o",
457 executable.path,
458 ] + gc_linkopts + ['"${STAMP_XDEFS[@]}"']
Alan Donovan312d1a52017-10-02 10:10:28 -0400459
alandonovanf935de82021-01-22 14:46:13 -0500460 # workaround for a bug in ld(1) on Mac OS X.
461 # http://lists.apple.com/archives/Darwin-dev/2006/Sep/msg00084.html
462 # TODO(yugui) Remove this workaround once rules_go stops supporting XCode 7.2
463 # or earlier.
464 if not _is_darwin_cpu(ctx):
465 link_cmd += ["-s"]
Alan Donovan312d1a52017-10-02 10:10:28 -0400466
alandonovanf935de82021-01-22 14:46:13 -0500467 link_cmd += [
468 "-extld",
469 ld,
470 "-extldflags",
471 "'%s'" % " ".join(extldflags),
472 ] + [lib.path for lib in libs]
Alan Donovan312d1a52017-10-02 10:10:28 -0400473
alandonovanf935de82021-01-22 14:46:13 -0500474 # Avoided -s on OSX but but it requires dsymutil to be on $PATH.
475 # TODO(yugui) Remove this workaround once rules_go stops supporting XCode 7.2
476 # or earlier.
477 cmds = ["export PATH=$PATH:/usr/bin"]
Alan Donovan312d1a52017-10-02 10:10:28 -0400478
alandonovanf935de82021-01-22 14:46:13 -0500479 cmds += [
480 "STAMP_XDEFS=()",
481 ]
Alan Donovan312d1a52017-10-02 10:10:28 -0400482
alandonovanf935de82021-01-22 14:46:13 -0500483 stamp_inputs = []
484 if ctx.attr.linkstamp:
485 # read workspace status files, converting "KEY value" lines
486 # to "-X $linkstamp.KEY=value" arguments to the go linker.
487 stamp_inputs = [ctx.info_file, ctx.version_file]
488 for f in stamp_inputs:
489 cmds += [
490 "while read -r key value || [[ -n $key ]]; do",
491 " STAMP_XDEFS+=(-X \"%s.$key=$value\")" % ctx.attr.linkstamp,
492 "done < " + f.path,
493 ]
Alan Donovan312d1a52017-10-02 10:10:28 -0400494
alandonovanf935de82021-01-22 14:46:13 -0500495 cmds += [" ".join(link_cmd)]
Alan Donovan312d1a52017-10-02 10:10:28 -0400496
alandonovanf935de82021-01-22 14:46:13 -0500497 f = _emit_generate_params_action(cmds, ctx, lib.basename + ".GoLinkFile.params")
Alan Donovan312d1a52017-10-02 10:10:28 -0400498
alandonovanf935de82021-01-22 14:46:13 -0500499 ctx.action(
500 inputs = [f] + (list(transitive_go_libraries) + [lib] + list(cgo_deps) +
501 ctx.files.toolchain + ctx.files._crosstool) + stamp_inputs,
502 outputs = [executable],
503 command = f.path,
504 mnemonic = "GoLink",
505 env = go_environment_vars(ctx),
506 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400507
508def go_binary_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500509 """go_binary_impl emits actions for compiling and linking a go executable."""
510 lib_result = go_library_impl(ctx)
511 _emit_go_link_action(
512 ctx,
513 transitive_go_libraries = lib_result.transitive_go_libraries,
514 transitive_go_library_paths = lib_result.transitive_go_library_paths,
515 cgo_deps = lib_result.transitive_cgo_deps,
516 libs = lib_result.files,
517 executable = ctx.outputs.executable,
518 gc_linkopts = _gc_linkopts(ctx),
519 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400520
alandonovanf935de82021-01-22 14:46:13 -0500521 return struct(
522 files = depset([ctx.outputs.executable]),
523 runfiles = lib_result.runfiles,
524 cgo_object = lib_result.cgo_object,
525 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400526
527def go_test_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500528 """go_test_impl implements go testing.
Alan Donovan312d1a52017-10-02 10:10:28 -0400529
alandonovanf935de82021-01-22 14:46:13 -0500530 It emits an action to run the test generator, and then compiles the
531 test into a binary."""
Alan Donovan312d1a52017-10-02 10:10:28 -0400532
alandonovanf935de82021-01-22 14:46:13 -0500533 lib_result = go_library_impl(ctx)
534 main_go = ctx.new_file(ctx.label.name + "_main_test.go")
535 main_object = ctx.new_file(ctx.label.name + "_main_test.o")
536 main_lib = ctx.new_file(ctx.label.name + "_main_test.a")
537 go_import = _go_importpath(ctx)
Alan Donovan312d1a52017-10-02 10:10:28 -0400538
alandonovanf935de82021-01-22 14:46:13 -0500539 cmds = [
540 "UNFILTERED_TEST_FILES=(%s)" %
541 " ".join(["'%s'" % f.path for f in lib_result.go_sources]),
542 "FILTERED_TEST_FILES=()",
543 "while read -r line; do",
544 ' if [ -n "$line" ]; then',
545 ' FILTERED_TEST_FILES+=("$line")',
546 " fi",
547 'done < <(\'%s\' -cgo "${UNFILTERED_TEST_FILES[@]}")' %
548 ctx.executable._filter_tags.path,
549 " ".join([
550 "'%s'" % ctx.executable.test_generator.path,
551 "--package",
552 go_import,
553 "--output",
554 "'%s'" % main_go.path,
555 '"${FILTERED_TEST_FILES[@]}"',
556 ]),
557 ]
558 f = _emit_generate_params_action(
559 cmds,
560 ctx,
561 ctx.label.name + ".GoTestGenTest.params",
562 )
563 inputs = (list(lib_result.go_sources) + list(ctx.files.toolchain) +
564 [f, ctx.executable._filter_tags, ctx.executable.test_generator])
565 ctx.action(
566 inputs = inputs,
567 outputs = [main_go],
568 command = f.path,
569 mnemonic = "GoTestGenTest",
570 env = dict(go_environment_vars(ctx), RUNDIR = ctx.label.package),
571 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400572
alandonovanf935de82021-01-22 14:46:13 -0500573 _emit_go_compile_action(
574 ctx,
575 sources = depset([main_go]),
576 deps = ctx.attr.deps + [lib_result],
577 libpaths = lib_result.transitive_go_library_paths,
578 out_object = main_object,
579 gc_goopts = _gc_goopts(ctx),
580 )
581 _emit_go_pack_action(ctx, main_lib, [main_object])
582 _emit_go_link_action(
583 ctx,
584 transitive_go_library_paths = lib_result.transitive_go_library_paths,
585 transitive_go_libraries = lib_result.transitive_go_libraries,
586 cgo_deps = lib_result.transitive_cgo_deps,
587 libs = [main_lib],
588 executable = ctx.outputs.executable,
589 gc_linkopts = _gc_linkopts(ctx),
590 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400591
alandonovanf935de82021-01-22 14:46:13 -0500592 # TODO(bazel-team): the Go tests should do a chdir to the directory
593 # holding the data files, so open-source go tests continue to work
594 # without code changes.
595 runfiles = ctx.runfiles(files = [ctx.outputs.executable])
596 runfiles = runfiles.merge(lib_result.runfiles)
597 return struct(
598 files = depset([ctx.outputs.executable]),
599 runfiles = runfiles,
600 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400601
602go_env_attrs = {
603 "toolchain": attr.label(
604 default = Label("//go/toolchain:toolchain"),
605 allow_files = True,
606 cfg = "host",
607 ),
608 "go_tool": attr.label(
609 default = Label("//go/toolchain:go_tool"),
610 single_file = True,
611 allow_files = True,
612 cfg = "host",
613 ),
614 "go_prefix": attr.label(
615 providers = ["go_prefix"],
616 default = Label(
617 "//:go_prefix",
618 relative_to_caller_repository = True,
619 ),
620 allow_files = False,
621 cfg = "host",
622 ),
623 "go_src": attr.label(
624 default = Label("//go/toolchain:go_src"),
625 allow_files = True,
626 cfg = "host",
627 ),
628 "go_include": attr.label(
629 default = Label("//go/toolchain:go_include"),
630 single_file = True,
631 allow_files = True,
632 cfg = "host",
633 ),
634 "go_root": attr.label(
635 providers = ["go_root"],
636 default = Label(
637 "//go/toolchain:go_root",
638 ),
639 allow_files = False,
640 cfg = "host",
641 ),
642 "_filter_tags": attr.label(
643 default = Label("//go/tools/filter_tags"),
644 cfg = "host",
645 executable = True,
646 single_file = True,
647 ),
648 "_filter_exec": attr.label(
649 default = Label("//go/tools/filter_exec"),
650 cfg = "host",
651 executable = True,
652 single_file = True,
653 ),
654 "_asm": attr.label(
655 default = Label("//go/tools/builders:asm"),
656 cfg = "host",
657 executable = True,
658 single_file = True,
659 ),
660}
661
662go_library_attrs = go_env_attrs + {
663 "data": attr.label_list(
664 allow_files = True,
665 cfg = "data",
666 ),
667 "srcs": attr.label_list(allow_files = go_filetype),
668 "deps": attr.label_list(
669 providers = [
670 "transitive_go_library_paths",
671 "transitive_go_libraries",
672 "transitive_cgo_deps",
673 ],
674 ),
675 "importpath": attr.string(),
676 "library": attr.label(
677 providers = [
678 "direct_deps",
679 "go_sources",
680 "asm_sources",
681 "cgo_object",
682 "gc_goopts",
683 ],
684 ),
685 "gc_goopts": attr.string_list(),
686}
687
688_crosstool_attrs = {
689 "_crosstool": attr.label(
690 default = Label("//tools/defaults:crosstool"),
691 ),
692}
693
694go_link_attrs = go_library_attrs + _crosstool_attrs + {
695 "gc_linkopts": attr.string_list(),
696 "linkstamp": attr.string(),
697 "x_defs": attr.string_dict(),
698}
699
700go_library = rule(
701 go_library_impl,
702 attrs = go_library_attrs + {
703 "cgo_object": attr.label(
704 providers = [
705 "cgo_obj",
706 "cgo_deps",
707 ],
708 ),
709 },
710 fragments = ["cpp"],
711)
712
713go_binary = rule(
714 go_binary_impl,
715 attrs = go_library_attrs + _crosstool_attrs + go_link_attrs,
716 executable = True,
717 fragments = ["cpp"],
718)
719
720go_test = rule(
721 go_test_impl,
722 attrs = go_library_attrs + _crosstool_attrs + go_link_attrs + {
723 "test_generator": attr.label(
724 executable = True,
725 default = Label(
726 "//go/tools:generate_test_main",
727 ),
728 cfg = "host",
729 ),
730 },
731 executable = True,
732 fragments = ["cpp"],
733 test = True,
734)
735
736def _pkg_dir(workspace_root, package_name):
alandonovanf935de82021-01-22 14:46:13 -0500737 if workspace_root and package_name:
738 return workspace_root + "/" + package_name
739 if workspace_root:
740 return workspace_root
741 if package_name:
742 return package_name
743 return "."
Alan Donovan312d1a52017-10-02 10:10:28 -0400744
745def _exec_path(path):
alandonovanf935de82021-01-22 14:46:13 -0500746 if path.startswith("/"):
747 return path
748 return "${execroot}/" + path
Alan Donovan312d1a52017-10-02 10:10:28 -0400749
750def _cgo_filter_srcs_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500751 srcs = ctx.files.srcs
752 dsts = []
753 cmds = []
754 for src in srcs:
755 stem, _, ext = src.path.rpartition(".")
756 dst_basename = "%s.filtered.%s" % (stem, ext)
757 dst = ctx.new_file(src, dst_basename)
758 cmds += [
759 "if '%s' -cgo -quiet '%s'; then" %
Alan Donovan312d1a52017-10-02 10:10:28 -0400760 (ctx.executable._filter_tags.path, src.path),
alandonovanf935de82021-01-22 14:46:13 -0500761 " cp '%s' '%s'" % (src.path, dst.path),
762 "else",
763 " echo -n >'%s'" % dst.path,
764 "fi",
765 ]
766 dsts.append(dst)
Alan Donovan312d1a52017-10-02 10:10:28 -0400767
alandonovanf935de82021-01-22 14:46:13 -0500768 if ctx.label.package == "":
769 script_name = ctx.label.name + ".CGoFilterSrcs.params"
770 else:
771 script_name = ctx.label.package + "/" + ctx.label.name + ".CGoFilterSrcs.params"
772 f = _emit_generate_params_action(cmds, ctx, script_name)
773 ctx.action(
774 inputs = [f, ctx.executable._filter_tags] + srcs,
775 outputs = dsts,
776 command = f.path,
777 mnemonic = "CgoFilterSrcs",
778 )
779 return struct(
780 files = depset(dsts),
781 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400782
783_cgo_filter_srcs = rule(
784 implementation = _cgo_filter_srcs_impl,
785 attrs = {
786 "srcs": attr.label_list(
787 allow_files = cgo_filetype,
788 ),
789 "_filter_tags": attr.label(
790 default = Label("//go/tools/filter_tags"),
791 cfg = "host",
792 executable = True,
793 single_file = True,
794 ),
795 },
796 fragments = ["cpp"],
797)
798
799def _cgo_codegen_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500800 go_srcs = ctx.files.srcs
801 srcs = go_srcs + ctx.files.c_hdrs
802 linkopts = ctx.attr.linkopts
803 copts = ctx.fragments.cpp.c_options + ctx.attr.copts
804 deps = depset([], order = "topological")
805 for d in ctx.attr.deps:
806 srcs += list(d.cc.transitive_headers)
807 deps += d.cc.libs
808 copts += ["-D" + define for define in d.cc.defines]
809 for inc in d.cc.include_directories:
810 copts += ["-I", _exec_path(inc)]
811 for hdr in ctx.files.c_hdrs:
812 copts += ["-iquote", hdr.dirname]
813 for inc in d.cc.quote_include_directories:
814 copts += ["-iquote", _exec_path(inc)]
815 for inc in d.cc.system_include_directories:
816 copts += ["-isystem", _exec_path(inc)]
817 for lib in d.cc.libs:
818 if lib.basename.startswith("lib") and lib.basename.endswith(".so"):
819 linkopts += ["-L", lib.dirname, "-l", lib.basename[3:-3]]
820 else:
821 linkopts += [lib.path]
822 linkopts += d.cc.link_flags
Alan Donovan312d1a52017-10-02 10:10:28 -0400823
alandonovanf935de82021-01-22 14:46:13 -0500824 p = _pkg_dir(ctx.label.workspace_root, ctx.label.package) + "/"
825 if p == "./":
826 p = "" # workaround when cgo_library in repository root
827 out_dir = (ctx.configuration.genfiles_dir.path + "/" +
828 p + ctx.attr.outdir)
829 cc = ctx.fragments.cpp.compiler_executable
830 cmds = [
831 # We cannot use env for CC because $(CC) on OSX is relative
832 # and '../' does not work fine due to symlinks.
833 "export CC=$(cd $(dirname {cc}); pwd)/$(basename {cc})".format(cc = cc),
834 "export CXX=$CC",
835 'objdir="%s/gen"' % out_dir,
836 "execroot=$(pwd)",
837 'mkdir -p "$objdir"',
838 "unfiltered_go_files=(%s)" % " ".join(["'%s'" % f.path for f in go_srcs]),
839 "filtered_go_files=()",
840 'for file in "${unfiltered_go_files[@]}"; do',
841 ' stem=$(basename "$file" .go)',
842 ' if %s -cgo -quiet "$file"; then' % ctx.executable._filter_tags.path,
843 ' filtered_go_files+=("$file")',
844 " else",
845 ' grep --max-count 1 "^package " "$file" >"$objdir/$stem.go"',
846 ' echo -n >"$objdir/$stem.c"',
847 " fi",
848 "done",
849 "if [ ${#filtered_go_files[@]} -eq 0 ]; then",
850 " echo no buildable Go source files in %s >&1" % str(ctx.label),
851 " exit 1",
852 "fi",
853 '"$GOROOT/bin/go" tool cgo -objdir "$objdir" -- %s "${filtered_go_files[@]}"' %
854 " ".join(['"%s"' % copt for copt in copts]),
855 # Rename the outputs using glob so we don't have to understand cgo's mangling
856 # TODO(#350): might be fixed by this?.
857 'for file in "${filtered_go_files[@]}"; do',
858 ' stem=$(basename "$file" .go)',
859 ' mv "$objdir/"*"$stem.cgo1.go" "$objdir/$stem.go"',
860 ' mv "$objdir/"*"$stem.cgo2.c" "$objdir/$stem.c"',
861 "done",
862 "rm -f $objdir/_cgo_.o $objdir/_cgo_flags",
Alan Donovan312d1a52017-10-02 10:10:28 -0400863 ]
864
alandonovanf935de82021-01-22 14:46:13 -0500865 f = _emit_generate_params_action(cmds, ctx, out_dir + ".CGoCodeGenFile.params")
Alan Donovan312d1a52017-10-02 10:10:28 -0400866
alandonovanf935de82021-01-22 14:46:13 -0500867 inputs = (srcs + ctx.files.toolchain + ctx.files._crosstool +
868 [f, ctx.executable._filter_tags])
869 ctx.action(
870 inputs = inputs,
871 outputs = ctx.outputs.outs,
872 mnemonic = "CGoCodeGen",
873 progress_message = "CGoCodeGen %s" % ctx.label,
874 command = f.path,
875 env = go_environment_vars(ctx) + {
876 "CGO_LDFLAGS": " ".join(linkopts),
877 },
878 )
879 return struct(
880 label = ctx.label,
881 files = depset(ctx.outputs.outs),
882 cgo_deps = deps,
883 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400884
885_cgo_codegen_rule = rule(
886 _cgo_codegen_impl,
887 attrs = go_env_attrs + _crosstool_attrs + {
888 "srcs": attr.label_list(
889 allow_files = go_filetype,
890 non_empty = True,
891 ),
892 "c_hdrs": attr.label_list(
893 allow_files = cc_hdr_filetype,
894 ),
895 "deps": attr.label_list(
896 allow_files = False,
897 providers = ["cc"],
898 ),
899 "copts": attr.string_list(),
900 "linkopts": attr.string_list(),
901 "outdir": attr.string(mandatory = True),
902 "outs": attr.output_list(
903 mandatory = True,
904 non_empty = True,
905 ),
906 },
907 fragments = ["cpp"],
908 output_to_genfiles = True,
909)
910
alandonovanf935de82021-01-22 14:46:13 -0500911def _cgo_codegen(
912 name,
913 srcs,
914 c_hdrs = [],
915 deps = [],
916 copts = [],
917 linkopts = [],
918 go_tool = None,
919 toolchain = None):
920 """Generates glue codes for interop between C and Go
Alan Donovan312d1a52017-10-02 10:10:28 -0400921
alandonovanf935de82021-01-22 14:46:13 -0500922 Args:
923 name: A unique name of the rule
924 srcs: list of Go source files.
925 Each of them must contain `import "C"`.
926 c_hdrs: C/C++ header files necessary to determine kinds of
927 C/C++ identifiers in srcs.
928 deps: A list of cc_library rules.
929 The generated codes are expected to be linked with these deps.
930 linkopts: A list of linker options,
931 These flags are passed to the linker when the generated codes
932 are linked into the target binary.
933 """
934 outdir = name + ".dir"
935 outgen = outdir + "/gen"
Alan Donovan312d1a52017-10-02 10:10:28 -0400936
alandonovanf935de82021-01-22 14:46:13 -0500937 go_thunks = []
938 c_thunks = []
939 for s in srcs:
940 if not s.endswith(".go"):
941 fail("not a .go file: %s" % s)
942 basename = s[:-3]
943 if basename.rfind("/") >= 0:
944 basename = basename[basename.rfind("/") + 1:]
945 go_thunks.append(outgen + "/" + basename + ".go")
946 c_thunks.append(outgen + "/" + basename + ".c")
Alan Donovan312d1a52017-10-02 10:10:28 -0400947
alandonovanf935de82021-01-22 14:46:13 -0500948 outs = struct(
949 name = name,
950 outdir = outgen,
951 go_thunks = go_thunks,
952 c_thunks = c_thunks,
953 c_exports = [
954 outgen + "/_cgo_export.c",
955 outgen + "/_cgo_export.h",
956 ],
957 c_dummy = outgen + "/_cgo_main.c",
958 gotypes = outgen + "/_cgo_gotypes.go",
959 )
Alan Donovan312d1a52017-10-02 10:10:28 -0400960
alandonovanf935de82021-01-22 14:46:13 -0500961 _cgo_codegen_rule(
962 name = name,
963 srcs = srcs,
964 c_hdrs = c_hdrs,
965 deps = deps,
966 copts = copts,
967 linkopts = linkopts,
968 go_tool = go_tool,
969 toolchain = toolchain,
970 outdir = outdir,
971 outs = outs.go_thunks + outs.c_thunks + outs.c_exports + [
972 outs.c_dummy,
973 outs.gotypes,
974 ],
975 visibility = ["//visibility:private"],
976 )
977 return outs
Alan Donovan312d1a52017-10-02 10:10:28 -0400978
979def _cgo_import_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -0500980 cmds = [
981 (ctx.file.go_tool.path + " tool cgo" +
982 " -dynout " + ctx.outputs.out.path +
983 " -dynimport " + ctx.file.cgo_o.path +
984 " -dynpackage $(%s %s)" % (
985 ctx.executable._extract_package.path,
986 ctx.file.sample_go_src.path,
987 )),
988 ]
989 f = _emit_generate_params_action(cmds, ctx, ctx.outputs.out.path + ".CGoImportGenFile.params")
990 ctx.action(
991 inputs = (ctx.files.toolchain +
992 [
993 f,
994 ctx.file.go_tool,
995 ctx.executable._extract_package,
996 ctx.file.cgo_o,
997 ctx.file.sample_go_src,
998 ]),
999 outputs = [ctx.outputs.out],
1000 command = f.path,
1001 mnemonic = "CGoImportGen",
1002 env = go_environment_vars(ctx),
1003 )
1004 return struct(
1005 files = depset([ctx.outputs.out]),
1006 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001007
1008_cgo_import = rule(
1009 _cgo_import_impl,
1010 attrs = go_env_attrs + {
1011 "cgo_o": attr.label(
1012 allow_files = True,
1013 single_file = True,
1014 ),
1015 "sample_go_src": attr.label(
1016 allow_files = True,
1017 single_file = True,
1018 ),
1019 "out": attr.output(
1020 mandatory = True,
1021 ),
1022 "_extract_package": attr.label(
1023 default = Label("//go/tools/extract_package"),
1024 executable = True,
1025 cfg = "host",
1026 ),
1027 },
1028 fragments = ["cpp"],
1029)
1030
1031def _cgo_genrule_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -05001032 return struct(
1033 label = ctx.label,
1034 go_sources = ctx.files.srcs,
1035 asm_sources = [],
1036 asm_headers = [],
1037 cgo_object = ctx.attr.cgo_object,
1038 direct_deps = ctx.attr.deps,
1039 gc_goopts = [],
1040 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001041
1042_cgo_genrule = rule(
1043 _cgo_genrule_impl,
1044 attrs = {
1045 "srcs": attr.label_list(allow_files = FileType([".go"])),
1046 "cgo_object": attr.label(
1047 providers = [
1048 "cgo_obj",
1049 "cgo_deps",
1050 ],
1051 ),
1052 "deps": attr.label_list(
1053 providers = [
1054 "direct_deps",
1055 "transitive_go_library_paths",
1056 "transitive_go_libraries",
1057 "transitive_cgo_deps",
1058 ],
1059 ),
1060 },
1061 fragments = ["cpp"],
1062)
1063
1064"""Generates symbol-import directives for cgo
1065
1066Args:
1067 cgo_o: The loadable object to extract dynamic symbols from.
1068 sample_go_src: A go source which is compiled together with the generated file.
1069 The generated file will have the same Go package name as this file.
1070 out: Destination of the generated codes.
1071"""
1072
1073def _cgo_object_impl(ctx):
alandonovanf935de82021-01-22 14:46:13 -05001074 arguments = _c_linker_options(ctx, blocklist = [
1075 # never link any dependency libraries
1076 "-l",
1077 "-L",
1078 # manage flags to ld(1) by ourselves
1079 "-Wl,",
1080 ])
1081 arguments += [
1082 "-o",
1083 ctx.outputs.out.path,
1084 "-nostdlib",
1085 "-Wl,-r",
1086 ]
1087 if _is_darwin_cpu(ctx):
1088 arguments += ["-shared", "-Wl,-all_load"]
1089 else:
1090 arguments += ["-Wl,-whole-archive"]
Alan Donovan312d1a52017-10-02 10:10:28 -04001091
alandonovanf935de82021-01-22 14:46:13 -05001092 lo = ctx.files.src[-1]
1093 arguments += [lo.path]
Alan Donovan312d1a52017-10-02 10:10:28 -04001094
alandonovanf935de82021-01-22 14:46:13 -05001095 ctx.action(
1096 inputs = [lo] + ctx.files._crosstool,
1097 outputs = [ctx.outputs.out],
1098 mnemonic = "CGoObject",
1099 progress_message = "Linking %s" % ctx.outputs.out.short_path,
1100 executable = ctx.fragments.cpp.compiler_executable,
1101 arguments = arguments,
1102 )
1103 runfiles = ctx.runfiles(collect_data = True)
1104 runfiles = runfiles.merge(ctx.attr.src.data_runfiles)
1105 return struct(
1106 files = depset([ctx.outputs.out]),
1107 cgo_obj = ctx.outputs.out,
1108 cgo_deps = ctx.attr.cgogen.cgo_deps,
1109 runfiles = runfiles,
1110 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001111
1112_cgo_object = rule(
1113 _cgo_object_impl,
1114 attrs = _crosstool_attrs + {
1115 "src": attr.label(
1116 mandatory = True,
1117 providers = ["cc"],
1118 ),
1119 "cgogen": attr.label(
1120 mandatory = True,
1121 providers = ["cgo_deps"],
1122 ),
1123 "out": attr.output(
1124 mandatory = True,
1125 ),
1126 },
1127 fragments = ["cpp"],
1128)
1129
1130"""Generates _all.o to be archived together with Go objects.
1131
1132Args:
1133 src: source static library which contains objects
1134 cgogen: _cgo_codegen rule which knows the dependency cc_library() rules
1135 to be linked together with src when we generate the final go binary.
1136"""
1137
1138def _setup_cgo_library(name, srcs, cdeps, copts, clinkopts, go_tool, toolchain):
alandonovanf935de82021-01-22 14:46:13 -05001139 go_srcs = [s for s in srcs if s.endswith(".go")]
1140 c_hdrs = [s for s in srcs if any([s.endswith(ext) for ext in hdr_exts])]
1141 c_srcs = [s for s in srcs if not s in (go_srcs + c_hdrs)]
Alan Donovan312d1a52017-10-02 10:10:28 -04001142
alandonovanf935de82021-01-22 14:46:13 -05001143 # Split cgo files into .go parts and .c parts (plus some other files).
1144 cgogen = _cgo_codegen(
1145 name = name + ".cgo",
1146 srcs = go_srcs,
1147 c_hdrs = c_hdrs,
1148 deps = cdeps,
1149 copts = copts,
1150 linkopts = clinkopts,
1151 go_tool = go_tool,
1152 toolchain = toolchain,
Alan Donovan312d1a52017-10-02 10:10:28 -04001153 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001154
alandonovanf935de82021-01-22 14:46:13 -05001155 # Filter c_srcs with build constraints.
1156 c_filtered_srcs = []
1157 if len(c_srcs) > 0:
1158 c_filtered_srcs_name = name + "_filter_cgo_srcs"
1159 _cgo_filter_srcs(
1160 name = c_filtered_srcs_name,
1161 srcs = c_srcs,
1162 )
1163 c_filtered_srcs.append(":" + c_filtered_srcs_name)
Alan Donovan312d1a52017-10-02 10:10:28 -04001164
alandonovanf935de82021-01-22 14:46:13 -05001165 pkg_dir = _pkg_dir(
1166 "external/" + REPOSITORY_NAME[1:] if len(REPOSITORY_NAME) > 1 else "",
1167 PACKAGE_NAME,
1168 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001169
alandonovanf935de82021-01-22 14:46:13 -05001170 # Platform-specific settings
1171 native.config_setting(
1172 name = name + "_windows_setting",
1173 values = {
1174 "cpu": "x64_windows_msvc",
1175 },
1176 )
1177 platform_copts = select({
1178 ":" + name + "_windows_setting": ["-mthreads"],
1179 "//conditions:default": ["-pthread"],
1180 })
1181 platform_linkopts = select({
1182 ":" + name + "_windows_setting": ["-mthreads"],
1183 "//conditions:default": ["-pthread"],
1184 })
Alan Donovan312d1a52017-10-02 10:10:28 -04001185
alandonovanf935de82021-01-22 14:46:13 -05001186 # Bundles objects into an archive so that _cgo_.o and _all.o can share them.
1187 native.cc_library(
1188 name = cgogen.outdir + "/_cgo_lib",
1189 srcs = cgogen.c_thunks + cgogen.c_exports + c_filtered_srcs + c_hdrs,
1190 deps = cdeps,
1191 copts = copts + platform_copts + [
1192 "-I",
1193 pkg_dir,
1194 "-I",
1195 "$(GENDIR)/" + pkg_dir + "/" + cgogen.outdir,
1196 # The generated thunks often contain unused variables.
1197 "-Wno-unused-variable",
1198 ],
1199 linkopts = clinkopts + platform_linkopts,
1200 linkstatic = 1,
1201 # _cgo_.o and _all.o keep all objects in this archive.
1202 # But it should not be very annoying in the final binary target
1203 # because _cgo_object rule does not propagate alwayslink=1
1204 alwayslink = 1,
1205 visibility = ["//visibility:private"],
1206 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001207
alandonovanf935de82021-01-22 14:46:13 -05001208 # Loadable object which cgo reads when it generates _cgo_import.go
1209 native.cc_binary(
1210 name = cgogen.outdir + "/_cgo_.o",
1211 srcs = [cgogen.c_dummy],
1212 deps = cdeps + [cgogen.outdir + "/_cgo_lib"],
1213 copts = copts,
1214 linkopts = clinkopts,
1215 visibility = ["//visibility:private"],
1216 )
1217 _cgo_import(
1218 name = "%s.cgo.importgen" % name,
1219 cgo_o = cgogen.outdir + "/_cgo_.o",
1220 out = cgogen.outdir + "/_cgo_import.go",
1221 sample_go_src = go_srcs[0],
1222 go_tool = go_tool,
1223 toolchain = toolchain,
1224 visibility = ["//visibility:private"],
1225 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001226
alandonovanf935de82021-01-22 14:46:13 -05001227 _cgo_object(
1228 name = cgogen.outdir + "/_cgo_object",
1229 src = cgogen.outdir + "/_cgo_lib",
1230 out = cgogen.outdir + "/_all.o",
1231 cgogen = cgogen.name,
1232 visibility = ["//visibility:private"],
1233 )
1234 return cgogen
Alan Donovan312d1a52017-10-02 10:10:28 -04001235
alandonovanf935de82021-01-22 14:46:13 -05001236def cgo_genrule(
1237 name,
1238 srcs,
1239 copts = [],
1240 clinkopts = [],
1241 cdeps = [],
1242 **kwargs):
1243 cgogen = _setup_cgo_library(
1244 name = name,
1245 srcs = srcs,
1246 cdeps = cdeps,
1247 copts = copts,
1248 clinkopts = clinkopts,
1249 toolchain = None,
1250 go_tool = None,
1251 )
1252 _cgo_genrule(
1253 name = name,
1254 srcs = cgogen.go_thunks + [
1255 cgogen.gotypes,
1256 cgogen.outdir + "/_cgo_import.go",
1257 ],
1258 cgo_object = cgogen.outdir + "/_cgo_object",
1259 **kwargs
1260 )
Alan Donovan312d1a52017-10-02 10:10:28 -04001261
alandonovanf935de82021-01-22 14:46:13 -05001262def cgo_library(
1263 name,
1264 srcs,
1265 toolchain = None,
1266 go_tool = None,
1267 copts = [],
1268 clinkopts = [],
1269 cdeps = [],
1270 **kwargs):
1271 """Builds a cgo-enabled go library.
Alan Donovan312d1a52017-10-02 10:10:28 -04001272
alandonovanf935de82021-01-22 14:46:13 -05001273 Args:
1274 name: A unique name for this rule.
1275 srcs: List of Go, C and C++ files that are processed to build a Go library.
1276 Those Go files must contain `import "C"`.
1277 C and C++ files can be anything allowed in `srcs` attribute of
1278 `cc_library`.
1279 copts: Add these flags to the C++ compiler.
1280 clinkopts: Add these flags to the C++ linker.
1281 cdeps: List of C/C++ libraries to be linked into the binary target.
1282 They must be `cc_library` rules.
1283 deps: List of other libraries to be linked to this library target.
1284 data: List of files needed by this rule at runtime.
Alan Donovan312d1a52017-10-02 10:10:28 -04001285
alandonovanf935de82021-01-22 14:46:13 -05001286 NOTE:
1287 `srcs` cannot contain pure-Go files, which do not have `import "C"`.
1288 So you need to define another `go_library` when you build a go package with
1289 both cgo-enabled and pure-Go sources.
1290
1291 ```
1292 cgo_library(
1293 name = "cgo_enabled",
1294 srcs = ["cgo-enabled.go", "foo.cc", "bar.S", "baz.a"],
1295 )
1296
1297 go_library(
1298 name = "go_default_library",
1299 srcs = ["pure-go.go"],
1300 library = ":cgo_enabled",
1301 )
1302 ```
1303 """
1304 cgogen = _setup_cgo_library(
1305 name = name,
1306 srcs = srcs,
1307 cdeps = cdeps,
1308 copts = copts,
1309 clinkopts = clinkopts,
1310 go_tool = go_tool,
1311 toolchain = toolchain,
Alan Donovan312d1a52017-10-02 10:10:28 -04001312 )
1313
1314 go_library(
alandonovanf935de82021-01-22 14:46:13 -05001315 name = name,
1316 srcs = cgogen.go_thunks + [
1317 cgogen.gotypes,
1318 cgogen.outdir + "/_cgo_import.go",
1319 ],
1320 cgo_object = cgogen.outdir + "/_cgo_object",
1321 go_tool = go_tool,
1322 toolchain = toolchain,
1323 **kwargs
Alan Donovan312d1a52017-10-02 10:10:28 -04001324 )