Closed kmoffett closed 1 year ago
The idea seems sound, but I would rather something like 'unspecified' or 'none' than 'any',
To clarify the intent. We might have a platform that adds the cpu:any constraint specifically so that no CPU based toolchains match and that selects on CPU fail unless you've gone to a specific transition. Right?
Is one of the goals here to guarantee caching across top-level flag settings?
What's the pseudocode of a bazel invocation / consuming rule? I think I saw in a related chat you want to apply this as a self-transition onto some rules you own?
Yes, essentially I have some rules where the output is intended to be architecture-independent, and I want to prohibit them from accidentally depending on a platform-specific executable.
As one example, when building a Debian package with arch "all", generally no architecture-specific executables should be included (though firmware images are an exception). By transitioning to this proposed //cpu:any
value, you can prevent any arch-specific toolchains from matching.
In my specific case, I have some internal rules that expect to produce arch-independent configuration outputs, and I want to prevent my users from accidentally depending on CPU-specific executables as data
inputs; they wouldn't be able to execute them directly in the configs anyways, and they would break cross-platform compatibility of the configs if they tried anyways.
(E.G. this could be an outgoing transition from a .deb
packaging rule for arch=all
packages, or as an incoming transition on a rule that produces architecture-independent data, which should also improve the cache hit rate in multi-arch builds)
As for the naming, there's some relevant prior art:
BuildArch: noarch
(vs BuildArch: x86_64
et. al.)Architecture: all
(vs Architecture: amd64
et. al.).dsc
: Architecture: any
(source package builds on any arch but produces arch-specific binary packages).I don't think //cpu:none
makes sense, because this is still usable to produce executables, they just need to be architecture-independent.
I'm not sure about //cpu:unspecified
either, because that sounds like it could get misused by accident for specialty compilers where we just don't know what CPU they target.
My intent with //cpu:any
(or perhaps //cpu:all
) is to reflect that this is building for all CPU architectures, it must not be specific to any single CPU, if that makes sense?
So the top-level would have to set some platform that consumes this setting (since you can't set or transition on a constraint_value
directly). What is that platform? Would there be multiple?
As I'm reading, you're saying the enforcement comes from no arch-specific toolchains matching. Like.. basically no cc targets could appear in the deps (without a transition) since they'd fundamentally require an arch-specific C++ toolchain?
Note I'm going OOO for two weeks. Hopefully @aiuto can pick up the thread.
Yes, there would need to be a platform created that specifies this constraint setting. And yes, the enforcement is from the fact that no arch-specific toolchain would match.
There will definitely be multiple platforms, because this CPU constraint doesn't have anything to do with which OS is used. For example, a shell-script is probably going to be cross-CPU compatible, but might still require //os:linux
.
In some cases, it actually might be plausible to have both arch-specific and arch-agnostic variants of the same target. Consider Java compilation, which produces arch-agnostic bytecode, but in some cases can use JNI libraries for better performance.
An existing rule might do:
java_library(
name = "foo",
srcs = ["Foo.java"],
deps = select({
"@platforms//cpu:x86_64": [":foo_jni_impl"],
"@platforms//cpu:armv7-mf": [":foo_jni_impl"],
"//conditions:default": [":foo_impl"],
}),
)
Even if the Java runtime doesn't support //cpu:any
(since it requires a concrete execution platform), the Java compiler could easily declare that it can build for //cpu:any
Then, a user could build arch-independent Java binaries by targeting a platform with //cpu:any
and be guaranteed not to rely on any JNI libraries.
Long discussion. Agreed on :all
Doesn't :all
conflict with the default Blaze-generated target that means "all targets in this package"?
Do not think the current impl is a good idea, i.e. a cpu:any target cannot be used where a cpu:x86_64 target is needed. To achive what you want better use the below.
load("@bazel_skylib//lib:selects.bzl", "selects")
selects.config_setting_group(
name = "any",
match_any = [
"@platforms//cpu:x86_64",
"@platforms//cpu:list_all_possible_values_in_match_any",
],
visibility = ["//visibility:private"],
)
alias(
name = "noarch",
actual = select({":any":"//:incompatible", "//conditions:default": "//conditions:default"})
)
We can have this noarch
in //os:BUILD
@aiuto for awareness.
@kmoffett PTAL at the above comment
Some builds are expected to only produce architecture-independent data files, such as configuration files, database seed data, composited images, or even some kinds of interpreted scripts (Shell, Python, Perl, etc).
When such a build is being performed, this constraint value may be used to ensure that architecture-dependent builds cannot be performed (except by way of another transition).
As a final example, consider building a package of NIC firmware images for many different NIC models. The package overall is architecture-independent, and should be built with
//cpu:any
, then each individual image rule has a transition to the suitable architecture for that specific NIC model.