如何:在 windows 上的 bazel 中使用 rules_go 生成 .so 文件

How to: generate .so file using rules_go in bazel on windows

我已经切换(或者,正在切换)到使用 bazel,尽管我在 Windows 上这样做。 我有兴趣从 Java 调用我的 Go 代码,所以我从 this tutorial.

开始

我能够使用与他们的 Github 示例相同的代码来完成这项工作,并且一切正常。我尝试将其适应我的 bazel 构建。如果我将 go build -o awesome.so -buildmode=c-shared awesome.go 生成的 awesome.so 文件作为资源包含在我的 java_library 中,我可以使一切正常工作。

相关文件如下所示。

然而,理想情况下,我希望通过 bazel 生成所有内容,但尽管到目前为止我进行了所有尝试,但我的 go_binary 规则始终输出 awesome.a(和 awesome.x)。如果我切换到使用 //go:awesome 作为来自 java:client_lib 的资源,我能够成功地将 awesome.a 输出视为资源,这表明让我的 go_binary 输出 awesome.so 是拼图的最后一块,但是正确的标志组合到目前为止还没有找到。

基本上我只是想让我的 go_binary 规则具有与 运行ning go build -o awesome.so --buildmode=c-shared awesome.go.

相同的行为

理论上,如果我需要另一条规则来弥合差距,我没问题,但由于我在 windows 并且 bash 到目前为止已经命中或未命中,使用 genrule 因为中间体目前看起来不太有前途。

请指教,谢谢!


工作区

...

# bazelbuild/rules_go for golang support.
http_archive(
    name = "io_bazel_rules_go",
    sha256 = "b725e6497741d7fc2d55fcc29a276627d10e43fa5d0bb692692890ae30d98d00",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.24.3/rules_go-v0.24.3.tar.gz",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.24.3/rules_go-v0.24.3.tar.gz",
    ],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

go_rules_dependencies()

go_register_toolchains()
...

go/awesome.go是从文章中复制过来的。
go/BUILD

load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

package(default_visibility = ["//visibility:public"])

go_binary(
    name = "awesome",
    srcs = glob(["*.go"]),
    cgo = True,
    copts = [
        "-fPIC",  # I tried adding this after some other reading about .a->.so
    ],
    gc_linkopts = [
        "-shared", # I think this is equivalent to the linkmode=c-shared below, but... <shrug>
    ],
    linkmode = "c-shared",
    static = "off",
)

# This one uses the pre-built awesome.so, and this works.
filegroup(
    name = "prebuilt_awesome_resource",
    srcs = ["awesome.so"],
)

java/Client.java 是从 github repo linked in the article 复制的(对库的位置稍作调整)。
java/BUILD

package(default_visibility = ["//visibility:public"])

java_import(
    name = "jna",
    jars = ["jna.jar"],
)

java_library(
    name = "client_lib",
    srcs = glob(["*.java"]),
    resources = [
        #        "//go:awesome",  # I'd rather use this one.
        "//go:prebuilt_awesome_resource",
    ],
    deps = [
        ":jna",
    ],
)

java_binary(
    name = "client",
    main_class = "Client",
    runtime_deps = [
        ":client_lib",
    ],
)

而且,因为重要的是 运行:

%programdata%/basel.bazelrc

startup --output_user_root="C:/_bazel_out"
build --compiler=mingw-gcc

这可能无法准确回答您的问题,但我可以举一个在 macOS 上从 C 程序调用 Go 共享库的示例。希望这能帮助您完成大部分工作。

  • 对于go_binary,你只需要linkmode = "c-shared"。对于包含 cgo 代码或具有导出定义的每个包,您还需要 cgo = True。您不需要 -shared-fPICstatic = "off".
  • 导出的定义应标有 //export 注释。
  • 有一个隐式声明的目标,其后缀为 .c_hdrs,用于为 Go 库构建头文件。在下面的示例中是 :go_hello.c_hdrs。实际头文件名是go_hello.h,匹配目标名
  • 您需要使用 cc_import 规则包装生成的文件,使其可用作 C/C++ 依赖项。 #2433 是一个未解决的问题来简化该过程,但它最近才在 Bazel 中成为可能。
  • 任何可以消耗 cc_library 的东西都可以以相同的方式消耗 cc_import 目标。所以你应该能够通过 JNI 调用 Go 函数,尽管我从未尝试过。

BUILD.bazel

load("@io_bazel_rules_go//go:def.bzl", "go_binary")

go_binary(
    name = "go_hello",
    srcs = ["hello.go"],
    cgo = True,
    linkmode = "c-shared",
)

cc_import(
    name = "c_hello",
    hdrs = [":go_hello.c_hdrs"],
    shared_library = ":go_hello",
)

cc_binary(
    name = "use",
    srcs = ["use.c"],
    deps = [":c_hello"],
)

hello.go

package main

import "fmt"
import "C"

//export SayHello
func SayHello() {
    fmt.Println("hello")
}

func main() {}

use.c

#include "go_hello.h"

int main() {
  SayHello();
  return 0;
}

嗯,我想我需要去耻辱魔方坐一会儿。

在我为编译器寻找的所有选项中,我错过了检查 go_binary 上的其他属性。具体来说,显而易见的是 out。实际对应 go build

上的 -o 标志的那个

我将 out = "awesome.so" 添加到我的 go_binary 规则中,果然,一切正常。

好吧,这浪费了几个小时。感谢 Jay 的帮助,很抱歉问了一个愚蠢的问题。