From 79a3f8c39c554040d33685cafa44e93a4022cd9c Mon Sep 17 00:00:00 2001 From: Bruno Deferrari Date: Sat, 14 Aug 2021 19:36:03 -0300 Subject: [PATCH] Add `no-caml-startup` feature flag that avoids the `caml_startup` symbol. Will also be enabled if the `OCAML_INTEROP_NO_CAML_STARTUP` environment variable is set. This will make `OCamlRuntime::init_persistent()` a noop. The main motivation for this feature flag is to make code that uses ocaml-rs and ocaml-interop loadable from `dune utop`: https://github.com/zshipko/ocaml-rs/issues/70 --- CHANGELOG.md | 4 ++++ Cargo.toml | 1 + build.rs | 14 ++++++++++++++ src/runtime.rs | 28 ++++++++++++++++------------ testing/ocaml-caller/rust/Cargo.toml | 2 +- 5 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 build.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 839436b..02e1c2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `no-caml-startup` feature flag that disables calls to `caml_startup` when initializing the runtime. This makes `OCamlRuntime::init_persistent()` a noop. It is useful for being able to load code that uses ocaml-interop in an utop toplevel (for example, when running `dune utop`). Will be enabled if the environment variable `OCAML_INTEROP_NO_CAML_STARTUP` is set. + ## [0.8.4] - 2021-05-18 ### Added diff --git a/Cargo.toml b/Cargo.toml index 7b6df82..f30ba90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,4 @@ static_assertions = "1.1.0" [features] without-ocamlopt = ["ocaml-sys/without-ocamlopt", "ocaml-boxroot-sys/without-ocamlopt"] caml-state = ["ocaml-sys/caml-state"] +no-caml-startup = [] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..411c8b0 --- /dev/null +++ b/build.rs @@ -0,0 +1,14 @@ +// Copyright (c) Viable Systems and TezEdge Contributors +// SPDX-License-Identifier: MIT + +const OCAML_INTEROP_NO_CAML_STARTUP: &'static str = "OCAML_INTEROP_NO_CAML_STARTUP"; + +fn main() { + println!( + "cargo:rerun-if-env-changed={}", + OCAML_INTEROP_NO_CAML_STARTUP + ); + if std::env::var(OCAML_INTEROP_NO_CAML_STARTUP).is_ok() { + println!("cargo:rustc-cfg=feature=\"no-caml-startup\""); + } +} diff --git a/src/runtime.rs b/src/runtime.rs index 1ea57ac..b74542f 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -2,8 +2,7 @@ // SPDX-License-Identifier: MIT use ocaml_boxroot_sys::{boxroot_setup, boxroot_teardown}; -use ocaml_sys::{caml_shutdown, caml_startup}; -use std::{marker::PhantomData, sync::Once}; +use std::marker::PhantomData; use crate::{memory::OCamlRef, value::OCaml}; @@ -30,15 +29,20 @@ impl OCamlRuntime { /// /// After the first invocation, this method does nothing. pub fn init_persistent() { - static INIT: Once = Once::new(); - - INIT.call_once(|| { - let arg0 = "ocaml\0".as_ptr() as *const ocaml_sys::Char; - let c_args = vec![arg0, core::ptr::null()]; - unsafe { - caml_startup(c_args.as_ptr()); - } - }) + #[cfg(not(feature = "no-caml-startup"))] + { + static INIT: std::sync::Once = std::sync::Once::new(); + + INIT.call_once(|| { + let arg0 = "ocaml\0".as_ptr() as *const ocaml_sys::Char; + let c_args = vec![arg0, core::ptr::null()]; + unsafe { + ocaml_sys::caml_startup(c_args.as_ptr()); + } + }) + } + #[cfg(feature = "no-caml-startup")] + panic!("Rust code that is called from an OCaml program should not try to initialize the runtime."); } /// Recover the runtime handle. @@ -77,7 +81,7 @@ impl Drop for OCamlRuntime { fn drop(&mut self) { unsafe { boxroot_teardown(); - caml_shutdown(); + ocaml_sys::caml_shutdown(); } } } diff --git a/testing/ocaml-caller/rust/Cargo.toml b/testing/ocaml-caller/rust/Cargo.toml index da3c8a2..7096d40 100644 --- a/testing/ocaml-caller/rust/Cargo.toml +++ b/testing/ocaml-caller/rust/Cargo.toml @@ -9,5 +9,5 @@ crate-type = ["staticlib", "cdylib"] [dependencies] ocaml-interop = { path = "../../../../.." } -# Above is for building with dune, bellow is for biulding from this directory +# Above is for building with dune, bellow is for building from this directory # ocaml-interop = { path = "../../.." }