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