tools-deps

Discuss tools.deps.alpha, tools.build, and the clj/clojure command-line scripts! See also #depstar #clj-new
dharrigan 2020-08-06T19:15:03.044900Z

I have a question, related to this <https://clojure.org/guides/dev_startup_time>. Say I have a deps.edn that has an alias that pulls in a few other sources, via extra-deps, using a couple of :local/root declarations, i.e., one that loads in rebel readline (with little customisation) and another which launches a nrepl (with some middleware injected). Can I still benefit from what the guide says? Can I compile the extra-deps includes, so that my clj startup is reduced?

alexmiller 2020-08-06T19:16:01.045400Z

sure

alexmiller 2020-08-06T19:16:14.045600Z

it's all on the same classpath

dharrigan 2020-08-06T19:17:02.046200Z

Okay, but where would the classes directory live, i.e., if I have something like this...

dharrigan 2020-08-06T19:17:05.046500Z

:rebel {:extra-deps {local-rebel {:local/root "/home/david/.clojure/libs/local.rebel" :deps/manifest :deps}
                       local-nrepl {:local/root "/home/david/.clojure/libs/local.nrepl" :deps/manifest :deps}}
          :main-opts ["-m" "local.rebel.main"]}

alexmiller 2020-08-06T19:17:23.047100Z

I'd put it in its own alias and then use multiple aliases

alexmiller 2020-08-06T19:17:50.047600Z

ie, it's actually the same as what's in the doc, you just might have extra tool aliases in play

dharrigan 2020-08-06T19:18:18.048300Z

okay, let me have a play around. My clj startup at the moment is taking about 8 seconds to launch...

alexmiller 2020-08-06T19:18:21.048500Z

so clj -A:dev:rebel or whatever

alexmiller 2020-08-06T19:18:38.048900Z

or actually you've got main args in there

alexmiller 2020-08-06T19:18:54.049400Z

so you might want to do clj -R:dev:rebel when doing the compilation

alexmiller 2020-08-06T19:19:03.049700Z

so you get just the deps but not the main stuff

dharrigan 2020-08-06T19:19:16.050Z

okay, will have a play 🙂 Thank you Alex! 🙂

alexmiller 2020-08-06T19:19:27.050300Z

🍺

dharrigan 2020-08-06T19:19:39.050500Z

I'd love one thanks 🙂

souenzzo 2020-08-06T19:29:50.050700Z

Oh.... Mine is ~2min on good machines and we really don't care about that

dharrigan 2020-08-06T19:36:23.050900Z

:shocked_face_with_exploding_head:

seancorfield 2020-08-06T19:38:43.052Z

I only restart my REPL about once a week so even a few minutes startup wouldn't really bother me. I'm curious about workflows where startup times of eight seconds is problematic @dharrigan?

1👍
souenzzo 2020-08-06T19:39:45.052400Z

I open the repl less then once a day. (it remains open)

dharrigan 2020-08-06T19:40:10.053100Z

I have a need, a need for speed 🙂 I guess I'm just learning about if by applying some of the recommendations in that web page I can shave off some time! No harm in trying to optimise if I can 🙂

1😆
dharrigan 2020-08-06T19:45:25.053300Z

Interesting, got it down to 3 seconds 🙂

1👍
alexmiller 2020-08-06T19:59:10.053700Z

I'll send you my bill

1😂
dharrigan 2020-08-06T19:59:45.054100Z

Errrr....would an I.O.U suffice?

dharrigan 2020-08-06T20:00:22.054700Z

I.O.U one beer, fresh from the tap, if when you get to Ireland/UK 🙂

alexmiller 2020-08-06T20:01:34.055Z

I hope I can leave my house again someday

lread 2020-08-06T20:23:47.057Z

@dharrigan’s avatar is a duck… he already has a bill!

seancorfield 2020-08-06T20:25:17.058600Z

@alexmiller So I went and tried that dev startup time stuff (for the first time). I compiled a bunch of big libraries that my code relies on that rarely change, but did not compile my own code, then a ran a "load file" on my app's main file and it threw an exception about a clojure.core.cache.CacheProtocol not found... so I'm guessing there's a possibility for this pre-compile step to mess up in some way?

alexmiller 2020-08-06T20:26:03.058800Z

depends how you compiled everything

dharrigan 2020-08-06T20:26:31.059300Z

He's the Egyptian Household God of Frustration.

alexmiller 2020-08-06T20:26:46.059800Z

if you're trying to compile independent libs then you might not be compiling in the same order you actually load them in via your app

alexmiller 2020-08-06T20:27:52.061300Z

and then you can get into the case of recompiling a protocol, which can definitely go wrong

seancorfield 2020-08-06T20:27:57.061500Z

When I tried to repro with a (require 'api.main) instead of the load-file that the editor does, that seemed to work, so maybe it's something specific to load-file?

alexmiller 2020-08-06T20:28:39.061900Z

require will load too under the hood, but maybe

seancorfield 2020-08-06T20:29:49.062600Z

Ah, no difference. I started a fresh REPL, with those libraries precompiled and require failed this time, just as load-file had before.

seancorfield 2020-08-06T20:30:31.063100Z

So, you have to transitively compile "everything" to make this work, so that compile order doesn't matter?

lread 2020-08-06T20:30:33.063200Z

TIL!: https://www.youtube.com/watch?v=im29S6ZWRDI

alexmiller 2020-08-06T20:30:55.064200Z

transitively compiling everything should work (b/c it's exactly what your app does when it loads)

seancorfield 2020-08-06T20:30:59.064400Z

What about a project where you have multiple entry point nses, that represent separate applications?

alexmiller 2020-08-06T20:31:01.064500Z

other things might work :)

alexmiller 2020-08-06T20:31:28.065Z

you could use more than one alias/classes dir if you find that to be a problem

alexmiller 2020-08-06T20:32:11.066300Z

or you could still use just compile with one and use from the other entry point. you might miss some stuff but presumably it's mostly the same in deps.

seancorfield 2020-08-06T20:32:28.066500Z

Currently, I start a REPL once a week (roughly) and just load code into it as needed so I usually end up with our entire code base loaded into the REPL eventually.

dharrigan 2020-08-06T20:33:07.067400Z

Best Show Evar!

1
alexmiller 2020-08-06T20:33:08.067600Z

you are a bit outside the target user of this page :)

seancorfield 2020-08-06T20:33:31.068300Z

Compiling two different entry points that overlap might fall into the "recompiling a protocol" area?

alexmiller 2020-08-06T20:33:43.068500Z

depends

alexmiller 2020-08-06T20:34:37.069600Z

I am shorthanding the actual problem (recompilation itself is not the actual problem)

seancorfield 2020-08-06T20:35:39.070700Z

So the problematic piece (that surprises me a bit) is that (compile 'clojure.core.memoize) does not seem to transitively compile clojure.core.cache which I would have expected... I think that's the root of my earlier problem perhaps?

alexmiller 2020-08-06T20:36:10.070900Z

https://clojure.atlassian.net/browse/CLJ-1544

alexmiller 2020-08-06T20:36:41.071200Z

it should transitively compile anything loaded by clojure.core.memoize

alexmiller 2020-08-06T20:36:52.071600Z

but not everything in core.cache is used by memoize

seancorfield 2020-08-06T20:39:19.072600Z

When I look in the classes tree after (compile 'clojure.core.memoize) there are no core.cache classes at all.

2020-08-06T20:41:06.073500Z

what about if you compile clojure.core.cache? my kind of guess would be it is already compiled/loaded somewhere else in your repl

alexmiller 2020-08-06T20:41:07.073600Z

any chance you've already loaded something that has loaded core.cache prior?

alexmiller 2020-08-06T20:41:27.074300Z

compile piggybacks load so if it's not being loaded (b/c it already is), it won't be compiled

seancorfield 2020-08-06T20:43:43.075900Z

Ah, that is a possibility, because something in my dev tooling might well be using that... If I explicitly (compile 'clojure.core.cache) I do see the .class files produced for it which would suggest it isn't loaded previously?

seancorfield 2020-08-06T20:43:56.076200Z

(or am I misunderstanding your point?)

2020-08-06T20:44:37.076900Z

that is interesting, I wouldn't expect to see those if clojure.core.cache was previously loaded

alexmiller 2020-08-06T20:45:32.077700Z

I suspect you're getting the equivalent of :reload at the top level namespace you compile

alexmiller 2020-08-06T20:45:38.077900Z

but not on the ones below

seancorfield 2020-08-06T20:45:55.078300Z

Yup, confirmed. A "bare" REPL with just my dev tooling loaded has clojure.core.cache clojure.core.protocols clojure.core.server clojure.core.specs.alpha clojure.data.priority-map ... (non-`clojure.*` stuff omitted).

2020-08-06T20:46:39.079300Z

ah, right, compile calls load-one directly, bypassing the already loaded check

seancorfield 2020-08-06T20:47:02.079800Z

So, yeah, I'd need to explicitly (compile 'clojure.core.cache) to make all this work, right?

alexmiller 2020-08-06T20:48:17.080200Z

you can do what's in the bottom of that guide (kind of), which is to address a similar problem (when user.clj has already loaded stuff)

alexmiller 2020-08-06T20:48:42.080500Z

(binding [*compile-files* true] (require 'clojure.core.memoize :reload-all))

alexmiller 2020-08-06T20:49:05.080900Z

the only thing that makes load do compile is that dynvar

alexmiller 2020-08-06T20:49:13.081100Z

and the :reload-all will force a reload

seancorfield 2020-08-06T20:56:11.083900Z

I'm going to stick a list of (compile 'x.y.z) forms in a compile.clj file so I can do load-file on it to compile "everything" that I want pre-compiled and I'll add to it as/when I run into problems. FWIW, just with the set of libs I've put in that list so far, a cold (require 'api.main) has dropped from 18 seconds to 10 seconds. Like I say, since I only restart my REPL occasionally, that's really not a concern but now I'm curious about this idea of pre-compiling dependencies that rarely change...

seancorfield 2020-08-06T20:56:53.084800Z

...and if a dependency does change, presumably you'd have to force a recompile of the newer version (and everything that depended on it) in order to pick those changes up?

alexmiller 2020-08-06T20:57:02.085Z

you don't have to

alexmiller 2020-08-06T20:57:17.085400Z

a newer dependency should have newer .clj files and be preferred

alexmiller 2020-08-06T20:57:25.085600Z

it will just be slower till you recompile

alexmiller 2020-08-06T20:57:58.085800Z

clojure takes the newer .class or .clj

alexmiller 2020-08-06T20:58:32.086400Z

I guess if you changed deps to a newer version of a lib that was still older than your local .class files that wouldn't have that effect

alexmiller 2020-08-06T20:59:29.087300Z

I spent a half day trying to build this into clj so it could do it automatically (since it knows when your deps go stale). it was tricky for a bunch of reasons but maybe a future feature

alexmiller 2020-08-06T21:00:10.087900Z

the point where your .cpcache is stale is also the point when you want to recompile

alexmiller 2020-08-06T21:00:20.088200Z

so was trying to hook that

seancorfield 2020-08-06T21:00:35.088600Z

Yeah, discussions about it being a possible future feature of clj was what made me even curious to try it, once it was brought up here.

alexmiller 2020-08-06T21:03:14.089500Z

relevant for tools that replace the classpath too