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

V2 #249

Open
peterebden opened this issue Mar 13, 2024 · 1 comment
Open

V2 #249

peterebden opened this issue Mar 13, 2024 · 1 comment

Comments

@peterebden
Copy link
Contributor

peterebden commented Mar 13, 2024

I've said informally in a bunch of places that I want to do a v2 of this plugin. The changes would include:

  • Require go_toolchain (or go_system_toolchain)
  • Require go_stdlib to be used
  • Remove install_std stuff from go_toolchain
  • Possibly simplify/restructure go_toolchain if all that gotool really needs is the binary (little unsure here but I'd like to optimise it better for not passing heaps of files around the place)
  • Remove go_module in favour of go_repo
  • Remove legacy_imports config option
  • Remove coverageredesign config option, make it always on
  • Move cgo_test (Move cgo_test to cgo.build_defs #217)
  • Get rid of all the stdlib-specific stuff in the package driver (it's obsolete once go_stdlib is in use and it doesn't fully work properly now since we can't easily find where the compiled artifacts are)
  • The minimum supported Go version is at least v1.20 (for coverageredesign if nothing else)
  • Remove any dead code (notably please_go/install and the old paths in please_go/gotest, plus anything in the defs)
  • Anything else?
@izissise
Copy link
Contributor

izissise commented Mar 16, 2024

Hello, I'm made a modded version of go-rules, because I need the following features:

  • Multiple toolchains declaration for different architecture/os/go_version combos
  • No dependency on cc_library for cgo
  • Auto dependencies
  • Build function (go_repo, ...) take toolchain rule has parameter

Note: bl is an alias to buildlabel has described here thought-machine/please#3110
it is used here mainly to get full labels to put in files later included in subrepos

The gist of the code is this:

# /golang/golang.build_defs

def go_toolchain(
    name: str,
    architecture: str,
    srcs: list,
    visibility: list,
    go_subrepo_defs: list,
    go_defs: list,
    tags: list = [],
    copy_cmd: str = "tar -xf $SRCS_TL && mv go $OUTS_TL",
    strip_srcs: bool = False,
    install_std: bool = None,
    default_static=True,
    buildmode="",
    cgo_enabled=1,
    please_go_tool=[],
    go_auto_deps=[],
    cc_tool="",
    ar_tool="",
    strip_tool="",
    ld_tool="",
    c_flags=[],
    ld_flags=[],
):
    if not architecture:
        architecture = f"{CONFIG.HOSTOS}_{CONFIG.HOSTARCH}"

    cmd = f'set -eux && export GODEBUG="installgoroot=all" && {copy_cmd} && chmod +x $OUTS_TL/bin/*; rm -rf $OUTS_TL/test'

    flags = " ".join(c_flags)
    ld_flags = " ".join(ld_flags)
    cmd += f' && export CGO_ENABLED=1 && export CFLAGS="{flags}" && export CC=$TOOLS_CC'

    tag_flag = (" -tags " + ",".join(tags)) if tags else ""
    goos, _, goarch = architecture.partition("_")
    cmd += f" && (export GOOS={goos} && export GOARCH={goarch} && $OUTS_TL/bin/go install{tag_flag} --trimpath std)"

    if install_std:
        cmd += f" && {{ $OUTS_TL/bin/go install{tag_flag} --trimpath std || true; }}"
    if strip_srcs:
        trim_toolchain = "mv $OUTS_TL/src src && mkdir $OUTS_TL/src && mv src/unsafe $OUTS_TL/src/unsafe"
        cmd = f"{cmd} && {trim_toolchain}"

    script = 'prg=${0##*/} && dir=$(cd "${BASH_SOURCE%/*}" && pwd) && export PATH="$dir/../bin":"$PATH" && hash -r;'
    script += f"export CGO_ENABLED={cgo_enabled} && export GOOS={goos} && export GOARCH={goarch};"
    script += 'exec "$prg" "$@"'

    cmd += f"""
        mkdir $OUTS_TL/plz/ && printf '#!/bin/env bash\n%s\n' '{script}' > $OUTS_TL/plz/h && chmod +x $OUTS_TL/plz/h && (
            cd $OUTS_TL/plz/;
            ln -s h go
            ln -s h gofmt;
            ln -s h please_go;
            ln -s h go_auto_deps;
        );
        # Lets copy tools and defs
        mv "$SRCS_GO_AUTO_DEPS" $OUTS_TL/bin/go_auto_deps
        mv "$SRCS_PLEASE_GO" $OUTS_TL/bin/please_go
        mv "$SRCS_TL_DEFS" $OUTS_TL_DEFS
    """

    please_go_tool_tl = bl(target=name, subtarget="please_go", aslist=False)
    go_tool = bl(target=name, subtarget="go", aslist=False)
    subrepo_def = bl(
        target=text_file(
            name=f"{name}.subrepo.build_defs",
            visibility=["PUBLIC"],
            strip=True,
            content="subinclude("
            + json(go_subrepo_defs)
            + ")"
            + f"""
            CONFIG["OS"] = '{goos}'
            CONFIG["ARCH"] = '{goarch}'
            CONFIG["GO"] = {{
                'PLEASE_GO_TOOL': '{please_go_tool_tl}',
                'GO_TOOL': '{go_tool}',
                'AR_TOOL': '{ar_tool}',
                'CC_TOOL': '{cc_tool}',
                'STRIP_TOOL': '{strip_tool}',
                'C_FLAGS': [],
                'LD_FLAGS': [],
                'BUILD_TAGS': [],
                'BUILDMODE': '{buildmode}',
                'CGO_ENABLED': '{cgo_enabled}',
                'COVERAGEREDESIGN': False,
                'CPP_COVERAGE': False,
                'DEFAULT_STATIC': {default_static},
                'DELVE_TOOL': 'dlv',
                'PKG_INFO': True,
                'RACE': False,
                'TEST_ROOT_COMPAT': False,
                'VALIDATE_MODULE_VERSION': False,
                'IMPORT_PATH': None,
                'LEGACY_IMPORTS': None,
                'SPLIT_DEBUG_INFO': None,
                'REQUIRE_LICENCES': None,
                'STDLIB': None,
            }}
        """,
        ),
    )
    return build_rule(
        name=name,
        srcs={
            "tl": srcs,
            "please_go": please_go_tool,
            "go_auto_deps": go_auto_deps,
            "tl_defs": [
                text_file(
                    name=f"{name}.build_defs",
                    strip=True,
                    content=f"""
                    tl_goos = '{goos}'
                    tl_goarch = '{goarch}'
                """
                    + "tl_go_defs = "
                    + json(go_defs)
                    + "\n"
                    + "tl_subrepo_defs = "
                    + json(subrepo_def)
                    + "\n",
                )
            ],
        },
        cmd=cmd,
        outs={
            "tl": [name],
            "tl_defs": [f"{name}_toolchain.build_defs"],
        },
        entry_points={
            "go": f"{name}/plz/go",
            "gofmt": f"{name}/plz/gofmt",
            "please_go": f"{name}/plz/please_go",
            "go_auto_deps": f"{name}/plz/go_auto_deps",
        },
        tools={
            "CC": [cc_tool],
        },
        binary=True,
        visibility=visibility,
        building_description="🧰 Installing...",
    )


def go_toolchain_get(version: str = "", url: str = "", hashes: list = []):
    if url and version:
        fail("Either version or url should be provided but not both")

    if version:
        sdk_url = f"https://golang.org/dl/go{version}.{CONFIG.HOSTOS}-{CONFIG.HOSTARCH}.tar.gz"
    else:
        sdk_url = (
            url if isinstance(url, str) else url[f"{CONFIG.HOSTOS}-{CONFIG.HOSTARCH}"]
        )

    return remote_file(
        name=f"golang_{CONFIG.HOSTOS}_{CONFIG.HOSTARCH}_{version}",
        _tag="download",
        url=sdk_url,
        hashes=hashes,
    )

def go_toolchains_init(go_rule_version: str):
    go_build_defs = remote_file(
        name=f"go_build_defs_{go_rule_version}",
        url=[
            f"https://raw.githubusercontent.com/please-build/go-rules/v{go_rule_version}/build_defs/go.build_defs"
        ],
    )

    subrepo_defs = bl(
        target=genrule(
            name=f"subrepo_defs_{go_rule_version}",
            srcs=[go_build_defs, "golang_ext.subrepo.build_defs"],
            outs=["go.subrepo.build_defs"],
            cmd="cat $SRCS > $OUT",
        )
    )

    go_auto_deps = bl(
        target=filegroup(
            name=f"go_auto_deps_{go_rule_version}",
            binary=True,
            srcs=["go_auto_deps.sh"],
        )
    )

    subinclude(  # FIXME defer this subinclude because it does a network call
        genrule(
            name=f"please_go_def_{go_rule_version}_func",
            srcs=[
                remote_file(
                    name=f"please_go_tool_def_{go_rule_version}",
                    url=[
                        f"https://raw.githubusercontent.com/please-build/go-rules/v{go_rule_version}/tools/BUILD"
                    ],
                )
            ],
            outs=["please_go.build_defs"],
            cmd="""
            set -eux
            { printf 'def please_go_def():\n' && awk '{print "  " $0}' "$SRCS" && printf '  return ":please_go"'; } > "$OUTS"
        """,
        )
    )
    please_go_tool = bl(target=please_go_def())
    # return global labels
    return subrepo_defs, please_go_tool, go_auto_deps
    
def go_repository(
    module: str,
    toolchain: str,
    version: str = "",
    download: str = None,
    name: str = None,
    install: list = [],
    requirements: list = [],
    licences: list = None,
    patch: list = None,
    visibility: list = ["PUBLIC"],
    deps: list = [],
    build_tags: list = [],
    third_party_path: str = "",
    strip: list = None,
    labels: list = [],
    buildmode: str = "",
    auto_deps: bool = False,
):
    pass # I can give you the rest of the code if it interest you
# /golang/BUILD
defs = bl(
    target=filegroup(
        name="defs",
        srcs=["golang.build_defs"],
    ),
)

subinclude(defs)

go_subrepo_defs, please_go_tool, go_auto_deps = go_toolchains_init(
    CONFIG.GO_RULES_VERSION
)

versions = ["1.21.3", "1.22.0"]
archs = [
    {
        "arch": "linux_arm64",
        "cc": "aarch64-linux-gnu-gcc",
        "ar": "aarch64-linux-gnu-ar",
        "strip": "aarch64-linux-gnu-strip",
    },
    {
        "arch": "linux_amd64",
        "cc": "gcc",
        "ar": "ar",
        "strip": "strip",
    },
]
for v in versions:
    go_tl_src = go_toolchain_get(
        version=v,
        hashes=[
            "6f5bb222c12a62111713c5dba1e05e25073f49e17ee5b10ab109080f5d2ddcd1",  # 1.21.3 darwin-amd64
            "7fec0a270e5172d098b74bb3480ae1d9b14e8c0f5013c9b317e61d77cef8d9c3",  # 1.21.3 darwin-arm64
            "eda6cf7495c95fc3f57d3a62cb63d321269198e1a6960563a1d894ed767b1301",  # 1.21.3 freebsd-amd64
            "1241381b2843fae5a9707eec1f8fb2ef94d827990582c7c7c32f5bdfbfd420c8",  # 1.21.3 linux-amd64
            "fc90fa48ae97ba6368eecb914343590bbb61b388089510d0c56c2dde52987ef3",  # 1.21.3 linux-arm64
            "ebca81df938d2d1047cc992be6c6c759543cf309d401b86af38a6aed3d4090f4",  # 1.22.0 darwin-amd64
            "bf8e388b09134164717cd52d3285a4ab3b68691b80515212da0e9f56f518fb1e",  # 1.22.0 darwin-arm64
            "f6c8a87aa03b92c4b0bf3d558e28ea03006eb29db78917daec5cfb6ec1046265",  # 1.22.0 linux-amd64
            "6a63fef0e050146f275bf02a0896badfe77c11b6f05499bb647e7bd613a45a10",  # 1.22.0 linux-arm64
        ],
    )
    for a in archs:
        go_toolchain(
            name=f"{v}_{a.arch}",
            visibility=["PUBLIC"],
            srcs=[go_tl_src],
            architecture=a.arch,
            install_std=True,
            go_defs=defs,
            go_subrepo_defs=go_subrepo_defs,
            please_go_tool=please_go_tool,
            go_auto_deps=go_auto_deps,
            cc_tool=a.cc,
            ar_tool=a.ar,
            strip_tool=a.strip,
        )

This give multiple toolchain available named 1.21.3_linux_arm64 etc that can be given to go_repository

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