justinethier / cyclone

:cyclone: A brand-new compiler that allows practical application development using R7RS Scheme. We provide modern features and a stable system capable of generating fast native binaries.
http://justinethier.github.io/cyclone/
MIT License
823 stars 42 forks source link

Automatically load C libraries when importing a library in the REPL #447

Open justinethier opened 3 years ago

justinethier commented 3 years ago

icyc is throwing an error when importing Arthur's python library because libpython is not being loaded by the interpreter.

Currently the workaround is:

cyclone> (import-shared-object "libpython3.8.so")
#t
cyclone> (import (cyclone python))
ok

However, a better solution is for icyc (or really the Cyclone libraries it is using) to take care of this automatically.

It looks like it should be possible to reverse engineer library names from the c-linker-options directives. In that case the interpreter can automatically do this work as part of an import. If not, or as a failsafe, we may need another library directive to instruct the interpreter to load this library.  

arthurmaciel commented 3 years ago

A spinoff for the Future™:

@justinethier, considering the existence of import-shared-object, do you believe we could provide a c-call macro in (cyclone foreign), similiar to Julia's ccall, that would write the C function to a file, compile it as a shared lib, load it in the REPL and run it? I suppose there could a more decent way to do it :)

Something with the following syntax (or something more clear):

(c-call C-function-name-or-list-of-name-and-lib 
        return-value-type 
        list-of-parameters'-types 
        list-of-parameters))

So, using Julia's examples:

;; Julia:  t = ccall(:clock, Int32, ())
(define t
        (c-call "clock"
                 int
                 '()))
;; Julia: path = ccall(:getenv, Cstring, (Cstring,), "SHELL")
(define path
        (c-call "getenv"
                 string
                 '(string)
                 "SHELL"))
;; Julia: 
;;     hostname = Vector{UInt8}(undef, 256) # MAXHOSTNAMELEN
;;     err = ccall((:gethostname, "libc"), Int32,
;;                 (Ptr{UInt8}, Csize_t),
;;                 hostname, sizeof(hostname))

(define hostname (make-bytevector 256))

(define err
        (c-call '("gethostname" "libc")
                 int
                 '(bytevector int)
                 hostname (bytevector-length hostname))
justinethier commented 3 years ago

@arthurmaciel That's a really cool idea! We will have to figure out the details but I like this idea of being able to dynamically make C calls.