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

Rule depending on target #379

Open
cbarrete opened this issue Aug 6, 2023 · 2 comments
Open

Rule depending on target #379

cbarrete opened this issue Aug 6, 2023 · 2 comments

Comments

@cbarrete
Copy link
Contributor

cbarrete commented Aug 6, 2023

Hi,

I'm trying to write a rule that calls a binary that is an artifact of a buck2 target: the target is a compiler written in C++, the rule is meant to create targets built using that compiler.

To make things more concrete, I have the following (simplified) structure:

  • a compiler.cpp file, which can be built to get a my_lang compiler
  • a rules.bzl in which I define a my_lang_binary rule for building my_lang files
  • a BUCK file in which I define a compiler target using cxx_binary, as well as a target using my my_lang_binary rule
  • a main.my_lang which I would like to build using my_lang_binary

my_lang_binary currently only creates an empty file using touch. Instead I would like it to call the output binary of the compiler target defined in my BUCK file, but I haven't found a way for a .bzl file to depend on/load a BUCK file. Is this doable? If so how? If not, is there a suggested alternative approach that doesn't require e.g. first installing my compiler in my PATH and relying on that?

As a secondary issue, will buck2 be able to deal with the cyclic dependency (compiler defined in BUCK, custom rule defined in rules.bzl and depending on the target from BUCK, BUCK also calling this custom rule)? If not, I suppose that I'll have to create a subdirectory for the targets that use my custom my_lang_binary rule, as there can only be a single BUCK file per directory, right?

Thanks for your time, any pointers would be greatly appreciated!

@dtolnay
Copy link

dtolnay commented Aug 7, 2023

The compiler needs to come into the my_lang_binary rule as an execution dependency (attribute).

The cycle isn't going to be an issue.

# BUCK

load("//:rules.bzl", "my_lang_binary")

cxx_binary(
    name = "compiler",
    srcs = ["compiler.cpp"],
)

my_lang_binary(
    name = "main",
    srcs = ["main.my_lang"],
)
# rules.bzl

def _my_lang_binary_impl(ctx: AnalysisContext) -> list[Provider]:
    output = ctx.actions.declare_output("compiled")

    ctx.actions.run(
        [
            ctx.attrs.compiler[RunInfo],
            output.as_output(),
            ctx.attrs.srcs,
        ],
        category = "my_lang",
    )

    return [DefaultInfo(default_output = output)]

my_lang_binary = rule(
    impl = _my_lang_binary_impl,
    attrs = {
        "compiler": attrs.default_only(attrs.exec_dep(providers = [RunInfo], default = "//:compiler")),
        "srcs": attrs.list(attrs.source(), default = []),
    },
)
// compiler.cpp

#include <fstream>

int main(int argc, char *argv[]) {
  if (argc < 2) {
    return 1;
  }

  std::ofstream ofs{argv[1], std::ios::binary};

  for (int i = 2; i < argc; ++i) {
    std::ifstream ifs{argv[i], std::ios::binary};
    ofs << ifs.rdbuf();
    ifs.close();
    if (ifs.fail()) {
      return 1;
    }
  }

  ofs.close();
  if (ofs.fail()) {
    return 1;
  }
}

To build the compiler and run it on main.my_lang:

$ buck2 build :main --show-output

@cbarrete
Copy link
Contributor Author

cbarrete commented Aug 7, 2023

Thank you so much for your time and detailed answer, I've just reproduced it and it works flawlessly.
I'll have to read some more documentation about the pieces I wasn't aware of.
Would you like me to turn this into an example and submit a PR for it? I'd love to make this more accessible for anyone who might want to do something similar in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants