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