facebook / buck2

Build system, successor to Buck
https://buck2.build/
Apache License 2.0
3.33k stars 194 forks source link

How to use multiple execution platforms #612

Open Overhatted opened 1 month ago

Overhatted commented 1 month ago

I have a project that can be built for either Linux or Windows, without any cross-compilation so Linux and Windows are also the two execution platforms. Since there is remote execution, I wanted to be able to build for Linux from my Windows machine using RE.

To keep this short I created a sample project: https://github.com/facebook/buck2/compare/main...Overhatted:buck2-strip-prefix:multiple_target_platforms It takes inspiration from the following issue: #487 The project just runs some Linux commands which obviously doesn't make sense to do on Windows but it's just a sample for me to understand the execution platform resolution.

When running "buck2 build --target-platforms root//platforms:linux tests:tests" on Windows, I wanted it to select the Linux execution platform automatically (since it's the only one with the "config//os/constraints:linux" constraint) but it tries to run it on the Windows platform, presumably because it is the first one declared, so I don't think I'm using the constraints correctly.

To reproduce the project above:

  1. Initialize the repository by running: buck2 init --git, cd prelude and then git reset --hard 3b5706b425a88a8641aad8d8ffcc6cdf441b9db0.
  2. Fill the correct remote execution information in .buckconfig
  3. Change the "container-image" value to point to a Windows and a Linux docker image available on the RE, depending on the value of platform_name.

Running the command, "buck2 build --target-platforms root//platforms:linux tests:tests", I wanted the genrule commands to be ran on Linux but instead they are ran on Windows, demonstrated by the error message I receive: 'Failed to start process: exec: "sh": executable file not found in %PATH%'

How can I add constraints to the execution platform so that Buck2 automatically selects the correct execution platform for the selected target platform?

JakobDegen commented 1 month ago

I wanted it to select the Linux execution platform automatically (since it's the only one with the "config//os/constraints:linux" constraint) but it tries to run it on the Windows platform, presumably because it is the first one declared

Correct.

How can I add constraints to the execution platform so that Buck2 automatically selects the correct execution platform for the selected target platform?

There is no general way to do that, but I'll explain how to solve your problem before I explain why.

You have a couple options and the best one depends on the particular situation. For this one, you have a :tests target that uses a bunch of cmd_args that assume things are running on Linux. In that case, it's appropriate to just set exec_compatible_with = ["config//os:linux"] on the target. This tells buck that that target can only be built on a Linux execution platform, and so it will not pick an execution platform that doesn't have the Linux constraint. This sort of case is somewhat common.

An equally common case is that someone has a build tool like a compiler that only supports running on a particular platform. This comes up particularly for things that don't support cross-compilation, where you end up with something like "I have to choose between three different compilers based on target platform, and all of them can only run on a specific execution platform." In that case, the preferred thing to do is to say target_compatible_with = ["config//os:windows"] on the compiler's target. Because the compiler's target should be an exec_dep of the target running the compiler (possibly via a toolchain), that target compatibility restriction will effect the execution platform of the target using the compiler.

Now getting back to why there's no way to express these restrictions on the platform definition: Note that in all of the above cases, the restrictions that we told buck about only apply to a specific target or a family of targets that all share some exec dep. This acknowledges the general principle that "which platform can this be built on" is a property that is local to a specific build step, and does not apply universally across a build, a target platform, or the repo. As a result, buck is in general happy to cross-compile only some parts of your build and not others. Coming from other build systems that might be surprising, but it is actually a good thing. It can help you make efficient use of resources by compiling things locally or using a cheaper remote execution platform (ie not mac). It also allows you to do things like have a single build which packages one component that must be built on Mac and one component that must be built on Windows.