Finding the path of a loaded module

Suppose I want to load a dynamic link library, contained in a racket module. How would I determine where the loaded module can be found?

I'd want to do something like this from an FFI module

(define-ffi-definer define-lib
  (ffi-lib "./lib/library.so"))

And hopefully the library.so is then loaded from "lib" subdirectory of the current module directory.

What you're looking for may be in here: 6.1 Module Basics.

(find-collects-dir) ; is the main collection directory

(find-user-collects-dir) ; is the user directory

(get-collects-search-dirs) ; returns a list of multiple module search paths

It's not very helpful that racket calls these "collects", which you would never think to search for.

Neal

Actually, I found the answer:

(define-runtime-path libao-async-path "./lib/libao-play-async")

(define-ffi-definer define-libao-async
  (ffi-lib libao-async-path '("0" #f)
           #:get-lib-dirs (λ ()
                            (let ((sp (cons (build-path ".") (get-lib-search-dirs))))
                              ;(displayln sp)
                              sp))
           #:fail (λ () (error "Cannot load libao-play-async"))
           ))

So 'define-runtime-path' seems to do the job.

I have a binding to libao, but ao_play seems to block the thread it is working in.
I tried using the new parallel threads of racket, but it somehow still blocks, leaving drracket almost unusable and generating a lot of ticks, because the samples are fed to slow, so I eventually created an extra library (not my preference) that I can feed music samples an that are played in a different thread (using real C pthreads).

See code at: hans/racket-sound: Racket libao FFI binding - racket-sound - GitEA bij dijkewijk

Using define-runtime-path is the right starting point. If you use it, you should not need to also use the #:get-lib-dirs argument (and including the current directory at runtime there can be dangerous!).

A potential enhancement can be to instead use:

(define-runtime-path libao-async-path
  '(so "libao-play-async" ("0" #f)))

and add this to your existing info.rkt file:

#lang info
;; ... add to existing content ...
(define install-platform #rx"^x86_64-linux(?:-natipkg)?$") ; or whatever is relevant
(define copy-foreign-libs '("libao/lib/libao-play-async.so.0"))

The copy-foreign-libs directive tells raco setup to install the foreign library into an appropriate place, including graceful handling for system linker directives like $ORIGIN and @loader_path. The so variant of define-runtime-path finds libraries that were potentially installed that way, and also records them as dependencies for the executable builder. Altogether, the architecture prepares you for potentially building the foreign library for additional platforms in the future, at which point you may want to organize your packaging so that only code for the relevant platform has to be installed.


This part is surprising, and it's probably worth a look by someone who is more up-to-date than I am on OS parallelism support. As I first guess, have you checked if the unsafe threads from ffi/unsafe/os-thread have the same problems?

1 Like

Hi Philip, ffi/unsafe/os-thread does the trick. Tested it today in Windows. It's delicate to implement, but I got it working quite easy. This saves me a custom shared library. Thanks a lot!

1 Like

Unfortunately this way of working, although better in performance, still is too slow; still generating 'ticks' in the audio. So I had to go back to my little C shared library that processes the audio for me in a operating system thread.

I wonder if it helps running your program in a terminal instead of inside DrRacket?
DrRacket adds helpful debug instructions to your program, so potentially things could run faster in the terminal.

Looks like running it using 'racket' on the terminal instead of inside DrRacket works better. However, it seems to trigger memory corruption problems, which I don't get with DrRacket (maybe related with this)?

I also don't get this problem on Windows.

For me it feels like the 'garbage collector' kicks in every now and then. I.e. regarding the ‘audio clicks’.

When I experience this - it is almost always, because I have made a mistake in the FFI bindings.

That’s 3 or 4 FFI’s :thinking: that come together in my program. Is it possible to track the problem down to an FFI call? The program doesn’t crash.

I wanted to make an issue on the repo, but do to that I need to login.
How do I create a user?

Thanks for the message. I've enabled the possibility. It's possible to register now.

I have made a new user soegaard.
However, the site tells me it sends an activation email.
Nothing appears in Gmail - I also checked the spam folder.

Oh - and important to note - login requires that the account is activated.

Yeah. It is my local gitea repo, didn't think I needed to allow other users. I probably need to do som mail configuration. For now I've activated your account manually.

1 Like

Thanks. The activation worked.