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

compile_command.json write to root directory #718

Open
pollend opened this issue Jul 13, 2024 · 7 comments
Open

compile_command.json write to root directory #718

pollend opened this issue Jul 13, 2024 · 7 comments

Comments

@pollend
Copy link
Contributor

pollend commented Jul 13, 2024

Is it possible to have a rule write to the root directory of the project? i can grab the file and copy it back to the root but is there a better way to do this?

genrule(
  name = 'compile_commands',
  out  = 'compile_commands.json',
  cmd  = 'cp $(location //:TF[full-compilation-database]) $OUT'
)
@cbarrete
Copy link
Contributor

You can't have a rule write outside of buck-out (without hacks anyway), but you can do something like buck2 build //my:target[full-compilation-database] --out ..

Unsollicited tip: --out - will print the contents of the output to stdout instead.

@pollend
Copy link
Contributor Author

pollend commented Jul 13, 2024

that's annoying. I couldn't get full-compilation-database to work with clangd. I ended up writing this bxl script so i can generate the correct commands for clangd.

cat $(buck2 bxl //compile_command.bxl:gen_compile_command -- --base_dir $(pwd))  > compile_commands.json
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load(
    "@prelude//cxx:comp_db.bzl",
    "CxxCompilationDbInfo",
)
load("@prelude//:paths.bzl", "paths")
load("@prelude//paths.bzl", "paths")

def _gen_compile_command(ctx: BxlContext) -> None:
    target_filter = ctx.cli_args.targets or "..."
    targets = ctx.configured_targets(target_filter, target_platform = ctx.cli_args.platform)

    entries = [] 
    infos = {}
    
    for target in targets:
        providers = ctx.analysis(target).providers()
        compile_db_info = providers.get(CxxCompilationDbInfo)
        if compile_db_info != None:
            infos |= compile_db_info.info
    for key in infos:
        cmd_entry = infos[key]
        entry = {}
        entry["directory"] = ctx.cli_args.base_dir 
        entry["file"] = cmd_entry.src.short_path
        cxx = cmd_entry.cxx_compile_cmd
        if cxx:
            entry["command"] = cmd_args(cxx.base_compile_cmd, cxx.argsfile.input_args[0], cmd_entry.args, delimiter = " ")

        entries.append(entry)
   
    actions = ctx.bxl_actions(target_platform = ctx.cli_args.platform).actions
    db_artifact = actions.write_json("compile_commands.json", entries)
    db_artifact_ensured = ctx.output.ensure(db_artifact)
    ctx.output.print(db_artifact_ensured)


gen_compile_command = bxl_main(
    impl = _gen_compile_command,
    cli_args = {
        "base_dir": cli_args.option(cli_args.string()),
        "targets": cli_args.option(cli_args.target_expr()),
        "platform": cli_args.option(cli_args.target_label())
    },
)

@cbarrete
Copy link
Contributor

Right, this is something which I've also hit and reported at #307. I personally worked around it by forking Meta's compile commands generation script and getting it to output absolute paths instead, so that my users don't have to call/learn about BXL.

It's really unfortunate that the defaults are just broken though, every new user is going to hit this. I really wish that Meta would change the defaults and opt into relative paths internally. Please chime in the other issue if you agree!

@pollend
Copy link
Contributor Author

pollend commented Jul 15, 2024

here is what i do for windows.

$CommandPath = buck2 bxl //compile_command.bxl:gen_compile_command -- --base_dir (Get-Location).Path
cat $CommandPath | Out-File compile_commands.json

@zjturner
Copy link
Contributor

I have a PR up that is -- imo anyway -- a better and faster compile_commands generator bxl. Note that it's easy to put outputs anywhere you want if you invoke python from the bxl, perhaps via an anonymous action. The python script can reach out of the sandbox, and you could (for example) pass it a path to the json as well as a path to the desired output location, and the python script can just copy it there.

@zjturner
Copy link
Contributor

#510

@pollend
Copy link
Contributor Author

pollend commented Aug 9, 2024

I've just been updating this script for my own use.

# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load(
    "@prelude//cxx:comp_db.bzl",
    "CxxCompilationDbInfo",
)
load("@prelude//paths.bzl", "paths")

def _gen_compile_command(ctx: BxlContext) -> None:
    entries = [] 
    query_targets = {}
    for filter in ctx.cli_args.filter:
        targets = ctx.configured_targets(filter, target_platform = ctx.cli_args.platform)
        for target in targets:
            query_targets[target.label.raw_target()] = target 

    for key in query_targets:
        target = query_targets[key]

        providers = ctx.analysis(target).providers()
        compile_db_info = providers.get(CxxCompilationDbInfo)

        if compile_db_info != None:
            for key in compile_db_info.info:
                cmd_entry = compile_db_info.info[key]
                entry = {}
                entry["directory"] = ctx.fs.abs_path_unsafe("root//") #"{}".format(target.label.path))
                entry["file"] = cmd_entry.src.short_path
                cxx = cmd_entry.cxx_compile_cmd
                if cxx:
                    entry["command"] = cmd_args(cxx.base_compile_cmd, cxx.argsfile.input_args[0], cmd_entry.args, delimiter = " ")
                entries.append(entry)
   
    actions = ctx.bxl_actions(target_platform = ctx.cli_args.platform).actions
    db_artifact = actions.write_json("compile_commands.json", entries)
    db_artifact_ensured = ctx.output.ensure(db_artifact)
    ctx.output.print(db_artifact_ensured)


gen_compile_command = bxl_main(
    impl = _gen_compile_command,
    cli_args = {
        "filter": cli_args.list(cli_args.target_expr()),
        "platform": cli_args.option(cli_args.target_label())
    },
)

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

3 participants