diff --git a/src/ccall.cpp b/src/ccall.cpp index d9d25c7a939f0..eb915e955bc83 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -606,6 +606,9 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va arg1 = update_julia_type(ctx, arg1, (jl_value_t*)jl_voidpointer_type); jl_ptr = emit_unbox(ctx, ctx.types().T_ptr, arg1, (jl_value_t*)jl_voidpointer_type); } + else if (jl_is_cpointer_type(jl_typeof(ptr))) { + fptr = *(void(**)(void))jl_data_ptr(ptr); + } else { out.gcroot = ptr; if (jl_is_tuple(ptr) && jl_nfields(ptr) == 1) { @@ -633,9 +636,6 @@ static void interpret_symbol_arg(jl_codectx_t &ctx, native_sym_arg_t &out, jl_va } } } - else if (jl_is_cpointer_type(jl_typeof(ptr))) { - fptr = *(void(**)(void))jl_data_ptr(ptr); - } else if (jl_is_tuple(ptr) && jl_nfields(ptr) > 1) { jl_value_t *t0 = jl_fieldref(ptr, 0); if (jl_is_symbol(t0)) diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 2671bebfd7f55..265322b072e5e 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -634,7 +634,6 @@ JL_DLLEXPORT jl_value_t *jl_atomic_fence(jl_value_t *order_sym) JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) { JL_TYPECHK(cglobal, type, ty); - JL_GC_PUSH1(&v); jl_value_t *rt = ty == (jl_value_t*)jl_nothing_type ? (jl_value_t*)jl_voidpointer_type : // a common case (jl_value_t*)jl_apply_type1((jl_value_t*)jl_pointer_type, ty); @@ -643,24 +642,16 @@ JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) if (!jl_is_concrete_type(rt)) jl_error("cglobal: type argument not concrete"); + if (jl_is_pointer(v)) + return jl_bitcast(rt, v); + if (jl_is_tuple(v) && jl_nfields(v) == 1) v = jl_fieldref(v, 0); - if (jl_is_pointer(v)) { - v = jl_bitcast(rt, v); - JL_GC_POP(); - return v; - } - - char *f_lib = NULL; + jl_value_t *f_lib = NULL; + JL_GC_PUSH2(&v, &f_lib); if (jl_is_tuple(v) && jl_nfields(v) > 1) { - jl_value_t *t1 = jl_fieldref(v, 1); - if (jl_is_symbol(t1)) - f_lib = jl_symbol_name((jl_sym_t*)t1); - else if (jl_is_string(t1)) - f_lib = jl_string_data(t1); - else - JL_TYPECHK(cglobal, symbol, t1) + f_lib = jl_fieldref(v, 1); v = jl_fieldref(v, 0); } @@ -672,14 +663,18 @@ JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) else JL_TYPECHK(cglobal, symbol, v) - if (!f_lib) - f_lib = (char*)jl_dlfind(f_name); - void *ptr; - jl_dlsym(jl_get_library(f_lib), f_name, &ptr, 1); + if (f_lib) { + ptr = jl_lazy_load_and_lookup(f_lib, f_name); + } + else { + void *handle = jl_get_library((char*)jl_dlfind(f_name)); + jl_dlsym(handle, f_name, &ptr, 1); + } + JL_GC_POP(); + jl_value_t *jv = jl_gc_alloc(jl_current_task->ptls, sizeof(void*), rt); *(void**)jl_data_ptr(jv) = ptr; - JL_GC_POP(); return jv; } diff --git a/stdlib/Libdl/test/runtests.jl b/stdlib/Libdl/test/runtests.jl index ef7b8abf83337..159fa9d4f559d 100644 --- a/stdlib/Libdl/test/runtests.jl +++ b/stdlib/Libdl/test/runtests.jl @@ -266,7 +266,7 @@ mktempdir() do dir end ## Tests for LazyLibrary -@testset "LazyLibrary" begin; mktempdir() do dir +@testset "LazyLibrary" begin lclf_path = joinpath(private_libdir, "libccalllazyfoo.$(Libdl.dlext)") lclb_path = joinpath(private_libdir, "libccalllazybar.$(Libdl.dlext)") @@ -278,7 +278,7 @@ end global lclf_loaded = false global lclb_loaded = false - # We don't provide `dlclose()` on `LazyLibrary`'s, you have to manage it yourself: + # We don't provide `dlclose()` on `LazyLibrary`'s since it is dangerous, you have to manage it yourself: function close_libs() global lclf_loaded = false global lclb_loaded = false @@ -294,8 +294,12 @@ end @test !any(contains.(dllist(), lclb_path)) end - global libccalllazyfoo = LazyLibrary(lclf_path; on_load_callback=() -> global lclf_loaded = true) - global libccalllazybar = LazyLibrary(lclb_path; dependencies=[libccalllazyfoo], on_load_callback=() -> global lclb_loaded = true) + let libccalllazyfoo = LazyLibrary(lclf_path; on_load_callback=() -> global lclf_loaded = true), + libccalllazybar = LazyLibrary(lclb_path; dependencies=[libccalllazyfoo], on_load_callback=() -> global lclb_loaded = true) + eval(:(const libccalllazyfoo = $libccalllazyfoo)) + eval(:(const libccalllazybar = $libccalllazybar)) + end + Core.@latestworld # Creating `LazyLibrary` doesn't actually load anything @test !lclf_loaded @@ -308,7 +312,8 @@ end close_libs() # Test that the library gets loaded when you use `ccall()` - @test ccall((:bar, libccalllazybar), Cint, (Cint,), 2) == 6 + compiled_bar() = ccall((:bar, libccalllazybar), Cint, (Cint,), 2) + @test ccall((:bar, libccalllazybar), Cint, (Cint,), 2) == compiled_bar() == 6 @test lclf_loaded @test lclb_loaded close_libs() @@ -324,11 +329,17 @@ end @test lclf_loaded close_libs() + # Test that `cglobal()` works, both compiled and runtime emulation + compiled_cglobal() = cglobal((:bar, libccalllazybar)) + @test cglobal((:bar, libccalllazybar)) === compiled_cglobal() === dlsym(dlopen(libccalllazybar), :bar) + @test lclf_loaded + close_libs() + # Test that we can use lazily-evaluated library names: libname = LazyLibraryPath(private_libdir, "libccalllazyfoo.$(Libdl.dlext)") lazy_name_lazy_lib = LazyLibrary(libname) @test dlpath(lazy_name_lazy_lib) == realpath(string(libname)) -end; end +end @testset "Docstrings" begin @test isempty(Docs.undocumented_names(Libdl))