Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go: add assembler_flags field for adding arbitrary extra assembler flags #17731

Merged
merged 1 commit into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/python/pants/backend/go/target_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,32 @@ class GoTestAddressSanitizerEnabledField(GoRaceDetectorEnabledField):
)


class GoAssemblerFlagsField(StringSequenceField):
alias = "assembler_flags"
help = softwrap(
"""
Extra flags to pass to the Go assembler (i.e., `go tool asm`) when assembling Go-format assembly code.

Note: These flags will not be added to gcc/clang-format assembly that is assembled in packages using Cgo.

This field can be specified on several different target types:

- On `go_mod` targets, the assembler flags are used when building any package involving the module
including both first-party (i.e., `go_package` targets) and third-party dependencies.

- On `go_binary` targets, the assembler flags are used when building any packages comprising that binary
including third-party dependencies. These assembler flags will be added after any assembler flags
added by any `assembler_flags` field set on the applicable `go_mod` target.

- On `go_package` targets, the assembler flags are used only for building that specific package and not
for any other package. These assembler flags will be added after any assembler flags added by any
`assembler_flags` field set on the applicable `go_mod` target or applicable `go_binary` target.

Run `go doc cmd/asm` to see the flags supported by `go tool asm`.
"""
)


class GoCompilerFlagsField(StringSequenceField):
alias = "compiler_flags"
help = softwrap(
Expand Down Expand Up @@ -290,6 +316,7 @@ class GoModTarget(TargetGenerator):
GoRaceDetectorEnabledField,
GoMemorySanitizerEnabledField,
GoAddressSanitizerEnabledField,
GoAssemblerFlagsField,
GoCompilerFlagsField,
GoLinkerFlagsField,
)
Expand Down Expand Up @@ -372,6 +399,7 @@ class GoPackageTarget(Target):
GoTestRaceDetectorEnabledField,
GoTestMemorySanitizerEnabledField,
GoTestAddressSanitizerEnabledField,
GoAssemblerFlagsField,
GoCompilerFlagsField,
SkipGoTestsField,
)
Expand Down Expand Up @@ -420,6 +448,7 @@ class GoBinaryTarget(Target):
GoRaceDetectorEnabledField,
GoMemorySanitizerEnabledField,
GoAddressSanitizerEnabledField,
GoAssemblerFlagsField,
GoCompilerFlagsField,
GoLinkerFlagsField,
RestartableField,
Expand Down
2 changes: 2 additions & 0 deletions src/python/pants/backend/go/util_rules/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class AssembleGoAssemblyFilesRequest:
dir_path: str
asm_header_path: str | None
import_path: str
extra_assembler_flags: tuple[str, ...]


@dataclass(frozen=True)
Expand Down Expand Up @@ -160,6 +161,7 @@ def obj_output_path(s_file: str) -> str:
os.path.join(goroot.path, "pkg", "include"),
*maybe_asm_header_path_args,
*maybe_package_import_path_args,
*request.extra_assembler_flags,
"-o",
obj_output_path(s_file),
str(os.path.normpath(PurePath(".", request.dir_path, s_file))),
Expand Down
19 changes: 19 additions & 0 deletions src/python/pants/backend/go/util_rules/build_opts.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pants.backend.go.subsystems.gotest import GoTestSubsystem
from pants.backend.go.target_types import (
GoAddressSanitizerEnabledField,
GoAssemblerFlagsField,
GoCgoEnabledField,
GoCompilerFlagsField,
GoLinkerFlagsField,
Expand Down Expand Up @@ -62,6 +63,11 @@ class GoBuildOptions:
# Note: These flags come from `go_mod` and `go_binary` targets.
linker_flags: tuple[str, ...] = ()

# Extra flags to pass to the Go assembler (i.e., `go tool asm`).
# Note: These flags come from `go_mod` and `go_binary` targets. Package-specific assembler flags
# may still come from `go_package` targets.
assembler_flags: tuple[str, ...] = ()

def __post_init__(self):
assert not (self.with_race_detector and self.with_msan)
assert not (self.with_race_detector and self.with_asan)
Expand Down Expand Up @@ -94,6 +100,7 @@ class GoBuildOptionsFieldSet(FieldSet):
asan: GoAddressSanitizerEnabledField
compiler_flags: GoCompilerFlagsField
linker_flags: GoLinkerFlagsField
assembler_flags: GoAssemblerFlagsField


@dataclass(frozen=True)
Expand Down Expand Up @@ -350,13 +357,25 @@ async def go_extract_build_options_from_target(
if target_fields is not None:
linker_flags.extend(target_fields.linker_flags.value or [])

# Extract any extra assembler flags specified on `go_mod` or `go_binary` targets.
# Note: An `assembler_flags` field specified on a `go_package` target is extracted elsewhere.
assembler_flags: list[str] = []
if go_mod_target_fields is not None:
# To avoid duplication of options, only add the module-specific assembler flags if the target for this request
# is not a `go_mod` target (i.e., because it does not conform to the field set or has a different address).
if target_fields is None or go_mod_target_fields.address != target_fields.address:
assembler_flags.extend(go_mod_target_fields.assembler_flags.value or [])
if target_fields is not None:
assembler_flags.extend(target_fields.assembler_flags.value or [])

return GoBuildOptions(
cgo_enabled=cgo_enabled,
with_race_detector=with_race_detector,
with_msan=with_msan,
with_asan=with_asan,
compiler_flags=tuple(compiler_flags),
linker_flags=tuple(linker_flags),
assembler_flags=tuple(assembler_flags),
)


Expand Down
74 changes: 74 additions & 0 deletions src/python/pants/backend/go/util_rules/build_opts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,77 @@ def assert_flags(address: Address, expected_value: Iterable[str]) -> None:
assert_flags(Address("mod_with_field", target_name="mod"), ["-foo"])
assert_flags(Address("mod_with_field", target_name="bin_without_field"), ["-foo"])
assert_flags(Address("mod_with_field", target_name="bin_with_field"), ["-foo", "-bar"])


def test_assembler_flags_fields(rule_runner: RuleRunner) -> None:
rule_runner.write_files(
{
"mod_with_field/BUILD": dedent(
"""\
go_mod(
name="mod",
assembler_flags=["-foo"],
)

go_package(name="pkg")

go_binary(
name="bin_without_field",
)

go_binary(
name="bin_with_field",
assembler_flags=["-bar"],
)
"""
),
"mod_with_field/go.mod": "module example.pantsbuild.org/mod_with_field\n",
"mod_with_field/main.go": dedent(
"""\
package main
func main() {}
"""
),
"mod_with_field/pkg_with_field/BUILD": dedent(
"""
go_package(
assembler_flags=["-xyzzy"],
)
"""
),
"mod_with_field/pkg_with_field/foo.go": dedent(
"""\
package pkg_with_field
"""
),
}
)

def assert_flags(address: Address, expected_value: Iterable[str]) -> None:
opts = rule_runner.request(
GoBuildOptions,
(
GoBuildOptionsFromTargetRequest(
address=address,
),
),
)
assert opts.assembler_flags == tuple(
expected_value
), f"{address}: expected `assembler_flags` to be {expected_value}"

assert_flags(Address("mod_with_field", target_name="mod"), ["-foo"])
assert_flags(Address("mod_with_field", target_name="bin_without_field"), ["-foo"])
assert_flags(Address("mod_with_field", target_name="bin_with_field"), ["-foo", "-bar"])
assert_flags(Address("mod_with_field", target_name="pkg"), ["-foo"])
assert_flags(Address("mod_with_field/pkg_with_field"), ["-foo"])

build_request = rule_runner.request(
BuildGoPackageRequest,
[
BuildGoPackageTargetRequest(
Address("mod_with_field/pkg_with_field"), build_opts=GoBuildOptions()
)
],
)
assert build_request.pkg_specific_assembler_flags == ("-xyzzy",)
10 changes: 9 additions & 1 deletion src/python/pants/backend/go/util_rules/build_pkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def __init__(
fortran_files: tuple[str, ...] = (),
prebuilt_object_files: tuple[str, ...] = (),
pkg_specific_compiler_flags: tuple[str, ...] = (),
pkg_specific_assembler_flags: tuple[str, ...] = (),
) -> None:
"""Build a package and its dependencies as `__pkg__.a` files.

Expand Down Expand Up @@ -105,6 +106,7 @@ def __init__(
self.fortran_files = fortran_files
self.prebuilt_object_files = prebuilt_object_files
self.pkg_specific_compiler_flags = pkg_specific_compiler_flags
self.pkg_specific_assembler_flags = pkg_specific_assembler_flags
self._hashcode = hash(
(
self.import_path,
Expand All @@ -127,6 +129,7 @@ def __init__(
self.fortran_files,
self.prebuilt_object_files,
self.pkg_specific_compiler_flags,
self.pkg_specific_assembler_flags,
)
)

Expand Down Expand Up @@ -154,7 +157,8 @@ def __repr__(self) -> str:
f"objc_files={self.objc_files}, "
f"fortran_files={self.fortran_files}, "
f"prebuilt_object_files={self.prebuilt_object_files}, "
f"pkg_specific_compiler_flags={self.pkg_specific_compiler_flags}"
f"pkg_specific_compiler_flags={self.pkg_specific_compiler_flags}, "
f"pkg_specific_assembler_flags={self.pkg_specific_assembler_flags}"
")"
)

Expand Down Expand Up @@ -185,6 +189,7 @@ def __eq__(self, other):
and self.fortran_files == other.fortran_files
and self.prebuilt_object_files == other.prebuilt_object_files
and self.pkg_specific_compiler_flags == other.pkg_specific_compiler_flags
and self.pkg_specific_assembler_flags == other.pkg_specific_assembler_flags
# TODO: Use a recursive memoized __eq__ if this ever shows up in profiles.
and self.direct_dependencies == other.direct_dependencies
)
Expand Down Expand Up @@ -628,6 +633,9 @@ async def build_go_package(
dir_path=request.dir_path,
asm_header_path=asm_header_path,
import_path=request.import_path,
extra_assembler_flags=tuple(
*request.build_opts.assembler_flags, *request.pkg_specific_assembler_flags
),
),
)
assembly_result = assembly_fallible_result.result
Expand Down
8 changes: 8 additions & 0 deletions src/python/pants/backend/go/util_rules/build_pkg_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pants.backend.go.dependency_inference import GoModuleImportPathsMapping
from pants.backend.go.target_type_rules import GoImportPathMappingRequest
from pants.backend.go.target_types import (
GoAssemblerFlagsField,
GoCompilerFlagsField,
GoImportPathField,
GoPackageSourcesField,
Expand Down Expand Up @@ -287,6 +288,12 @@ async def setup_build_go_package_target_request(
if compiler_flags_field and compiler_flags_field.value:
pkg_specific_compiler_flags = compiler_flags_field.value

pkg_specific_assembler_flags: tuple[str, ...] = ()
if target.has_field(GoAssemblerFlagsField):
assembler_flags_field = target.get(GoAssemblerFlagsField)
if assembler_flags_field and assembler_flags_field.value:
pkg_specific_assembler_flags = assembler_flags_field.value

all_direct_dependencies = await Get(Targets, DependenciesRequest(target[Dependencies]))

first_party_dep_import_path_targets = []
Expand Down Expand Up @@ -398,6 +405,7 @@ async def setup_build_go_package_target_request(
embed_config=embed_config,
with_coverage=with_coverage,
pkg_specific_compiler_flags=tuple(pkg_specific_compiler_flags),
pkg_specific_assembler_flags=tuple(pkg_specific_assembler_flags),
)
return FallibleBuildGoPackageRequest(result, import_path)

Expand Down