Created
August 28, 2017 19:59
-
-
Save leblancd/472fac6ca89e79b72712bed3a7834d7d to your computer and use it in GitHub Desktop.
~/.cache/bazel/_bazel_openstack/af47442b3010651ec1a7861f7dccb62e/external/io_bazel_rules_go/go/private/library.bzl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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. | |
load("@io_bazel_rules_go//go/private:common.bzl", "get_go_toolchain", "DEFAULT_LIB", "VENDOR_PREFIX", "go_filetype") | |
load("@io_bazel_rules_go//go/private:asm.bzl", "emit_go_asm_action") | |
load("@io_bazel_rules_go//go/private:providers.bzl", "GoLibrary", "GoSource") | |
def emit_library_actions(ctx, sources, deps, cgo_object, library, want_coverage): | |
go_toolchain = get_go_toolchain(ctx) | |
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')] | |
dep_runfiles = [d.data_runfiles for d in deps] | |
if library: | |
golib = library[GoLibrary] | |
gosrc = library[GoSource] | |
go_srcs += gosrc.go_sources | |
asm_srcs += gosrc.asm_sources | |
asm_hdrs += gosrc.asm_headers | |
deps += golib.direct_deps | |
dep_runfiles += [library.data_runfiles] | |
if golib.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, | |
golib.name)) | |
cgo_object = golib.cgo_object | |
if not go_srcs: | |
fail("may not be empty", "srcs") | |
transitive_cgo_deps = depset([], order="link") | |
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] | |
importpath = go_importpath(ctx) | |
lib_name = importpath + ".a" | |
out_lib = ctx.new_file("~lib~/"+lib_name) | |
out_object = ctx.new_file("~lib~/" + ctx.label.name + ".o") | |
searchpath = out_lib.path[:-len(lib_name)] | |
race_lib = ctx.new_file("~race~/"+lib_name) | |
race_object = ctx.new_file("~race~/" + ctx.label.name + ".o") | |
searchpath_race = race_lib.path[:-len(lib_name)] | |
gc_goopts = get_gc_goopts(ctx) | |
direct_go_library_deps = [] | |
direct_go_library_deps_race = [] | |
direct_search_paths = [] | |
direct_search_paths_race = [] | |
direct_import_paths = [] | |
transitive_go_library_deps = depset() | |
transitive_go_library_deps_race = depset() | |
transitive_go_library_paths = depset([searchpath]) | |
transitive_go_library_paths_race = depset([searchpath_race]) | |
for dep in deps: | |
golib = dep[GoLibrary] | |
direct_go_library_deps += [golib.library] | |
direct_go_library_deps_race += [golib.race] | |
direct_search_paths += [golib.searchpath] | |
direct_search_paths_race += [golib.searchpath_race] | |
direct_import_paths += [golib.importpath] | |
transitive_go_library_deps += golib.transitive_go_libraries | |
transitive_go_library_deps_race += golib.transitive_go_libraries_race | |
transitive_cgo_deps += golib.transitive_cgo_deps | |
transitive_go_library_paths += golib.transitive_go_library_paths | |
transitive_go_library_paths_race += golib.transitive_go_library_paths_race | |
if want_coverage: | |
go_srcs = _emit_go_cover_action(ctx, out_object, go_srcs) | |
emit_go_compile_action(ctx, | |
sources = go_srcs, | |
libs = direct_go_library_deps, | |
lib_paths = direct_search_paths, | |
direct_paths = direct_import_paths, | |
out_object = out_object, | |
gc_goopts = gc_goopts, | |
) | |
emit_go_pack_action(ctx, out_lib, [out_object] + extra_objects) | |
emit_go_compile_action(ctx, | |
sources = go_srcs, | |
libs = direct_go_library_deps_race, | |
lib_paths = direct_search_paths_race, | |
direct_paths = direct_import_paths, | |
out_object = race_object, | |
gc_goopts = gc_goopts + ["-race"], | |
) | |
emit_go_pack_action(ctx, race_lib, [race_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]), | |
library = out_lib, | |
race = race_lib, | |
searchpath = searchpath, | |
searchpath_race = searchpath_race, | |
runfiles = runfiles, | |
go_sources = go_srcs, | |
asm_sources = asm_srcs, | |
asm_headers = asm_hdrs, | |
importpath = importpath, | |
cgo_object = cgo_object, | |
direct_deps = deps, | |
transitive_cgo_deps = transitive_cgo_deps, | |
transitive_go_libraries = transitive_go_library_deps + [out_lib], | |
transitive_go_libraries_race = transitive_go_library_deps_race + [race_lib], | |
transitive_go_library_paths = transitive_go_library_paths, | |
transitive_go_library_paths_race = transitive_go_library_paths_race, | |
gc_goopts = gc_goopts, | |
) | |
def _go_library_impl(ctx): | |
"""Implements the go_library() rule.""" | |
cgo_object = None | |
if hasattr(ctx.attr, "cgo_object"): | |
cgo_object = ctx.attr.cgo_object | |
lib_result = emit_library_actions(ctx, | |
sources = depset(ctx.files.srcs), | |
deps = ctx.attr.deps, | |
cgo_object = cgo_object, | |
library = ctx.attr.library, | |
want_coverage = ctx.coverage_instrumented(), | |
) | |
return [ | |
GoLibrary( | |
label = ctx.label, | |
library = lib_result.library, | |
race = lib_result.race, | |
searchpath = lib_result.searchpath, | |
searchpath_race = lib_result.searchpath_race, | |
importpath = lib_result.importpath, | |
cgo_object = lib_result.cgo_object, | |
direct_deps = lib_result.direct_deps, | |
transitive_cgo_deps = lib_result.transitive_cgo_deps, | |
transitive_go_libraries = lib_result.transitive_go_libraries, | |
transitive_go_libraries_race = lib_result.transitive_go_libraries_race, | |
transitive_go_library_paths = lib_result.transitive_go_library_paths, | |
transitive_go_library_paths_race = lib_result.transitive_go_library_paths_race, | |
gc_goopts = lib_result.gc_goopts, | |
), | |
GoSource( | |
go_sources = lib_result.go_sources, | |
asm_sources = lib_result.asm_sources, | |
asm_headers = lib_result.asm_headers, | |
), | |
DefaultInfo( | |
files = lib_result.files, | |
runfiles = lib_result.runfiles, | |
), | |
OutputGroupInfo( | |
race = depset([lib_result.race]), | |
), | |
] | |
go_library = rule( | |
_go_library_impl, | |
attrs = { | |
"data": attr.label_list(allow_files = True, cfg = "data"), | |
"srcs": attr.label_list(allow_files = go_filetype), | |
"deps": attr.label_list(providers = [GoLibrary]), | |
"importpath": attr.string(), | |
"library": attr.label(providers = [GoLibrary]), | |
"gc_goopts": attr.string_list(), | |
"cgo_object": attr.label( | |
providers = [ | |
"cgo_obj", | |
"cgo_deps", | |
], | |
), | |
#TODO(toolchains): Remove _toolchain attribute when real toolchains arrive | |
"_go_toolchain": attr.label(default = Label("@io_bazel_rules_go_toolchain//:go_toolchain")), | |
"_go_prefix": attr.label(default=Label("//:go_prefix", relative_to_caller_repository = True)), | |
}, | |
fragments = ["cpp"], | |
) | |
def go_importpath(ctx): | |
"""Returns the expected importpath of the go_library being built. | |
Args: | |
ctx: The skylark 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 get_gc_goopts(ctx): | |
gc_goopts = ctx.attr.gc_goopts | |
if ctx.attr.library: | |
gc_goopts += ctx.attr.library[GoLibrary].gc_goopts | |
return gc_goopts | |
def emit_go_compile_action(ctx, sources, libs, lib_paths, direct_paths, out_object, gc_goopts): | |
"""Construct the command line for compiling Go code. | |
Args: | |
ctx: The skylark Context. | |
sources: an iterable of source code artifacts (or CTs? or labels?) | |
libs: a depset of representing all imported libraries. | |
lib_paths: the set of paths to search for imported libraries. | |
direct_paths: iterable of of import paths for the package's direct deps, | |
including those in the library attribute. Used for strict dep checking. | |
out_object: the object file that should be produced | |
gc_goopts: additional flags to pass to the compiler. | |
""" | |
go_toolchain = get_go_toolchain(ctx) | |
gc_goopts = [ctx.expand_make_variables("gc_goopts", f, {}) for f in gc_goopts] | |
inputs = depset([go_toolchain.go]) + sources + libs | |
go_sources = [s.path for s in sources if not s.basename.startswith("_cgo")] | |
cgo_sources = [s.path for s in sources if s.basename.startswith("_cgo")] | |
args = [go_toolchain.go.path] | |
for src in go_sources: | |
args += ["-src", src] | |
for dep in direct_paths: | |
args += ["-dep", dep] | |
args += ["-o", out_object.path, "-trimpath", ".", "-I", "."] | |
for path in lib_paths: | |
args += ["-I", path] | |
args += ["--"] + gc_goopts + cgo_sources | |
ctx.action( | |
inputs = list(inputs), | |
outputs = [out_object], | |
mnemonic = "GoCompile", | |
executable = go_toolchain.compile, | |
arguments = args, | |
env = go_toolchain.env, | |
) | |
def emit_go_pack_action(ctx, out_lib, objects): | |
"""Construct the command line for packing objects together. | |
Args: | |
ctx: The skylark Context. | |
out_lib: the archive that should be produced | |
objects: an iterable of object files to be added to the output archive file. | |
""" | |
go_toolchain = get_go_toolchain(ctx) | |
ctx.action( | |
inputs = objects + go_toolchain.tools, | |
outputs = [out_lib], | |
mnemonic = "GoPack", | |
executable = go_toolchain.go, | |
arguments = ["tool", "pack", "c", out_lib.path] + [a.path for a in objects], | |
env = go_toolchain.env, | |
) | |
def _emit_go_cover_action(ctx, out_object, sources): | |
"""Construct the command line for test coverage instrument. | |
Args: | |
ctx: The skylark Context. | |
out_object: the object file for the library being compiled. Used to name | |
cover files. | |
sources: an iterable of Go source files. | |
Returns: | |
A list of Go source code files which might be coverage instrumented. | |
""" | |
go_toolchain = get_go_toolchain(ctx) | |
outputs = [] | |
# TODO(linuxerwang): make the mode configurable. | |
count = 0 | |
for src in sources: | |
if (not src.basename.endswith(".go") or | |
src.basename.endswith("_test.go") or | |
src.basename.endswith(".cover.go")): | |
outputs += [src] | |
continue | |
cover_var = "GoCover_%d" % count | |
out = ctx.new_file(out_object, out_object.basename + '_' + src.basename[:-3] + '_' + cover_var + '.cover.go') | |
outputs += [out] | |
ctx.action( | |
inputs = [src] + go_toolchain.tools, | |
outputs = [out], | |
mnemonic = "GoCover", | |
executable = go_toolchain.go, | |
arguments = ["tool", "cover", "--mode=set", "-var=%s" % cover_var, "-o", out.path, src.path], | |
env = go_toolchain.env, | |
) | |
count += 1 | |
return outputs |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment