From 17f5f395cf7a0342cd211ab7aa85053b3c3d3812 Mon Sep 17 00:00:00 2001 From: Frej Soya Date: Thu, 28 Sep 2023 00:50:49 +0200 Subject: [PATCH] Add link flags for external dependencies when using ctypes. Required when the external lib is not statically linked, in which case linker needs to be aware at runtime what libs to call. This is the case for - dune exec .bc - dune utop - mdx tests That is add to ocamlmklib, link flags such as -l -L from ctypes if info is available. If dependent library are not installed in expected locations, env variable such as LD_LIBRARY_PATH must be extended when required program is run, depending on os. This may be fixed adding by relocatable paths to link flags. Signed-off-by: Frej Soya --- src/dune_rules/ctypes/ctypes_rules.ml | 3 +- src/dune_rules/ctypes/ctypes_rules.mli | 3 +- src/dune_rules/lib_rules.ml | 4 +- .../ctypes/bytecode-stubs-external-lib.t/dune | 4 + .../dune-project | 3 + .../bytecode-stubs-external-lib.t/example.ml | 2 + .../bytecode-stubs-external-lib.t/run.t | 82 +++++++++++++++++++ .../stubgen/dune | 14 ++++ .../stubgen/function_description.ml | 8 ++ .../stubgen/type_description.ml | 3 + test/blackbox-tests/test-cases/ctypes/dune | 1 + 11 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune-project create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/example.ml create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/run.t create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/dune create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/function_description.ml create mode 100644 test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/type_description.ml diff --git a/src/dune_rules/ctypes/ctypes_rules.ml b/src/dune_rules/ctypes/ctypes_rules.ml index d27cc6d1396e..2388ea285d6a 100644 --- a/src/dune_rules/ctypes/ctypes_rules.ml +++ b/src/dune_rules/ctypes/ctypes_rules.ml @@ -483,8 +483,7 @@ let gen_rules ~cctx ~(buildable : Buildable.t) ~loc ~scope ~dir ~sctx = ~c_types_includer_module)) ;; -let ctypes_cclib_flags sctx ~expander ~(buildable : Buildable.t) = - let standard = Action_builder.return [] in +let ctypes_cclib_flags ?(standard = Action_builder.return []) sctx ~expander ~(buildable : Buildable.t) = match buildable.ctypes with | None -> standard | Some ctypes -> diff --git a/src/dune_rules/ctypes/ctypes_rules.mli b/src/dune_rules/ctypes/ctypes_rules.mli index 27c1241e1179..689d8673c50d 100644 --- a/src/dune_rules/ctypes/ctypes_rules.mli +++ b/src/dune_rules/ctypes/ctypes_rules.mli @@ -10,7 +10,8 @@ val gen_rules -> unit Memo.t val ctypes_cclib_flags - : Super_context.t + : ?standard:(string list Action_builder.t) + -> Super_context.t -> expander:Expander.t -> buildable:Dune_file.Buildable.t -> string list Action_builder.t diff --git a/src/dune_rules/lib_rules.ml b/src/dune_rules/lib_rules.ml index b362c67b72a1..96c98b2ff15b 100644 --- a/src/dune_rules/lib_rules.ml +++ b/src/dune_rules/lib_rules.ml @@ -331,9 +331,7 @@ let build_stubs lib ~cctx ~dir ~expander ~requires ~dir_contents ~vlib_stubs_o_f Cxx_flags.get_flags ~for_:Link (Context.build_context ctx) | _ -> Action_builder.return [] in - let c_library_flags = - Expander.expand_and_eval_set expander lib.c_library_flags ~standard - in + let c_library_flags = Ctypes_rules.ctypes_cclib_flags sctx ~expander ~buildable:lib.buildable ~standard in let lib_o_files_for_all_modes = Mode.Map.Multi.for_all_modes o_files in let for_all_modes = List.rev_append vlib_stubs_o_files lib_o_files_for_all_modes in if Mode.Dict.Set.to_list modes.ocaml diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune new file mode 100644 index 000000000000..2ca1e427745b --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune @@ -0,0 +1,4 @@ +(executable + (name example) + (modes byte) + (libraries examplelib)) diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune-project b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune-project new file mode 100644 index 000000000000..d993321861b0 --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/dune-project @@ -0,0 +1,3 @@ +(lang dune 3.10) + +(using ctypes 0.3) diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/example.ml b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/example.ml new file mode 100644 index 000000000000..eebafeb3114f --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/example.ml @@ -0,0 +1,2 @@ +let () = + Printf.printf "%d\n" (Examplelib.C.Functions.add2 2) diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/run.t b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/run.t new file mode 100644 index 000000000000..4b948ec62e0a --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/run.t @@ -0,0 +1,82 @@ + +Build an example library as a DLL and set up the environment so that it looks +like a system/distro library that can be probed with pkg-config and dynamically +loaded. + + + +Run the program in bytecode + $ LIBEX=$(realpath "$PWD/../libexample") + $ tree $LIBEX + /workspace_root/test/blackbox-tests/test-cases/ctypes/libexample + |-- example.h -> ../../../../../../../../default/test/blackbox-tests/test-cases/ctypes/libexample/example.h + |-- libexample.a -> ../../../../../../../../default/test/blackbox-tests/test-cases/ctypes/libexample/libexample.a + |-- libexample.so -> ../../../../../../../../default/test/blackbox-tests/test-cases/ctypes/libexample/libexample.so + `-- pkgconfig + `-- libexample.pc -> ../../../../../../../../../default/test/blackbox-tests/test-cases/ctypes/libexample/pkgconfig/libexample.pc + + 1 directory, 4 files + +Build the stubs.so + + + $ PKG_CONFIG_PATH="$LIBEX/pkgconfig" PKG_CONFIG_ARGN="--define-prefix" dune build stubgen/dllexamplelib_stubs.so + + $ PKG_CONFIG_PATH="$LIBEX/pkgconfig" PKG_CONFIG_ARGN="--define-prefix" dune build ./example.bc + +ocamlrun + bytcode with ocaml requires CAML_LD_LIBRARY_PATH. +Explictly set LIBRARY_PATH at runtime,otherwise dlopen cannot find libexample. +Eventually setting proper build flags for libexample + + $ dune clean + $ PKG_CONFIG_PATH="$LIBEX/pkgconfig" PKG_CONFIG_ARGN="--define-prefix" DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$LIBEX" CAML_LD_LIBRARY_PATH="$CAML_LD_LIBRARY_PATH:$PWD/_build/default/stubgen" dune exec ./example.bc --display=short + ocamlc stubgen/.examplelib.objs/byte/examplelib.{cmi,cmo,cmt} + ocamldep stubgen/.examplelib.objs/examplelib__C.impl.d + ocamldep stubgen/.examplelib.objs/examplelib__Function_description.impl.d + ocamldep stubgen/.examplelib.objs/examplelib__Libexample__function_gen__Function_description__Functions.impl.d + ocamldep stubgen/.examplelib.objs/examplelib__Libexample__type_gen.impl.d + cc .dune/ccomp/ccomp + pkg-config stubgen/.pkg-config/libexample.cflags + ocamldep stubgen/.examplelib.objs/examplelib__Type_description.impl.d + ocamldep stubgen/.examplelib.objs/examplelib__Types_generated.impl.d + pkg-config stubgen/.pkg-config/libexample.libs + ocamlc stubgen/.examplelib.objs/byte/examplelib__Type_description.{cmi,cmo,cmt} + ocamlopt stubgen/.examplelib.objs/native/examplelib.{cmx,o} + ocamlopt stubgen/.examplelib.objs/native/examplelib__Type_description.{cmx,o} + ocamlc stubgen/.examplelib.objs/byte/examplelib__Libexample__type_gen.{cmi,cmo,cmt} + ocamlopt stubgen/.examplelib.objs/native/examplelib__Libexample__type_gen.{cmx,o} + ocamlopt stubgen/libexample__type_gen.exe + libexample__type_gen stubgen/libexample__c_cout_generated_types.c + cc stubgen/libexample__c_cout_generated_types.exe + libexample__c_cout_generated_types stubgen/libexample__c_generated_types.ml + ocamldep stubgen/.examplelib.objs/examplelib__Libexample__c_generated_types.impl.d + ocamlc stubgen/.examplelib.objs/byte/examplelib__Libexample__c_generated_types.{cmi,cmo,cmt} + ocamlc stubgen/.examplelib.objs/byte/examplelib__Types_generated.{cmi,cmo,cmt} + ocamlopt stubgen/.examplelib.objs/native/examplelib__Libexample__c_generated_types.{cmx,o} + ocamlc stubgen/.examplelib.objs/byte/examplelib__Function_description.{cmi,cmo,cmt} + ocamlopt stubgen/.examplelib.objs/native/examplelib__Types_generated.{cmx,o} + ocamlopt stubgen/.examplelib.objs/native/examplelib__Function_description.{cmx,o} + ocamlc stubgen/.examplelib.objs/byte/examplelib__Libexample__function_gen__Function_description__Functions.{cmi,cmo,cmt} + ocamlopt stubgen/.examplelib.objs/native/examplelib__Libexample__function_gen__Function_description__Functions.{cmx,o} + ocamlopt stubgen/libexample__function_gen__Function_description__Functions.exe + libexample__function_gen__Function_description__Functions stubgen/libexample__c_generated_functions__Function_description__Functions.ml + libexample__function_gen__Function_description__Functions stubgen/libexample__c_cout_generated_functions__Function_description__Functions.c + ocamldep stubgen/.examplelib.objs/examplelib__Libexample__c_generated_functions__Function_description__Functions.impl.d + cc stubgen/libexample__c_cout_generated_functions__Function_description__Functions.o + ocamlc stubgen/.examplelib.objs/byte/examplelib__Libexample__c_generated_functions__Function_description__Functions.{cmi,cmo,cmt} + ocamlmklib stubgen/dllexamplelib_stubs.so,stubgen/libexamplelib_stubs.a + ocamlc stubgen/.examplelib.objs/byte/examplelib__C.{cmi,cmo,cmt} + ocamlc .example.eobjs/byte/dune__exe__Example.{cmi,cmti} + ocamlc stubgen/examplelib.cma + ocamlc .example.eobjs/byte/dune__exe__Example.{cmo,cmt} + ocamlc example.bc + 4 + +Utop works with ctypes pkg-config external library. + + $ DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$LIBEX" PKG_CONFIG_PATH="$LIBEX/pkgconfig" PKG_CONFIG_ARGN="--define-prefix" dune utop --display=short ./ -- example.ml + pkg-config stubgen/.pkg-config/libexample.cflags + pkg-config stubgen/.pkg-config/libexample.libs + ocamlc .utop/.utop.eobjs/byte/dune__exe__Utop.{cmi,cmo,cmt} + ocamlc .utop/utop.bc + 4 diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/dune b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/dune new file mode 100644 index 000000000000..a426491271df --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/dune @@ -0,0 +1,14 @@ +(library + (name examplelib) + (flags (:standard -w -9-27)) + (ctypes + (external_library_name libexample) + (build_flags_resolver pkg_config) + (headers (include "example.h")) + (type_description + (instance Types) + (functor Type_description)) + (function_description + (instance Functions) + (functor Function_description)) + (generated_entry_point C))) diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/function_description.ml b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/function_description.ml new file mode 100644 index 000000000000..05c43d79e2fa --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/function_description.ml @@ -0,0 +1,8 @@ +open Ctypes + +module Types = Types_generated + +module Functions (F : Ctypes.FOREIGN) = struct + open F + let add2 = foreign "example_add2" (int @-> returning int) +end diff --git a/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/type_description.ml b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/type_description.ml new file mode 100644 index 000000000000..41693fda9b31 --- /dev/null +++ b/test/blackbox-tests/test-cases/ctypes/bytecode-stubs-external-lib.t/stubgen/type_description.ml @@ -0,0 +1,3 @@ +module Types (F : Ctypes.TYPE) = struct + +end diff --git a/test/blackbox-tests/test-cases/ctypes/dune b/test/blackbox-tests/test-cases/ctypes/dune index 3d9ec9e03096..a3d6c3586aac 100644 --- a/test/blackbox-tests/test-cases/ctypes/dune +++ b/test/blackbox-tests/test-cases/ctypes/dune @@ -27,6 +27,7 @@ (cram (applies_to + bytecode-stubs-external-lib lib-pkg_config lib-pkg_config-multiple-fd lib-external-name-need-mangling