我想在工作区中下载并构建ruby。我一直在尝试通过模仿rules_go来实现这一点。我有那部分工作。我遇到的问题是,每次调用ruby_download_sdk
时,它都会重建openssl和ruby工件。在下面的代码中,下载工件被缓存,但是始终执行openssl和ruby的构建。
def ruby_download_sdk(name, version = None):
# TODO detect os and arch
os, arch = "osx", "x86_64"
_ruby_download_sdk(
name = name,
version = version,
)
_register_toolchains(name, os, arch)
def _ruby_download_sdk_impl(repository_ctx):
# TODO detect platform
platform = ("osx", "x86_64")
_sdk_build_file(repository_ctx, platform)
_remote_sdk(repository_ctx)
_ruby_download_sdk = repository_rule(
_ruby_download_sdk_impl,
attrs = {
"version": attr.string(),
},
)
def _remote_sdk(repository_ctx):
_download_openssl(repository_ctx, version = "1.1.1c")
_download_ruby(repository_ctx, version = "2.6.3")
openssl_path, ruby_path = "openssl/build", ""
_build(repository_ctx, "openssl", openssl_path, ruby_path)
_build(repository_ctx, "ruby", openssl_path, ruby_path)
def _build(repository_ctx, name, openssl_path, ruby_path):
script_name = "build-{}.sh".format(name)
template_name = "build-{}.template".format(name)
repository_ctx.template(
script_name,
Label("@rules_ruby//ruby/private:{}".format(template_name)),
substitutions = {
"{ssl_build}": openssl_path,
"{ruby_build}": ruby_path,
}
)
repository_ctx.report_progress("Building {}".format(name))
res = repository_ctx.execute(["./" + script_name], timeout=20*60)
if res.return_code != 0:
print("res %s" % res.return_code)
print(" -stdout: %s" % res.stdout)
print(" -stderr: %s" % res.stderr)
关于我如何使bazel知道的建议,以便它不会每次都重建这些构建工件?
答案 0 :(得分:0)
问题是,bazel并不能真正构建您的红宝石和openssl。当它准备好您的构建树并运行存储库规则时,它只是按照说明执行了一个shell脚本,这显然是在构建过程中发生的,但是这一事实对于bazel基本上是不透明的(并且也发生在bazel自己构建之前)。 >
可能还有其他选择,但我认为以下是您的选择:
将外部环境及其结果作为外部依赖项进行预构建。对于需要支持的所有平台(包括确保正确的检测和相应的下载),您需要这样做的明显缺点(可能会也可能不会很痛苦)。好处是您实际上只构建一次(每个平台),并且还可以控制在所有主机上使用的工具。这可能是我的主要选择。
像其他C语言源一样构建ssl和ruby,使它们成为另一个目标。但是,这意味着您需要对他们的构建进行标准化(描述和维护不了解Bazel的项目的bazel构建)。
您可以沿着开始的路径继续前进,而将bazel排除在外。即对于这些构建,可以扩展魔术,并在例如使用确定性位置的构建脚本中使用扩展脚本,还可以在清单文件中显示周围的内容(也可以减少损坏的可能性),从而有可能确定构建确实已经进行,您可以收集以前的结果。