Fork me on GitHub
#tools-build
<
2023-01-05
>
oly13:01:26

So I have tried moving from depstar to tools.build how ever the resulting uberjar returns "Error: Could not find or load main class" I have opened the jar file and checked the src exists I have also checked the manifest has the correct entrypoint. what's my next step to diagnosing why it can't find the class ?

oly13:01:22

also worth noting I have (gen-class) in dpestar I had :aot true but I have not seen an equivalent in tools.build

Alex Miller (Clojure team)13:01:46

You need to include the compile-clj task

oly13:01:31

yeah I have that step, I have the clean cop-dir compile-clj and uber parts

Alex Miller (Clojure team)13:01:18

Are there classes in the jar?

oly13:01:38

The build is almost identical to that base example, and the resulting jar file looks good I can see my classes and the libraries.

oly13:01:37

So I have this in the manifest Main-Class: com.atomjuice.car_cli.core and i can find core.clj at com/atomjuice/car_cli/core.clj

Alex Miller (Clojure team)13:01:19

The clj doesn’t matter, only the class (for the main)

Alex Miller (Clojure team)13:01:14

So is there a core.class?

oly13:01:15

inside the jar I can not see core/class path

Alex Miller (Clojure team)13:01:44

Ok, so that’s the cause of the error

Alex Miller (Clojure team)13:01:23

next question is why you’re not seeing compile-clj make the class

Alex Miller (Clojure team)13:01:21

Is :src-dirs correct there?

oly13:01:26

(b/compile-clj {:basis     basis               ; compile clojure code
                  :src-dirs  ["src"]
                  :class-dir jar-content})
So I do have a question regarding src-dirs is is this relative to where the build.clj runs as the project is a polylith project

Alex Miller (Clojure team)13:01:56

It’s relative to the directory you run the build from by default

oly13:01:01

so there are src folder all over the place, so my build is in workspace/project/car-cli/build.clj but the the srcs are in workspace/bases/car-cli and worspace/components/foo styles paths

Alex Miller (Clojure team)13:01:41

You can change your project context using set-project-root! or (in latest) with-project-root

oly13:01:12

do I still need to add each src folder ?

oly13:01:25

there are probably about 30 and growing

Alex Miller (Clojure team)13:01:24

You need to set :srcs to include any directory where you want everything compiled (there are other options in compile-clj) but the paths are actually defined via the basis, which might already be covering this via :local/root deps

Alex Miller (Clojure team)13:01:06

I’ve lost track of what polylith is doing these days so not sure if that covers it

oly13:01:25

/workspace/component/foo/src/
/workspace/component/bar/src/
/workspace/bases/project/src/
/workspace/project/build.clj
So this is the structure, and as you say the project deps.edn includes all the :local/roots to the components

Alex Miller (Clojure team)13:01:38

I suspect @U04V70XH6 probably has some good advice about this but he won’t be online for a couple hrs

oly13:01:42

okay, thanks for the awesome help @U064X3EF3 at least I have a better idea of whats going on, I suspected the src-dir folder then dismissed it because it looked like everything was in the jar. before depstar just worked and I did not need to worry about this part so I don't know enough about the construction of jars.

Alex Miller (Clojure team)13:01:37

Actually if you omit :src-dirs in compile-clj it will use the paths in the basis and everything else should get compiled transitively so you can probably do that

Alex Miller (Clojure team)13:01:10

Assuming you set the project root context

oly13:01:33

Okay I will give that a try and see what happens 🙂

seancorfield18:01:05

The build task should run in the projects/* folders effectively and just use the basis computed there. I can't provide more details when I get back from vacation (Hawaii) but check my blog posts about Polylith - I may have discussed this in one of them http://corfield.org

oly09:01:48

I managed to get around it by adding the bases of the project to the build.clj. I have my build in projects/project-name are you saying I would be better of having the build a level up, ie a shared build for all projects ? Hope you enjoyed Hawaii got a working solution but more info would be great, I did look over some of your blog and have used it in the past for other polylith help, not sure it helped with this specific issue.

seancorfield22:01:12

FWIW we have one build.clj at root of the repo and we bind the tools.build project root to the projects/* folder for each project as we build it. I thought I'd shared that code in one of my blog posts but maybe not...

seancorfield20:01:16

@UU67HFS2X Here's our uberjar creation code at work:

(doseq [p projects]
      (println "\nRunning: uber on" p)
      (let [project-dir (str "projects/" p)
            aliases     (with-dir (io/file project-dir) (get-project-aliases))]
        ;; ignore any projects that don't build as uberjars:
        (when-let [uberjar-opts (:uberjar aliases)]
          (binding [b/*project-root* project-dir]
            (bb/clean {})
            (bb/uber (assoc uberjar-opts :compile-opts {:direct-linking true}))))))
projects is the sequence of (Polylith) projects to build. Each projects/*/deps.edn contains an alias called :uberjars that has :uber-file and :main -- so the uber task knows the JAR file to produce and the main ns to compile. bb is my build-clj wrapper for tools.build but you could easily use tools.build directly here with maybe some additional default options. Our build.clj lives in the workspace root, next to workspace.edn, and we run builds from that folder:
clojure -T:build uberjars :projects '[api login]'
which would build the api and login projects. The key here is the binding of clojure.tools.build/*project-root* to the actually project directory. Here's the get-project-aliases function:
(defn- get-project-aliases []
  (let [edn-fn (juxt :root-edn :project-edn)]
    (-> (t/find-edn-maps)
        (edn-fn)
        (t/merge-edns)
        :aliases)))
and this is from the :require in our build ns:
[clojure.tools.build.api :as b]
            [clojure.tools.deps :as t]
            [clojure.tools.deps.util.dir :refer [with-dir]]
            [org.corfield.build :as bb]
Hopefully, that is everything you need to replicate how we're using tools.build with Polylith to build uberjars. If not, let's take this discussion to the #C013B7MQHJQ channel.

oly13:01:31

@U04V70XH6 Thanks for taking the time for getting that for me, I will apply the same to mind, may help resolve some of my other issues I have been seeing