I have experimented with ClojureCLR, calling Clojure from C#, C# from Clojure etc., and everything seem to work great. But one thing which is not yet clear to me is how to use Clojure dependencies when using the Clojure NuGet package in a C# application. Where will Clojure look for dependencies in that case?
I tried using -M -e to run some code from the command-line. With the regular CLI, you could run clojure -M -e '(clojure-version)' and that works on WSL2, but not on PS:
PS C:\Users\seanc> cljr -M -e '(clojure-version)'
Starting main
clojure-version : The term 'clojure-version' is not recognized as the name of a
cmdlet, function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and try again.
At line:1 char:137
+ ... pha1\tools\net6.0\any\tools\run-clojure-main.ps1 -e (clojure-version)
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (clojure-version:String) [], Command
NotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
After a lot of experimentation, I discovered that the following works:
PS C:\Users\seanc> cljr -M -e "'(clojure-version)'"
Starting main
"1.12.0-alpha9"
(double-quotes around single-quotes around the code) Is that the preferred/canonical solution for quoting on PS?There are problems with PowerShell arg processing that I've run into. The original CLI had code with some very explicit hacks for processing input to their PS script. The fix I put in for the problems Linux uses were happening (not recognizing the tool name) was due to wrapping the arguments with double quotes -- works for PS, not for Linux shells. I'll do a little more research and put the results on the README. Thanks for working it out.
I knew I had about this somewhere. It's actually mentioned in the CLI reference in the sections [Quoting keys and values](https://clojure.org/reference/clojure_cli#quoting).
> On Windows, WSL2 shells can follow the advice above, but using clojure.exe, additional escape quoting is required for string values. Unfortunately the combination of quoting rules for converting command line Windows program arguments, quoting, and word splitting are https://stackoverflow.com/a/59681993/7671.
>
> To pass a string value at the top level, if the string value does not have spaces, you can use '\"str\"'. If the string value does have spaces (or not) you should use '"""str value"""'.
PS D:> clj -X clojure.core/prn :string1 '\"no-spaces\"' :string2 '"""has spaces"""'
{:string1 "no-spaces", :string2 "has spaces"}
> For string values nested inside other collections, use double quotes if there are spaces and triple quotes if there are not:
PS D:> clj -X clojure.core/prn :val '{:s1 """nospaces""" :s2 ""has spaces""}'
{:val {:s1 "nospaces", :s2 "has spaces"}}OK, I wasn't sure if the native cljr tool would have the same restrictions...
PS C:\Users\seanc> cljr -M -e '"""(println 123)"""'
WARNING: Use of :paths external to the project has been deprecated, please remove: .
Starting main
123
I have no deps.edn in this folder -- is that what is causing the WARNING, or is there something in the system deps.edn causing this?
Also, probably ought to remove Starting main as people expect the CLI's output to be just what their code outputs.The lack of deps.edn is causing the warning.
So noted on the "starting main" message.
> The lack of deps.edn is causing the warning.
There's no such warning from the Clojure CLI without a deps.edn which is why I'm asking.
(I feel we've discussed this in the past, and there's something in cljr's system deps that is causing this?)
I'll double-check. PIck one of: (a) I forgot; (b) I did it wrong.
It will be fixed in alpha6. But maybe I'll wait a day or two before putting out yet another alpha.
I’m wanting to use a local C# class in my Clojure code, but am unsure how to include this on startup, I’d like to do something like this in deps.edn, while allowing hello.main to know about and :import my local .NET class.
{:paths ["src/cljr" "path/to/dotnet/build"]
:aliases {:run {:main-opts ["-m" "hello.main"]}}}
How can I achieve this? If it helps, I have a sample project (https://github.com/brandoncorrea/hello-cljr) with a src/dotnet/Hello/World.cs class that I’d like to use in my src/cljr/hello/main.cljr namespace.Yes, I, too, would like to be able to do this. This is one of the big missing pieces in the tooling. I'm willing to expend any amount of time/energy to addressing this, but I really need help designing this -- I just don't know what all the pain points are and how best to solve this cleanly. Some of this is addressed in the Clojure(JVM) CLI tool with tools and preps. The CLI guide [states](https://clojure.org/reference/clojure_cli#deps_prep): > Source libs with Clojure source can immediately be added to the classpath of a project using it. However, some source libs require some preparation before they can be added, for example due to needing Java compilation, or copying / replacing resource files, etc. There is an entire library ( [tools.build](https://clojure.org/guides/tools_build) ) of functions for building Clojure projects. It is very JVM-specific, so I have not bothered to port it. We need our own. For your situation, we can imagine invoking a compile of your C# source, building an assembly. How we automate loading of that asssembly -- well, see below. In addition, the CLR differs from the JVM in ways that make the kind of integration I'd like to see a bit more difficult. On the JVM, you could invoke a compile of some Java source, stick a jar on the classpath, and away you go; the mechanisms of class loading in the JVM along with how Clojure(JVM) looks classes takes care of things. In the CLR world, we have to deal with assembly loading and other matters. It is not as clean and I would say ClojureCLR could probably use some more sophisticated machinery. I've thought about extending the use of CLOJURE_LOAD_PATH to include the discovery of assemblies. Thought is needed on this. Another aspect of this is how to take advantage of Nuget. Clojure(JVM) uses maven for a lot of things. I did not replicate that work -- not our ballpark. I can fairly easily deal with the adding nuget coordinates to go along with :local and :git coordinates in deps.edn files. The problem is how we want to package things in that world. There are several different kinds of things to package: • Pure C#/F# (i.e. non-Clojure) projects. One has to deal with platform-dependencies and probably other things I'm not even aware of. Pulling in the package is the easy part. • Pure Clojure projects. Just Clojure source code. I do that already. I came up with a design over 10 years ago. I'm not sure it was the right design. I'm sure there is a better way. • Mixed projects. I could really use help with this. If some folks are interested, maybe I could start a Discussion over on my clojure-clr-next repo? (I don't own the clojure-clr repo, so not there.)
The discussion has been created. https://github.com/dmiller/clojure-clr-next/discussions/5 Let's go!
I’m willing to collaborate on this. I will say, it’s been a minute since I’ve written much C# code. Also, I haven’t worked on any of the core clojure libs, so I will not be much help when it comes to defining interfaces/patterns already set out on the JVM side.
I don't think of of those disclaimers are disqualifying. 🙂
Happy to help where I can. Not much C# experience but lots of general experience with different platforms/languages/systems.
[ANN] Clojure.Cljr (the cljr command) just published version 0.1.0-alpha3. A bug fix that will affect non-Windows users only.
Clojure.Cljr-0.1.0-alpha4 just published. Now returning the exit code from the tool or exec process that gets spawned.
I ran:
dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha4
on WSL2 and it installed (but warned me to run dotnet workload update -- which I found needed sudo). Then I ran it on the Windows side under Powershell and it said Tool 'clojure.cljr' is already installed, so I ran cljr -version and it reported:
ClojureCLR CLI Version: 0.1.0.0
So how can I tell which alpha I have installed on PS? Or does the WSL2 dotnet install also install it on the Windows side?I believe you have to install separately on the WSL2 and Windows sides. I'll crank up another alpha that shows the alpha version. I was just returning the AssemblyName.Version value. That does not have the alpha/beta/etc. designation. There is another route by which to get the additional info.
> cljr --version
ClojureCLR CLI Version: 0.1.0-alpha5
Alpha5 is now available.Thanks. Confirmed you are right:
PS C:\Users\seanc> dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha5
Tool 'clojure.cljr' is already installed.
Alpha 5 is definitely not installed on Windows, but I don't remember (and can't tell) what alpha version is installed...
...so how can I upgrade the Windows version to the new alpha?I just did the install command in two places, a regular PS terminal and a WSL2 terminal. They functioned independently.
On WSL2, it worked as (I) expected:
(~)-(!2013)-> dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha5
Tool 'clojure.cljr' was successfully updated from version '0.1.0-alpha4' to version '0.1.0-alpha5'.
Sun Oct 27 11:00:47
(~)-(!2014)-> cljr --version
ClojureCLR CLI Version: 0.1.0-alpha5
whereas it won't just upgrade on Windows.PS C:\Users\seanc> dotnet tool uninstall --global Clojure.Cljr
Tool 'clojure.cljr' (version '0.1.0-alpha1') was successfully uninstalled.
PS C:\Users\seanc> dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha5
You can invoke the tool using the following command: cljr
Tool 'clojure.cljr' (version '0.1.0-alpha5') was successfully installed.
PS C:\Users\seanc> cljr -version
ClojureCLR CLI Version: 0.1.0-alpha5
It is expected that I'd need to uninstall the current version before installing the upgrade?it upgraded for me on both platforms. I uninstalled to get to zero, then installed alpha 4, then installed alpha5. WSL:
david@DESKTOP-IBDM5GL:~/test/clr.core.memoize$ dotnet tool uninstall Clojure.Cljr -g
Tool 'clojure.cljr' (version '0.1.0-alpha5') was successfully uninstalled.
david@DESKTOP-IBDM5GL:~/test/clr.core.memoize$ dotnet tool install Clojure.Cljr -g --version 0.1.0-alpha4
You can invoke the tool using the following command: cljr
Tool 'clojure.cljr' (version '0.1.0-alpha4') was successfully installed.
david@DESKTOP-IBDM5GL:~/test/clr.core.memoize$ dotnet tool install Clojure.Cljr -g --version 0.1.0-alpha5
Tool 'clojure.cljr' was successfully updated from version '0.1.0-alpha4' to version '0.1.0-alpha5'.
PS on Windows:
PS C:\Users\dmill> dotnet tool uninstall --global Clojure.Cljr
Tool 'clojure.cljr' (version '0.1.0-alpha5') was successfully uninstalled.
PS C:\Users\dmill> dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha4
You can invoke the tool using the following command: cljr
Tool 'clojure.cljr' (version '0.1.0-alpha4') was successfully installed.
PS C:\Users\dmill> dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha5
Tool 'clojure.cljr' was successfully updated from version '0.1.0-alpha4' to version '0.1.0-alpha5'.
Interesting. So maybe some issue with old my cljr install was before perhaps? I'll keep an eye on this in future.
Can you post reminders of how to install/upgrade things when you post new versions (for those of us not familiar with .NET tooling)?
Sure. I've now done it enough that I actually remember. Usually. Sorta. Installing as a global tool:
dotnet tool install --global Clojure.Cljr --version 0.1.0-alpha3
Installing as local tool (though I've never done this):
dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local Clojure.Cljr --version 0.1.0-alpha3
Once installed, you can invoke using cljr. Presumably you'd cd into a project with a deps.edn
(or a deps-clr.edn if you need to have different versions for ClojureCLR vs Clojure(JVM)):
cljr -X:deps tree
cljr -X:test
cljr
This information and more available on the README at the [repo](https://github.com/clojure/clr.core.cli).