Hello Camm, *,
I am testing your instructions to load and use an external library
dynamically linked and I have a couple of issues.
First, I am unable to load libjula.so because of an undefined symbol:
Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/
>(si:mdlsym "jl_init" "libjulia.so")
Error:
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by SYSTEM:MDLSYM.
Condition in SYSTEM:MDLSYM [or a callee]: INTERNAL-SIMPLE-ERROR: dlopen
failure on "libjulia.so": "/usr/local/lib/libjulia.so: undefined symbol:
jl_pgcstack_static_semaphore"
Broken at SYSTEM:MDLSYM. Type :H for Help.
1 Return to top level.
This is the same with your macro below. This does not happen with SBCL,
Clozure CL or pure C (just tested). I looked at the Julia code and it
almost not used; the only pieces of code (MIT licence) are:
In a header file:
#if !defined(_OS_DARWIN_) && !defined(_OS_WINDOWS_)
#define JULIA_DEFINE_FAST_TLS
\
static __attribute__((tls_model("local-exec"))) __thread jl_gcframe_t
**jl_pgcstack_localexec;
\
JL_DLLEXPORT _Atomic(char) jl_pgcstack_static_semaphore;
\
JL_DLLEXPORT jl_gcframe_t **jl_get_pgcstack_static(void)
\
{
\
return jl_pgcstack_localexec;
\
}
\
JL_DLLEXPORT jl_gcframe_t ***jl_pgcstack_addr_static(void)
\
{
\
return &jl_pgcstack_localexec;
\
}
#else
#define JULIA_DEFINE_FAST_TLS
#endif
and in a C file:
#if !defined(_OS_WINDOWS_) && !defined(_OS_DARWIN_)
void (*jl_pgcstack_setkey)(void*, void*(*)(void)) = lookup_symbol(
libjulia_internal, "jl_pgcstack_setkey");
if (jl_pgcstack_setkey == NULL) {
jl_loader_print_stderr("ERROR: Cannot find jl_pgcstack_setkey()
function within libjulia-internal!\n");
exit(1);
}
void *fptr = lookup_symbol(RTLD_DEFAULT, "jl_get_pgcstack_static");
void *(*key)(void) = lookup_symbol(RTLD_DEFAULT,
"jl_pgcstack_addr_static");
_Atomic(char) *semaphore = lookup_symbol(RTLD_DEFAULT,
"jl_pgcstack_static_semaphore");
if (fptr != NULL && key != NULL && semaphore != NULL) {
char already_used = 0;
atomic_compare_exchange_strong(semaphore, &already_used, 1);
if (already_used == 0) // RMW succeeded - we have exclusive access
jl_pgcstack_setkey(fptr, key);
}
#endif
So, since it seems to me it is just an optimization, for experimental
purpose, I removed those pieces of code and rebuilt Julia and was able to
load libjulia. I still wonder why GCL, contrary to the mentioned CL
implementations, encounters the error above: undefined symbol.
The second issue is related to the macro you mentioned below, I cannot give
a path to the library at run time:
(si::defdlfun (:void "jl_init" (|make_absolute_filename|
"/lib/julia_wrap.so")) :void)
julia_wrap.so is in a FriCAS lib directory and not in the ld library path
so I need to give the full path. Here '(|make_absolute_filename|
"/lib/julia_wrap.so")' is not executed so GCLcomplains about the fact it's
not of type STRING. Accessory I do not know if ':void' instead of ':void*'
can be used. I tested the two.
Do you think I need to use more low-level operations with lib-name, mdl
etc. the one used above in GCL, etc. and in fact, I do not know how?
julia_wrap.so is a wrapper linked against libjulia, and dload-ed by FriCAS,
it's necessary, see some examples here eventually:
https://docs.julialang.org/en/v1/manual/embedding/
Maybe later I will ask some other questions about the GCL garbage collector
to know if there is a "terminate" hook in it, I need it, I have two
interface types in my Julia interface one where Julia operates directly on
CL arrays, and another one where datas are in the Julia process stored in a
hashed dictionary, so when GCL is GC-ing CL variables (a very simple class
object in my interface that contains the key) I need to inform the Julia GC
it can also GC them, i.e. delete them from the dictionary.
Hoping I am relatively clear, regards,
- Greg
Le jeu. 29 mai 2025 à 22:23, Camm Maguire <[email protected]> a écrit :
> Greetings!
>
> Grégory Vanuxem <[email protected]> writes:
>
> > Hi Waldek,
> >
> > Many thanks for this quick response and fix. Just tested on official
> FriCAS and the 2 problems you mentioned previously gone away.
> >
> > The .fricas.input file is still not "read" but for my mid-term work it
> is not a big problem, my startup file is just displaying computation times
> and augmenting line
> > length of output to 110. Maybe this is related to my Kali distribution
> on WSL2, I don't know.
> >
> > The )read command is to blame on my settings:
> >
> > (1) -> )sys pws
> >
> > >> System error:
> > INTERNAL-SIMPLE-ERROR: The assertion !posix_spawnp(&pid, *p1,
> &file_actions, &attr, (void *)p1, environ) on line 65 of o/unixsys.c in
> function vsystem failed:
> > No such file or directory
> >
> > (1) -> )sys pwd
> > /home/greg
> > (1) -> )sys ls -l .fricas.input
> > -rw-r--r-- 1 greg greg 35 Feb 11 09:42 .fricas.input
> > (1) -> )read .fricas.input
> >
> > The file .fricas.input is needed but does not exist.
> >
> > BTW great improvements have been done for gcl-2.7.1, thanks to you and
> > Camm, it's a very good thing for me since I plan to code a wrapper in
> > Common Lisp using my C wrapper to Julia compatible with GCL. I did one
> > for Axiom in the past, a coding LISP game for me containing only
> > "and", "or "and "not" keywords (no
>
> Most happy to see a satisfied customer!
>
> > loops or conditionals). A direct wrapper to Fortran BLAS in fact. Now
> > I have to look at documentation changes for the GCL-2.7 series FFI.
> >
>
> I turn your attention to defdlfun. In 2.7.x we can establish persistent
> (across image saves) bindings to new external shared libraries on the
> fly, with the call overhead being a single pointer dereference:
>
>
> >(describe 'defdlfun)
>
> DEFDLFUN - internal symbol in COMMON-LISP-USER package
> From ((DEFDLFUN . External Shared Libraries) gcl-si.info):
>
> -- Macro: DEFDLFUN
> Package:SYSTEM
>
> Syntax:
> (compile (DEFDLFUN {RETURN NAME &optional LIBNAME) ARGS*))
>
> GCL specific: Produces an entry function to function NAME in
> external shared library LIBNAME with the specified args/return
> signature. This function must be compiled to run. When inlined,
> the function call collapses to a single reference to a pointer
> which is automatically updated to the location of the external
> function at image startup. The connection to the external library
> is persistent across image saves and re-executions. The RETURN and
> ARGS specifiers are keywords from the following list corresponding
> to the accompanying C programming types:
>
> :char :short :int :long :float :double
>
> Unsigned versions available are:
>
> :uchar :ushort :uint
>
> Complex float and complex double types can be access via:
>
> :fcomplex :dcomples
>
> Pointers to types available are
>
> :void* :char* :long* :float* :double*
>
> Example usage:
>
>
>
>
> GCL (GNU Common Lisp) 2.7.0 Thu Oct 26 12:00:01 PM EDT 2023
> CLtL1 git: Version_2_7_0pre38
> Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
> Binary License: GPL due to GPL'ed components: (XGCL READLINE
> UNEXEC)
> Modifications of this banner must retain notice of a compatible
> license
> Dedicated to the memory of W. Schelter
>
> Use (help) to get some basic information on how to use GCL.
> Temporary directory for compiler files set to /tmp/
>
> >(do-symbols (s :lib) (print s))
>
> LIB:|libm|
> LIB:|libc|
> NIL
>
> >(compile (si::defdlfun (:double "cblas_ddot" "libblas.so")
> :uint :double* :uint :double* :uint))
>
> ;; Compiling /tmp/gazonk_653784_0.lsp.
> ;; End of Pass 1.
> ;; End of Pass 2.
> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0,
> Speed=3
> ;; Finished compiling /tmp/gazonk_653784_0.o.
> ;; Loading #P"/tmp/gazonk_653784_0.o"
> ;; start address for /tmp/gazonk_653784_0.o 0x2700860
> ;; Finished loading #P"/tmp/gazonk_653784_0.o"
> #<function 0000000001a4a860>
> NIL
> NIL
>
> >(do-symbols (s :lib) (print s))
>
> LIB:|libblas|
> LIB:|libm|
> LIB:|libc|
> NIL
>
> >(do-symbols (s 'lib::|libblas|) (unless (find-symbol
> (symbol-name s) :user) (print s)))
>
> |libblas|:|cblas_ddot|
> NIL
> NIL
>
> >(setq a (make-array 3 :element-type 'long-float) b (make-array
> 3 :element-type 'long-float))
>
> #(0.0 0.0 0.0)
>
> >(setf (aref a 1) 1.2 (aref b 1) 2.3)
>
> 2.3
>
> >(|libblas|:|cblas_ddot| 3 a 1 b 1)
>
> 2.76
>
> >(compile (defun foo (a b) (declare ((vector long-float) a b))
> (|libblas|:|cblas_ddot| (length a) a 1 b 1)))
>
> ;; Compiling /tmp/gazonk_653784_0.lsp.
> ;; End of Pass 1.
> ;; End of Pass 2.
> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0,
> Speed=3
> ;; Finished compiling /tmp/gazonk_653784_0.o.
> ;; Loading #P"/tmp/gazonk_653784_0.o"
> ;; start address for /tmp/gazonk_653784_0.o 0x2715050
> ;; Finished loading #P"/tmp/gazonk_653784_0.o"
> #<function 0000000001a62140>
> NIL
> NIL
>
> >(compile (defun bar (a b) (declare (inline
> |libblas|:|cblas_ddot|) ((vector long-float) a b)) (|libblas|:|cblas_ddot|
> (length a) a 1 b 1)))
>
> ;; Compiling /tmp/gazonk_653784_0.lsp.
> ;; End of Pass 1.
> ;; End of Pass 2.
> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0,
> Speed=3
> ;; Finished compiling /tmp/gazonk_653784_0.o.
> ;; Loading #P"/tmp/gazonk_653784_0.o"
> ;; start address for /tmp/gazonk_653784_0.o 0x2729570
> ;; Finished loading #P"/tmp/gazonk_653784_0.o"
> #<function 0000000001a62740>
> NIL
> NIL
>
> >(foo a b)
>
> 2.76
>
> >(bar a b)
>
> 2.76
>
> >(setq compiler::*disassemble-objdump* nil)
>
> NIL
>
> >(disassemble '|libblas|:|cblas_ddot|)
>
> ;; Compiling /tmp/gazonk_653784_0.lsp.
> ;; End of Pass 1.
> ;; End of Pass 2.
> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0,
> Speed=3
> ;; Finished compiling /tmp/gazonk_653784_0.o.
>
> #include "gazonk_653784_0.h"
> void init_code(){do_init((void *)VV);}
> /* local entry for function libblas::cblas_ddot */
>
> static object LI1__cblas_ddot___gazonk_653784_0(fixnum V6,object
> V7,fixnum V8,object V9,fixnum V10)
> { VMB1 VMS1 VMV1
> if(!(((char)tp0(make_fixnum(V6)))==(1))){
> goto T8;
> }
> if(!((0)<=(V6))){
> goto T13;
> }
> if(!((V6)<=((fixnum)4294967295))){
> goto T11;
> }
> goto T12;
>
> goto T13;
> T13:;
> goto T11;
>
> goto T12;
> T12:;
> goto T7;
>
> goto T11;
> T11:;
> goto T6;
>
> goto T8;
> T8:;
> goto T6;
>
> goto T7;
> T7:;
> goto T5;
>
> goto T6;
> T6:;
> goto T3;
>
> goto T5;
> T5:;
> goto T2;
>
> goto T3;
> T3:;
> V11= CMPmake_fixnum(V6);
> V6= fixint((fcall.argd=4,/* SYSTEM::CHECK-TYPE-SYMBOL
> */(object )(*LnkLI2)(((object)VV[1]),(V11),((object)VV[2]),Cnil)));
> goto T2;
> T2:;
> switch(tp6(V7)){
> case 428:
> goto T27;
> T27:;
> case 492:
> goto T28;
> T28:;
> goto T25;
>
> default:
> goto T29;
> T29:;
> goto T24;
>
> goto T24;
> }
> goto T24;
>
> goto T25;
> T25:;
> goto T23;
>
> goto T24;
> T24:;
> goto T22;
>
> goto T23;
> T23:;
> goto T21;
>
> goto T22;
> T22:;
> goto T19;
>
> goto T21;
> T21:;
> goto T18;
>
> goto T19;
> T19:;
> V7= (fcall.argd=4,/* SYSTEM::CHECK-TYPE-SYMBOL */(object
> )(*LnkLI2)(((object)VV[3]),(V7),((object)VV[4]),Cnil));
> goto T18;
> T18:;
> if(!(((char)tp0(make_fixnum(V8)))==(1))){
> goto T39;
> }
> if(!((0)<=(V8))){
> goto T44;
> }
> if(!((V8)<=((fixnum)4294967295))){
> goto T42;
> }
> goto T43;
>
> goto T44;
> T44:;
> goto T42;
>
> goto T43;
> T43:;
> goto T38;
>
> goto T42;
> T42:;
> goto T37;
>
> goto T39;
> T39:;
> goto T37;
>
> goto T38;
> T38:;
> goto T36;
>
> goto T37;
> T37:;
> goto T34;
>
> goto T36;
> T36:;
> goto T33;
>
> goto T34;
> T34:;
> V12= CMPmake_fixnum(V8);
> V8= fixint((fcall.argd=4,/* SYSTEM::CHECK-TYPE-SYMBOL
> */(object )(*LnkLI2)(((object)VV[5]),(V12),((object)VV[2]),Cnil)));
> goto T33;
> T33:;
> switch(tp6(V9)){
> case 428:
> goto T58;
> T58:;
> case 492:
> goto T59;
> T59:;
> goto T56;
>
> default:
> goto T60;
> T60:;
> goto T55;
>
> goto T55;
> }
> goto T55;
>
> goto T56;
> T56:;
> goto T54;
>
> goto T55;
> T55:;
> goto T53;
>
> goto T54;
> T54:;
> goto T52;
>
> goto T53;
> T53:;
> goto T50;
>
> goto T52;
> T52:;
> goto T49;
>
> goto T50;
> T50:;
> V9= (fcall.argd=4,/* SYSTEM::CHECK-TYPE-SYMBOL */(object
> )(*LnkLI2)(((object)VV[6]),(V9),((object)VV[4]),Cnil));
> goto T49;
> T49:;
> if(!(((char)tp0(make_fixnum(V10)))==(1))){
> goto T70;
> }
> if(!((0)<=(V10))){
> goto T75;
> }
> if(!((V10)<=((fixnum)4294967295))){
> goto T73;
> }
> goto T74;
>
> goto T75;
> T75:;
> goto T73;
>
> goto T74;
> T74:;
> goto T69;
>
> goto T73;
> T73:;
> goto T68;
>
> goto T70;
> T70:;
> goto T68;
>
> goto T69;
> T69:;
> goto T67;
>
> goto T68;
> T68:;
> goto T65;
>
> goto T67;
> T67:;
> goto T64;
>
> goto T65;
> T65:;
> V13= CMPmake_fixnum(V10);
> V10= fixint((fcall.argd=4,/* SYSTEM::CHECK-TYPE-SYMBOL
> */(object )(*LnkLI2)(((object)VV[7]),(V13),((object)VV[2]),Cnil)));
> goto T64;
> T64:;
> {object V14 =
> make_longfloat(((double(*)(uint,double*,uint,double*,uint))(dlcblas_ddot))((uint)V6,(double*)V7->v.v_self,(uint)V8,(double*)V9->v.v_self,(uint)V10));
> VMR1(V14);}
> }
> static object LnkTLI2(object first,...){object V1;va_list
> ap;va_start(ap,first);V1=(object
> )call_proc_new(((object)VV[0]),0,262147,(void **)(void
> *)&LnkLI2,0,first,ap);va_end(ap);return V1;} /* SYSTEM::CHECK-TYPE-SYMBOL */
> (9 (MAPC 'EVAL *COMPILER-COMPILE-DATA*))
> static object LI1__cblas_ddot___gazonk_653784_0(fixnum V6,object
> V7,fixnum V8,object V9,fixnum V10)
> ;
> static void *dlcblas_ddot;
> #define VMB1 object V13 ,V12 ,V11;
> #define VMS1
> #define VMV1
> #define VMRV1(a_,b_) return((object )a_);
> #define VMR1(a_) VMRV1(a_,0);
> #define VM1 0
> static void * VVi[9]={
> #define Cdata VV[8]
> (void *)(&dlcblas_ddot),
> (void *)(LI1__cblas_ddot___gazonk_653784_0)
> };
> #define VV (VVi)
> static object LnkTLI2(object,...);
> static object (*LnkLI2)() = (object (*)()) LnkTLI2;
> NIL
>
> >(disassemble 'foo)
>
> ;; Compiling /tmp/gazonk_653784_0.lsp.
> ;; End of Pass 1.
> ;; End of Pass 2.
> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0,
> Speed=3
> ;; Finished compiling /tmp/gazonk_653784_0.o.
>
> #include "gazonk_653784_0.h"
> void init_code(){do_init((void *)VV);}
> /* local entry for function COMMON-LISP-USER::FOO */
>
> static object LI1__FOO___gazonk_653784_0(object V3,object V4)
> { VMB1 VMS1 VMV1
>
> if(!(((char)((fixnum)((uchar*)((fixnum)V3))[(fixnum)2]&(fixnum)1))==(0))){
> goto T5;
> }
> goto T2;
>
> goto T5;
> T5:;
> V5= ((fixnum)((uint*)((fixnum)V3))[(fixnum)4]&268435455);
> goto T1;
>
> goto T2;
> T2:;
> V5=
> (((fixnum)((uint*)((fixnum)V3))[(fixnum)1]>>(fixnum)3)&268435455);
> goto T1;
> T1:;
> {object V6 = (/* libblas::cblas_ddot */(object
> )(*LnkLI2)(V5,(V3),(fixnum)1,(V4),(fixnum)1));
> VMR1(V6);}
> }
> static object LnkTLI2(object first,...){object V1;va_list
> ap;va_start(ap,first);V1=(object )call_proc_new(((object)VV[0]),0,5,(void
> **)(void *)&LnkLI2,1092,first,ap);va_end(ap);return V1;} /*
> libblas::cblas_ddot */
> (2 (MAPC 'EVAL *COMPILER-COMPILE-DATA*))
> static object LI1__FOO___gazonk_653784_0(object V3,object V4)
> ;
> #define VMB1 fixnum V5;
> #define VMS1
> #define VMV1
> #define VMRV1(a_,b_) return((object )a_);
> #define VMR1(a_) VMRV1(a_,0);
> #define VM1 0
> static void * VVi[2]={
> #define Cdata VV[1]
> (void *)(LI1__FOO___gazonk_653784_0)
> };
> #define VV (VVi)
> static object LnkTLI2(object,...);
> static object (*LnkLI2)() = (object (*)()) LnkTLI2;
> NIL
>
> >(disassemble 'bar)
>
> ;; Compiling /tmp/gazonk_653784_0.lsp.
> ;; End of Pass 1.
> ;; End of Pass 2.
> OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0,
> Speed=3
> ;; Finished compiling /tmp/gazonk_653784_0.o.
>
> #include "gazonk_653784_0.h"
> void init_code(){do_init((void *)VV);}
> /* local entry for function COMMON-LISP-USER::BAR */
>
> static object LI1__BAR___gazonk_653784_0(object V3,object V4)
> { VMB1 VMS1 VMV1
> {fixnum V5;
>
> if(!(((char)((fixnum)((uchar*)((fixnum)V3))[(fixnum)2]&(fixnum)1))==(0))){
> goto T5;
> }
> goto T2;
>
> goto T5;
> T5:;
> V5= ((fixnum)((uint*)((fixnum)V3))[(fixnum)4]&268435455);
> goto T1;
>
> goto T2;
> T2:;
> V5=
> (((fixnum)((uint*)((fixnum)V3))[(fixnum)1]>>(fixnum)3)&268435455);
> goto T1;
> T1:;
> {object V6 =
> make_longfloat(((double(*)(uint,double*,uint,double*,uint))(dlcblas_ddot))((uint)V5,(double*)V3->v.v_self,(uint)1,(double*)V4->v.v_self,(uint)1));
> VMR1(V6);}}
> }
> (2 (MAPC 'EVAL *COMPILER-COMPILE-DATA*))
> static object LI1__BAR___gazonk_653784_0(object V3,object V4)
> ;
> static void *dlcblas_ddot;
> #define VMB1
> #define VMS1
> #define VMV1
> #define VMRV1(a_,b_) return((object )a_);
> #define VMR1(a_) VMRV1(a_,0);
> #define VM1 0
> static void * VVi[2]={
> #define Cdata VV[1]
> (void *)(&dlcblas_ddot),
> (void *)(LI1__BAR___gazonk_653784_0)
> };
> #define VV (VVi)
> NIL
>
> >(si::save-system "ff")
> $ ./ff
> GCL (GNU Common Lisp) 2.7.0 Thu Oct 26 12:00:01 PM EDT 2023
> CLtL1 git: Version_2_7_0pre38
> Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
> Binary License: GPL due to GPL'ed components: (XGCL READLINE
> UNEXEC)
> Modifications of this banner must retain notice of a compatible
> license
> Dedicated to the memory of W. Schelter
>
> Use (help) to get some basic information on how to use GCL.
> Temporary directory for compiler files set to /tmp/
>
> >(foo a b)
>
> 2.76
>
> >(bar a b)
>
> 2.76
>
> >
>
>
> Take care,
>
>
> >
>
> > - Greg
> >
> > PS / I Cc-ed to gcl-devel
> >
> > Le sam. 24 mai 2025 à 15:30, Waldek Hebisch <[email protected]> a écrit :
> >
> > On Fri, May 23, 2025 at 09:56:29PM +0200, Grégory Vanuxem wrote:
> > > Hello,
> > >
> > > I don't know if you can reproduce this: if I start FriCAS from $HOME
> it
> > > starts nicely but if I start in another directory see the snippet
> below.
> > > I tried with gcl2.7.1-4 from a Debian based distribution and after
> with the
> > > official Debian sid and the same happens:
> > >
> > <snip>
> > >
> > > >> System error:
> > > INTERNAL-SIMPLE-PARSE-ERROR: "/home/greg//.fricas.input" is not a
> valid
> > > pathname on host NIL
> > >
> > >
> > > >> System error:
> > > INTERNAL-SIMPLE-ERROR: The tag |top_level| is undefined.
> >
> > Should be fixed now.
> >
> > --
> > Waldek Hebisch
> >
> > --
> > You received this message because you are subscribed to the Google
> Groups "FriCAS - computer algebra system" group.
> > To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected].
> > To view this discussion visit
> https://groups.google.com/d/msgid/fricas-devel/aDHJ1HqJwLlykCMl%40fricas.org
> .
>
> --
> Camm Maguire [email protected]
> ==========================================================================
> "The earth is but one country, and mankind its citizens." -- Baha'u'llah
>
> --
> You received this message because you are subscribed to the Google Groups
> "FriCAS - computer algebra system" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion visit
> https://groups.google.com/d/msgid/fricas-devel/87cybryxm6.fsf%40maguirefamily.org
> .
>