From 12b96b5e9a722b372f153436b1f6827709d0f2ab Mon Sep 17 00:00:00 2001 From: Taylor Wood Date: Tue, 9 Apr 2019 06:41:34 -0500 Subject: [PATCH] Workaround locking issue in 1.10 --- .gitignore | 2 +- README.md | 13 +++++++++++++ deps.edn | 3 ++- java/src/clojurl/LockFix.java | 11 +++++++++++ src/clojurl.clj | 24 +++++++++++++++++++++++- 5 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 java/src/clojurl/LockFix.java diff --git a/.gitignore b/.gitignore index 11dc89b..686eba3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .cpcache classes -clojurl +/clojurl diff --git a/README.md b/README.md index 16fb7f4..872664f 100644 --- a/README.md +++ b/README.md @@ -154,3 +154,16 @@ should satisfy ------------------------- Detected 1 error ``` + +## Compiling with Clojure 1.10 + +GraalVM native-image won't work with Clojure's `locking` macro, and Clojure 1.10 depends on a version of clojure.spec +(see [this commit](https://github.com/clojure/spec.alpha/commit/31165fec69ff86129a1ada8b3f50864922dfc88a)) that uses `locking`. +You can workaround this by compiling a Java class with a special locking mechanism, and patching any usages of `locking` e.g. in clojure.spec. + +You must first compile the Java class: +``` +➜ javac java/src/clojurl/LockFix.java -cp ~/.m2/repository/org/clojure/clojure/1.10.0/clojure-1.10.0.jar +``` + +Then patch any usages of `locking` and you should be able to compile a native image. See `clojurl.clj` for example. diff --git a/deps.edn b/deps.edn index 27434b0..485c100 100644 --- a/deps.edn +++ b/deps.edn @@ -1,8 +1,9 @@ {:deps {expound {:mvn/version "0.7.1"} - org.clojure/clojure {:mvn/version "1.9.0"} + org.clojure/clojure {:mvn/version "1.10.0"} org.clojure/tools.cli {:mvn/version "0.4.1"} org.martinklepsch/clj-http-lite {:mvn/version "0.4.1"} hickory {:mvn/version "0.7.1"}} + :paths ["src" "java/src"] :aliases {:native-image {:main-opts ["-m clj.native-image clojurl" "--report-unsupported-elements-at-runtime" diff --git a/java/src/clojurl/LockFix.java b/java/src/clojurl/LockFix.java new file mode 100644 index 0000000..108652c --- /dev/null +++ b/java/src/clojurl/LockFix.java @@ -0,0 +1,11 @@ +package clojurl; + +import clojure.lang.IFn; + +public class LockFix { + static public Object lock(final Object lockee, final IFn f) { + synchronized (lockee) { + return f.invoke(); + } + } +} diff --git a/src/clojurl.clj b/src/clojurl.clj index 1ce429a..a9bf8e7 100644 --- a/src/clojurl.clj +++ b/src/clojurl.clj @@ -6,10 +6,32 @@ [clojure.pprint :refer [pprint]] [expound.alpha :as expound] [hickory.core :as hick]) - (:gen-class)) + (:gen-class) + (:import (clojurl LockFix))) (set! *warn-on-reflection* true) +(defmacro locking* ;; patched version of clojure.core/locking to workaround GraalVM unbalanced monitor issue + "Executes exprs in an implicit do, while holding the monitor of x. + Will release the monitor of x in all circumstances." + {:added "1.0"} + [x & body] + `(let [lockee# ~x] + (LockFix/lock lockee# (^{:once true} fn* [] ~@body)))) + +(defn dynaload ;; patched version of clojure.spec.gen.alpha/dynaload to use patched locking macro + [s] + (let [ns (namespace s)] + (assert ns) + (locking* #'clojure.spec.gen.alpha/dynalock + (require (symbol ns))) + (let [v (resolve s)] + (if v + @v + (throw (RuntimeException. (str "Var " s " is not on the classpath"))))))) + +(alter-var-root #'clojure.spec.gen.alpha/dynaload (constantly dynaload)) + (def cli-options [["-u" "--uri URI" "URI of request" :id :url