Fork me on GitHub
#clr
<
2022-12-27
>
Emma Griffin22:12:34

Does anyone have experience loading native Linux files from ClojureCLR? I'm not doing so directly but using a library that does, without any success

bobcalco07:12:31

What library are you using? What kind of files specifically are you trying to load?

Emma Griffin14:12:25

https://github.com/TolikPylypchuk/SharpHook I can load the dll for the library fine but when I try to call certain methods I get an odd error about "no assembly found". The files are Linux shared object files from a C library that SharpHook is a wrapper for. The documentation for using the library doesn't suggest a need to explicitly load in the .so files at all though

bobcalco16:12:39

Sorry - I'm still not entirely clear what your objective is. That library is specifically to hook UI events generated by mouse and keyboard actions (an example use case here might be for record/replay functionality for an editor that wants to support "macros," or a general test automation tool). It wraps a specific native library for that purpose and is not a generic Foreign Function Interface (FFI) wrapper. But it sounds like you're looking for a general way to load *.so files and call into them. If your goal is the latter, then the approach requires getting jiggy with FFI on the CLR (see System.Runtime.InteropServices namespace for the relevant classes). The simplest approach might be to write a thin C# wrapper that uses externs around the library entry points you want to call using P/Invoke. You'll need to deal with marshalling data in such a wrapper, which can have a single static class interface which you call from the Clojure side to keep the Clojure code from becoming too gnarly. I haven't tried directly loading a native library from Clojure, but I'll look into it. My instinct is to use P/Invoke in a C# DLL which you can then call simply from Clojure using static class syntax. Here is a starting point to understand native interop on .NET if you've not delved into that particular circle of hell yet: https://learn.microsoft.com/en-us/dotnet/standard/native-interop/

bobcalco16:12:22

Depending on the DLL/SO file you want to work with, do a search to see if someone else has already written a P/Invoke wrapper for it. Many popular native libraries already have .NET wrappers someone wrote for them. But it's good to learn the native FFI stuff with some hands-on experience. What specific library are you trying to load?

bobcalco16:12:23

Incidentally studying the code of SharpHook and its wrapping of the libuiohook library would be a good start to see how it's done.

Emma Griffin14:12:12

Yeah, I've been trying to dynamically load the library's DLL in C# and been running into the same issue as I have for ClojureCLR. The library works fine in C# when I rely on dotnet to build the project from a .csproj file, but I haven't been able to figure out what it's doing. I can dynamically load SharpHook.dll from ClojureCLR or C# and I can access it's classes and methods but run into errors involving assembly files not being found when I actually attempt to invoke any of the methods for any of the classes provided by the SharpHook library. Trying to load the .so file dynamically via System.Reflection.Assembly.LoadFrom("libuiohook.so") also fails with a complaint about having a bad file type/the wrong IL format. I have a couple more ideas I'm going to try out to see if they work, but I'm confused as to why this method call fails when I should be able to load shared object files in .NET core, if I'm not mistaken.

Emma Griffin14:12:33

If I do need to make a wrapper in C#, that's fine, but from what I understand SharpHook already is that wrapper, so I'm not sure why I can't simply dynamically load that.

Emma Griffin14:12:48

To answer your previous question, it's to provide a ClojureScript and ClojureCLR port to https://github.com/D00mch/robot . The ClojureScript port seems to be mostly done but the ClojureCLR port has been much more of a headache due primarily to tooling.

Emma Griffin14:12:17

SharpHook seemed like the sensible choice unless I wanted to basically interop directly with the underlying C library which I'll do if I have to but that seems like overkill.

Emma Griffin14:12:56

The motivation for porting this library was in hopes of using it as a dependency for a broader library for testing graphical applications built in Clojure/ClojureScript/ClojureCLR. I don't know if I'll ever finish that unless I get a lot more free time on my hands, but having this library ported to all three platforms would be a good first start. The other motivation of course being the more libraries ported to ClojureCLR the better, so that the broader Clojure community is aware the language is still alive and being used for active development.

👍 1
Emma Griffin15:12:39

Suddenly it seems to at least partially work in ClojureCLR and C# despite not having changed my code since yesterday. I wonder if there's some dotnet shenanigans going on, I'll have to investigate further and see if I can isolate the issue.

Emma Griffin16:12:33

I think I found what changed. Apparently placing the .so file in the same directory as SharpHook.dll is sufficient for SharpHook.dll to find it once dynamically loaded. Statically loading the dependency using dotnet from the CLI in conjunction with using SharpHook; in the C# source code results in this not being necessary, but this is obviously not something that can be replicated directly in ClojureCLR. lein-clr seems to operate in a way that is contrary to being able to actually manage packages like this so I'm tempted to abandon it outright for this port and just rely on dotnet , nuget , and custom scripts to make this work. But this is definitely becoming more and more of a hack by the minute. The need for deps.edn support is very apparent, though @U45FQSBF1 we should be careful not to repeat the woes of lein-clr when implementing it, especially with regards to .NET dependencies that rely on native libraries.

👍 1
dmiller16:12:09

so noted.

1