如何:在 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
、-fPIC
或 static = "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 的帮助,很抱歉问了一个愚蠢的问题。
我已经切换(或者,正在切换)到使用 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
、-fPIC
或static = "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 的帮助,很抱歉问了一个愚蠢的问题。