diff --git a/Changes b/Changes
index a7f17cd..68bcf8c 100644
--- a/Changes
+++ b/Changes
@@ -3,8 +3,8 @@ Release 1.12 (2021-03-03)
 - PR #94: remove source preprocessing and simplify configuration [Xavier Leroy]
 - PR #93: fix parallel build [Guillaume Melquiond]
 - PR #92: fix benchmark for subtraction [Guillaume Melquiond]
-- require OCaml 4.04 or later [Xavier Leroy]
-- add CI testing on macOS  [Xavier Leroy]
+- Require OCaml 4.04 or later [Xavier Leroy]
+- Add CI testing on macOS  [Xavier Leroy]
 
 Release 1.11 (2020-11-09)
 - Fixes #72, #75, #78: multiple fixes for of_string, support for underscores [hhugo]
diff --git a/META b/META
index 1b2b5af..1828d24 100644
--- a/META
+++ b/META
@@ -3,6 +3,8 @@ requires = ""
 version = "1.12"
 archive(byte) = "zarith.cma"
 archive(native) = "zarith.cmxa"
+plugin(byte) = "zarith.cma"
+plugin(native) = "zarith.cmxs"
 
 package "top" (
   version = "1.12"
diff --git a/README.md b/README.md
index 7c2a5c9..62029fd 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ arbitrary-precision integers.
 
 The module is simply named `Z`.  Its interface is similar to that of
 the `Int32`, `Int64` and `Nativeint` modules from the OCaml standard
-library, with some additional functions.  See the file `z.mlip` for
+library, with some additional functions.  See the file `z.mli` for
 documentation.
 
 The implementation uses GMP (the GNU Multiple Precision arithmetic
diff --git a/big_int_Z.ml b/big_int_Z.ml
index 3939d02..31d54f3 100644
--- a/big_int_Z.ml
+++ b/big_int_Z.ml
@@ -124,6 +124,8 @@ let int64_of_big_int x =
 
 let float_of_big_int = Z.to_float
 
+let big_int_of_float = Z.of_float
+
 let and_big_int = Z.logand
 
 let or_big_int = Z.logor
diff --git a/big_int_Z.mli b/big_int_Z.mli
index 31275d3..a888820 100644
--- a/big_int_Z.mli
+++ b/big_int_Z.mli
@@ -68,6 +68,7 @@ val int32_of_big_int : Z.t -> int32
 val nativeint_of_big_int : Z.t -> nativeint
 val int64_of_big_int : Z.t -> int64
 val float_of_big_int : Z.t -> float
+val big_int_of_float : float -> Z.t
 val and_big_int : Z.t -> Z.t -> Z.t
 val or_big_int : Z.t -> Z.t -> Z.t
 val xor_big_int : Z.t -> Z.t -> Z.t
diff --git a/caml_z.c b/caml_z.c
index f8c3179..6fc3aa5 100644
--- a/caml_z.c
+++ b/caml_z.c
@@ -1497,7 +1497,7 @@ CAMLprim value ml_z_mul(value arg1, value arg2)
 #if Z_FAST_PATH && !Z_FAST_PATH_IN_OCAML
   if (Is_long(arg1) && Is_long(arg2) &&
       ml_z_mul_overflows(arg1, arg2) == Val_false) {
-    return Val_long(Long_val(a1) * Long_val(a2));
+    return Val_long(Long_val(arg1) * Long_val(arg2));
   }
 #endif
   /* mpn_ version */
@@ -3049,15 +3049,16 @@ CAMLprim value ml_z_kronecker(value a, value b)
 CAMLprim value ml_z_remove(value a, value b)
 {
   CAMLparam2(a,b);
-  CAMLlocal1(r);
+  CAMLlocal2(r,tmp);
   mpz_t ma, mb, mr;
   int i;
   ml_z_mpz_init_set_z(ma, a);
   ml_z_mpz_init_set_z(mb, b);
   mpz_init(mr);
   i = mpz_remove(mr, ma, mb);
+  tmp = ml_z_from_mpz(mr);
   r = caml_alloc_small(2, 0);
-  Field(r,0) = ml_z_from_mpz(mr);
+  Field(r,0) = tmp;
   Field(r,1) = Val_int(i);
   mpz_clear(ma);
   mpz_clear(mb);
diff --git a/configure b/configure
index 585a002..adb302a 100755
--- a/configure
+++ b/configure
@@ -116,7 +116,7 @@ searchbin()
     echo_n "binary $1: "
     case "$1" in
       /*|./*|../*)
-        if test -f "$1" -a -x "$1"
+        if test -f "$1" && test -x "$1"
         then echo "found"; return 1
         else echo "not found"; return 0
         fi;;
@@ -125,7 +125,7 @@ searchbin()
     for i in $PATH
     do
         if test -z "$i"; then i='.'; fi
-        if test -f $i/$1 -a -x $i/$1; then echo "found in $i"; unset IFS; return 1; fi
+        if test -f $i/$1 && test -x $i/$1; then echo "found in $i"; unset IFS; return 1; fi
     done
     echo "not found"
     unset IFS
@@ -198,7 +198,9 @@ searchbinreq $ocaml
 searchbinreq $ocamlc
 searchbinreq $ocamldep
 searchbinreq $ocamlmklib
-searchbinreq $ocamldoc
+if searchbin $ocamldoc; then
+  ocamldoc=''
+fi
 
 if test -n "$CC"; then
   searchbinreq "$CC"
@@ -265,7 +267,7 @@ fi
 # installation method
 
 searchbin ocamlfind
-if test $? -eq 1 -a $ocamlfind != "no"; then 
+if test $? -eq 1 && test $ocamlfind != "no"; then 
     instmeth='findlib'
     if test "$installdir" = "auto"
     then installdir=`ocamlfind printconf destdir`; fi
@@ -296,7 +298,7 @@ fi
 
 # check GMP, MPIR
 
-if test "$gmp" = 'gmp' -o "$gmp" = 'auto'; then
+if test "$gmp" = 'gmp' || test "$gmp" = 'auto'; then
     checkinc gmp.h
     if test $? -eq 1; then
         checklib gmp
@@ -307,7 +309,7 @@ if test "$gmp" = 'gmp' -o "$gmp" = 'auto'; then
         fi
     fi
 fi
-if test "$gmp" = 'mpir' -o "$gmp" = 'auto'; then
+if test "$gmp" = 'mpir' || test "$gmp" = 'auto'; then
     checkinc mpir.h
     if test $? -eq 1; then
         checklib mpir
diff --git a/project.mak b/project.mak
index fd1c158..82a5aba 100644
--- a/project.mak
+++ b/project.mak
@@ -49,9 +49,9 @@ ifeq ($(HASOCAMLOPT),yes)
 TOBUILD += zarith.cmxa $(CMXOBJ)
 TOINSTALL += zarith.$(LIBSUFFIX)
 endif
-
-OCAMLFLAGS = -I +compiler-libs
-OCAMLOPTFLAGS = -I +compiler-libs
+DEBUG = -g
+OCAMLFLAGS += $(DEBUG) -I +compiler-libs
+OCAMLOPTFLAGS += $(DEBUG) -I +compiler-libs
 
 ifeq ($(HASDYNLINK),yes)
 TOBUILD += zarith.cmxs
@@ -71,23 +71,27 @@ tests:
 	make -C tests test
 
 zarith.cma: $(MLSRC:%.ml=%.cmo)
-	$(OCAMLMKLIB) -failsafe -o zarith $+ $(LIBS)
+	$(OCAMLMKLIB) $(DEBUG) -failsafe -o zarith $+ $(LIBS)
 
 zarith.cmxa: $(MLSRC:%.ml=%.cmx)
-	$(OCAMLMKLIB) -failsafe -o zarith $+ $(LIBS)
+	$(OCAMLMKLIB) $(DEBUG) -failsafe -o zarith $+ $(LIBS)
 
 zarith.cmxs: zarith.cmxa libzarith.$(LIBSUFFIX)
 	$(OCAMLOPT) -shared -o $@ -I . zarith.cmxa -linkall
 
 libzarith.$(LIBSUFFIX): $(CSRC:%.c=%.$(OBJSUFFIX))
-	$(OCAMLMKLIB) -failsafe -o zarith $+ $(LIBS)
+	$(OCAMLMKLIB) $(DEBUG) -failsafe -o zarith $+ $(LIBS)
 
 zarith_top.cma: zarith_top.cmo
-	$(OCAMLC) -o $@ -a $<
+	$(OCAMLC) $(DEBUG) -o $@ -a $<
 
 doc: $(MLISRC)
+ifneq ($(OCAMLDOC),)
 	mkdir -p html
 	$(OCAMLDOC) -html -d html -charset utf8 $+
+else
+	$(error ocamldoc is required to build the documentation)
+endif
 
 zarith_version.ml: META
 	(echo "let"; grep "version" META | head -1) > zarith_version.ml
diff --git a/q.ml b/q.ml
index 3c57831..8abfc08 100644
--- a/q.ml
+++ b/q.ml
@@ -534,8 +534,8 @@ let of_string =
     try
       let i  = String.index s '/' in
       make
-        (Z.of_substring s 0 i)
-        (Z.of_substring s (i+1) (String.length s-i-1))
+        (Z.of_substring s ~pos:0 ~len:i)
+        (Z.of_substring s ~pos:(i+1) ~len:(String.length s-i-1))
     with Not_found ->
       of_scientific_notation s
 
diff --git a/q.mli b/q.mli
index 957b723..6ee4127 100644
--- a/q.mli
+++ b/q.mli
@@ -274,19 +274,25 @@ val (///): Z.t -> Z.t -> t
 (** Creates a rational from two [Z.t]. *)
 
 val (=): t -> t -> bool
-(** Same as [equal]. *)
+(** Same as [equal].
+    @since 1.8 *)
 
 val (<): t -> t -> bool
-(** Same as [lt]. *)
+(** Same as [lt].
+    @since 1.8 *)
 
 val (>): t -> t -> bool
-(** Same as [gt]. *)
+(** Same as [gt].
+    @since 1.8 *)
 
 val (<=): t -> t -> bool
-(** Same as [leq]. *)
+(** Same as [leq].
+    @since 1.8 *)
 
 val (>=): t -> t -> bool
-(** Same as [geq]. *)
+(** Same as [geq].
+    @since 1.8 *)
 
 val (<>): t -> t -> bool
-(** [a <> b] is equivalent to [not (equal a b)]. *)
+(** [a <> b] is equivalent to [not (equal a b)].
+    @since 1.8 *)
diff --git a/z.mli b/z.mli
index 2d155c5..b558284 100644
--- a/z.mli
+++ b/z.mli
@@ -99,7 +99,8 @@ val of_string: string -> t
 val of_substring : string -> pos:int -> len:int -> t
 (** [of_substring s ~pos ~len] is the same as [of_string (String.sub s
     pos len)]
- *)
+    @since 1.4
+*)
 
 val of_string_base: int -> string -> t
 (** Parses a number represented as a string in the specified base,
@@ -112,6 +113,7 @@ external of_substring_base
   = "ml_z_of_substring_base"
 (** [of_substring_base base s ~pos ~len] is the same as [of_string_base
     base (String.sub s pos len)]
+    @since 1.4
 *)
 
 
@@ -196,12 +198,14 @@ external divisible: t -> t -> bool = "ml_z_divisible"
 (** [divisible a b] returns [true] if [a] is exactly divisible by [b].
     Unlike the other division functions, [b = 0] is accepted 
     (only 0 is considered divisible by 0).
+    @since 1.10
 *)
 
 external congruent: t -> t -> t -> bool = "ml_z_congruent"
 (** [congruent a b c] returns [true] if [a] is congruent to [b] modulo [c].
     Unlike the other division functions, [c = 0] is accepted 
     (only equal numbers are considered equal congruent 0).
+    @since 1.10
 *)
 
 
@@ -252,7 +256,9 @@ external numbits: t -> int = "ml_z_numbits" [@@noalloc]
     If [x] is zero, [numbits x] returns 0.  Otherwise,
     [numbits x] returns a positive integer [n] such that
     [2^{n-1} <= |x| < 2^n].  Note that [numbits] is defined
-    for negative arguments, and that [numbits (-x) = numbits x]. *)
+    for negative arguments, and that [numbits (-x) = numbits x].
+    @since 1.4
+*)
 
 external trailing_zeros: t -> int = "ml_z_trailing_zeros" [@@noalloc]
 (** Returns the number of trailing 0 bits in the given number.
@@ -260,13 +266,17 @@ external trailing_zeros: t -> int = "ml_z_trailing_zeros" [@@noalloc]
     Otherwise, [trailing_zeros x] returns a nonnegative integer [n]
     which is the largest [n] such that [2^n] divides [x] evenly.
     Note that [trailing_zeros] is defined for negative arguments,
-    and that [trailing_zeros (-x) = trailing_zeros x]. *)
+    and that [trailing_zeros (-x) = trailing_zeros x].
+    @since 1.4
+*)
 
 val testbit: t -> int -> bool
 (** [testbit x n] return the value of bit number [n] in [x]:
     [true] if the bit is 1, [false] if the bit is 0.
     Bits are numbered from 0.  Raise [Invalid_argument] if [n]
-    is negative. *)
+    is negative.
+    @since 1.4
+*)
 
 external popcount: t -> int = "ml_z_popcount"
 (** Counts the number of bits set.
@@ -287,16 +297,20 @@ external hamdist: t -> t -> int = "ml_z_hamdist"
  *)
 
 val to_int: t -> int
-(** Converts to a base integer. May raise an [Overflow]. *)
+(** Converts to a signed OCaml [int].
+    Raises an [Overflow] if the value does not fit in a signed OCaml [int]. *)
 
 external to_int32: t -> int32 = "ml_z_to_int32"
-(** Converts to a 32-bit integer. May raise [Overflow]. *)
+(** Converts to a signed 32-bit integer [int32].
+    Raises an [Overflow] if the value does not fit in a signed [int32]. *)
 
 external to_int64: t -> int64 = "ml_z_to_int64"
-(** Converts to a 64-bit integer. May raise [Overflow]. *)
+(** Converts to a signed 64-bit integer [int64].
+    Raises an [Overflow] if the value does not fit in a signed [int64]. *)
 
 external to_nativeint: t -> nativeint = "ml_z_to_nativeint"
-(** Converts to a native integer. May raise [Overflow]. *)
+(** Converts to a native signed integer [nativeint].
+    Raises an [Overflow] if the value does not fit in a signed [nativeint]. *)
 
 val to_float: t -> float
 (** Converts to a floating-point value.
@@ -337,16 +351,16 @@ external format: string -> t -> string = "ml_z_format"
  *)
 
 external fits_int: t -> bool = "ml_z_fits_int" [@@noalloc]
-(** Whether the argument fits in a regular [int]. *)
+(** Whether the argument fits in an OCaml signed [int]. *)
 
 external fits_int32: t -> bool = "ml_z_fits_int32" [@@noalloc]
-(** Whether the argument fits in an [int32]. *)
+(** Whether the argument fits in a signed [int32]. *)
 
 external fits_int64: t -> bool = "ml_z_fits_int64" [@@noalloc]
-(** Whether the argument fits in an [int64]. *)
+(** Whether the argument fits in a signed [int64]. *)
 
 external fits_nativeint: t -> bool = "ml_z_fits_nativeint" [@@noalloc]
-(** Whether the argument fits in a [nativeint]. *)
+(** Whether the argument fits in a signed [nativeint]. *)
 
 
 (** {1 Printing} *)
@@ -409,10 +423,14 @@ val max: t -> t -> t
 (** Returns the maximum of its arguments. *)
 
 val is_even: t -> bool
-(** Returns true if the argument is even (divisible by 2), false if odd. *)
+(** Returns true if the argument is even (divisible by 2), false if odd.
+    @since 1.4
+*)
 
 val is_odd: t -> bool
-(** Returns true if the argument is odd, false if even. *)
+(** Returns true if the argument is odd, false if even.
+    @since 1.4
+*)
 
 external hash: t -> int = "ml_z_hash" [@@noalloc]
 (** Hashes a number, producing a small integer.
@@ -460,7 +478,9 @@ external powm_sec: t -> t -> t -> t = "ml_z_powm_sec"
     arguments.  Used in cryptographic applications, it provides better
     resistance to side-channel attacks than [Z.powm].
     The exponent [exp] must be positive, and the modulus [mod]
-    must be odd.  Otherwise, [Invalid_arg] is raised. *)
+    must be odd. Otherwise, [Invalid_arg] is raised.
+    @since 1.4
+*)
 
 external invert: t -> t -> t = "ml_z_invert"
 (** [invert base mod] returns the inverse of [base] modulo [mod].
@@ -480,55 +500,58 @@ external nextprime: t -> t = "ml_z_nextprime"
  *)
 
 external jacobi: t -> t -> int = "ml_z_jacobi"
-(** [jacobi a b] returns the Jacobi symbol [(a/b)]. *)
+(** [jacobi a b] returns the Jacobi symbol [(a/b)].
+    @since 1.10 *)
 
 external legendre: t -> t -> int = "ml_z_legendre"
-(** [legendre a b] returns the Legendre symbol [(a/b)]. *)
+(** [legendre a b] returns the Legendre symbol [(a/b)].
+    @since 1.10 *)
 
 external kronecker: t -> t -> int = "ml_z_kronecker"
-(** [kronecker a b] returns the Kronecker symbol [(a/b)]. *)
+(** [kronecker a b] returns the Kronecker symbol [(a/b)].
+    @since 1.10 *)
 
 external remove: t -> t -> t * int = "ml_z_remove"
 (** [remove a b] returns [a] after removing all the occurences of the
     factor [b]. 
     Also returns how many occurrences were removed.
- *)
+    @since 1.10 *)
 
 external fac: int -> t = "ml_z_fac"
 (** [fac n] returns the factorial of [n] ([n!]).
     Raises an [Invaid_argument] if [n] is non-positive.
-*)
+    @since 1.10 *)
   
 external fac2: int -> t = "ml_z_fac2"
 (** [fac2 n] returns the double factorial of [n] ([n!!]).
     Raises an [Invaid_argument] if [n] is non-positive.
-*)
+    @since 1.10 *)
   
  external facM: int -> int -> t = "ml_z_facM"
 (** [facM n m] returns the [m]-th factorial of [n].
     Raises an [Invaid_argument] if [n] or [m] is non-positive.
-*)
+    @since 1.10 *)
 
 external primorial: int -> t = "ml_z_primorial"
 (** [primorial n] returns the product of all positive prime numbers less
     than or equal to [n].
     Raises an [Invaid_argument] if [n] is non-positive.
-*)
+    @since 1.10 *)
 
 external bin: t -> int -> t = "ml_z_bin"
 (** [bin n k] returns the binomial coefficient [n] over [k].
     Raises an [Invaid_argument] if [k] is non-positive.
-*)
+    @since 1.10 *)
 
 external fib: int -> t = "ml_z_fib"
 (** [fib n] returns the [n]-th Fibonacci number.
     Raises an [Invaid_argument] if [n] is non-positive.
-*)
+    @since 1.10 *)
 
 external lucnum: int -> t = "ml_z_lucnum"
 (** [lucnum n] returns the [n]-th Lucas number.
     Raises an [Invaid_argument] if [n] is non-positive.
-*)
+    @since 1.10 *)
 
 
 (** {1 Powers} *)
@@ -563,7 +586,7 @@ external rootrem: t -> int -> t * t = "ml_z_rootrem"
     [x-root**n].
     [n] must be positive and, if [n] is even, then [x] must be nonnegative.
     Otherwise, an [Invalid_argument] is raised.
- *)
+    @since 1.10 *)
 
 external perfect_power: t -> bool = "ml_z_perfect_power"
 (** True if the argument has the form [a^b], with [b>1] *)
@@ -575,13 +598,17 @@ val log2: t -> int
 (** Returns the base-2 logarithm of its argument, rounded down to
     an integer.  If [x] is positive, [log2 x] returns the largest [n]
     such that [2^n <= x].  If [x] is negative or zero, [log2 x] raise
-    the [Invalid_argument] exception. *)
+    the [Invalid_argument] exception.
+    @since 1.4
+*)
 
 val log2up: t -> int
 (** Returns the base-2 logarithm of its argument, rounded up to
     an integer.  If [x] is positive, [log2up x] returns the smallest [n]
     such that [x <= 2^n].  If [x] is negative or zero, [log2up x] raise
-    the [Invalid_argument] exception. *)
+    the [Invalid_argument] exception.
+    @since 1.4
+*)
 
 (** {1 Representation} *)
 
@@ -590,9 +617,10 @@ external size: t -> int = "ml_z_size" [@@noalloc]
 
 external extract: t -> int -> int -> t = "ml_z_extract"
 (** [extract a off len] returns a nonnegative number corresponding to bits
-    [off] to [off]+[len]-1 of [b].
+    [off] to [off]+[len]-1 of [a].
     Negative [a] are considered in infinite-length 2's complement
     representation.
+    Raises an [Invalid_argument] if [off] is strictly negative, or if [len] is negative or null.
  *)
 
 val signed_extract: t -> int -> int -> t
@@ -601,6 +629,7 @@ val signed_extract: t -> int -> int -> t
     (that is, bit [off + len - 1] of [a]).  The result is between
     [- 2{^[len]-1}] (included) and [2{^[len]-1}] (excluded),
     and equal to [extract a off len] modulo [2{^len}].
+    Raises an [Invalid_argument] if [off] is strictly negative, or if [len] is negative or null.
  *)
 
 external to_bits: t -> string = "ml_z_to_bits"
@@ -712,7 +741,9 @@ end
 (** {1 Miscellaneous} *)
 
 val version: string
-(** Library version. *)
+(** Library version.
+    @since 1.1
+*)
 
 (**/**)
 
diff --git a/z_mlgmpidl.ml b/z_mlgmpidl.ml
index 023d731..429426c 100644
--- a/z_mlgmpidl.ml
+++ b/z_mlgmpidl.ml
@@ -28,10 +28,10 @@ let mpz_of_z x =
   r
 
 let z_of_mpzf x =
-  z_of_mpz (Mpzf.mpz x)
+  z_of_mpz (Mpzf._mpz x)
 
 let mpzf_of_z x =
-  Mpzf.mpzf (mpz_of_z x)
+  Mpzf._mpzf (mpz_of_z x)
 
 let q_of_mpq x =
   let n,d = Mpz.init (), Mpz.init () in
@@ -43,7 +43,7 @@ let mpq_of_q x =
   Mpq.of_mpz2 (mpz_of_z x.Q.num) (mpz_of_z x.Q.den)
 
 let q_of_mpqf x =
-  q_of_mpq (Mpqf.mpq x)
+  q_of_mpq (Mpqf._mpq x)
 
 let mpqf_of_q x =
-  Mpqf.mpqf (mpq_of_q x)
+  Mpqf._mpqf (mpq_of_q x)
diff --git a/zarith.opam b/zarith.opam
index b299715..2c406c9 100644
--- a/zarith.opam
+++ b/zarith.opam
@@ -9,6 +9,7 @@ authors: [
 homepage: "https://github.com/ocaml/Zarith"
 bug-reports: "https://github.com/ocaml/Zarith/issues"
 dev-repo: "git+https://github.com/ocaml/Zarith.git"
+license: "LGPL-2.0-only WITH OCaml-LGPL-linking-exception"
 build: [
   ["./configure"] {os != "openbsd" & os != "freebsd" & os != "macos"}
   [