You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1325 lines
40 KiB
1325 lines
40 KiB
# Copyright 2014 The Bazel Authors. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# (From https://github.com/bazelbuild/rules_go/blob/master/go/def.bzl@a6f9d0c)
|
|
|
|
load("//go/private:repositories.bzl", "go_repositories")
|
|
load("//go/private:go_repository.bzl", "go_repository", "new_go_repository")
|
|
load("//go/private:go_prefix.bzl", "go_prefix")
|
|
load("//go/private:json.bzl", "json_marshal")
|
|
|
|
"""These are bare-bones Go rules.
|
|
|
|
In order of priority:
|
|
|
|
- BUILD file must be written by hand.
|
|
|
|
- No support for SWIG
|
|
|
|
- No test sharding or test XML.
|
|
|
|
"""
|
|
|
|
_DEFAULT_LIB = "go_default_library"
|
|
|
|
_VENDOR_PREFIX = "/vendor/"
|
|
|
|
go_filetype = FileType([
|
|
".go",
|
|
".s",
|
|
".S",
|
|
".h", # may be included by .s
|
|
])
|
|
|
|
# be consistent to cc_library.
|
|
hdr_exts = [
|
|
".h",
|
|
".hh",
|
|
".hpp",
|
|
".hxx",
|
|
".inc",
|
|
]
|
|
|
|
cc_hdr_filetype = FileType(hdr_exts)
|
|
|
|
# Extensions of files we can build with the Go compiler or with cc_library.
|
|
# This is a subset of the extensions recognized by go/build.
|
|
cgo_filetype = FileType([
|
|
".go",
|
|
".c",
|
|
".cc",
|
|
".cxx",
|
|
".cpp",
|
|
".s",
|
|
".S",
|
|
".h",
|
|
".hh",
|
|
".hpp",
|
|
".hxx",
|
|
])
|
|
|
|
################
|
|
|
|
def go_environment_vars(ctx):
|
|
"""Return a map of environment variables for use with actions, based on
|
|
the arguments. Uses the ctx.fragments.cpp.cpu attribute, if present,
|
|
and picks a default of target_os="linux" and target_arch="amd64"
|
|
otherwise.
|
|
|
|
Args:
|
|
The starlark Context.
|
|
|
|
Returns:
|
|
A dict of environment variables for running Go tool commands that build for
|
|
the target OS and architecture.
|
|
"""
|
|
default_toolchain = {"GOOS": "linux", "GOARCH": "amd64"}
|
|
bazel_to_go_toolchain = {
|
|
"k8": {"GOOS": "linux", "GOARCH": "amd64"},
|
|
"piii": {"GOOS": "linux", "GOARCH": "386"},
|
|
"darwin": {"GOOS": "darwin", "GOARCH": "amd64"},
|
|
"darwin_x86_64": {"GOOS": "darwin", "GOARCH": "amd64"},
|
|
"freebsd": {"GOOS": "freebsd", "GOARCH": "amd64"},
|
|
"armeabi-v7a": {"GOOS": "linux", "GOARCH": "arm"},
|
|
"arm": {"GOOS": "linux", "GOARCH": "arm"},
|
|
}
|
|
env = {}
|
|
if hasattr(ctx.file, "go_tool"):
|
|
env["GOROOT"] = ctx.file.go_tool.dirname + "/.."
|
|
env.update(bazel_to_go_toolchain.get(ctx.fragments.cpp.cpu, default_toolchain))
|
|
return env
|
|
|
|
def _is_darwin_cpu(ctx):
|
|
cpu = ctx.fragments.cpp.cpu
|
|
return cpu == "darwin" or cpu == "darwin_x86_64"
|
|
|
|
def _emit_generate_params_action(cmds, ctx, fn):
|
|
cmds_all = [
|
|
# Use bash explicitly. /bin/sh is default, and it may be linked to a
|
|
# different shell, e.g., /bin/dash on Ubuntu.
|
|
"#!/bin/bash",
|
|
"set -e",
|
|
]
|
|
cmds_all += cmds
|
|
cmds_all_str = "\n".join(cmds_all) + "\n"
|
|
f = ctx.new_file(ctx.configuration.bin_dir, fn)
|
|
ctx.file_action(
|
|
output = f,
|
|
content = cmds_all_str,
|
|
executable = True,
|
|
)
|
|
return f
|
|
|
|
def _emit_go_asm_action(ctx, source, hdrs, out_obj):
|
|
"""Construct the command line for compiling Go Assembly code.
|
|
Constructs a symlink tree to accomodate for workspace name.
|
|
Args:
|
|
ctx: The starlark Context.
|
|
source: a source code artifact
|
|
hdrs: list of .h files that may be included
|
|
out_obj: the artifact (configured target?) that should be produced
|
|
"""
|
|
params = {
|
|
"go_tool": ctx.file.go_tool.path,
|
|
"includes": [f.dirname for f in hdrs] + [ctx.file.go_include.path],
|
|
"source": source.path,
|
|
"out": out_obj.path,
|
|
}
|
|
|
|
inputs = hdrs + ctx.files.toolchain + [source]
|
|
ctx.action(
|
|
inputs = inputs,
|
|
outputs = [out_obj],
|
|
mnemonic = "GoAsmCompile",
|
|
executable = ctx.executable._asm,
|
|
arguments = [json_marshal(params)],
|
|
)
|
|
|
|
def _go_importpath(ctx):
|
|
"""Returns the expected importpath of the go_library being built.
|
|
|
|
Args:
|
|
ctx: The starlark Context
|
|
|
|
Returns:
|
|
Go importpath of the library
|
|
"""
|
|
path = ctx.attr.importpath
|
|
if path != "":
|
|
return path
|
|
path = ctx.attr.go_prefix.go_prefix
|
|
if path.endswith("/"):
|
|
path = path[:-1]
|
|
if ctx.label.package:
|
|
path += "/" + ctx.label.package
|
|
if ctx.label.name != _DEFAULT_LIB:
|
|
path += "/" + ctx.label.name
|
|
if path.rfind(_VENDOR_PREFIX) != -1:
|
|
path = path[len(_VENDOR_PREFIX) + path.rfind(_VENDOR_PREFIX):]
|
|
if path[0] == "/":
|
|
path = path[1:]
|
|
return path
|
|
|
|
def _emit_go_compile_action(ctx, sources, deps, libpaths, out_object, gc_goopts):
|
|
"""Construct the command line for compiling Go code.
|
|
|
|
Args:
|
|
ctx: The starlark Context.
|
|
sources: an iterable of source code artifacts (or CTs? or labels?)
|
|
deps: an iterable of dependencies. Each dependency d should have an
|
|
artifact in d.transitive_go_libraries representing all imported libraries.
|
|
libpaths: the set of paths to search for imported libraries.
|
|
out_object: the object file that should be produced
|
|
gc_goopts: additional flags to pass to the compiler.
|
|
"""
|
|
if ctx.coverage_instrumented():
|
|
sources = _emit_go_cover_action(ctx, sources)
|
|
|
|
# Compile filtered files.
|
|
args = [
|
|
"-cgo",
|
|
ctx.file.go_tool.path,
|
|
"tool",
|
|
"compile",
|
|
"-o",
|
|
out_object.path,
|
|
"-trimpath",
|
|
"-abs-.",
|
|
"-I",
|
|
"-abs-.",
|
|
]
|
|
inputs = depset(sources + ctx.files.toolchain)
|
|
for dep in deps:
|
|
inputs += dep.transitive_go_libraries
|
|
for path in libpaths:
|
|
args += ["-I", path]
|
|
args += gc_goopts + [("" if i.basename.startswith("_cgo") else "-filter-") + i.path for i in sources]
|
|
ctx.action(
|
|
inputs = list(inputs),
|
|
outputs = [out_object],
|
|
mnemonic = "GoCompile",
|
|
executable = ctx.executable._filter_exec,
|
|
arguments = args,
|
|
env = go_environment_vars(ctx),
|
|
)
|
|
|
|
return sources
|
|
|
|
def _emit_go_pack_action(ctx, out_lib, objects):
|
|
"""Construct the command line for packing objects together.
|
|
|
|
Args:
|
|
ctx: The starlark Context.
|
|
out_lib: the archive that should be produced
|
|
objects: an iterable of object files to be added to the output archive file.
|
|
"""
|
|
ctx.action(
|
|
inputs = objects + ctx.files.toolchain,
|
|
outputs = [out_lib],
|
|
mnemonic = "GoPack",
|
|
executable = ctx.file.go_tool,
|
|
arguments = ["tool", "pack", "c", out_lib.path] + [a.path for a in objects],
|
|
env = go_environment_vars(ctx),
|
|
)
|
|
|
|
def _emit_go_cover_action(ctx, sources):
|
|
"""Construct the command line for test coverage instrument.
|
|
|
|
Args:
|
|
ctx: The starlark Context.
|
|
sources: an iterable of Go source files.
|
|
|
|
Returns:
|
|
A list of Go source code files which might be coverage instrumented.
|
|
"""
|
|
outputs = []
|
|
|
|
# TODO(linuxerwang): make the mode configurable.
|
|
count = 0
|
|
|
|
for src in sources:
|
|
if not src.path.endswith(".go") or src.path.endswith("_test.go"):
|
|
outputs += [src]
|
|
continue
|
|
|
|
cover_var = "GoCover_%d" % count
|
|
out = ctx.new_file(src, src.basename[:-3] + "_" + cover_var + ".cover.go")
|
|
outputs += [out]
|
|
ctx.action(
|
|
inputs = [src] + ctx.files.toolchain,
|
|
outputs = [out],
|
|
mnemonic = "GoCover",
|
|
executable = ctx.file.go_tool,
|
|
arguments = ["tool", "cover", "--mode=set", "-var=%s" % cover_var, "-o", out.path, src.path],
|
|
env = go_environment_vars(ctx),
|
|
)
|
|
count += 1
|
|
|
|
return outputs
|
|
|
|
def go_library_impl(ctx):
|
|
"""Implements the go_library() rule."""
|
|
|
|
sources = depset(ctx.files.srcs)
|
|
go_srcs = depset([s for s in sources if s.basename.endswith(".go")])
|
|
asm_srcs = [s for s in sources if s.basename.endswith(".s") or s.basename.endswith(".S")]
|
|
asm_hdrs = [s for s in sources if s.basename.endswith(".h")]
|
|
deps = ctx.attr.deps
|
|
dep_runfiles = [d.data_runfiles for d in deps]
|
|
|
|
cgo_object = None
|
|
if hasattr(ctx.attr, "cgo_object"):
|
|
cgo_object = ctx.attr.cgo_object
|
|
|
|
if ctx.attr.library:
|
|
go_srcs += ctx.attr.library.go_sources
|
|
asm_srcs += ctx.attr.library.asm_sources
|
|
asm_hdrs += ctx.attr.library.asm_headers
|
|
deps += ctx.attr.library.direct_deps
|
|
dep_runfiles += [ctx.attr.library.data_runfiles]
|
|
if ctx.attr.library.cgo_object:
|
|
if cgo_object:
|
|
fail("go_library %s cannot have cgo_object because the package " +
|
|
"already has cgo_object in %s" % (
|
|
ctx.label.name,
|
|
ctx.attr.library.name,
|
|
))
|
|
cgo_object = ctx.attr.library.cgo_object
|
|
if not go_srcs:
|
|
fail("may not be empty", "srcs")
|
|
|
|
transitive_cgo_deps = depset([], order = "topological")
|
|
if cgo_object:
|
|
dep_runfiles += [cgo_object.data_runfiles]
|
|
transitive_cgo_deps += cgo_object.cgo_deps
|
|
|
|
extra_objects = [cgo_object.cgo_obj] if cgo_object else []
|
|
for src in asm_srcs:
|
|
obj = ctx.new_file(src, "%s.dir/%s.o" % (ctx.label.name, src.basename[:-2]))
|
|
_emit_go_asm_action(ctx, src, asm_hdrs, obj)
|
|
extra_objects += [obj]
|
|
|
|
lib_name = _go_importpath(ctx) + ".a"
|
|
out_lib = ctx.new_file(lib_name)
|
|
out_object = ctx.new_file(ctx.label.name + ".o")
|
|
search_path = out_lib.path[:-len(lib_name)]
|
|
gc_goopts = _gc_goopts(ctx)
|
|
transitive_go_libraries = depset([out_lib])
|
|
transitive_go_library_paths = depset([search_path])
|
|
for dep in deps:
|
|
transitive_go_libraries += dep.transitive_go_libraries
|
|
transitive_cgo_deps += dep.transitive_cgo_deps
|
|
transitive_go_library_paths += dep.transitive_go_library_paths
|
|
|
|
go_srcs = _emit_go_compile_action(
|
|
ctx,
|
|
sources = go_srcs,
|
|
deps = deps,
|
|
libpaths = transitive_go_library_paths,
|
|
out_object = out_object,
|
|
gc_goopts = gc_goopts,
|
|
)
|
|
_emit_go_pack_action(ctx, out_lib, [out_object] + extra_objects)
|
|
|
|
dylibs = []
|
|
if cgo_object:
|
|
dylibs += [d for d in cgo_object.cgo_deps if d.path.endswith(".so")]
|
|
|
|
runfiles = ctx.runfiles(files = dylibs, collect_data = True)
|
|
for d in dep_runfiles:
|
|
runfiles = runfiles.merge(d)
|
|
|
|
return struct(
|
|
label = ctx.label,
|
|
files = depset([out_lib]),
|
|
runfiles = runfiles,
|
|
go_sources = go_srcs,
|
|
asm_sources = asm_srcs,
|
|
asm_headers = asm_hdrs,
|
|
cgo_object = cgo_object,
|
|
direct_deps = ctx.attr.deps,
|
|
transitive_cgo_deps = transitive_cgo_deps,
|
|
transitive_go_libraries = transitive_go_libraries,
|
|
transitive_go_library_paths = transitive_go_library_paths,
|
|
gc_goopts = gc_goopts,
|
|
)
|
|
|
|
def _c_linker_options(ctx, blocklist = []):
|
|
"""Extracts flags to pass to $(CC) on link from the current context
|
|
|
|
Args:
|
|
ctx: the current context
|
|
blocklist: Any flags starts with any of these prefixes are filtered out from
|
|
the return value.
|
|
|
|
Returns:
|
|
A list of command line flags
|
|
"""
|
|
cpp = ctx.fragments.cpp
|
|
features = ctx.features
|
|
options = cpp.compiler_options(features)
|
|
options += cpp.unfiltered_compiler_options(features)
|
|
options += cpp.link_options
|
|
options += cpp.mostly_static_link_options(ctx.features, False)
|
|
filtered = []
|
|
for opt in options:
|
|
if any([opt.startswith(prefix) for prefix in blocklist]):
|
|
continue
|
|
filtered.append(opt)
|
|
return filtered
|
|
|
|
def _gc_goopts(ctx):
|
|
gc_goopts = [
|
|
ctx.expand_make_variables("gc_goopts", f, {})
|
|
for f in ctx.attr.gc_goopts
|
|
]
|
|
if ctx.attr.library:
|
|
gc_goopts += ctx.attr.library.gc_goopts
|
|
return gc_goopts
|
|
|
|
def _gc_linkopts(ctx):
|
|
gc_linkopts = [
|
|
ctx.expand_make_variables("gc_linkopts", f, {})
|
|
for f in ctx.attr.gc_linkopts
|
|
]
|
|
for k, v in ctx.attr.x_defs.items():
|
|
gc_linkopts += ["-X", "%s='%s'" % (k, v)]
|
|
return gc_linkopts
|
|
|
|
def _extract_extldflags(gc_linkopts, extldflags):
|
|
"""Extracts -extldflags from gc_linkopts and combines them into a single list.
|
|
|
|
Args:
|
|
gc_linkopts: a list of flags passed in through the gc_linkopts attributes.
|
|
ctx.expand_make_variables should have already been applied.
|
|
extldflags: a list of flags to be passed to the external linker.
|
|
|
|
Return:
|
|
A tuple containing the filtered gc_linkopts with external flags removed,
|
|
and a combined list of external flags.
|
|
"""
|
|
filtered_gc_linkopts = []
|
|
is_extldflags = False
|
|
for opt in gc_linkopts:
|
|
if is_extldflags:
|
|
is_extldflags = False
|
|
extldflags += [opt]
|
|
elif opt == "-extldflags":
|
|
is_extldflags = True
|
|
else:
|
|
filtered_gc_linkopts += [opt]
|
|
return filtered_gc_linkopts, extldflags
|
|
|
|
def _emit_go_link_action(
|
|
ctx,
|
|
transitive_go_library_paths,
|
|
transitive_go_libraries,
|
|
cgo_deps,
|
|
libs,
|
|
executable,
|
|
gc_linkopts):
|
|
"""Sets up a symlink tree to libraries to link together."""
|
|
config_strip = len(ctx.configuration.bin_dir.path) + 1
|
|
pkg_depth = executable.dirname[config_strip:].count("/") + 1
|
|
|
|
ld = "%s" % ctx.fragments.cpp.compiler_executable
|
|
extldflags = _c_linker_options(ctx) + [
|
|
"-Wl,-rpath,$ORIGIN/" + ("../" * pkg_depth),
|
|
]
|
|
for d in cgo_deps:
|
|
if d.basename.endswith(".so"):
|
|
short_dir = d.dirname[len(d.root.path):]
|
|
extldflags += ["-Wl,-rpath,$ORIGIN/" + ("../" * pkg_depth) + short_dir]
|
|
gc_linkopts, extldflags = _extract_extldflags(gc_linkopts, extldflags)
|
|
|
|
link_cmd = [
|
|
ctx.file.go_tool.path,
|
|
"tool",
|
|
"link",
|
|
"-L",
|
|
".",
|
|
]
|
|
for path in transitive_go_library_paths:
|
|
link_cmd += ["-L", path]
|
|
link_cmd += [
|
|
"-o",
|
|
executable.path,
|
|
] + gc_linkopts + ['"${STAMP_XDEFS[@]}"']
|
|
|
|
# workaround for a bug in ld(1) on Mac OS X.
|
|
# http://lists.apple.com/archives/Darwin-dev/2006/Sep/msg00084.html
|
|
# TODO(yugui) Remove this workaround once rules_go stops supporting XCode 7.2
|
|
# or earlier.
|
|
if not _is_darwin_cpu(ctx):
|
|
link_cmd += ["-s"]
|
|
|
|
link_cmd += [
|
|
"-extld",
|
|
ld,
|
|
"-extldflags",
|
|
"'%s'" % " ".join(extldflags),
|
|
] + [lib.path for lib in libs]
|
|
|
|
# Avoided -s on OSX but but it requires dsymutil to be on $PATH.
|
|
# TODO(yugui) Remove this workaround once rules_go stops supporting XCode 7.2
|
|
# or earlier.
|
|
cmds = ["export PATH=$PATH:/usr/bin"]
|
|
|
|
cmds += [
|
|
"STAMP_XDEFS=()",
|
|
]
|
|
|
|
stamp_inputs = []
|
|
if ctx.attr.linkstamp:
|
|
# read workspace status files, converting "KEY value" lines
|
|
# to "-X $linkstamp.KEY=value" arguments to the go linker.
|
|
stamp_inputs = [ctx.info_file, ctx.version_file]
|
|
for f in stamp_inputs:
|
|
cmds += [
|
|
"while read -r key value || [[ -n $key ]]; do",
|
|
" STAMP_XDEFS+=(-X \"%s.$key=$value\")" % ctx.attr.linkstamp,
|
|
"done < " + f.path,
|
|
]
|
|
|
|
cmds += [" ".join(link_cmd)]
|
|
|
|
f = _emit_generate_params_action(cmds, ctx, lib.basename + ".GoLinkFile.params")
|
|
|
|
ctx.action(
|
|
inputs = [f] + (list(transitive_go_libraries) + [lib] + list(cgo_deps) +
|
|
ctx.files.toolchain + ctx.files._crosstool) + stamp_inputs,
|
|
outputs = [executable],
|
|
command = f.path,
|
|
mnemonic = "GoLink",
|
|
env = go_environment_vars(ctx),
|
|
)
|
|
|
|
def go_binary_impl(ctx):
|
|
"""go_binary_impl emits actions for compiling and linking a go executable."""
|
|
lib_result = go_library_impl(ctx)
|
|
_emit_go_link_action(
|
|
ctx,
|
|
transitive_go_libraries = lib_result.transitive_go_libraries,
|
|
transitive_go_library_paths = lib_result.transitive_go_library_paths,
|
|
cgo_deps = lib_result.transitive_cgo_deps,
|
|
libs = lib_result.files,
|
|
executable = ctx.outputs.executable,
|
|
gc_linkopts = _gc_linkopts(ctx),
|
|
)
|
|
|
|
return struct(
|
|
files = depset([ctx.outputs.executable]),
|
|
runfiles = lib_result.runfiles,
|
|
cgo_object = lib_result.cgo_object,
|
|
)
|
|
|
|
def go_test_impl(ctx):
|
|
"""go_test_impl implements go testing.
|
|
|
|
It emits an action to run the test generator, and then compiles the
|
|
test into a binary."""
|
|
|
|
lib_result = go_library_impl(ctx)
|
|
main_go = ctx.new_file(ctx.label.name + "_main_test.go")
|
|
main_object = ctx.new_file(ctx.label.name + "_main_test.o")
|
|
main_lib = ctx.new_file(ctx.label.name + "_main_test.a")
|
|
go_import = _go_importpath(ctx)
|
|
|
|
cmds = [
|
|
"UNFILTERED_TEST_FILES=(%s)" %
|
|
" ".join(["'%s'" % f.path for f in lib_result.go_sources]),
|
|
"FILTERED_TEST_FILES=()",
|
|
"while read -r line; do",
|
|
' if [ -n "$line" ]; then',
|
|
' FILTERED_TEST_FILES+=("$line")',
|
|
" fi",
|
|
'done < <(\'%s\' -cgo "${UNFILTERED_TEST_FILES[@]}")' %
|
|
ctx.executable._filter_tags.path,
|
|
" ".join([
|
|
"'%s'" % ctx.executable.test_generator.path,
|
|
"--package",
|
|
go_import,
|
|
"--output",
|
|
"'%s'" % main_go.path,
|
|
'"${FILTERED_TEST_FILES[@]}"',
|
|
]),
|
|
]
|
|
f = _emit_generate_params_action(
|
|
cmds,
|
|
ctx,
|
|
ctx.label.name + ".GoTestGenTest.params",
|
|
)
|
|
inputs = (list(lib_result.go_sources) + list(ctx.files.toolchain) +
|
|
[f, ctx.executable._filter_tags, ctx.executable.test_generator])
|
|
ctx.action(
|
|
inputs = inputs,
|
|
outputs = [main_go],
|
|
command = f.path,
|
|
mnemonic = "GoTestGenTest",
|
|
env = dict(go_environment_vars(ctx), RUNDIR = ctx.label.package),
|
|
)
|
|
|
|
_emit_go_compile_action(
|
|
ctx,
|
|
sources = depset([main_go]),
|
|
deps = ctx.attr.deps + [lib_result],
|
|
libpaths = lib_result.transitive_go_library_paths,
|
|
out_object = main_object,
|
|
gc_goopts = _gc_goopts(ctx),
|
|
)
|
|
_emit_go_pack_action(ctx, main_lib, [main_object])
|
|
_emit_go_link_action(
|
|
ctx,
|
|
transitive_go_library_paths = lib_result.transitive_go_library_paths,
|
|
transitive_go_libraries = lib_result.transitive_go_libraries,
|
|
cgo_deps = lib_result.transitive_cgo_deps,
|
|
libs = [main_lib],
|
|
executable = ctx.outputs.executable,
|
|
gc_linkopts = _gc_linkopts(ctx),
|
|
)
|
|
|
|
# TODO(bazel-team): the Go tests should do a chdir to the directory
|
|
# holding the data files, so open-source go tests continue to work
|
|
# without code changes.
|
|
runfiles = ctx.runfiles(files = [ctx.outputs.executable])
|
|
runfiles = runfiles.merge(lib_result.runfiles)
|
|
return struct(
|
|
files = depset([ctx.outputs.executable]),
|
|
runfiles = runfiles,
|
|
)
|
|
|
|
go_env_attrs = {
|
|
"toolchain": attr.label(
|
|
default = Label("//go/toolchain:toolchain"),
|
|
allow_files = True,
|
|
cfg = "host",
|
|
),
|
|
"go_tool": attr.label(
|
|
default = Label("//go/toolchain:go_tool"),
|
|
single_file = True,
|
|
allow_files = True,
|
|
cfg = "host",
|
|
),
|
|
"go_prefix": attr.label(
|
|
providers = ["go_prefix"],
|
|
default = Label(
|
|
"//:go_prefix",
|
|
relative_to_caller_repository = True,
|
|
),
|
|
allow_files = False,
|
|
cfg = "host",
|
|
),
|
|
"go_src": attr.label(
|
|
default = Label("//go/toolchain:go_src"),
|
|
allow_files = True,
|
|
cfg = "host",
|
|
),
|
|
"go_include": attr.label(
|
|
default = Label("//go/toolchain:go_include"),
|
|
single_file = True,
|
|
allow_files = True,
|
|
cfg = "host",
|
|
),
|
|
"go_root": attr.label(
|
|
providers = ["go_root"],
|
|
default = Label(
|
|
"//go/toolchain:go_root",
|
|
),
|
|
allow_files = False,
|
|
cfg = "host",
|
|
),
|
|
"_filter_tags": attr.label(
|
|
default = Label("//go/tools/filter_tags"),
|
|
cfg = "host",
|
|
executable = True,
|
|
single_file = True,
|
|
),
|
|
"_filter_exec": attr.label(
|
|
default = Label("//go/tools/filter_exec"),
|
|
cfg = "host",
|
|
executable = True,
|
|
single_file = True,
|
|
),
|
|
"_asm": attr.label(
|
|
default = Label("//go/tools/builders:asm"),
|
|
cfg = "host",
|
|
executable = True,
|
|
single_file = True,
|
|
),
|
|
}
|
|
|
|
go_library_attrs = go_env_attrs + {
|
|
"data": attr.label_list(
|
|
allow_files = True,
|
|
cfg = "data",
|
|
),
|
|
"srcs": attr.label_list(allow_files = go_filetype),
|
|
"deps": attr.label_list(
|
|
providers = [
|
|
"transitive_go_library_paths",
|
|
"transitive_go_libraries",
|
|
"transitive_cgo_deps",
|
|
],
|
|
),
|
|
"importpath": attr.string(),
|
|
"library": attr.label(
|
|
providers = [
|
|
"direct_deps",
|
|
"go_sources",
|
|
"asm_sources",
|
|
"cgo_object",
|
|
"gc_goopts",
|
|
],
|
|
),
|
|
"gc_goopts": attr.string_list(),
|
|
}
|
|
|
|
_crosstool_attrs = {
|
|
"_crosstool": attr.label(
|
|
default = Label("//tools/defaults:crosstool"),
|
|
),
|
|
}
|
|
|
|
go_link_attrs = go_library_attrs + _crosstool_attrs + {
|
|
"gc_linkopts": attr.string_list(),
|
|
"linkstamp": attr.string(),
|
|
"x_defs": attr.string_dict(),
|
|
}
|
|
|
|
go_library = rule(
|
|
go_library_impl,
|
|
attrs = go_library_attrs + {
|
|
"cgo_object": attr.label(
|
|
providers = [
|
|
"cgo_obj",
|
|
"cgo_deps",
|
|
],
|
|
),
|
|
},
|
|
fragments = ["cpp"],
|
|
)
|
|
|
|
go_binary = rule(
|
|
go_binary_impl,
|
|
attrs = go_library_attrs + _crosstool_attrs + go_link_attrs,
|
|
executable = True,
|
|
fragments = ["cpp"],
|
|
)
|
|
|
|
go_test = rule(
|
|
go_test_impl,
|
|
attrs = go_library_attrs + _crosstool_attrs + go_link_attrs + {
|
|
"test_generator": attr.label(
|
|
executable = True,
|
|
default = Label(
|
|
"//go/tools:generate_test_main",
|
|
),
|
|
cfg = "host",
|
|
),
|
|
},
|
|
executable = True,
|
|
fragments = ["cpp"],
|
|
test = True,
|
|
)
|
|
|
|
def _pkg_dir(workspace_root, package_name):
|
|
if workspace_root and package_name:
|
|
return workspace_root + "/" + package_name
|
|
if workspace_root:
|
|
return workspace_root
|
|
if package_name:
|
|
return package_name
|
|
return "."
|
|
|
|
def _exec_path(path):
|
|
if path.startswith("/"):
|
|
return path
|
|
return "${execroot}/" + path
|
|
|
|
def _cgo_filter_srcs_impl(ctx):
|
|
srcs = ctx.files.srcs
|
|
dsts = []
|
|
cmds = []
|
|
for src in srcs:
|
|
stem, _, ext = src.path.rpartition(".")
|
|
dst_basename = "%s.filtered.%s" % (stem, ext)
|
|
dst = ctx.new_file(src, dst_basename)
|
|
cmds += [
|
|
"if '%s' -cgo -quiet '%s'; then" %
|
|
(ctx.executable._filter_tags.path, src.path),
|
|
" cp '%s' '%s'" % (src.path, dst.path),
|
|
"else",
|
|
" echo -n >'%s'" % dst.path,
|
|
"fi",
|
|
]
|
|
dsts.append(dst)
|
|
|
|
if ctx.label.package == "":
|
|
script_name = ctx.label.name + ".CGoFilterSrcs.params"
|
|
else:
|
|
script_name = ctx.label.package + "/" + ctx.label.name + ".CGoFilterSrcs.params"
|
|
f = _emit_generate_params_action(cmds, ctx, script_name)
|
|
ctx.action(
|
|
inputs = [f, ctx.executable._filter_tags] + srcs,
|
|
outputs = dsts,
|
|
command = f.path,
|
|
mnemonic = "CgoFilterSrcs",
|
|
)
|
|
return struct(
|
|
files = depset(dsts),
|
|
)
|
|
|
|
_cgo_filter_srcs = rule(
|
|
implementation = _cgo_filter_srcs_impl,
|
|
attrs = {
|
|
"srcs": attr.label_list(
|
|
allow_files = cgo_filetype,
|
|
),
|
|
"_filter_tags": attr.label(
|
|
default = Label("//go/tools/filter_tags"),
|
|
cfg = "host",
|
|
executable = True,
|
|
single_file = True,
|
|
),
|
|
},
|
|
fragments = ["cpp"],
|
|
)
|
|
|
|
def _cgo_codegen_impl(ctx):
|
|
go_srcs = ctx.files.srcs
|
|
srcs = go_srcs + ctx.files.c_hdrs
|
|
linkopts = ctx.attr.linkopts
|
|
copts = ctx.fragments.cpp.c_options + ctx.attr.copts
|
|
deps = depset([], order = "topological")
|
|
for d in ctx.attr.deps:
|
|
srcs += list(d.cc.transitive_headers)
|
|
deps += d.cc.libs
|
|
copts += ["-D" + define for define in d.cc.defines]
|
|
for inc in d.cc.include_directories:
|
|
copts += ["-I", _exec_path(inc)]
|
|
for hdr in ctx.files.c_hdrs:
|
|
copts += ["-iquote", hdr.dirname]
|
|
for inc in d.cc.quote_include_directories:
|
|
copts += ["-iquote", _exec_path(inc)]
|
|
for inc in d.cc.system_include_directories:
|
|
copts += ["-isystem", _exec_path(inc)]
|
|
for lib in d.cc.libs:
|
|
if lib.basename.startswith("lib") and lib.basename.endswith(".so"):
|
|
linkopts += ["-L", lib.dirname, "-l", lib.basename[3:-3]]
|
|
else:
|
|
linkopts += [lib.path]
|
|
linkopts += d.cc.link_flags
|
|
|
|
p = _pkg_dir(ctx.label.workspace_root, ctx.label.package) + "/"
|
|
if p == "./":
|
|
p = "" # workaround when cgo_library in repository root
|
|
out_dir = (ctx.configuration.genfiles_dir.path + "/" +
|
|
p + ctx.attr.outdir)
|
|
cc = ctx.fragments.cpp.compiler_executable
|
|
cmds = [
|
|
# We cannot use env for CC because $(CC) on OSX is relative
|
|
# and '../' does not work fine due to symlinks.
|
|
"export CC=$(cd $(dirname {cc}); pwd)/$(basename {cc})".format(cc = cc),
|
|
"export CXX=$CC",
|
|
'objdir="%s/gen"' % out_dir,
|
|
"execroot=$(pwd)",
|
|
'mkdir -p "$objdir"',
|
|
"unfiltered_go_files=(%s)" % " ".join(["'%s'" % f.path for f in go_srcs]),
|
|
"filtered_go_files=()",
|
|
'for file in "${unfiltered_go_files[@]}"; do',
|
|
' stem=$(basename "$file" .go)',
|
|
' if %s -cgo -quiet "$file"; then' % ctx.executable._filter_tags.path,
|
|
' filtered_go_files+=("$file")',
|
|
" else",
|
|
' grep --max-count 1 "^package " "$file" >"$objdir/$stem.go"',
|
|
' echo -n >"$objdir/$stem.c"',
|
|
" fi",
|
|
"done",
|
|
"if [ ${#filtered_go_files[@]} -eq 0 ]; then",
|
|
" echo no buildable Go source files in %s >&1" % str(ctx.label),
|
|
" exit 1",
|
|
"fi",
|
|
'"$GOROOT/bin/go" tool cgo -objdir "$objdir" -- %s "${filtered_go_files[@]}"' %
|
|
" ".join(['"%s"' % copt for copt in copts]),
|
|
# Rename the outputs using glob so we don't have to understand cgo's mangling
|
|
# TODO(#350): might be fixed by this?.
|
|
'for file in "${filtered_go_files[@]}"; do',
|
|
' stem=$(basename "$file" .go)',
|
|
' mv "$objdir/"*"$stem.cgo1.go" "$objdir/$stem.go"',
|
|
' mv "$objdir/"*"$stem.cgo2.c" "$objdir/$stem.c"',
|
|
"done",
|
|
"rm -f $objdir/_cgo_.o $objdir/_cgo_flags",
|
|
]
|
|
|
|
f = _emit_generate_params_action(cmds, ctx, out_dir + ".CGoCodeGenFile.params")
|
|
|
|
inputs = (srcs + ctx.files.toolchain + ctx.files._crosstool +
|
|
[f, ctx.executable._filter_tags])
|
|
ctx.action(
|
|
inputs = inputs,
|
|
outputs = ctx.outputs.outs,
|
|
mnemonic = "CGoCodeGen",
|
|
progress_message = "CGoCodeGen %s" % ctx.label,
|
|
command = f.path,
|
|
env = go_environment_vars(ctx) + {
|
|
"CGO_LDFLAGS": " ".join(linkopts),
|
|
},
|
|
)
|
|
return struct(
|
|
label = ctx.label,
|
|
files = depset(ctx.outputs.outs),
|
|
cgo_deps = deps,
|
|
)
|
|
|
|
_cgo_codegen_rule = rule(
|
|
_cgo_codegen_impl,
|
|
attrs = go_env_attrs + _crosstool_attrs + {
|
|
"srcs": attr.label_list(
|
|
allow_files = go_filetype,
|
|
non_empty = True,
|
|
),
|
|
"c_hdrs": attr.label_list(
|
|
allow_files = cc_hdr_filetype,
|
|
),
|
|
"deps": attr.label_list(
|
|
allow_files = False,
|
|
providers = ["cc"],
|
|
),
|
|
"copts": attr.string_list(),
|
|
"linkopts": attr.string_list(),
|
|
"outdir": attr.string(mandatory = True),
|
|
"outs": attr.output_list(
|
|
mandatory = True,
|
|
non_empty = True,
|
|
),
|
|
},
|
|
fragments = ["cpp"],
|
|
output_to_genfiles = True,
|
|
)
|
|
|
|
def _cgo_codegen(
|
|
name,
|
|
srcs,
|
|
c_hdrs = [],
|
|
deps = [],
|
|
copts = [],
|
|
linkopts = [],
|
|
go_tool = None,
|
|
toolchain = None):
|
|
"""Generates glue codes for interop between C and Go
|
|
|
|
Args:
|
|
name: A unique name of the rule
|
|
srcs: list of Go source files.
|
|
Each of them must contain `import "C"`.
|
|
c_hdrs: C/C++ header files necessary to determine kinds of
|
|
C/C++ identifiers in srcs.
|
|
deps: A list of cc_library rules.
|
|
The generated codes are expected to be linked with these deps.
|
|
linkopts: A list of linker options,
|
|
These flags are passed to the linker when the generated codes
|
|
are linked into the target binary.
|
|
"""
|
|
outdir = name + ".dir"
|
|
outgen = outdir + "/gen"
|
|
|
|
go_thunks = []
|
|
c_thunks = []
|
|
for s in srcs:
|
|
if not s.endswith(".go"):
|
|
fail("not a .go file: %s" % s)
|
|
basename = s[:-3]
|
|
if basename.rfind("/") >= 0:
|
|
basename = basename[basename.rfind("/") + 1:]
|
|
go_thunks.append(outgen + "/" + basename + ".go")
|
|
c_thunks.append(outgen + "/" + basename + ".c")
|
|
|
|
outs = struct(
|
|
name = name,
|
|
outdir = outgen,
|
|
go_thunks = go_thunks,
|
|
c_thunks = c_thunks,
|
|
c_exports = [
|
|
outgen + "/_cgo_export.c",
|
|
outgen + "/_cgo_export.h",
|
|
],
|
|
c_dummy = outgen + "/_cgo_main.c",
|
|
gotypes = outgen + "/_cgo_gotypes.go",
|
|
)
|
|
|
|
_cgo_codegen_rule(
|
|
name = name,
|
|
srcs = srcs,
|
|
c_hdrs = c_hdrs,
|
|
deps = deps,
|
|
copts = copts,
|
|
linkopts = linkopts,
|
|
go_tool = go_tool,
|
|
toolchain = toolchain,
|
|
outdir = outdir,
|
|
outs = outs.go_thunks + outs.c_thunks + outs.c_exports + [
|
|
outs.c_dummy,
|
|
outs.gotypes,
|
|
],
|
|
visibility = ["//visibility:private"],
|
|
)
|
|
return outs
|
|
|
|
def _cgo_import_impl(ctx):
|
|
cmds = [
|
|
(ctx.file.go_tool.path + " tool cgo" +
|
|
" -dynout " + ctx.outputs.out.path +
|
|
" -dynimport " + ctx.file.cgo_o.path +
|
|
" -dynpackage $(%s %s)" % (
|
|
ctx.executable._extract_package.path,
|
|
ctx.file.sample_go_src.path,
|
|
)),
|
|
]
|
|
f = _emit_generate_params_action(cmds, ctx, ctx.outputs.out.path + ".CGoImportGenFile.params")
|
|
ctx.action(
|
|
inputs = (ctx.files.toolchain +
|
|
[
|
|
f,
|
|
ctx.file.go_tool,
|
|
ctx.executable._extract_package,
|
|
ctx.file.cgo_o,
|
|
ctx.file.sample_go_src,
|
|
]),
|
|
outputs = [ctx.outputs.out],
|
|
command = f.path,
|
|
mnemonic = "CGoImportGen",
|
|
env = go_environment_vars(ctx),
|
|
)
|
|
return struct(
|
|
files = depset([ctx.outputs.out]),
|
|
)
|
|
|
|
_cgo_import = rule(
|
|
_cgo_import_impl,
|
|
attrs = go_env_attrs + {
|
|
"cgo_o": attr.label(
|
|
allow_files = True,
|
|
single_file = True,
|
|
),
|
|
"sample_go_src": attr.label(
|
|
allow_files = True,
|
|
single_file = True,
|
|
),
|
|
"out": attr.output(
|
|
mandatory = True,
|
|
),
|
|
"_extract_package": attr.label(
|
|
default = Label("//go/tools/extract_package"),
|
|
executable = True,
|
|
cfg = "host",
|
|
),
|
|
},
|
|
fragments = ["cpp"],
|
|
)
|
|
|
|
def _cgo_genrule_impl(ctx):
|
|
return struct(
|
|
label = ctx.label,
|
|
go_sources = ctx.files.srcs,
|
|
asm_sources = [],
|
|
asm_headers = [],
|
|
cgo_object = ctx.attr.cgo_object,
|
|
direct_deps = ctx.attr.deps,
|
|
gc_goopts = [],
|
|
)
|
|
|
|
_cgo_genrule = rule(
|
|
_cgo_genrule_impl,
|
|
attrs = {
|
|
"srcs": attr.label_list(allow_files = FileType([".go"])),
|
|
"cgo_object": attr.label(
|
|
providers = [
|
|
"cgo_obj",
|
|
"cgo_deps",
|
|
],
|
|
),
|
|
"deps": attr.label_list(
|
|
providers = [
|
|
"direct_deps",
|
|
"transitive_go_library_paths",
|
|
"transitive_go_libraries",
|
|
"transitive_cgo_deps",
|
|
],
|
|
),
|
|
},
|
|
fragments = ["cpp"],
|
|
)
|
|
|
|
"""Generates symbol-import directives for cgo
|
|
|
|
Args:
|
|
cgo_o: The loadable object to extract dynamic symbols from.
|
|
sample_go_src: A go source which is compiled together with the generated file.
|
|
The generated file will have the same Go package name as this file.
|
|
out: Destination of the generated codes.
|
|
"""
|
|
|
|
def _cgo_object_impl(ctx):
|
|
arguments = _c_linker_options(ctx, blocklist = [
|
|
# never link any dependency libraries
|
|
"-l",
|
|
"-L",
|
|
# manage flags to ld(1) by ourselves
|
|
"-Wl,",
|
|
])
|
|
arguments += [
|
|
"-o",
|
|
ctx.outputs.out.path,
|
|
"-nostdlib",
|
|
"-Wl,-r",
|
|
]
|
|
if _is_darwin_cpu(ctx):
|
|
arguments += ["-shared", "-Wl,-all_load"]
|
|
else:
|
|
arguments += ["-Wl,-whole-archive"]
|
|
|
|
lo = ctx.files.src[-1]
|
|
arguments += [lo.path]
|
|
|
|
ctx.action(
|
|
inputs = [lo] + ctx.files._crosstool,
|
|
outputs = [ctx.outputs.out],
|
|
mnemonic = "CGoObject",
|
|
progress_message = "Linking %s" % ctx.outputs.out.short_path,
|
|
executable = ctx.fragments.cpp.compiler_executable,
|
|
arguments = arguments,
|
|
)
|
|
runfiles = ctx.runfiles(collect_data = True)
|
|
runfiles = runfiles.merge(ctx.attr.src.data_runfiles)
|
|
return struct(
|
|
files = depset([ctx.outputs.out]),
|
|
cgo_obj = ctx.outputs.out,
|
|
cgo_deps = ctx.attr.cgogen.cgo_deps,
|
|
runfiles = runfiles,
|
|
)
|
|
|
|
_cgo_object = rule(
|
|
_cgo_object_impl,
|
|
attrs = _crosstool_attrs + {
|
|
"src": attr.label(
|
|
mandatory = True,
|
|
providers = ["cc"],
|
|
),
|
|
"cgogen": attr.label(
|
|
mandatory = True,
|
|
providers = ["cgo_deps"],
|
|
),
|
|
"out": attr.output(
|
|
mandatory = True,
|
|
),
|
|
},
|
|
fragments = ["cpp"],
|
|
)
|
|
|
|
"""Generates _all.o to be archived together with Go objects.
|
|
|
|
Args:
|
|
src: source static library which contains objects
|
|
cgogen: _cgo_codegen rule which knows the dependency cc_library() rules
|
|
to be linked together with src when we generate the final go binary.
|
|
"""
|
|
|
|
def _setup_cgo_library(name, srcs, cdeps, copts, clinkopts, go_tool, toolchain):
|
|
go_srcs = [s for s in srcs if s.endswith(".go")]
|
|
c_hdrs = [s for s in srcs if any([s.endswith(ext) for ext in hdr_exts])]
|
|
c_srcs = [s for s in srcs if not s in (go_srcs + c_hdrs)]
|
|
|
|
# Split cgo files into .go parts and .c parts (plus some other files).
|
|
cgogen = _cgo_codegen(
|
|
name = name + ".cgo",
|
|
srcs = go_srcs,
|
|
c_hdrs = c_hdrs,
|
|
deps = cdeps,
|
|
copts = copts,
|
|
linkopts = clinkopts,
|
|
go_tool = go_tool,
|
|
toolchain = toolchain,
|
|
)
|
|
|
|
# Filter c_srcs with build constraints.
|
|
c_filtered_srcs = []
|
|
if len(c_srcs) > 0:
|
|
c_filtered_srcs_name = name + "_filter_cgo_srcs"
|
|
_cgo_filter_srcs(
|
|
name = c_filtered_srcs_name,
|
|
srcs = c_srcs,
|
|
)
|
|
c_filtered_srcs.append(":" + c_filtered_srcs_name)
|
|
|
|
pkg_dir = _pkg_dir(
|
|
"external/" + REPOSITORY_NAME[1:] if len(REPOSITORY_NAME) > 1 else "",
|
|
PACKAGE_NAME,
|
|
)
|
|
|
|
# Platform-specific settings
|
|
native.config_setting(
|
|
name = name + "_windows_setting",
|
|
values = {
|
|
"cpu": "x64_windows_msvc",
|
|
},
|
|
)
|
|
platform_copts = select({
|
|
":" + name + "_windows_setting": ["-mthreads"],
|
|
"//conditions:default": ["-pthread"],
|
|
})
|
|
platform_linkopts = select({
|
|
":" + name + "_windows_setting": ["-mthreads"],
|
|
"//conditions:default": ["-pthread"],
|
|
})
|
|
|
|
# Bundles objects into an archive so that _cgo_.o and _all.o can share them.
|
|
native.cc_library(
|
|
name = cgogen.outdir + "/_cgo_lib",
|
|
srcs = cgogen.c_thunks + cgogen.c_exports + c_filtered_srcs + c_hdrs,
|
|
deps = cdeps,
|
|
copts = copts + platform_copts + [
|
|
"-I",
|
|
pkg_dir,
|
|
"-I",
|
|
"$(GENDIR)/" + pkg_dir + "/" + cgogen.outdir,
|
|
# The generated thunks often contain unused variables.
|
|
"-Wno-unused-variable",
|
|
],
|
|
linkopts = clinkopts + platform_linkopts,
|
|
linkstatic = 1,
|
|
# _cgo_.o and _all.o keep all objects in this archive.
|
|
# But it should not be very annoying in the final binary target
|
|
# because _cgo_object rule does not propagate alwayslink=1
|
|
alwayslink = 1,
|
|
visibility = ["//visibility:private"],
|
|
)
|
|
|
|
# Loadable object which cgo reads when it generates _cgo_import.go
|
|
native.cc_binary(
|
|
name = cgogen.outdir + "/_cgo_.o",
|
|
srcs = [cgogen.c_dummy],
|
|
deps = cdeps + [cgogen.outdir + "/_cgo_lib"],
|
|
copts = copts,
|
|
linkopts = clinkopts,
|
|
visibility = ["//visibility:private"],
|
|
)
|
|
_cgo_import(
|
|
name = "%s.cgo.importgen" % name,
|
|
cgo_o = cgogen.outdir + "/_cgo_.o",
|
|
out = cgogen.outdir + "/_cgo_import.go",
|
|
sample_go_src = go_srcs[0],
|
|
go_tool = go_tool,
|
|
toolchain = toolchain,
|
|
visibility = ["//visibility:private"],
|
|
)
|
|
|
|
_cgo_object(
|
|
name = cgogen.outdir + "/_cgo_object",
|
|
src = cgogen.outdir + "/_cgo_lib",
|
|
out = cgogen.outdir + "/_all.o",
|
|
cgogen = cgogen.name,
|
|
visibility = ["//visibility:private"],
|
|
)
|
|
return cgogen
|
|
|
|
def cgo_genrule(
|
|
name,
|
|
srcs,
|
|
copts = [],
|
|
clinkopts = [],
|
|
cdeps = [],
|
|
**kwargs):
|
|
cgogen = _setup_cgo_library(
|
|
name = name,
|
|
srcs = srcs,
|
|
cdeps = cdeps,
|
|
copts = copts,
|
|
clinkopts = clinkopts,
|
|
toolchain = None,
|
|
go_tool = None,
|
|
)
|
|
_cgo_genrule(
|
|
name = name,
|
|
srcs = cgogen.go_thunks + [
|
|
cgogen.gotypes,
|
|
cgogen.outdir + "/_cgo_import.go",
|
|
],
|
|
cgo_object = cgogen.outdir + "/_cgo_object",
|
|
**kwargs
|
|
)
|
|
|
|
def cgo_library(
|
|
name,
|
|
srcs,
|
|
toolchain = None,
|
|
go_tool = None,
|
|
copts = [],
|
|
clinkopts = [],
|
|
cdeps = [],
|
|
**kwargs):
|
|
"""Builds a cgo-enabled go library.
|
|
|
|
Args:
|
|
name: A unique name for this rule.
|
|
srcs: List of Go, C and C++ files that are processed to build a Go library.
|
|
Those Go files must contain `import "C"`.
|
|
C and C++ files can be anything allowed in `srcs` attribute of
|
|
`cc_library`.
|
|
copts: Add these flags to the C++ compiler.
|
|
clinkopts: Add these flags to the C++ linker.
|
|
cdeps: List of C/C++ libraries to be linked into the binary target.
|
|
They must be `cc_library` rules.
|
|
deps: List of other libraries to be linked to this library target.
|
|
data: List of files needed by this rule at runtime.
|
|
|
|
NOTE:
|
|
`srcs` cannot contain pure-Go files, which do not have `import "C"`.
|
|
So you need to define another `go_library` when you build a go package with
|
|
both cgo-enabled and pure-Go sources.
|
|
|
|
```
|
|
cgo_library(
|
|
name = "cgo_enabled",
|
|
srcs = ["cgo-enabled.go", "foo.cc", "bar.S", "baz.a"],
|
|
)
|
|
|
|
go_library(
|
|
name = "go_default_library",
|
|
srcs = ["pure-go.go"],
|
|
library = ":cgo_enabled",
|
|
)
|
|
```
|
|
"""
|
|
cgogen = _setup_cgo_library(
|
|
name = name,
|
|
srcs = srcs,
|
|
cdeps = cdeps,
|
|
copts = copts,
|
|
clinkopts = clinkopts,
|
|
go_tool = go_tool,
|
|
toolchain = toolchain,
|
|
)
|
|
|
|
go_library(
|
|
name = name,
|
|
srcs = cgogen.go_thunks + [
|
|
cgogen.gotypes,
|
|
cgogen.outdir + "/_cgo_import.go",
|
|
],
|
|
cgo_object = cgogen.outdir + "/_cgo_object",
|
|
go_tool = go_tool,
|
|
toolchain = toolchain,
|
|
**kwargs
|
|
)
|