thought-machine / please

High-performance extensible build system for reproducible multi-language builds.
https://please.build
Apache License 2.0
2.45k stars 205 forks source link

pkl + plz: multi-directory genrule outs #3123

Open sean- opened 6 months ago

sean- commented 6 months ago

Howdy. I've started tinkering with pkl and am pretty pleased with it (no pun intended), but am running into a few quirks integrating it into plz. Using the following example.pkl file:

@go.Package { name = "github.com/example/mycmd/pkl" }
module example.mycmd.Config
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.6.0#/go.pkl"

typealias LogLevel = "trace"|"debug"|"info"|"warn"|"error"
log_level: LogLevel = "trace"

foo_param: String

To generate the .go files by hand, you run:

pkl-gen-go --base-path=github.com/example/mycmd/pkl example.pkl

which emits the following files:

Config.pkl.go
init.pkl.go
loglevel/LogLevel.pkl.go

The problem is loglevel/LogLevel.pkl.go and my genrule() command. The BUILD.plz that I'm using now is:

# mycmd/pkl/BUILD.plz
go_library(
    name = "pkl",
    srcs = [
        ":gen-go",
    ],
    visibility = ["//mycmd/..."],
    deps = [
        ":gen-go",
        "//mycmd/pkl/loglevel",
    ],
)

PKL_FILENAME = "example.pkl"

genrule(
    name = "gen-go",
    srcs = [
        PKL_FILENAME,
    ],
    outs = [
        "Config.pkl.go",
        "init.pkl.go",
    ],
    # FIXME(seanc@): Replace env HOME garbage with
    # `--cache-dir=$(plz_out)/pkl-gen-go/v0.6.0` once it becomes available.
    cmd = "env HOME=$(echo $HOME | perl -p -e 's#plz-out(.*)#plz-out/.pkl-gen-go/v0.6.0#') pkl-gen-go --base-path=github.com/example/mycmd/resources/pkl/mycmd resources/pkl/mycmd/{}".format(PKL_FILENAME),
    exit_on_error = True,
    labels = ["codegen"],
    optional_outs = [
        PKL_FILENAME,
    ],
    tools = ["pkl-gen-go"],
)

and:

# mycmd/pkl/loglevel/BUILD.plz
go_library(
    name = "loglevel",
    srcs = [
        "LogLevel.pkl.go",
    ],
    visibility = ["//mycmd/pkl/..."],
    deps = [
        "//third_party/go:pkl",
    ],
)

If I add loglevel/LogLevel.pkl.go to outs, I get the following error:

$ plz build
Build stopped after 340ms. 1 target failed:
    //resources/pkl/optimizer:gen-go
trying to output file resources/pkl/optimizer/loglevel/LogLevel.pkl.go, but that directory belongs to another package (resources/pkl/optimizer/loglevel)

~Two~ One question:

  1. How do I copy loglevel/LogLevel.pkl.go so I don't need a random build file for every subdirectory? Ideally, outs would include loglevel/LogLevel.pkl.go and it would be copied to loglevel/LogLevel.pkl.go, but that doesn't appear to be the case. ~2. My editor's language server doesn't like the missing *.pkl..go files, so I have to manually generate the .pkl.go files in mycmd/pkl/. Is there a way to copy or have symlinks created for the generated files? Something like mycmd/pkl/Config.pkl.go -> ./plz-out/go/src/mycmd/pkl/Config.pkl.go? Protobuf has a similar problem, iirc.~
sean- commented 5 months ago

Regarding the second question, I'm going to answer my own question and post this here for future eyeballs. I just discovered the:

; .plzconfig
[Build]
LinkGeneratedSources = soft
UpdateGitignore = true

options and the codegen label, which generate the right symlinks automatically!

# BUILD.plz:
genrule(
    name = "gen-go",
    srcs = [
        PKL_FILENAME,
    ],
    outs = [
        "Config.pkl.go",
        "init.pkl.go",
    ],
    # FIXME(seanc@): Replace env HOME garbage with
    # `--cache-dir=$(plz_out)/pkl-gen-go/v0.6.0` once it becomes available.
    cmd = "env HOME=$(echo $HOME | perl -p -e 's#plz-out(.*)#plz-out/.pkl-gen-go/v0.6.0#') pkl-gen-go --base-path=github.com/example/mycmd/resources/pkl/mycmd resources/pkl/mycmd/{}".format(PKL_FILENAME),
    exit_on_error = True,
    labels = ["codegen"],
    optional_outs = [
        PKL_FILENAME,
    ],
    tools = ["pkl-gen-go"],
)
➜ ll resources/pkl/optimizer
total 40
-rw-r--r--  1 seanc  staff    10 Apr 17 22:29 .gitignore
-rw-r--r--  1 seanc  staff  1617 Apr 18 08:48 BUILD.plz
lrwxr-xr-x  1 seanc  staff    80 Apr 18 08:49 Config.pkl.go -> /Users/seanc/src/example/mycmd/plz-out/gen/resources/pkl/mycmd/Config.pkl.go
lrwxr-xr-x  1 seanc  staff    78 Apr 18 08:49 init.pkl.go -> /Users/seanc/src/example/mycmd/plz-out/gen/resources/pkl/mycmd/init.pkl.go
drwxr-xr-x  5 seanc  staff   160 Apr 17 22:29 loglevel
-rw-r--r--  1 seanc  staff  1972 Apr 17 22:29 mycmd.pkl
Tatskaari commented 5 months ago

I might suggest wrapping go_library() for your project:

_orig_go_lib = go_library

def go_library(name, src, pki_src, etc...):
    if not pki_srcs:
        return _orig_go_lib(...)
    else srcs += [genrule(...)] # the genrule from above
    return _orig_go_lib(...)

alternatively you can call this pki_go_library or something.