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