我正在尝试将Maven项目迁移到Bazel并且遇到Datanucleus增强问题。
在构建jar
文件之后,Datanucleus会查看它并进行一些字节码操作以增强可持久化的类。在Bazel中执行此操作的方法是定义一个规则,该规则采用*.jar
规则的java_library
输出,并创建一个新的增强版本的库。
我遇到的问题是,对于我的规则,我需要来自外部库的datanucleus-core
包。当我尝试从genrule
$(location //third_party:datanucleus_core)
访问它时,它指向一个没有类的jar:
(genrule) cmd = "echo $(location //third_party:datanucleus_core)"
bazel-out/local-fastbuild/bin/third_party/liborg_datanucleus_datanucleus_core.jar
(genrule) cmd = "jar tf $(location //third_party:datanucleus_core)"
META-INF/
META-INF/MANIFEST.MF
Bazel在jar
genrule
解析的$(location //third_party:datanucleus_core)
文件仅包含META-INF/MANIFEST.MF
,其中包含以下内容:
Manifest-Version: 1.0
Created-By: blaze
我尝试使用java_binary
规则将正确的datanucleus_core.jar
添加到类路径中,但Datanucleus就地增强了我的库,并且无法在磁盘上写入其更改(重写规则的输入文件)。此外,java_binary
规则不应用于构建。
所以问题是在运行Datanucleus实用程序的Bazel中增强jar
库的最佳方法是什么,该实用程序是作为Maven存储库中的第三方依赖项提供的?
Bazel构建标签:0.3.2-homebrew
,操作系统:OS X El Capitan (10.11.6)
,java:1.8.0_92
更新
Datanucleus依赖声明:
# WORKSPACE
maven_jar(
name = "org_datanucleus_datanucleus_core",
artifact = "org.datanucleus:datanucleus-core:5.0.3",
)
# third_party/BUILD
java_library(
name = "org_datanucleus_datanucleus_core",
visibility = ["//visibility:public"],
exports = ["@org_datanucleus_datanucleus_core//jar"],
)
(在我的问题中,我将org_datanucleus_datanucleus_core
缩短为datanucleus_core
)
答案 0 :(得分:3)
正如Neil Stockton所提到的,你无法在jar中增强类。所以,基本策略将是:
步骤2& 3必须归为4,因为Bazel坚持要求您声明所有输入和输入。输出到构建规则(并且您无法知道.java文件将生成什么.class文件,因此Bazel总是将它们捣乱)。
创建一个datanucleus.bzl
文件以声明您的增强规则。它应该类似于:
# Run datastore enhancements on the java_library named "jarname".
def enhance(jarname):
# src is the name of the jar file your java_library rule generates.
src = "lib" + jarname + ".jar"
native.genrule(
name = jarname + "-enhancement",
srcs = [
src,
"//third_party:datanucleus_core"
],
outs = [jarname + "-enhanced.jar"],
cmd = """
# Un-jar the .class files.
jar tf $(location {0})
# Run the enhance.
classes=""
for $$class in $$(find . -name *.class); do
java -cp {0}:$(location //third_party:datanucleus_core) $$class
classes="$$classes $$class"
done
# jar them back up.
jar cf $@ $$classes""".format(src),
)
(我对数据存储区不太熟悉,因此cmd
可能需要进行一些修改,但应该是一般的想法。)
然后,在你的BUILD文件中,你会这样做:
java_library(
name = "my-lib",
srcs = glob(["*.java"]),
deps = ["..."],
)
# import the rule you wrote.
load('//:datanucleus.bzl', 'enhance')
enhance("my-lib")
现在你可以做到:
bazel build //:my-lib-enhanced.jar
并使用my-lib-enhanced.jar
作为其他java_
规则中的依赖项。
有关.bzl文件的更多信息:https://bazel.build/versions/master/docs/skylark/concepts.html。
编辑根据jar添加更多信息:
有几个选项可以获得包含datanucleus内容的jar。首先,你不需要间接层:你可以说:
srcs = [
src,
"@datanucleus_core//jar"
],
这将为您提供实际的罐子。
如果出于某种原因,您需要将jar放在third_party中,则可以修改third_party / BUILD以创建 deploy jar ,这是一个捆绑了所有依赖关系的java二进制文件部署(因为你实际上并没有将它用作二进制文件,你可以使用你想要的主类名称):
java_binary(
name = "datanucleus-core",
main_class = "whatever",
runtime_deps = ["@org_datanucleus_datanucleus_core//jar"],
)
genrule(
name = "your-lib",
srcs = [":datanucleus-core_deploy.jar", ...],
)
:datanucleus-core_deploy.jar
被称为隐式目标:它仅在请求时构建,但可以通过java_binary
声明生成。