使用ProGuard混淆Clojure Uberjars

12

我想知道是否有人有使用proguard混淆他们使用leiningen编译的uberjars的经验。我已尽力在Google上寻找解决方案,但实在找不到答案。我想知道这是否可能。

我一直在尝试混淆一个默认的lein项目。这是core.clj文件:

(ns proguard.core
(:gen-class))

(defn -main
  "I don't do a whole lot."
  [& args]
  (println "Hello, World!"))

项目文件:

(defproject proguard "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]]
  :aot :all
  :main proguard.core)

我的Proguard配置文件:

-injars clojure/proguard/target/proguard-0.1.0-SNAPSHOT-standalone.jar
-outjars clojure/test-project

-libraryjars /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/rt.jar

-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-dontpreverify
-dontnote
-printseeds

-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

-keep class clojure.core__init { public static void load(); }
-keep class clojure.core_proxy__init { public static void load(); }
-keep class clojure.core_print__init { public static void load(); }
-keep class clojure.genclass__init { public static void load(); }
-keep class clojure.core_deftype__init { public static void load(); }
-keep class clojure.core.protocols__init { public static void load(); }
-keep class clojure.gvec__init { public static void load(); }
-keep class clojure.java.io__init { public static void load(); }
-keep class clojure.lang__init { public static void load(); }

-keep class proguard.core__init {
    public static void load();
}
-keep class proguard.core {
    public *** super*(...);
}

每当我尝试运行混淆后的jar文件时,会出现以下错误:
Exception in thread "main" java.lang.ExceptionInInitializerError
    at clojure.lang.ve.<init>(Unknown Source)
    at clojure.lang.ve.c(Unknown Source)
    at clojure.lang.yf.a(Unknown Source)
    at proguard.core.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: clojure.lang.PersistentList, compiling:(clojure/core.clj:20)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.b(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.bj.a(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.b(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.xh.a(Unknown Source)
    at clojure.lang.xh.a(Unknown Source)
    at clojure.lang.xh.b(Unknown Source)
    at clojure.lang.xh.d(Unknown Source)
    at clojure.lang.xh.c(Unknown Source)
    at clojure.lang.xh.<clinit>(Unknown Source)
    ... 4 more
Caused by: java.lang.ClassNotFoundException: clojure.lang.PersistentList
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at clojure.lang.ec.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at clojure.lang.xh.h(Unknown Source)
    at clojure.lang.bp.b(Unknown Source)
    at clojure.lang.bp.a(Unknown Source)
    at clojure.lang.bq.a(Unknown Source)
    ... 19 more

我不太确定我在这里做错了什么...我尝试遵循一个Clojure针对Proguard的教程 (使用Proguard混淆),但是它是特定于Android和Ant的,因此我想知道对于使用Lein的桌面应用程序,这个过程是否完全不同。
提前感谢。

我没有使用proguard的经验,但从堆栈跟踪来看,这个混淆器已经将clojure运行时从uberjar中排除了。你必须保留clojure.jar中的所有类才能使程序正常工作,而不仅仅是几个__init类,就像你的配置文件中所显示的那样。我猜测你需要将clojure.jar添加到-libraryjars列表中。 - Vladimir Matveev
嘿,感谢您指引我正确的方向!整个clojure.jar确实需要保持不变。我很快就会回答自己的问题。[编辑:嗯,我想我不能这样做,因为问题还太年轻了...] - deadringer
既然问题已经存在一段时间了,你应该正确回答自己的问题。目前这种情况下,答案在问题之前,会让人感到困惑。 - Tom
我已经做过了。请看下面的答案。 - deadringer
1个回答

15

从上面复制:

混淆uberjars

1. 准备你的project.clj文件

这是我的一个副本(简单的,带有注释的默认lein项目):

(defproject proguard "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]]
  :main proguard.core
  ;;; Make sure everything is aot compiled
  :aot :all
  ;;; Remove source .clj files from the resulting jar
  :omit-source true
  )

这里没有更多的内容了... 确保在你的命名空间声明中包含 (:gen-class)

使用 lein uberjar 命令构建超级jar,我们就可以进行下一步了。

2. 准备ProGuard配置文件

再次附上我的文件副本,带有注释。

# Our uberjar
-injars clojure/proguard/target/proguard-0.1.0-SNAPSHOT-standalone.jar
# Our output direcotry
-outjars clojure/obfuscated

# Link to rt.jar. I'm on a Mac so your path may differ
-libraryjars /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/rt.jar

# ProGuard options. Detailed explanation here http://proguard.sourceforge.net/index.html#manual/usage.html
-dontskipnonpubliclibraryclassmembers
-dontnote
-printseeds

# What we will be doing is obfuscating, shrinking and optimizing the jar. 
# If you experience any problems start out with obfuscation and add the 
# -dontoptimize  and the -dontshrink flags and see if it works.

# Tell proguard to leave the clojure runtime alone
# You would need to add any other classes that you wish to preserve here.
-keep class clojure.** { *; }

# Keep our core__init class
-keep class proguard.core__init {
    public static void load();
}

# Keep classes that contain a main method (otherwise we won't be able to run the jar)
-keepclasseswithmembers public class * {
    public static void main(java.lang.String[]);
}

就是这样。现在使用你的新配置文件运行proguard,命令如下:java -jar proguard.jar @myconfig.pro。由于使用了-printseeds标志,您应该会看到大量输出(如果您不想看到将被proguard保留的类,当然可以删除该标志)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接