1*9bb1b549SSpandan Das# Copyright 2014 The Bazel Authors. All rights reserved. 2*9bb1b549SSpandan Das# 3*9bb1b549SSpandan Das# Licensed under the Apache License, Version 2.0 (the "License"); 4*9bb1b549SSpandan Das# you may not use this file except in compliance with the License. 5*9bb1b549SSpandan Das# You may obtain a copy of the License at 6*9bb1b549SSpandan Das# 7*9bb1b549SSpandan Das# http://www.apache.org/licenses/LICENSE-2.0 8*9bb1b549SSpandan Das# 9*9bb1b549SSpandan Das# Unless required by applicable law or agreed to in writing, software 10*9bb1b549SSpandan Das# distributed under the License is distributed on an "AS IS" BASIS, 11*9bb1b549SSpandan Das# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9bb1b549SSpandan Das# See the License for the specific language governing permissions and 13*9bb1b549SSpandan Das# limitations under the License. 14*9bb1b549SSpandan Das 15*9bb1b549SSpandan Dasload( 16*9bb1b549SSpandan Das "//go/private:context.bzl", 17*9bb1b549SSpandan Das "go_context", 18*9bb1b549SSpandan Das) 19*9bb1b549SSpandan Dasload( 20*9bb1b549SSpandan Das "//go/private:common.bzl", 21*9bb1b549SSpandan Das "as_list", 22*9bb1b549SSpandan Das "asm_exts", 23*9bb1b549SSpandan Das "cgo_exts", 24*9bb1b549SSpandan Das "go_exts", 25*9bb1b549SSpandan Das "split_srcs", 26*9bb1b549SSpandan Das) 27*9bb1b549SSpandan Dasload( 28*9bb1b549SSpandan Das "//go/private:go_toolchain.bzl", 29*9bb1b549SSpandan Das "GO_TOOLCHAIN", 30*9bb1b549SSpandan Das) 31*9bb1b549SSpandan Dasload( 32*9bb1b549SSpandan Das "//go/private/rules:binary.bzl", 33*9bb1b549SSpandan Das "gc_linkopts", 34*9bb1b549SSpandan Das) 35*9bb1b549SSpandan Dasload( 36*9bb1b549SSpandan Das "//go/private:providers.bzl", 37*9bb1b549SSpandan Das "GoArchive", 38*9bb1b549SSpandan Das "GoLibrary", 39*9bb1b549SSpandan Das "GoSource", 40*9bb1b549SSpandan Das "INFERRED_PATH", 41*9bb1b549SSpandan Das "get_archive", 42*9bb1b549SSpandan Das) 43*9bb1b549SSpandan Dasload( 44*9bb1b549SSpandan Das "//go/private/rules:transition.bzl", 45*9bb1b549SSpandan Das "go_transition", 46*9bb1b549SSpandan Das) 47*9bb1b549SSpandan Dasload( 48*9bb1b549SSpandan Das "//go/private:mode.bzl", 49*9bb1b549SSpandan Das "LINKMODE_NORMAL", 50*9bb1b549SSpandan Das) 51*9bb1b549SSpandan Dasload( 52*9bb1b549SSpandan Das "@bazel_skylib//lib:structs.bzl", 53*9bb1b549SSpandan Das "structs", 54*9bb1b549SSpandan Das) 55*9bb1b549SSpandan Das 56*9bb1b549SSpandan Dasdef _go_test_impl(ctx): 57*9bb1b549SSpandan Das """go_test_impl implements go testing. 58*9bb1b549SSpandan Das 59*9bb1b549SSpandan Das It emits an action to run the test generator, and then compiles the 60*9bb1b549SSpandan Das test into a binary.""" 61*9bb1b549SSpandan Das 62*9bb1b549SSpandan Das go = go_context(ctx) 63*9bb1b549SSpandan Das 64*9bb1b549SSpandan Das # Compile the library to test with internal white box tests 65*9bb1b549SSpandan Das internal_library = go.new_library(go, testfilter = "exclude") 66*9bb1b549SSpandan Das internal_source = go.library_to_source(go, ctx.attr, internal_library, ctx.coverage_instrumented()) 67*9bb1b549SSpandan Das internal_archive = go.archive(go, internal_source) 68*9bb1b549SSpandan Das go_srcs = split_srcs(internal_source.srcs).go 69*9bb1b549SSpandan Das 70*9bb1b549SSpandan Das # Compile the library with the external black box tests 71*9bb1b549SSpandan Das external_library = go.new_library( 72*9bb1b549SSpandan Das go, 73*9bb1b549SSpandan Das name = internal_library.name + "_test", 74*9bb1b549SSpandan Das importpath = internal_library.importpath + "_test", 75*9bb1b549SSpandan Das testfilter = "only", 76*9bb1b549SSpandan Das ) 77*9bb1b549SSpandan Das external_source = go.library_to_source(go, struct( 78*9bb1b549SSpandan Das srcs = [struct(files = go_srcs)], 79*9bb1b549SSpandan Das embedsrcs = [struct(files = internal_source.embedsrcs)], 80*9bb1b549SSpandan Das deps = internal_archive.direct + [internal_archive], 81*9bb1b549SSpandan Das x_defs = ctx.attr.x_defs, 82*9bb1b549SSpandan Das ), external_library, ctx.coverage_instrumented()) 83*9bb1b549SSpandan Das external_source, internal_archive = _recompile_external_deps(go, external_source, internal_archive, [t.label for t in ctx.attr.embed]) 84*9bb1b549SSpandan Das external_archive = go.archive(go, external_source) 85*9bb1b549SSpandan Das 86*9bb1b549SSpandan Das # now generate the main function 87*9bb1b549SSpandan Das repo_relative_rundir = ctx.attr.rundir or ctx.label.package or "." 88*9bb1b549SSpandan Das if ctx.label.workspace_name: 89*9bb1b549SSpandan Das # The test is contained in an external repository (Label.workspace_name is always the empty 90*9bb1b549SSpandan Das # string for the main repository, which is the canonical repository name of this repo). 91*9bb1b549SSpandan Das # The test runner cd's into the directory corresponding to the main repository, so walk up 92*9bb1b549SSpandan Das # and then down. 93*9bb1b549SSpandan Das run_dir = "../" + ctx.label.workspace_name + "/" + repo_relative_rundir 94*9bb1b549SSpandan Das else: 95*9bb1b549SSpandan Das run_dir = repo_relative_rundir 96*9bb1b549SSpandan Das 97*9bb1b549SSpandan Das main_go = go.declare_file(go, path = "testmain.go") 98*9bb1b549SSpandan Das arguments = go.builder_args(go, "gentestmain") 99*9bb1b549SSpandan Das arguments.add("-output", main_go) 100*9bb1b549SSpandan Das if go.coverage_enabled: 101*9bb1b549SSpandan Das if go.mode.race: 102*9bb1b549SSpandan Das arguments.add("-cover_mode", "atomic") 103*9bb1b549SSpandan Das else: 104*9bb1b549SSpandan Das arguments.add("-cover_mode", "set") 105*9bb1b549SSpandan Das arguments.add("-cover_format", go.cover_format) 106*9bb1b549SSpandan Das arguments.add( 107*9bb1b549SSpandan Das # the l is the alias for the package under test, the l_test must be the 108*9bb1b549SSpandan Das # same with the test suffix 109*9bb1b549SSpandan Das "-import", 110*9bb1b549SSpandan Das "l=" + internal_source.library.importpath, 111*9bb1b549SSpandan Das ) 112*9bb1b549SSpandan Das arguments.add( 113*9bb1b549SSpandan Das "-import", 114*9bb1b549SSpandan Das "l_test=" + external_source.library.importpath, 115*9bb1b549SSpandan Das ) 116*9bb1b549SSpandan Das arguments.add("-pkgname", internal_source.library.importpath) 117*9bb1b549SSpandan Das arguments.add_all(go_srcs, before_each = "-src", format_each = "l=%s") 118*9bb1b549SSpandan Das ctx.actions.run( 119*9bb1b549SSpandan Das inputs = go_srcs, 120*9bb1b549SSpandan Das outputs = [main_go], 121*9bb1b549SSpandan Das mnemonic = "GoTestGenTest", 122*9bb1b549SSpandan Das executable = go.toolchain._builder, 123*9bb1b549SSpandan Das arguments = [arguments], 124*9bb1b549SSpandan Das ) 125*9bb1b549SSpandan Das 126*9bb1b549SSpandan Das test_gc_linkopts = gc_linkopts(ctx) 127*9bb1b549SSpandan Das if not go.mode.debug: 128*9bb1b549SSpandan Das # Disable symbol table and DWARF generation for test binaries. 129*9bb1b549SSpandan Das test_gc_linkopts.extend(["-s", "-w"]) 130*9bb1b549SSpandan Das 131*9bb1b549SSpandan Das # Link in the run_dir global for bzltestutil 132*9bb1b549SSpandan Das test_gc_linkopts.extend(["-X", "github.com/bazelbuild/rules_go/go/tools/bzltestutil.RunDir=" + run_dir]) 133*9bb1b549SSpandan Das 134*9bb1b549SSpandan Das # Now compile the test binary itself 135*9bb1b549SSpandan Das test_library = GoLibrary( 136*9bb1b549SSpandan Das name = go.label.name + "~testmain", 137*9bb1b549SSpandan Das label = go.label, 138*9bb1b549SSpandan Das importpath = "testmain", 139*9bb1b549SSpandan Das importmap = "testmain", 140*9bb1b549SSpandan Das importpath_aliases = (), 141*9bb1b549SSpandan Das pathtype = INFERRED_PATH, 142*9bb1b549SSpandan Das is_main = True, 143*9bb1b549SSpandan Das resolve = None, 144*9bb1b549SSpandan Das ) 145*9bb1b549SSpandan Das test_deps = external_archive.direct + [external_archive] + ctx.attr._testmain_additional_deps 146*9bb1b549SSpandan Das if ctx.configuration.coverage_enabled: 147*9bb1b549SSpandan Das test_deps.append(go.coverdata) 148*9bb1b549SSpandan Das test_source = go.library_to_source(go, struct( 149*9bb1b549SSpandan Das srcs = [struct(files = [main_go])], 150*9bb1b549SSpandan Das deps = test_deps, 151*9bb1b549SSpandan Das ), test_library, False) 152*9bb1b549SSpandan Das test_archive, executable, runfiles = go.binary( 153*9bb1b549SSpandan Das go, 154*9bb1b549SSpandan Das name = ctx.label.name, 155*9bb1b549SSpandan Das source = test_source, 156*9bb1b549SSpandan Das test_archives = [internal_archive.data], 157*9bb1b549SSpandan Das gc_linkopts = test_gc_linkopts, 158*9bb1b549SSpandan Das version_file = ctx.version_file, 159*9bb1b549SSpandan Das info_file = ctx.info_file, 160*9bb1b549SSpandan Das ) 161*9bb1b549SSpandan Das 162*9bb1b549SSpandan Das env = {} 163*9bb1b549SSpandan Das for k, v in ctx.attr.env.items(): 164*9bb1b549SSpandan Das env[k] = ctx.expand_location(v, ctx.attr.data) 165*9bb1b549SSpandan Das 166*9bb1b549SSpandan Das run_environment_info = RunEnvironmentInfo(env, ctx.attr.env_inherit) 167*9bb1b549SSpandan Das 168*9bb1b549SSpandan Das # Bazel only looks for coverage data if the test target has an 169*9bb1b549SSpandan Das # InstrumentedFilesProvider. If the provider is found and at least one 170*9bb1b549SSpandan Das # source file is present, Bazel will set the COVERAGE_OUTPUT_FILE 171*9bb1b549SSpandan Das # environment variable during tests and will save that file to the build 172*9bb1b549SSpandan Das # events + test outputs. 173*9bb1b549SSpandan Das return [ 174*9bb1b549SSpandan Das test_archive, 175*9bb1b549SSpandan Das DefaultInfo( 176*9bb1b549SSpandan Das files = depset([executable]), 177*9bb1b549SSpandan Das runfiles = runfiles, 178*9bb1b549SSpandan Das executable = executable, 179*9bb1b549SSpandan Das ), 180*9bb1b549SSpandan Das OutputGroupInfo( 181*9bb1b549SSpandan Das compilation_outputs = [internal_archive.data.file], 182*9bb1b549SSpandan Das ), 183*9bb1b549SSpandan Das coverage_common.instrumented_files_info( 184*9bb1b549SSpandan Das ctx, 185*9bb1b549SSpandan Das source_attributes = ["srcs"], 186*9bb1b549SSpandan Das dependency_attributes = ["data", "deps", "embed", "embedsrcs"], 187*9bb1b549SSpandan Das extensions = ["go"], 188*9bb1b549SSpandan Das ), 189*9bb1b549SSpandan Das run_environment_info, 190*9bb1b549SSpandan Das ] 191*9bb1b549SSpandan Das 192*9bb1b549SSpandan Das_go_test_kwargs = { 193*9bb1b549SSpandan Das "implementation": _go_test_impl, 194*9bb1b549SSpandan Das "attrs": { 195*9bb1b549SSpandan Das "data": attr.label_list( 196*9bb1b549SSpandan Das allow_files = True, 197*9bb1b549SSpandan Das doc = """List of files needed by this rule at run-time. This may include data files 198*9bb1b549SSpandan Das needed or other programs that may be executed. The [bazel] package may be 199*9bb1b549SSpandan Das used to locate run files; they may appear in different places depending on the 200*9bb1b549SSpandan Das operating system and environment. See [data dependencies] for more 201*9bb1b549SSpandan Das information on data files. 202*9bb1b549SSpandan Das """, 203*9bb1b549SSpandan Das ), 204*9bb1b549SSpandan Das "srcs": attr.label_list( 205*9bb1b549SSpandan Das allow_files = go_exts + asm_exts + cgo_exts, 206*9bb1b549SSpandan Das doc = """The list of Go source files that are compiled to create the package. 207*9bb1b549SSpandan Das Only `.go` and `.s` files are permitted, unless the `cgo` 208*9bb1b549SSpandan Das attribute is set, in which case, 209*9bb1b549SSpandan Das `.c .cc .cpp .cxx .h .hh .hpp .hxx .inc .m .mm` 210*9bb1b549SSpandan Das files are also permitted. Files may be filtered at build time 211*9bb1b549SSpandan Das using Go [build constraints]. 212*9bb1b549SSpandan Das """, 213*9bb1b549SSpandan Das ), 214*9bb1b549SSpandan Das "deps": attr.label_list( 215*9bb1b549SSpandan Das providers = [GoLibrary], 216*9bb1b549SSpandan Das doc = """List of Go libraries this test imports directly. 217*9bb1b549SSpandan Das These may be go_library rules or compatible rules with the [GoLibrary] provider. 218*9bb1b549SSpandan Das """, 219*9bb1b549SSpandan Das cfg = go_transition, 220*9bb1b549SSpandan Das ), 221*9bb1b549SSpandan Das "embed": attr.label_list( 222*9bb1b549SSpandan Das providers = [GoLibrary], 223*9bb1b549SSpandan Das doc = """List of Go libraries whose sources should be compiled together with this 224*9bb1b549SSpandan Das package's sources. Labels listed here must name `go_library`, 225*9bb1b549SSpandan Das `go_proto_library`, or other compatible targets with the [GoLibrary] and 226*9bb1b549SSpandan Das [GoSource] providers. Embedded libraries must have the same `importpath` as 227*9bb1b549SSpandan Das the embedding library. At most one embedded library may have `cgo = True`, 228*9bb1b549SSpandan Das and the embedding library may not also have `cgo = True`. See [Embedding] 229*9bb1b549SSpandan Das for more information. 230*9bb1b549SSpandan Das """, 231*9bb1b549SSpandan Das cfg = go_transition, 232*9bb1b549SSpandan Das ), 233*9bb1b549SSpandan Das "embedsrcs": attr.label_list( 234*9bb1b549SSpandan Das allow_files = True, 235*9bb1b549SSpandan Das doc = """The list of files that may be embedded into the compiled package using 236*9bb1b549SSpandan Das `//go:embed` directives. All files must be in the same logical directory 237*9bb1b549SSpandan Das or a subdirectory as source files. All source files containing `//go:embed` 238*9bb1b549SSpandan Das directives must be in the same logical directory. It's okay to mix static and 239*9bb1b549SSpandan Das generated source files and static and generated embeddable files. 240*9bb1b549SSpandan Das """, 241*9bb1b549SSpandan Das ), 242*9bb1b549SSpandan Das "env": attr.string_dict( 243*9bb1b549SSpandan Das doc = """Environment variables to set for the test execution. 244*9bb1b549SSpandan Das The values (but not keys) are subject to 245*9bb1b549SSpandan Das [location expansion](https://docs.bazel.build/versions/main/skylark/macros.html) but not full 246*9bb1b549SSpandan Das [make variable expansion](https://docs.bazel.build/versions/main/be/make-variables.html). 247*9bb1b549SSpandan Das """, 248*9bb1b549SSpandan Das ), 249*9bb1b549SSpandan Das "env_inherit": attr.string_list( 250*9bb1b549SSpandan Das doc = """Environment variables to inherit from the external environment. 251*9bb1b549SSpandan Das """, 252*9bb1b549SSpandan Das ), 253*9bb1b549SSpandan Das "importpath": attr.string( 254*9bb1b549SSpandan Das doc = """The import path of this test. Tests can't actually be imported, but this 255*9bb1b549SSpandan Das may be used by [go_path] and other tools to report the location of source 256*9bb1b549SSpandan Das files. This may be inferred from embedded libraries. 257*9bb1b549SSpandan Das """, 258*9bb1b549SSpandan Das ), 259*9bb1b549SSpandan Das "gc_goopts": attr.string_list( 260*9bb1b549SSpandan Das doc = """List of flags to add to the Go compilation command when using the gc compiler. 261*9bb1b549SSpandan Das Subject to ["Make variable"] substitution and [Bourne shell tokenization]. 262*9bb1b549SSpandan Das """, 263*9bb1b549SSpandan Das ), 264*9bb1b549SSpandan Das "gc_linkopts": attr.string_list( 265*9bb1b549SSpandan Das doc = """List of flags to add to the Go link command when using the gc compiler. 266*9bb1b549SSpandan Das Subject to ["Make variable"] substitution and [Bourne shell tokenization]. 267*9bb1b549SSpandan Das """, 268*9bb1b549SSpandan Das ), 269*9bb1b549SSpandan Das "rundir": attr.string( 270*9bb1b549SSpandan Das doc = """ A directory to cd to before the test is run. 271*9bb1b549SSpandan Das This should be a path relative to the root directory of the 272*9bb1b549SSpandan Das repository in which the test is defined, which can be the main or an 273*9bb1b549SSpandan Das external repository. 274*9bb1b549SSpandan Das 275*9bb1b549SSpandan Das The default behaviour is to change to the relative path 276*9bb1b549SSpandan Das corresponding to the test's package, which replicates the normal 277*9bb1b549SSpandan Das behaviour of `go test` so it is easy to write compatible tests. 278*9bb1b549SSpandan Das 279*9bb1b549SSpandan Das Setting it to `.` makes the test behave the normal way for a bazel 280*9bb1b549SSpandan Das test, except that the working directory is always that of the test's 281*9bb1b549SSpandan Das repository, which is not necessarily the main repository. 282*9bb1b549SSpandan Das 283*9bb1b549SSpandan Das Note: If runfile symlinks are disabled (such as on Windows by 284*9bb1b549SSpandan Das default), the test will run in the working directory set by Bazel, 285*9bb1b549SSpandan Das which is the subdirectory of the runfiles directory corresponding to 286*9bb1b549SSpandan Das the main repository. 287*9bb1b549SSpandan Das """, 288*9bb1b549SSpandan Das ), 289*9bb1b549SSpandan Das "x_defs": attr.string_dict( 290*9bb1b549SSpandan Das doc = """Map of defines to add to the go link command. 291*9bb1b549SSpandan Das See [Defines and stamping] for examples of how to use these. 292*9bb1b549SSpandan Das """, 293*9bb1b549SSpandan Das ), 294*9bb1b549SSpandan Das "linkmode": attr.string( 295*9bb1b549SSpandan Das default = LINKMODE_NORMAL, 296*9bb1b549SSpandan Das doc = """Determines how the binary should be built and linked. This accepts some of 297*9bb1b549SSpandan Das the same values as `go build -buildmode` and works the same way. 298*9bb1b549SSpandan Das <br><br> 299*9bb1b549SSpandan Das <ul> 300*9bb1b549SSpandan Das <li>`normal`: Builds a normal executable with position-dependent code.</li> 301*9bb1b549SSpandan Das <li>`pie`: Builds a position-independent executable.</li> 302*9bb1b549SSpandan Das <li>`plugin`: Builds a shared library that can be loaded as a Go plugin. Only supported on platforms that support plugins.</li> 303*9bb1b549SSpandan Das <li>`c-shared`: Builds a shared library that can be linked into a C program.</li> 304*9bb1b549SSpandan Das <li>`c-archive`: Builds an archive that can be linked into a C program.</li> 305*9bb1b549SSpandan Das </ul> 306*9bb1b549SSpandan Das """, 307*9bb1b549SSpandan Das ), 308*9bb1b549SSpandan Das "cgo": attr.bool( 309*9bb1b549SSpandan Das doc = """ 310*9bb1b549SSpandan Das If `True`, the package may contain [cgo] code, and `srcs` may contain 311*9bb1b549SSpandan Das C, C++, Objective-C, and Objective-C++ files and non-Go assembly files. 312*9bb1b549SSpandan Das When cgo is enabled, these files will be compiled with the C/C++ toolchain 313*9bb1b549SSpandan Das and included in the package. Note that this attribute does not force cgo 314*9bb1b549SSpandan Das to be enabled. Cgo is enabled for non-cross-compiling builds when a C/C++ 315*9bb1b549SSpandan Das toolchain is configured. 316*9bb1b549SSpandan Das """, 317*9bb1b549SSpandan Das ), 318*9bb1b549SSpandan Das "cdeps": attr.label_list( 319*9bb1b549SSpandan Das doc = """The list of other libraries that the c code depends on. 320*9bb1b549SSpandan Das This can be anything that would be allowed in [cc_library deps] 321*9bb1b549SSpandan Das Only valid if `cgo` = `True`. 322*9bb1b549SSpandan Das """, 323*9bb1b549SSpandan Das ), 324*9bb1b549SSpandan Das "cppopts": attr.string_list( 325*9bb1b549SSpandan Das doc = """List of flags to add to the C/C++ preprocessor command. 326*9bb1b549SSpandan Das Subject to ["Make variable"] substitution and [Bourne shell tokenization]. 327*9bb1b549SSpandan Das Only valid if `cgo` = `True`. 328*9bb1b549SSpandan Das """, 329*9bb1b549SSpandan Das ), 330*9bb1b549SSpandan Das "copts": attr.string_list( 331*9bb1b549SSpandan Das doc = """List of flags to add to the C compilation command. 332*9bb1b549SSpandan Das Subject to ["Make variable"] substitution and [Bourne shell tokenization]. 333*9bb1b549SSpandan Das Only valid if `cgo` = `True`. 334*9bb1b549SSpandan Das """, 335*9bb1b549SSpandan Das ), 336*9bb1b549SSpandan Das "cxxopts": attr.string_list( 337*9bb1b549SSpandan Das doc = """List of flags to add to the C++ compilation command. 338*9bb1b549SSpandan Das Subject to ["Make variable"] substitution and [Bourne shell tokenization]. 339*9bb1b549SSpandan Das Only valid if `cgo` = `True`. 340*9bb1b549SSpandan Das """, 341*9bb1b549SSpandan Das ), 342*9bb1b549SSpandan Das "clinkopts": attr.string_list( 343*9bb1b549SSpandan Das doc = """List of flags to add to the C link command. 344*9bb1b549SSpandan Das Subject to ["Make variable"] substitution and [Bourne shell tokenization]. 345*9bb1b549SSpandan Das Only valid if `cgo` = `True`. 346*9bb1b549SSpandan Das """, 347*9bb1b549SSpandan Das ), 348*9bb1b549SSpandan Das "pure": attr.string( 349*9bb1b549SSpandan Das default = "auto", 350*9bb1b549SSpandan Das doc = """Controls whether cgo source code and dependencies are compiled and linked, 351*9bb1b549SSpandan Das similar to setting `CGO_ENABLED`. May be one of `on`, `off`, 352*9bb1b549SSpandan Das or `auto`. If `auto`, pure mode is enabled when no C/C++ 353*9bb1b549SSpandan Das toolchain is configured or when cross-compiling. It's usually better to 354*9bb1b549SSpandan Das control this on the command line with 355*9bb1b549SSpandan Das `--@io_bazel_rules_go//go/config:pure`. See [mode attributes], specifically 356*9bb1b549SSpandan Das [pure]. 357*9bb1b549SSpandan Das """, 358*9bb1b549SSpandan Das ), 359*9bb1b549SSpandan Das "static": attr.string( 360*9bb1b549SSpandan Das default = "auto", 361*9bb1b549SSpandan Das doc = """Controls whether a binary is statically linked. May be one of `on`, 362*9bb1b549SSpandan Das `off`, or `auto`. Not available on all platforms or in all 363*9bb1b549SSpandan Das modes. It's usually better to control this on the command line with 364*9bb1b549SSpandan Das `--@io_bazel_rules_go//go/config:static`. See [mode attributes], 365*9bb1b549SSpandan Das specifically [static]. 366*9bb1b549SSpandan Das """, 367*9bb1b549SSpandan Das ), 368*9bb1b549SSpandan Das "race": attr.string( 369*9bb1b549SSpandan Das default = "auto", 370*9bb1b549SSpandan Das doc = """Controls whether code is instrumented for race detection. May be one of 371*9bb1b549SSpandan Das `on`, `off`, or `auto`. Not available when cgo is 372*9bb1b549SSpandan Das disabled. In most cases, it's better to control this on the command line with 373*9bb1b549SSpandan Das `--@io_bazel_rules_go//go/config:race`. See [mode attributes], specifically 374*9bb1b549SSpandan Das [race]. 375*9bb1b549SSpandan Das """, 376*9bb1b549SSpandan Das ), 377*9bb1b549SSpandan Das "msan": attr.string( 378*9bb1b549SSpandan Das default = "auto", 379*9bb1b549SSpandan Das doc = """Controls whether code is instrumented for memory sanitization. May be one of 380*9bb1b549SSpandan Das `on`, `off`, or `auto`. Not available when cgo is 381*9bb1b549SSpandan Das disabled. In most cases, it's better to control this on the command line with 382*9bb1b549SSpandan Das `--@io_bazel_rules_go//go/config:msan`. See [mode attributes], specifically 383*9bb1b549SSpandan Das [msan]. 384*9bb1b549SSpandan Das """, 385*9bb1b549SSpandan Das ), 386*9bb1b549SSpandan Das "gotags": attr.string_list( 387*9bb1b549SSpandan Das doc = """Enables a list of build tags when evaluating [build constraints]. Useful for 388*9bb1b549SSpandan Das conditional compilation. 389*9bb1b549SSpandan Das """, 390*9bb1b549SSpandan Das ), 391*9bb1b549SSpandan Das "goos": attr.string( 392*9bb1b549SSpandan Das default = "auto", 393*9bb1b549SSpandan Das doc = """Forces a binary to be cross-compiled for a specific operating system. It's 394*9bb1b549SSpandan Das usually better to control this on the command line with `--platforms`. 395*9bb1b549SSpandan Das 396*9bb1b549SSpandan Das This disables cgo by default, since a cross-compiling C/C++ toolchain is 397*9bb1b549SSpandan Das rarely available. To force cgo, set `pure` = `off`. 398*9bb1b549SSpandan Das 399*9bb1b549SSpandan Das See [Cross compilation] for more information. 400*9bb1b549SSpandan Das """, 401*9bb1b549SSpandan Das ), 402*9bb1b549SSpandan Das "goarch": attr.string( 403*9bb1b549SSpandan Das default = "auto", 404*9bb1b549SSpandan Das doc = """Forces a binary to be cross-compiled for a specific architecture. It's usually 405*9bb1b549SSpandan Das better to control this on the command line with `--platforms`. 406*9bb1b549SSpandan Das 407*9bb1b549SSpandan Das This disables cgo by default, since a cross-compiling C/C++ toolchain is 408*9bb1b549SSpandan Das rarely available. To force cgo, set `pure` = `off`. 409*9bb1b549SSpandan Das 410*9bb1b549SSpandan Das See [Cross compilation] for more information. 411*9bb1b549SSpandan Das """, 412*9bb1b549SSpandan Das ), 413*9bb1b549SSpandan Das "_go_context_data": attr.label(default = "//:go_context_data", cfg = go_transition), 414*9bb1b549SSpandan Das "_testmain_additional_deps": attr.label_list( 415*9bb1b549SSpandan Das providers = [GoLibrary], 416*9bb1b549SSpandan Das default = ["//go/tools/bzltestutil"], 417*9bb1b549SSpandan Das cfg = go_transition, 418*9bb1b549SSpandan Das ), 419*9bb1b549SSpandan Das # Required for Bazel to collect coverage of instrumented C/C++ binaries 420*9bb1b549SSpandan Das # executed by go_test. 421*9bb1b549SSpandan Das # This is just a shell script and thus cheap enough to depend on 422*9bb1b549SSpandan Das # unconditionally. 423*9bb1b549SSpandan Das "_collect_cc_coverage": attr.label( 424*9bb1b549SSpandan Das default = "@bazel_tools//tools/test:collect_cc_coverage", 425*9bb1b549SSpandan Das cfg = "exec", 426*9bb1b549SSpandan Das ), 427*9bb1b549SSpandan Das # Required for Bazel to merge coverage reports for Go and other 428*9bb1b549SSpandan Das # languages into a single report per test. 429*9bb1b549SSpandan Das # Using configuration_field ensures that the tool is only built when 430*9bb1b549SSpandan Das # run with bazel coverage, not with bazel test. 431*9bb1b549SSpandan Das "_lcov_merger": attr.label( 432*9bb1b549SSpandan Das default = configuration_field(fragment = "coverage", name = "output_generator"), 433*9bb1b549SSpandan Das cfg = "exec", 434*9bb1b549SSpandan Das ), 435*9bb1b549SSpandan Das "_allowlist_function_transition": attr.label( 436*9bb1b549SSpandan Das default = "@bazel_tools//tools/allowlists/function_transition_allowlist", 437*9bb1b549SSpandan Das ), 438*9bb1b549SSpandan Das }, 439*9bb1b549SSpandan Das "executable": True, 440*9bb1b549SSpandan Das "test": True, 441*9bb1b549SSpandan Das "toolchains": [GO_TOOLCHAIN], 442*9bb1b549SSpandan Das "doc": """This builds a set of tests that can be run with `bazel test`.<br><br> 443*9bb1b549SSpandan Das To run all tests in the workspace, and print output on failure (the 444*9bb1b549SSpandan Das equivalent of `go test ./...`), run<br> 445*9bb1b549SSpandan Das ``` 446*9bb1b549SSpandan Das bazel test --test_output=errors //... 447*9bb1b549SSpandan Das ```<br><br> 448*9bb1b549SSpandan Das To run a Go benchmark test, run<br> 449*9bb1b549SSpandan Das ``` 450*9bb1b549SSpandan Das bazel run //path/to:test -- -test.bench=. 451*9bb1b549SSpandan Das ```<br><br> 452*9bb1b549SSpandan Das You can run specific tests by passing the `--test_filter=pattern 453*9bb1b549SSpandan Das <test_filter_>` argument to Bazel. You can pass arguments to tests by passing 454*9bb1b549SSpandan Das `--test_arg=arg <test_arg_>` arguments to Bazel, and you can set environment 455*9bb1b549SSpandan Das variables in the test environment by passing 456*9bb1b549SSpandan Das `--test_env=VAR=value <test_env_>`. You can terminate test execution after the first 457*9bb1b549SSpandan Das failure by passing the `--test_runner_fast_fast <test_runner_fail_fast_>` argument 458*9bb1b549SSpandan Das to Bazel. This is equivalent to passing `--test_arg=-failfast <test_arg_>`.<br><br> 459*9bb1b549SSpandan Das To write structured testlog information to Bazel's `XML_OUTPUT_FILE`, tests 460*9bb1b549SSpandan Das ran with `bazel test` execute using a wrapper. This functionality can be 461*9bb1b549SSpandan Das disabled by setting `GO_TEST_WRAP=0` in the test environment. Additionally, 462*9bb1b549SSpandan Das the testbinary can be invoked with `-test.v` by setting 463*9bb1b549SSpandan Das `GO_TEST_WRAP_TESTV=1` in the test environment; this will result in the 464*9bb1b549SSpandan Das `XML_OUTPUT_FILE` containing more granular data.<br><br> 465*9bb1b549SSpandan Das ***Note:*** To interoperate cleanly with old targets generated by [Gazelle], `name` 466*9bb1b549SSpandan Das should be `go_default_test` for internal tests and 467*9bb1b549SSpandan Das `go_default_xtest` for external tests. Gazelle now generates 468*9bb1b549SSpandan Das the name based on the last component of the path. For example, a test 469*9bb1b549SSpandan Das in `//foo/bar` is named `bar_test`, and uses internal and external 470*9bb1b549SSpandan Das sources. 471*9bb1b549SSpandan Das """, 472*9bb1b549SSpandan Das} 473*9bb1b549SSpandan Das 474*9bb1b549SSpandan Dasgo_test = rule(**_go_test_kwargs) 475*9bb1b549SSpandan Das 476*9bb1b549SSpandan Dasdef _recompile_external_deps(go, external_source, internal_archive, library_labels): 477*9bb1b549SSpandan Das """Recompiles some archives in order to split internal and external tests. 478*9bb1b549SSpandan Das 479*9bb1b549SSpandan Das go_test, like 'go test', splits tests into two separate archives: an 480*9bb1b549SSpandan Das internal archive ('package foo') and an external archive 481*9bb1b549SSpandan Das ('package foo_test'). The library under test is embedded into the internal 482*9bb1b549SSpandan Das archive. The external archive may import it and may depend on symbols 483*9bb1b549SSpandan Das defined in the internal test files. 484*9bb1b549SSpandan Das 485*9bb1b549SSpandan Das To avoid conflicts, the library under test must not be linked into the test 486*9bb1b549SSpandan Das binary, since the internal test archive embeds the same sources. 487*9bb1b549SSpandan Das Libraries imported by the external test that transitively import the 488*9bb1b549SSpandan Das library under test must be recompiled too, or the linker will complain that 489*9bb1b549SSpandan Das export data they were compiled with doesn't match the export data they 490*9bb1b549SSpandan Das are linked with. 491*9bb1b549SSpandan Das 492*9bb1b549SSpandan Das This function identifies which archives may need to be recompiled, then 493*9bb1b549SSpandan Das declares new output files and actions to recompile them. This is an 494*9bb1b549SSpandan Das unfortunately an expensive process requiring O(V+E) time and space in the 495*9bb1b549SSpandan Das size of the test's dependency graph for each test. 496*9bb1b549SSpandan Das 497*9bb1b549SSpandan Das Args: 498*9bb1b549SSpandan Das go: go object returned by go_context. 499*9bb1b549SSpandan Das external_source: GoSource for the external archive. 500*9bb1b549SSpandan Das internal_archive: GoArchive for the internal archive. 501*9bb1b549SSpandan Das library_labels: labels for embedded libraries under test. 502*9bb1b549SSpandan Das 503*9bb1b549SSpandan Das Returns: 504*9bb1b549SSpandan Das external_soruce: recompiled GoSource for the external archive. If no 505*9bb1b549SSpandan Das recompilation is needed, the original GoSource is returned. 506*9bb1b549SSpandan Das internal_archive: recompiled GoArchive for the internal archive. If no 507*9bb1b549SSpandan Das recompilation is needed, the original GoSource is returned. 508*9bb1b549SSpandan Das """ 509*9bb1b549SSpandan Das 510*9bb1b549SSpandan Das # If no libraries are embedded in the internal archive, then nothing needs 511*9bb1b549SSpandan Das # to be recompiled. 512*9bb1b549SSpandan Das if not library_labels: 513*9bb1b549SSpandan Das return external_source, internal_archive 514*9bb1b549SSpandan Das 515*9bb1b549SSpandan Das # Build a map from labels to GoArchiveData. 516*9bb1b549SSpandan Das # If none of the librares embedded in the internal archive are in the 517*9bb1b549SSpandan Das # dependency graph, then nothing needs to be recompiled. 518*9bb1b549SSpandan Das arc_data_list = depset(transitive = [get_archive(dep).transitive for dep in external_source.deps]).to_list() 519*9bb1b549SSpandan Das label_to_arc_data = {a.label: a for a in arc_data_list} 520*9bb1b549SSpandan Das if all([l not in label_to_arc_data for l in library_labels]): 521*9bb1b549SSpandan Das return external_source, internal_archive 522*9bb1b549SSpandan Das 523*9bb1b549SSpandan Das # Build a depth-first post-order list of dependencies starting with the 524*9bb1b549SSpandan Das # external archive. Each archive appears after its dependencies and before 525*9bb1b549SSpandan Das # its dependents. 526*9bb1b549SSpandan Das # 527*9bb1b549SSpandan Das # This is tricky because Starlark doesn't support recursion or while loops. 528*9bb1b549SSpandan Das # We simulate a while loop by iterating over a list of 2N elements where 529*9bb1b549SSpandan Das # N is the number of archives. Each archive is pushed onto the stack 530*9bb1b549SSpandan Das # twice: once before its dependencies are pushed, and once after. 531*9bb1b549SSpandan Das 532*9bb1b549SSpandan Das # dep_list is the post-order list of dependencies we're building. 533*9bb1b549SSpandan Das dep_list = [] 534*9bb1b549SSpandan Das 535*9bb1b549SSpandan Das # stack is a stack of targets to process. We're done when it's empty. 536*9bb1b549SSpandan Das stack = [get_archive(dep).data.label for dep in external_source.deps] 537*9bb1b549SSpandan Das 538*9bb1b549SSpandan Das # deps_pushed tracks the status of each target. 539*9bb1b549SSpandan Das # DEPS_UNPROCESSED means the target is on the stack, but its dependencies 540*9bb1b549SSpandan Das # are not. 541*9bb1b549SSpandan Das # Non-negative integers are the number of dependencies on the stack that 542*9bb1b549SSpandan Das # still need to be processed. 543*9bb1b549SSpandan Das # A target is on the stack if its status is DEPS_UNPROCESSED or 0. 544*9bb1b549SSpandan Das DEPS_UNPROCESSED = -1 545*9bb1b549SSpandan Das deps_pushed = {l: DEPS_UNPROCESSED for l in stack} 546*9bb1b549SSpandan Das 547*9bb1b549SSpandan Das # dependents maps labels to lists of known dependents. When a target is 548*9bb1b549SSpandan Das # processed, its dependents' deps_pushed count is deprecated. 549*9bb1b549SSpandan Das dependents = {l: [] for l in stack} 550*9bb1b549SSpandan Das 551*9bb1b549SSpandan Das # step is a list to iterate over to simulate a while loop. i tracks 552*9bb1b549SSpandan Das # iterations. 553*9bb1b549SSpandan Das step = [None] * (2 * len(arc_data_list)) 554*9bb1b549SSpandan Das i = 0 555*9bb1b549SSpandan Das for _ in step: 556*9bb1b549SSpandan Das if len(stack) == 0: 557*9bb1b549SSpandan Das break 558*9bb1b549SSpandan Das i += 1 559*9bb1b549SSpandan Das 560*9bb1b549SSpandan Das label = stack.pop() 561*9bb1b549SSpandan Das if deps_pushed[label] == 0: 562*9bb1b549SSpandan Das # All deps have been added to dep_list. Append this target to the 563*9bb1b549SSpandan Das # list. If a dependent is not waiting for anything else, push 564*9bb1b549SSpandan Das # it back onto the stack. 565*9bb1b549SSpandan Das dep_list.append(label) 566*9bb1b549SSpandan Das for p in dependents.get(label, []): 567*9bb1b549SSpandan Das deps_pushed[p] -= 1 568*9bb1b549SSpandan Das if deps_pushed[p] == 0: 569*9bb1b549SSpandan Das stack.append(p) 570*9bb1b549SSpandan Das continue 571*9bb1b549SSpandan Das 572*9bb1b549SSpandan Das # deps_pushed[label] == None, indicating we don't know whether this 573*9bb1b549SSpandan Das # targets dependencies have been processed. Other targets processed 574*9bb1b549SSpandan Das # earlier may depend on them. 575*9bb1b549SSpandan Das deps_pushed[label] = 0 576*9bb1b549SSpandan Das arc_data = label_to_arc_data[label] 577*9bb1b549SSpandan Das for c in arc_data._dep_labels: 578*9bb1b549SSpandan Das if c not in deps_pushed: 579*9bb1b549SSpandan Das # Dependency not seen yet; push it. 580*9bb1b549SSpandan Das stack.append(c) 581*9bb1b549SSpandan Das deps_pushed[c] = None 582*9bb1b549SSpandan Das deps_pushed[label] += 1 583*9bb1b549SSpandan Das dependents[c] = [label] 584*9bb1b549SSpandan Das elif deps_pushed[c] != 0: 585*9bb1b549SSpandan Das # Dependency pushed, not processed; wait for it. 586*9bb1b549SSpandan Das deps_pushed[label] += 1 587*9bb1b549SSpandan Das dependents[c].append(label) 588*9bb1b549SSpandan Das if deps_pushed[label] == 0: 589*9bb1b549SSpandan Das # No dependencies to wait for; push self. 590*9bb1b549SSpandan Das stack.append(label) 591*9bb1b549SSpandan Das if i != len(step): 592*9bb1b549SSpandan Das fail("assertion failed: iterated %d times instead of %d" % (i, len(step))) 593*9bb1b549SSpandan Das 594*9bb1b549SSpandan Das # Determine which dependencies need to be recompiled because they depend 595*9bb1b549SSpandan Das # on embedded libraries. 596*9bb1b549SSpandan Das need_recompile = {} 597*9bb1b549SSpandan Das for label in dep_list: 598*9bb1b549SSpandan Das arc_data = label_to_arc_data[label] 599*9bb1b549SSpandan Das need_recompile[label] = any([ 600*9bb1b549SSpandan Das dep in library_labels or need_recompile[dep] 601*9bb1b549SSpandan Das for dep in arc_data._dep_labels 602*9bb1b549SSpandan Das ]) 603*9bb1b549SSpandan Das 604*9bb1b549SSpandan Das # Recompile the internal archive without dependencies that need 605*9bb1b549SSpandan Das # recompilation. This breaks a cycle which occurs because the deps list 606*9bb1b549SSpandan Das # is shared between the internal and external archive. The internal archive 607*9bb1b549SSpandan Das # can't import anything that imports itself. 608*9bb1b549SSpandan Das internal_source = internal_archive.source 609*9bb1b549SSpandan Das 610*9bb1b549SSpandan Das internal_deps = [] 611*9bb1b549SSpandan Das 612*9bb1b549SSpandan Das # Pass internal dependencies that need to be recompiled down to the builder to check if the internal archive 613*9bb1b549SSpandan Das # tries to import any of the dependencies. If there is, that means that there is a dependency cycle. 614*9bb1b549SSpandan Das need_recompile_deps = [] 615*9bb1b549SSpandan Das for dep in internal_source.deps: 616*9bb1b549SSpandan Das dep_data = get_archive(dep).data 617*9bb1b549SSpandan Das if not need_recompile[dep_data.label]: 618*9bb1b549SSpandan Das internal_deps.append(dep) 619*9bb1b549SSpandan Das else: 620*9bb1b549SSpandan Das need_recompile_deps.append(dep_data.importpath) 621*9bb1b549SSpandan Das 622*9bb1b549SSpandan Das x_defs = dict(internal_source.x_defs) 623*9bb1b549SSpandan Das x_defs.update(internal_archive.x_defs) 624*9bb1b549SSpandan Das attrs = structs.to_dict(internal_source) 625*9bb1b549SSpandan Das attrs["deps"] = internal_deps 626*9bb1b549SSpandan Das attrs["x_defs"] = x_defs 627*9bb1b549SSpandan Das internal_source = GoSource(**attrs) 628*9bb1b549SSpandan Das internal_archive = go.archive(go, internal_source, _recompile_suffix = ".recompileinternal", recompile_internal_deps = need_recompile_deps) 629*9bb1b549SSpandan Das 630*9bb1b549SSpandan Das # Build a map from labels to possibly recompiled GoArchives. 631*9bb1b549SSpandan Das label_to_archive = {} 632*9bb1b549SSpandan Das i = 0 633*9bb1b549SSpandan Das for label in dep_list: 634*9bb1b549SSpandan Das i += 1 635*9bb1b549SSpandan Das recompile_suffix = ".recompile%d" % i 636*9bb1b549SSpandan Das 637*9bb1b549SSpandan Das # If this library is the internal archive, use the recompiled version. 638*9bb1b549SSpandan Das if label == internal_archive.data.label: 639*9bb1b549SSpandan Das label_to_archive[label] = internal_archive 640*9bb1b549SSpandan Das continue 641*9bb1b549SSpandan Das 642*9bb1b549SSpandan Das # If this is a library embedded into the internal test archive, 643*9bb1b549SSpandan Das # use the internal test archive instead. 644*9bb1b549SSpandan Das if label in library_labels: 645*9bb1b549SSpandan Das label_to_archive[label] = internal_archive 646*9bb1b549SSpandan Das continue 647*9bb1b549SSpandan Das 648*9bb1b549SSpandan Das # Create a stub GoLibrary and GoSource from the archive data. 649*9bb1b549SSpandan Das arc_data = label_to_arc_data[label] 650*9bb1b549SSpandan Das library = GoLibrary( 651*9bb1b549SSpandan Das name = arc_data.name, 652*9bb1b549SSpandan Das label = arc_data.label, 653*9bb1b549SSpandan Das importpath = arc_data.importpath, 654*9bb1b549SSpandan Das importmap = arc_data.importmap, 655*9bb1b549SSpandan Das importpath_aliases = arc_data.importpath_aliases, 656*9bb1b549SSpandan Das pathtype = arc_data.pathtype, 657*9bb1b549SSpandan Das resolve = None, 658*9bb1b549SSpandan Das testfilter = None, 659*9bb1b549SSpandan Das is_main = False, 660*9bb1b549SSpandan Das ) 661*9bb1b549SSpandan Das deps = [label_to_archive[d] for d in arc_data._dep_labels] 662*9bb1b549SSpandan Das source = GoSource( 663*9bb1b549SSpandan Das library = library, 664*9bb1b549SSpandan Das mode = go.mode, 665*9bb1b549SSpandan Das srcs = as_list(arc_data.srcs), 666*9bb1b549SSpandan Das orig_srcs = as_list(arc_data.orig_srcs), 667*9bb1b549SSpandan Das orig_src_map = dict(zip(arc_data.srcs, arc_data._orig_src_map)), 668*9bb1b549SSpandan Das cover = arc_data._cover, 669*9bb1b549SSpandan Das embedsrcs = as_list(arc_data._embedsrcs), 670*9bb1b549SSpandan Das x_defs = dict(arc_data._x_defs), 671*9bb1b549SSpandan Das deps = deps, 672*9bb1b549SSpandan Das gc_goopts = as_list(arc_data._gc_goopts), 673*9bb1b549SSpandan Das runfiles = go._ctx.runfiles(files = arc_data.data_files), 674*9bb1b549SSpandan Das cgo = arc_data._cgo, 675*9bb1b549SSpandan Das cdeps = as_list(arc_data._cdeps), 676*9bb1b549SSpandan Das cppopts = as_list(arc_data._cppopts), 677*9bb1b549SSpandan Das copts = as_list(arc_data._copts), 678*9bb1b549SSpandan Das cxxopts = as_list(arc_data._cxxopts), 679*9bb1b549SSpandan Das clinkopts = as_list(arc_data._clinkopts), 680*9bb1b549SSpandan Das cgo_exports = as_list(arc_data._cgo_exports), 681*9bb1b549SSpandan Das ) 682*9bb1b549SSpandan Das 683*9bb1b549SSpandan Das # If this archive needs to be recompiled, use go.archive. 684*9bb1b549SSpandan Das # Otherwise, create a stub GoArchive, using the original file. 685*9bb1b549SSpandan Das if need_recompile[label]: 686*9bb1b549SSpandan Das recompile_suffix = ".recompile%d" % i 687*9bb1b549SSpandan Das archive = go.archive(go, source, _recompile_suffix = recompile_suffix) 688*9bb1b549SSpandan Das else: 689*9bb1b549SSpandan Das archive = GoArchive( 690*9bb1b549SSpandan Das source = source, 691*9bb1b549SSpandan Das data = arc_data, 692*9bb1b549SSpandan Das direct = deps, 693*9bb1b549SSpandan Das libs = depset(direct = [arc_data.file], transitive = [a.libs for a in deps]), 694*9bb1b549SSpandan Das transitive = depset(direct = [arc_data], transitive = [a.transitive for a in deps]), 695*9bb1b549SSpandan Das x_defs = source.x_defs, 696*9bb1b549SSpandan Das cgo_deps = depset(direct = arc_data._cgo_deps, transitive = [a.cgo_deps for a in deps]), 697*9bb1b549SSpandan Das cgo_exports = depset(direct = list(source.cgo_exports), transitive = [a.cgo_exports for a in deps]), 698*9bb1b549SSpandan Das runfiles = source.runfiles, 699*9bb1b549SSpandan Das mode = go.mode, 700*9bb1b549SSpandan Das ) 701*9bb1b549SSpandan Das label_to_archive[label] = archive 702*9bb1b549SSpandan Das 703*9bb1b549SSpandan Das # Finally, we need to replace external_source.deps with the recompiled 704*9bb1b549SSpandan Das # archives. 705*9bb1b549SSpandan Das attrs = structs.to_dict(external_source) 706*9bb1b549SSpandan Das attrs["deps"] = [label_to_archive[get_archive(dep).data.label] for dep in external_source.deps] 707*9bb1b549SSpandan Das return GoSource(**attrs), internal_archive 708