This changes the libnbd.syms file (the linker script) to use symbol versions. The only version currently used is ‘LIBNBD_1.0’ for a notional stable 1.0 release in the future. It is expected that future stable releases will use ‘LIBNBD_1.2’ etc. Note this only deals with new symbols, not with the question of how to deal with symbols which we decide to change incompatibly, if that issue ever arises. --- generator/generator | 72 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/generator/generator b/generator/generator index 60e0ab5..cc3d12d 100755 --- a/generator/generator +++ b/generator/generator @@ -840,6 +840,11 @@ type call = { * setting this to false. *) may_set_error : bool; + (* The first stable version that the symbol appeared in, for + * example (1, 2) if the symbol was added in development cycle + * 1.1.x and thus was the first stable version was 1.2 + *) + first_version : int * int; } and arg = | ArrayAndLen of arg * string (* array + number of entries *) @@ -884,7 +889,8 @@ and permitted_state = let default_call = { args = []; ret = RErr; shortdesc = ""; longdesc = ""; permitted_states = []; - is_locked = true; may_set_error = true } + is_locked = true; may_set_error = true; + first_version = (1, 0) } (* Calls. * @@ -2318,6 +2324,20 @@ let rec filter_map f = function | Some y -> y :: filter_map f xs | None -> filter_map f xs +(* group_by [1, "foo"; 2, "bar"; 2, "baz"; 2, "biz"; 3, "boo"; 4, "fizz"] + * - : (int * string list) list = + * [(1, ["foo"]); (2, ["bar"; "baz"; "biz"]); (3, ["boo"]); (4, ["fizz"])] + *) +let rec group_by = function +| [] -> [] +| [day, x] -> [day, [x]] +| (day1, x1) :: (day2, x2) :: rest when day1 = day2 -> + let rest = group_by ((day2, x2) :: rest) in + let day, xs = List.hd rest in + (day, x1 :: xs) :: List.tl rest +| (day, x) :: rest -> + (day, [x]) :: group_by rest + let chan = ref Pervasives.stdout let pr fs = ksprintf (fun str -> output_string !chan str) fs @@ -3067,22 +3087,50 @@ let () = | name, { ret = RUInt; may_set_error = true } -> failwithf "%s: if ret is RUInt, may_set_error must be false" name | _ -> () + ) handle_calls; + + (* First stable version must be 1.x where x is even. *) + List.iter ( + fun (name, { first_version = (major, minor) }) -> + if major <> 1 then + failwithf "%s: first_version must be 1.x" name; + if minor mod 2 <> 0 then + failwithf "%s: first_version must refer to a stable release" name ) handle_calls let generate_lib_libnbd_syms () = generate_header HashStyle; - pr "{\n"; - pr " global:\n"; - pr " nbd_create;\n"; - pr " nbd_close;\n"; - pr " nbd_get_errno;\n"; - pr " nbd_get_error;\n"; - List.iter (fun (name, _) -> pr " nbd_%s;\n" name) handle_calls; - pr "\n"; - pr " # Everything else is hidden.\n"; - pr " local: *;\n"; - pr "};\n" + (* Sort and group the calls by first_version, and emit them in order. *) + let cmp (_, {first_version = a}) (_, {first_version = b}) = compare a b in + let calls = List.sort cmp handle_calls in + let extract ((_, {first_version}) as call) = first_version, call in + let calls = List.map extract calls in + let calls = group_by calls in + + let prev = ref None in + List.iter ( + fun ((major, minor), calls) -> + pr "LIBNBD_%d.%d {\n" major minor; + pr " global:\n"; + if (major, minor) = (1, 0) then ( + pr " nbd_create;\n"; + pr " nbd_close;\n"; + pr " nbd_get_errno;\n"; + pr " nbd_get_error;\n" + ); + List.iter (fun (name, _) -> pr " nbd_%s;\n" name) calls; + pr " # Everything else is hidden.\n"; + pr " local: *;\n"; + pr "}"; + (match !prev with + | None -> () + | Some (old_major, old_minor) -> + pr " LIBNBD_%d.%d" old_minor old_minor + ); + pr ";\n"; + prev := Some (major, minor) + ) calls let rec name_of_arg = function | ArrayAndLen (arg, n) -> name_of_arg arg @ [n] -- 2.22.0