Using Clojure macros with cljx

202 Views Asked by At

I have a code-base for a graphics program in cljx that gets compiled to Clojure and ClojureScript.

I now want to introduce my first macro.

(defmacro optional-styled-primitive [args body] 
   (let [extra (conj args 'style)] 
     `(fn (~extra (->SShape ~'style ~body))
          (~args (->SShape {} ~body)) 
      )
   )
)

The purpose of this macro is to take a list of arguments, and an expression that uses those arguments to generate a geometry. And to return a function with two arities : one of which takes an optional style parameter. This macro is then to be used within the file where it's defined, to make a number of other functions that optionally take styles. For example :

(def square (optional-styled-primitive [n] [[0 0] [0 n] [n n] [n 0]]))

But introducing this macro, obviously, breaks the ClojureScript stage of the compilation.

What I can't figure out is what to do about it. The online discussions talk about ClojureScript needing to use :require-macros but I never actually export or require this macro anywhere. I just want to use it where it's defined. So how can I, in the middle of a file, tell the compiler to use Clojure to expand this macro, before it gets to the ClojureScript compiler?

1

There are 1 best solutions below

1
On

OK.

I've made some progress with this.

Here's what I did.

1) I refactored my macro definition out into a separate file called macros.cljx

2) In the file where I was using the macros, I did this. (A different require for clj and cljs)

(#+clj :require #+cljs :require-macros 
     [myapp.macros :refer [optional-styled-primitive]])

3) I updated my leiningen project.clj file :

:cljsbuild {:builds [{
     :source-paths ["target/classes" "src-cljs" ] ...

The important thing here I added "target/classes", which is the output-path where cljx puts the clj files it creates, to the cljsbuild source-paths. This is where the cljsbuild process can find the clj file with the macro definition.

I'm not sure if this is the right or principled way to solve the problem. But it now seems to be working (unless I'm confused by something).