Fork me on GitHub
#leiningen
<
2024-02-09
>
ghaskins12:02:53

I have a hybrid clojure/java app and am seeing an issue where my project doesn’t automatically invoke javac on the java sources, and I dont understand why. I have done this in the past. Any tips on what to check?

ghaskins12:02:02

I do have

:source-paths ["src/clojure"]
  :java-source-paths ["src/java"]
set, and I don’t have any prep-task overrides.

ghaskins12:02:18

So far the only thing that has worked has been to set up a :precomp profile like

:profiles {:precomp {:java-source-paths ["src/java"]}
and then running
lein with-profile precomp javac

ghaskins12:02:21

the fundamental issue seems to be that if I dont do this, it tries to process clojure files first…but the clojure code depends on the java code so it fails. I’ve done similar things in the past and it just worked, so I am scratching my head as to what is wrong in this project.

mikerod22:02:35

Have you altered prep-tasks anywhere?

ghaskins22:02:48

Not to my knowledge

mikerod22:02:14

I’d double check that.

ghaskins22:02:32

Theres nothing in the project file…but what I dont know is if some plugin may alter it

mikerod22:02:36

Use whatever profiles you are using and lein pprint it

ghaskins22:02:31

When I pprint it, it looks like its the default

ghaskins22:02:32

:prep-tasks ["javac" "compile"],

ghaskins22:02:48

$ lein --version
Leiningen 2.10.0 on Java 21.0.1 Java HotSpot(TM) 64-Bit Server VM

mikerod22:02:36

That seems fine to me then. javac is first.

ghaskins22:02:46

Yeah…its confounding

mikerod22:02:01

You can do DEBUG=true ahead of your lein command to get more details of what it is doing.

ghaskins22:02:09

ok., let me try that

ghaskins22:02:40

ok, that helped move the needle a bit. I immediately started with “DEBUG=true lein uberjar” to narrow it down and it actually did the right thing, giving me a hint that its not so much the overall config, but my flow

ghaskins22:02:13

I have a Makefile and in there are other tasks like lein eastwood and lein cloverage that run before the build

mikerod22:02:22

Yes. Progress. So then figure out what your flow task is running.

ghaskins22:02:26

so my problem seems to be i need to hook those the right way

mikerod22:02:40

That’s a possibility.

ghaskins22:02:07

I dont know if this is meaningful to you, but when I enable debugging for one of the broken tasks

ghaskins22:02:09

$ DEBUG=true lein cloverage
Leiningen's classpath: /usr/local/Cellar/leiningen/2.10.0/libexec/leiningen-2.10.0-standalone.jar
Applying task cloverage to []
Applying task javac to nil
Running javac with [@/var/folders/bl/s_t9lqxx2glgf9dv7h7z54g40000gn/T/.leiningen-cmdline84724007947143382.tmp]
Warning: environ value /Users/ghaskins/.jenv/versions/system for key :java-home has been overwritten with /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
Warning: protocol #'manetu.policyengine.api/policyengine is overwriting function test
WARNING: test already refers to: #'clojure.core/test in namespace: manetu.policyengine.api, being replaced by: #'manetu.policyengine.api/test
WARNING: test already refers to: #'clojure.core/test in namespace: manetu.policyengine.core, being replaced by: #'manetu.policyengine.core/test
Reflection warning, protojure/grpc/codec/lpm.clj:184:5 - reference to field close can't be resolved.
Exception in thread "main" Syntax error macroexpanding at (manetu/lambda_service/subservice/executor/wasm/guest_context.clj:1:1).

ghaskins22:02:33

Of course, if I run the precomp profile or build the uberjar first, javac runs in the right timing

ghaskins22:02:03

$ DEBUG=true lein uberjar
Leiningen's classpath: /usr/local/Cellar/leiningen/2.10.0/libexec/leiningen-2.10.0-standalone.jar
Applying task uberjar to []
Applying task javac to nil
Running javac with [@/var/folders/bl/s_t9lqxx2glgf9dv7h7z54g40000gn/T/.leiningen-cmdline15031772485933302220.tmp]
Compiling 35 source files to /Users/ghaskins/sandbox/git/mcp-lambda-service/target/uberjar/classes
Note: Annotation processing is enabled because one or more processors were found
  on the class path. A future release of javac may disable annotation processing
  unless at least one processor is specified by name (-processor), or a search
  path is specified (--processor-path, --processor-module-path), or annotation
  processing is enabled explicitly (-proc:only, -proc:full).
  Use -Xlint:-options to suppress this message.
  Use -proc:none to disable annotation processing.
Note: /Users/ghaskins/sandbox/git/mcp-lambda-service/src/java/io/github/kawamuray/wasmtime/Func.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

ghaskins22:02:29

Im basically missing this in the broken cases

ghaskins22:02:30

Compiling 35 source files to /Users/ghaskins/sandbox/git/mcp-lambda-service/target/uberjar/classes

mikerod22:02:06

When you run cloverage - you aren’t adding your profile precomp

mikerod22:02:12

So it isn’t getting the :java-source-paths.

ghaskins22:02:34

well, to be clear, I set that in the top-level config, too. I only added the precomp profile as a hack

mikerod22:02:51

Ok, at the top-level I’d expect it to work there

ghaskins22:02:11

yeah…and ive done this a bunch of other times in other projects, so its super weird

ghaskins22:02:21

I cant figure out what I am doing differently

mikerod22:02:26

cloverage fails and eastwood?

mikerod22:02:31

are these custom :aliases?

ghaskins22:02:02

no, i only have one alias for clj-kondo and I am not using it in this flow

ghaskins22:02:11

its only lein-plugins

ghaskins22:02:36

the operative part is

ghaskins22:02:38

:source-paths ["src/clojure"]
  :java-source-paths ["src/java"]

  :repl-options {:init-ns user}

  :eastwood {:add-linters [:unused-namespaces]
             :exclude-linters [:unused-meta-on-macro :local-shadows-var :unused-ret-vals]}

  :profiles {:precomp {:java-source-paths ["src/java"]}
             :dev     {:dependencies   [[clj-http "3.12.3" :exclusions [commons-io]]
                                        [org.clojure/tools.namespace "1.4.5"]
                                        [criterium "0.4.6"]
                                        [eftest "0.6.0"]
                                        [clj-kondo "2023.12.15"]
                                        [mockery "0.1.4"]
                                        [integrant/repl "0.3.3"]]
                       :resource-paths ["jna/target" "jna/target/release" "test/lambdas"]
                       :aliases        {"clj-kondo" ["run" "-m" "clj-kondo.main"]}}
             :uberjar {:aot                :all
                       :omit-source        true
                       :target-path        "target/uberjar"
                       :uberjar-name       "app.jar"
                       :uberjar-exclusions [#".*manetu.*\.clj[xcs]*"]
                       :jvm-opts           ["-Dclojure.compiler.direct-linking=true"]}}

ghaskins22:02:11

where

:profiles {:precomp {:java-source-paths ["src/java"]}
Was added in desperation as a hack

mikerod22:02:31

Did you try lein clean before DEBUG=true lein cloverage

ghaskins22:02:54

I had hammered it with rm -rf target, but let me do it the right way and see what happens

mikerod22:02:13

ah ok, probably that covered it - just making sure you didn’t somehow have old classfiles somewhere causing issue

ghaskins22:02:48

and as expected, same behavior

ghaskins22:02:33

its like it ignores the java-source-paths when the source-paths [“src/clojure”] is present

ghaskins22:02:01

or, maybe it schedules java-source-paths as secondary, but we never live long enough to get there

mikerod22:02:02

The default prep-tasks should run javac first and javac explicitly compiles the :java-source-paths that it finds.

mikerod22:02:11

So it is weird. It’s as if they are missing during certain tasks to me.

ghaskins22:02:20

Makes sense…and thats what I thought…so confounding

mikerod22:02:32

odd, you have issues for both eastwood and cloverage

ghaskins22:02:51

i didnt exhaustively look..let me try some of the other pre-build functions

mikerod22:02:57

But did you have issues with anything else before you tried using the profile precomp?

mikerod22:02:30

You said lein uberjar works with no special :aliases right? So it’d just be based on the top-level project.clj merged with the :uberjar profile.

ghaskins22:02:56

right…i didnt try any other flows…i have a top level makefile that does this (currently)

ghaskins22:02:10

all: scan test bin security-scan
precomp:
	lein with-profile precomp javac

scan: precomp
	lein cljfmt check
	lein bikeshed -l false -n false
	#lein kibit
	lein eastwood

ghaskins22:02:26

and so it was puking somewhere in the scan

ghaskins22:02:43

at the time, I didnt realize uberjar would actually work (should have thought to try that)

ghaskins22:02:59

(the precomp was added as a workaround for this, that wasnt there originally)

mikerod22:02:03

So everything there is a plugin basically

ghaskins22:02:04

it works with the precomp

ghaskins22:02:24

thats why I am wondering if its somehow related to the way the plugins interact

mikerod22:02:41

Yeah, with the precomp done first - you leave the classfiles in the :target-path and the other tasks will get them on their classpath

ghaskins22:02:54

yep, that much I understood

ghaskins22:02:14

the part I dont get is where lein is making the decision to compile the java-source-paths in some cases but not others

mikerod22:02:34

I don’t understand how every plugin would be susceptible to the same problem though. It isn’t something I’ve heard of I think.

ghaskins22:02:48

Heh…i love when I find weird problems

ghaskins22:02:03

Well, I feel better knowing that you dont know either

mikerod22:02:06

If it was one plugin, I’d wonder if it perhaps altered prep-tasks or didn’t merge with your project top-level - but even then that’d be pretty odd and probably always broken.

ghaskins22:02:09

i was banging my head on the wall

mikerod22:02:28

When I have these issues, I deal with it a bit of the tedious way.

ghaskins22:02:39

in any case, its largely academic at this point: my precomp hack works

ghaskins23:02:10

i was hoping to just learn a more lein-idiomatic way, but maybe its elusive

mikerod23:02:00

I’ll basically git clone the lein version you want to deal with. Then I’ll launch a repl directly in leiningen and try to recreate the project setup via something like leiningen.core.project/read and then make sure I get the same profile configuration state and then look for things like :java-source-paths there etc. I probably could write a tiny post on this at some point, but it’s not that elegant.

mikerod23:02:21

Yeah, in worst-case, you could just script that you manually ensure the javac is ran correctly before each plugin task - like you have.

ghaskins23:02:25

so, it looks like cljfmt is fine, probably because it doesnt need the classfiles present…bikeshed, eastwood, and cloverage all seem to suffer the same fate

ghaskins23:02:21

in any case, ty for talking it through with me. I at least discovered that the uberjar target works, which at least instills some confidence in me that the config isnt fundamentally broken

ghaskins23:02:46

something else is going on, but my hack in the makefile is fine for the time being

mikerod23:02:56

Ok, sounds good. I’m making a TODO to see if I can recreate your issue with a tiny project with cloverage as an example - to see if I can understand better what happened. I probably wont’ get to that for a few days though. I’ll let you know though if I find out anything interesting there.

👍 1
ghaskins23:02:16

I appreciate your time, ty

👍 1