Richard W.M. Jones
2016-Sep-02 14:21 UTC
[Libguestfs] [PATCH 0/4] generator: Some work to split large C files
By splitting up large C files we can make parallel compiles a bit faster. Rich.
Richard W.M. Jones
2016-Sep-02 14:21 UTC
[Libguestfs] [PATCH 1/4] generator: Add |> (revapply) operator for compat with OCaml < 4.01.
---
generator/utils.ml | 2 ++
generator/utils.mli | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/generator/utils.ml b/generator/utils.ml
index bb96eb6..3e81433 100644
--- a/generator/utils.ml
+++ b/generator/utils.ml
@@ -205,6 +205,8 @@ let files_equal n1 n2 | 1 -> false
| i -> failwithf "%s: failed with error code %d" cmd i
+let (|>) x f = f x
+
let rec filter_map f = function
| [] -> []
| x :: xs ->
diff --git a/generator/utils.mli b/generator/utils.mli
index a69328f..c7d3f2c 100644
--- a/generator/utils.mli
+++ b/generator/utils.mli
@@ -76,6 +76,10 @@ val files_equal : string -> string -> bool
(** [files_equal filename1 filename2] returns true if the files contain
the same content. *)
+val (|>) : 'a -> ('a -> 'b) -> 'b
+(** Added in OCaml 4.01, we can remove our definition when we
+ can assume this minimum version of OCaml. *)
+
val filter_map : ('a -> 'b option) -> 'a list -> 'b
list
val find_map : ('a -> 'b option) -> 'a list -> 'b
--
2.9.3
Richard W.M. Jones
2016-Sep-02 14:21 UTC
[Libguestfs] [PATCH 2/4] generator: Move all actions into a single list and add filter functions.
This mostly mechanical change moves all of the libguestfs API
lists of functions into a struct in the Actions module.
It also adds filter functions to be used elsewhere to get
subsets of these functions.
Original code Replacement
all_functions actions
daemon_functions actions |> daemon_functions
non_daemon_functions actions |> non_daemon_functions
external_functions actions |> external_functions
internal_functions actions |> internal_functions
documented_functions actions |> documented_functions
fish_functions actions |> fish_functions
*_functions_sorted ... replacement as above ... |> sort
---
generator/actions.ml | 83 +++++++++++++++++++++++++++---------------------
generator/actions.mli | 66 ++++++++++++++------------------------
generator/c.ml | 16 +++++-----
generator/checks.ml | 52 +++++++++++-------------------
generator/csharp.ml | 2 +-
generator/daemon.ml | 10 +++---
generator/erlang.ml | 10 +++---
generator/fish.ml | 20 +++++-------
generator/gobject.ml | 6 ++--
generator/golang.ml | 2 +-
generator/haskell.ml | 4 +--
generator/java.ml | 4 +--
generator/lua.ml | 8 ++---
generator/main.ml | 2 +-
generator/ocaml.ml | 12 +++----
generator/optgroups.ml | 2 +-
generator/perl.ml | 8 ++---
generator/php.ml | 6 ++--
generator/python.ml | 8 ++---
generator/ruby.ml | 4 +--
generator/tests_c_api.ml | 8 ++---
generator/xdr.ml | 4 +--
22 files changed, 155 insertions(+), 182 deletions(-)
diff --git a/generator/actions.ml b/generator/actions.ml
index aa26649..179902e 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13572,18 +13572,62 @@ let non_daemon_functions, daemon_functions
List.map make_camel_case_if_not_set daemon_functions in
non_daemon_functions, daemon_functions
+(* Before we add the non_daemon_functions and daemon_functions to
+ * a single list, verify the proc_nr field which should be the only
+ * difference between them. (Note more detailed checking is done
+ * in checks.ml).
+ *)
+let () + List.iter (
+ function
+ | { name = name; proc_nr = None } ->
+ failwithf "daemon function %s should have proc_nr = Some n >
0" name
+ | { name = name; proc_nr = Some n } when n <= 0 ->
+ failwithf "daemon function %s should have proc_nr = Some n >
0" name
+ | { proc_nr = Some _ } -> ()
+ ) daemon_functions;
+
+ List.iter (
+ function
+ | { name = name; proc_nr = Some _ } ->
+ failwithf "non-daemon function %s should have proc_nr = None"
name
+ | { proc_nr = None } -> ()
+ ) non_daemon_functions
+
+(* This is used to generate the src/MAX_PROC_NR file which
+ * contains the maximum procedure number, a surrogate for the
+ * ABI version number. See src/Makefile.am for the details.
+ *)
+let max_proc_nr + let proc_nrs = List.map (
+ function { proc_nr = Some n } -> n | { proc_nr = None } -> assert
false
+ ) daemon_functions in
+ List.fold_left max 0 proc_nrs
+
(* All functions. *)
-let all_functions = non_daemon_functions @ daemon_functions
+let actions = non_daemon_functions @ daemon_functions
+
+(* Filters which can be applied. *)
+let is_non_daemon_function = function
+ | { proc_nr = None } -> true
+ | { proc_nr = Some _ } -> false
+let non_daemon_functions = List.filter is_non_daemon_function
+
+let is_daemon_function f = not (is_non_daemon_function f)
+let daemon_functions = List.filter is_daemon_function
let is_external { visibility = v } = match v with
| VPublic | VPublicNoFish | VStateTest | VBindTest | VDebug -> true
| VInternal -> false
+let external_functions = List.filter is_external
let is_internal f = not (is_external f)
+let internal_functions = List.filter is_internal
let is_documented { visibility = v } = match v with
| VPublic | VPublicNoFish | VStateTest -> true
| VBindTest | VDebug | VInternal -> false
+let documented_functions = List.filter is_documented
let is_fish { visibility = v; style = (_, args, _) } (* Internal functions
are not exported to guestfish. *)
@@ -13595,42 +13639,9 @@ let is_fish { visibility = v; style = (_, args, _) }
* generate a pointer.
*)
not (List.exists (function Pointer _ -> true | _ -> false) args)
-
-let external_functions - List.filter is_external all_functions
-
-let internal_functions - List.filter is_internal all_functions
-
-let documented_functions - List.filter is_documented all_functions
-
-let fish_functions - List.filter is_fish all_functions
+let fish_functions = List.filter is_fish
(* In some places we want the functions to be displayed sorted
* alphabetically, so this is useful:
*)
-let all_functions_sorted = List.sort action_compare all_functions
-
-let external_functions_sorted - List.sort action_compare external_functions
-
-let internal_functions_sorted - List.sort action_compare internal_functions
-
-let documented_functions_sorted - List.sort action_compare
documented_functions
-
-let fish_functions_sorted - List.sort action_compare fish_functions
-
-(* This is used to generate the src/MAX_PROC_NR file which
- * contains the maximum procedure number, a surrogate for the
- * ABI version number. See src/Makefile.am for the details.
- *)
-let max_proc_nr - let proc_nrs = List.map (
- function { proc_nr = Some n } -> n | { proc_nr = None } -> 0
- ) daemon_functions in
- List.fold_left max 0 proc_nrs
+let sort = List.sort action_compare
diff --git a/generator/actions.mli b/generator/actions.mli
index 8020aaa..55bc36e 100644
--- a/generator/actions.mli
+++ b/generator/actions.mli
@@ -20,60 +20,42 @@
(** The libguestfs API. *)
-val non_daemon_functions : Types.action list
-(** API actions which are implemented within the library itself. *)
+val actions : Types.action list
+(** The list of functions in the libguestfs API. *)
-val daemon_functions : Types.action list
-(** API actions which are implemented by the daemon. *)
+val daemon_functions : Types.action list -> Types.action list
+val non_daemon_functions : Types.action list -> Types.action list
+(** Filter {!actions}, returning only daemon function /
+ non-daemon function respectively.
-val all_functions : Types.action list
-(** Concatenation of [non_daemon_functions] and [daemon_functions] lists. *)
+ The difference is that a daemon function is handled directly by
+ the daemon. A non-daemon function is implemented in the library side. *)
-val is_external : Types.action -> bool
-(** Returns true if function is external, false otherwise *)
+val external_functions : Types.action list -> Types.action list
+(** Filter {!actions}, returning only external functions. *)
-val is_internal : Types.action -> bool
-(** Returns true if function is internal, false otherwise *)
+val internal_functions : Types.action list -> Types.action list
+(** Filter {!actions}, returning only internal functions. *)
-val is_documented : Types.action -> bool
-(** Returns true if function should be documented, false otherwise *)
-
-val is_fish : Types.action -> bool
-(** Returns true if function should be in guestfish, false otherwise *)
-
-val external_functions : Types.action list
-(** [all_functions] filtered for external functions **)
-
-val internal_functions : Types.action list
-(** [all_functions] filtered for internal functions **)
-
-val documented_functions : Types.action list
-(** [all_functions] filtered for functions requiring documentation **)
-
-val fish_functions : Types.action list
-(** [all_functions] filtered for functions in guestfish **)
-
-val all_functions_sorted : Types.action list
-(** [all_functions] but sorted by name. *)
-
-val external_functions_sorted : Types.action list
-(** [external_functions] but sorted by name. *)
+val fish_functions : Types.action list -> Types.action list
+(** Filter {!actions}, returning only functions in guestfish. *)
-val internal_functions_sorted : Types.action list
-(** [internal_functions] but sorted by name. *)
+val documented_functions : Types.action list -> Types.action list
+(** Filter {!actions}, returning only functions requiring documentation. *)
-val documented_functions_sorted : Types.action list
-(** [documented_functions] but sorted by name. *)
+val sort : Types.action list -> Types.action list
+(** Sort the functions alphabetically by name
+ (see also {!Utils.action_compare}). *)
-val fish_functions_sorted : Types.action list
-(** [fish_functions] but sorted by name. *)
+val is_documented : Types.action -> bool
+(** Returns true if function should be documented, false otherwise. *)
val test_functions : Types.action list
(** Internal test functions used to test the language bindings. *)
+val fish_commands : Types.action list
+(** Non-API meta-commands available only in guestfish. *)
+
val max_proc_nr : int
(** The largest procedure number used (also saved in [src/MAX_PROC_NR] and
used as the minor version number of the shared library). *)
-
-val fish_commands : Types.action list
-(** Non-API meta-commands available only in guestfish. *)
diff --git a/generator/c.ml b/generator/c.ml
index 9643a96..35e08e3 100644
--- a/generator/c.ml
+++ b/generator/c.ml
@@ -52,10 +52,10 @@ let is_public { visibility = v } = match v with
let is_private f = not (is_public f)
let public_functions_sorted - List.filter is_public all_functions_sorted
+ List.filter is_public (actions |> sort)
let private_functions_sorted - List.filter is_private all_functions_sorted
+ List.filter is_private (actions |> sort)
(* Generate a C function prototype. *)
let rec generate_prototype ?(extern = true) ?(static = false)
@@ -218,7 +218,7 @@ and generate_actions_pod () | ({ once_had_no_optargs =
true } as f) ->
generate_actions_pod_back_compat_entry f;
generate_actions_pod_entry f
- ) documented_functions_sorted
+ ) (actions |> documented_functions |> sort)
and generate_actions_pod_entry ({ c_name = c_name;
style = ret, args, optargs as style } as f)
@@ -795,7 +795,7 @@ and generate_internal_actions_h () generate_prototype
~single_line:true ~newline:true ~handle:"g"
~prefix:"guestfs_impl_" ~optarg_proto:Argv
c_name style
- ) non_daemon_functions;
+ ) (actions |> non_daemon_functions);
pr "\n";
pr "#endif /* GUESTFS_INTERNAL_ACTIONS_H_ */\n"
@@ -1785,7 +1785,7 @@ and generate_client_actions hash () if hash_matches
hash f then generate_non_daemon_wrapper f
| { wrapper = false } ->
() (* no wrapper *)
- ) non_daemon_functions;
+ ) (actions |> non_daemon_functions);
(* Client-side stubs for each function. *)
let generate_daemon_stub { name = name; c_name = c_name;
@@ -2083,7 +2083,7 @@ and generate_client_actions hash () List.iter (
fun f ->
if hash_matches hash f then generate_daemon_stub f
- ) daemon_functions
+ ) (actions |> daemon_functions)
(* Functions which have optional arguments have two or three
* generated variants.
@@ -2231,7 +2231,7 @@ and generate_client_actions_variants () | ({ style =
_, _, (_::_); once_had_no_optargs = true } as f) ->
generate_va_variants f;
generate_back_compat_wrapper f
- ) all_functions_sorted
+ ) (actions |> sort)
(* Code for turning events and event bitmasks into printable strings. *)
and generate_event_string_c () @@ -2347,7 +2347,7 @@ and generate_linker_script
() "guestfs_" ^ c_name;
"guestfs_" ^ c_name ^ "_va";
"guestfs_" ^ c_name ^ "_argv"]
- ) all_functions
+ ) actions
) in
let struct_frees List.concat (
diff --git a/generator/checks.ml b/generator/checks.ml
index 9966280..6c65a99 100644
--- a/generator/checks.ml
+++ b/generator/checks.ml
@@ -58,7 +58,7 @@ let () if len >= 5 && String.sub name
(len-5) 5 = "_opts" then
failwithf "function name %s cannot end with _opts" name
*)
- ) (all_functions @ fish_commands);
+ ) (actions @ fish_commands);
(* Check added field was set to something. *)
List.iter (
@@ -67,7 +67,7 @@ let () added = (-1, _, _) } ->
failwithf "function %s has no 'added' (version when added)
field" name
| _ -> ()
- ) all_functions;
+ ) actions;
(* Check function parameter/return names. *)
List.iter (
@@ -131,14 +131,14 @@ let () );
List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) args;
List.iter (fun arg -> check_arg_ret_name (name_of_optargt arg))
optargs;
- ) all_functions;
+ ) actions;
(* Maximum of 63 optargs permitted. *)
List.iter (
fun { name = name; style = _, _, optargs } ->
if List.length optargs > 63 then
failwithf "maximum of 63 optional args allowed for %s" name;
- ) all_functions;
+ ) actions;
(* Some parameter types not supported for daemon functions. *)
List.iter (
@@ -150,7 +150,7 @@ let () | _ -> ()
in
List.iter check_arg_type args;
- ) daemon_functions;
+ ) (actions |> daemon_functions);
(* Check short descriptions. *)
List.iter (
@@ -160,7 +160,7 @@ let () let c = shortdesc.[String.length shortdesc-1]
in
if c = '\n' || c = '.' then
failwithf "short description of %s should not end with . or
\\n." name
- ) (all_functions @ fish_commands);
+ ) (actions @ fish_commands);
(* Check long descriptions. *)
List.iter (
@@ -169,31 +169,15 @@ let () failwithf "long description of %s
should not end with \\n." name;
if longdesc.[0] <> Char.uppercase longdesc.[0] then
failwithf "long description of %s should begin with
uppercase." name
- ) (all_functions @ fish_commands);
-
- (* Check proc_nrs. *)
- List.iter (
- function
- | { name = name; proc_nr = None } ->
- failwithf "daemon function %s should have proc_nr = Some n >
0" name
- | { name = name; proc_nr = Some n } when n <= 0 ->
- failwithf "daemon function %s should have proc_nr = Some n >
0" name
- | { proc_nr = Some _ } -> ()
- ) daemon_functions;
-
- List.iter (
- function
- | { name = name; proc_nr = Some _ } ->
- failwithf "non-daemon function %s should have proc_nr = None"
name
- | { proc_nr = None } -> ()
- ) non_daemon_functions;
+ ) (actions @ fish_commands);
+ (* Check proc_nrs don't overlap. *)
let proc_nrs List.map (
function
| { name = name; proc_nr = Some proc_nr } -> (name, proc_nr)
| _ -> assert false
- ) daemon_functions in
+ ) (actions |> daemon_functions) in
let proc_nrs List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2)
proc_nrs in
let rec loop = function
@@ -224,7 +208,7 @@ let () function
| { name = n' } when n = n' -> true
| _ -> false
- ) all_functions) then
+ ) actions) then
failwithf "%s: deprecated_by flag must be cross-reference to
another action" name
| None -> ()
);
@@ -243,7 +227,7 @@ let () name
| _ -> ()
)
- ) (all_functions @ fish_commands);
+ ) (actions @ fish_commands);
(* Check blocking flag is set on all daemon functions. *)
List.iter (
@@ -252,7 +236,7 @@ let () failwithf "%s: blocking flag should be
'true' on this daemon function"
name
| { blocking = true } -> ()
- ) daemon_functions;
+ ) (actions |> daemon_functions);
(* Check wrapper flag is set on all daemon functions. *)
List.iter (
@@ -261,7 +245,7 @@ let () failwithf "%s: wrapper flag should be
'true' on this daemon function"
name
| { wrapper = true } -> ()
- ) daemon_functions;
+ ) (actions |> daemon_functions);
(* Non-fish functions must have correct camel_name. *)
List.iter (
@@ -271,7 +255,7 @@ let () name;
if String.contains camel_name '_' then
failwithf "%s: camel case name must not contain '_'"
name;
- ) all_functions;
+ ) actions;
(* ConfigOnly should only be specified on non_daemon_functions. *)
List.iter (
@@ -279,7 +263,7 @@ let () | { name = name; config_only = true } ->
failwithf "%s cannot have ConfigOnly flag" name
| { config_only = false } -> ()
- ) (daemon_functions @ fish_commands);
+ ) ((actions |> daemon_functions) @ fish_commands);
(* once_had_no_optargs can only apply if the function now has optargs. *)
List.iter (
@@ -287,7 +271,7 @@ let () | { name = name; once_had_no_optargs = true;
style = _, _, [] } ->
failwithf "%s cannot have once_had_no_optargs flag and no
optargs" name
| { once_had_no_optargs = false } | { style = _, _, (_::_) } -> ()
- ) all_functions;
+ ) actions;
(* Check tests. *)
List.iter (
@@ -311,7 +295,7 @@ let ()
if not tested then
failwithf "function %s has tests but does not test itself"
name
- ) all_functions;
+ ) actions;
List.iter (
function
@@ -324,4 +308,4 @@ let () failwithf "%s test is marked
'IfAvailable %S', but since this function is in the %S optgroup, this is
unnecessary; use 'Always' instead" name o optgroup
| _ -> ()
) tests
- ) all_functions
+ ) actions
diff --git a/generator/csharp.ml b/generator/csharp.ml
index 0255e92..9dcdc77 100644
--- a/generator/csharp.ml
+++ b/generator/csharp.ml
@@ -290,7 +290,7 @@ namespace Guestfs
pr "\n";
List.iter generate_alias non_c_aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr " }
}
diff --git a/generator/daemon.ml b/generator/daemon.ml
index 1d79126..e24ae15 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -55,7 +55,7 @@ let generate_daemon_actions_h () pr "#define
GUESTFS_%s_%s_BITMASK (UINT64_C(1)<<%d)\n"
uc_shortname uc_n i
) optargs
- ) daemon_functions;
+ ) (actions |> daemon_functions);
List.iter (
fun { name = name; style = ret, args, optargs } ->
@@ -67,7 +67,7 @@ let generate_daemon_actions_h () generate_prototype
~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
name style;
- ) daemon_functions;
+ ) (actions |> daemon_functions);
pr "\n";
pr "#endif /* GUESTFSD_ACTIONS_H */\n"
@@ -508,7 +508,7 @@ cleanup_free_mountable (mountable_t *mountable)
pr "done_no_free:\n";
pr " return;\n";
pr "}\n\n";
- ) daemon_functions;
+ ) (actions |> daemon_functions);
(* Dispatch function. *)
pr "void dispatch_incoming_message (XDR *xdr_in)\n";
@@ -520,7 +520,7 @@ cleanup_free_mountable (mountable_t *mountable)
pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
pr " %s_stub (xdr_in);\n" name;
pr " break;\n"
- ) daemon_functions;
+ ) (actions |> daemon_functions);
pr " default:\n";
pr " reply_with_error (\"dispatch_incoming_message: unknown
procedure number %%d, set LIBGUESTFS_PATH to point to the matching libguestfs
appliance directory\", proc_nr);\n";
@@ -712,7 +712,7 @@ and generate_daemon_names () | { name = name; proc_nr =
Some proc_nr } ->
pr " [%d] = \"%s\",\n" proc_nr name
| { proc_nr = None } -> assert false
- ) daemon_functions;
+ ) (actions |> daemon_functions);
pr "};\n";
(* Generate the optional groups for the daemon to implement
diff --git a/generator/erlang.ml b/generator/erlang.ml
index a2facec..9bf0c59 100644
--- a/generator/erlang.ml
+++ b/generator/erlang.ml
@@ -52,7 +52,7 @@ let rec generate_erlang_erl () in
export name;
List.iter export aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\n";
@@ -180,7 +180,7 @@ loop(Port) ->
) aliases;
pr "\n"
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
and generate_erlang_c () generate_header CStyle GPLv2plus;
@@ -286,7 +286,7 @@ extern int64_t get_int64 (ETERM *term);
(* generate the function for typ *)
emit_copy_list_function typ
| typ, _ -> () (* empty *)
- ) (rstructs_used_by external_functions);
+ ) (rstructs_used_by (actions |> external_functions));
(* The wrapper functions. *)
List.iter (
@@ -459,7 +459,7 @@ extern int64_t get_int64 (ETERM *term);
pr "}\n";
pr "\n";
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\
@@ -478,7 +478,7 @@ dispatch (ETERM *message)
pr "if (atom_equals (fun, \"%s\"))\n" name;
pr " return run_%s (message);\n" name;
pr " else ";
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "return unknown_function (fun);
}
diff --git a/generator/fish.ml b/generator/fish.ml
index cc869d3..2acd484 100644
--- a/generator/fish.ml
+++ b/generator/fish.ml
@@ -42,7 +42,7 @@ type func let func_compare (n1, _) (n2, _) = compare n1 n2
let fish_functions_and_commands_sorted - List.sort action_compare
(fish_functions_sorted @ fish_commands)
+ List.sort action_compare ((actions |> fish_functions |> sort) @
fish_commands)
let doc_opttype_of = function
| OBool n -> "true|false"
@@ -68,7 +68,7 @@ let all_functions_commands_and_aliases_sorted let
aliases = List.map (fun x -> x, Alias name) aliases in
let foo = (name, Function shortdesc) :: aliases in
foo @ acc
- ) (fish_functions_sorted @ fish_commands) [] in
+ ) ((actions |> fish_functions |> sort) @ fish_commands) [] in
List.sort func_compare all
let c_quoted_indented ~indent str @@ -118,7 +118,7 @@ let generate_fish_cmds ()
fun { name = name } ->
pr "static int run_%s (const char *cmd, size_t argc, char
*argv[]);\n"
name
- ) fish_functions_sorted;
+ ) (actions |> fish_functions |> sort);
pr "\n";
@@ -210,7 +210,7 @@ Guestfish will prompt for these separately."
pr " .run = run_%s\n" name;
pr "};\n";
pr "\n";
- ) fish_functions_sorted;
+ ) (actions |> fish_functions |> sort);
(* list_commands function, which implements guestfish -h *)
pr "void\n";
@@ -276,7 +276,7 @@ Guestfish will prompt for these separately."
(* generate the function for typ *)
emit_print_list_function typ
| typ, _ -> () (* empty *)
- ) (rstructs_used_by fish_functions);
+ ) (rstructs_used_by (actions |> fish_functions));
(* Emit a print_TYPE function definition only if that function is used. *)
List.iter (
@@ -290,7 +290,7 @@ Guestfish will prompt for these separately."
pr "}\n";
pr "\n";
| typ, _ -> () (* empty *)
- ) (rstructs_used_by fish_functions);
+ ) (rstructs_used_by (actions |> fish_functions));
(* run_<action> actions *)
List.iter (
@@ -643,7 +643,7 @@ Guestfish will prompt for these separately."
pr " return ret;\n";
pr "}\n";
pr "\n"
- ) fish_functions_sorted;
+ ) (actions |> fish_functions |> sort);
(* run_action function *)
pr "int\n";
@@ -838,10 +838,6 @@ do_completion (const char *text, int start, int end)
and generate_fish_actions_pod () generate_header PODStyle GPLv2plus;
- let fishdoc_functions_sorted - List.filter is_documented
fish_functions_sorted
- in
-
let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
List.iter (
@@ -913,7 +909,7 @@ Guestfish will prompt for these separately.\n\n";
pr "This command depends on the feature C<%s>. See also
L</feature-available>.\n\n" opt
);
- ) fishdoc_functions_sorted
+ ) (actions |> fish_functions |> documented_functions |> sort)
(* Generate documentation for guestfish-only commands. *)
and generate_fish_commands_pod () diff --git a/generator/gobject.ml
b/generator/gobject.ml
index b89463e..7ee73a6 100644
--- a/generator/gobject.ml
+++ b/generator/gobject.ml
@@ -119,7 +119,7 @@ let filenames function
| { style = _, _, (_::_) } -> true
| { style = _, _, [] } -> false
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
)
let header_start filename @@ -709,7 +709,7 @@ gboolean guestfs_session_close
(GuestfsSession *session, GError **err);
fun ({ name = name; style = style } as f) ->
generate_gobject_proto name style f;
pr ";\n";
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
header_end filename
@@ -1315,4 +1315,4 @@ guestfs_session_close (GuestfsSession *session, GError
**err)
);
pr "}\n";
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
diff --git a/generator/golang.ml b/generator/golang.ml
index 1cb97fc..3140dbb 100644
--- a/generator/golang.ml
+++ b/generator/golang.ml
@@ -522,4 +522,4 @@ func return_hashtable (argv **C.char) map[string]string {
pr " return C.GoBytes (unsafe.Pointer (r), C.int (size)),
nil\n"
);
pr "}\n";
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
diff --git a/generator/haskell.ml b/generator/haskell.ml
index 66c921e..c04f0c2 100644
--- a/generator/haskell.ml
+++ b/generator/haskell.ml
@@ -62,7 +62,7 @@ module Guestfs (
List.iter (
fun { name = name; style = style } ->
if can_generate style then pr ",\n %s" name
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "
) where
@@ -211,7 +211,7 @@ assocListOfHashtable (a:b:rest) = (a,b) :
assocListOfHashtable rest
);
pr "\n";
)
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
and generate_haskell_prototype ~handle ?(hs = false) (ret, args, optargs) pr
"%s -> " handle;
diff --git a/generator/java.ml b/generator/java.ml
index aa7ed04..044866e 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -433,7 +433,7 @@ public class GuestFS {
generate_java_prototype ~privat:true ~native:true f.name f.style;
pr "\n";
pr "\n";
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "}\n"
@@ -1197,7 +1197,7 @@ get_all_event_callbacks (JNIEnv *env, guestfs_h *g, size_t
*len_rtn)
pr "}\n";
pr "\n"
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
and generate_java_struct_return typ jtyp cols pr " cl =
(*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n"
jtyp;
diff --git a/generator/lua.ml b/generator/lua.ml
index 89a8afd..d3b0b27 100644
--- a/generator/lua.ml
+++ b/generator/lua.ml
@@ -116,7 +116,7 @@ static void push_event (lua_State *L, uint64_t event);
| typ, (RStructListOnly | RStructAndList) ->
pr "static void push_%s (lua_State *L, struct guestfs_%s
*v);\n" typ typ;
pr "static void push_%s_list (lua_State *L, struct guestfs_%s_list
*v);\n" typ typ
- ) (rstructs_used_by external_functions);
+ ) (rstructs_used_by (actions |> external_functions));
pr "\
@@ -627,7 +627,7 @@ guestfs_int_lua_delete_event_callback (lua_State *L)
pr " return 1;\n";
pr "}\n";
pr "\n"
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\
static struct userdata *
@@ -863,7 +863,7 @@ push_event (lua_State *L, uint64_t event)
| typ, (RStructListOnly | RStructAndList) ->
generate_push_struct typ;
generate_push_struct_list typ
- ) (rstructs_used_by external_functions);
+ ) (rstructs_used_by (actions |> external_functions));
pr "\
/* Metamethods.
@@ -890,7 +890,7 @@ static luaL_Reg methods[] = {
List.iter (
fun { name = name } -> pr " { \"%s\", guestfs_int_lua_%s
},\n" name name
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\
diff --git a/generator/main.ml b/generator/main.ml
index 87616a8..69c625b 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -200,7 +200,7 @@ Run it from the top source directory using the command
output_to filename
(generate_gobject_optargs_source short name optargs f)
| { style = _, _, [] } -> ()
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
delete_except_generated
"gobject/include/guestfs-gobject/optargs-*.h";
delete_except_generated "gobject/src/optargs-*.c";
diff --git a/generator/ocaml.ml b/generator/ocaml.ml
index ef04540..f76a3ab 100644
--- a/generator/ocaml.ml
+++ b/generator/ocaml.ml
@@ -222,7 +222,7 @@ end
) non_c_aliases;
pr "\n";
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\
(** {2 Object-oriented API}
@@ -288,7 +288,7 @@ class guestfs : ?environment:bool -> ?close_on_exit:bool
-> unit -> object
pr "\n"
)
) non_c_aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "end\n"
@@ -364,7 +364,7 @@ let () fun { name = name; style = style; non_c_aliases
= non_c_aliases } ->
generate_ocaml_prototype ~is_external:true name style;
List.iter (fun alias -> pr "let %s = %s\n" alias name)
non_c_aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
(* OO API. *)
pr "
@@ -392,7 +392,7 @@ class guestfs ?environment ?close_on_exit () );
List.iter
(fun alias -> pr " method %s = self#%s\n" alias name)
non_c_aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr " end\n"
@@ -528,7 +528,7 @@ copy_table (char * const * argv)
(* generate the function for typ *)
emit_ocaml_copy_list_function typ
| typ, _ -> () (* empty *)
- ) (rstructs_used_by external_functions);
+ ) (rstructs_used_by (actions |> external_functions));
(* The wrappers. *)
List.iter (
@@ -779,7 +779,7 @@ copy_table (char * const * argv)
pr "}\n";
pr "\n"
)
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
(* Generate the OCaml bindings C errnos. *)
and generate_ocaml_c_errnos () diff --git a/generator/optgroups.ml
b/generator/optgroups.ml
index 0a7c1f3..a484ae7 100644
--- a/generator/optgroups.ml
+++ b/generator/optgroups.ml
@@ -40,7 +40,7 @@ let optgroups let fns = try Hashtbl.find h group with
Not_found -> [] in
Hashtbl.replace h group (fn :: fns)
| _ -> ()
- ) daemon_functions;
+ ) (actions |> daemon_functions);
let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
let groups List.map (
diff --git a/generator/perl.ml b/generator/perl.ml
index a665051..94d7c4f 100644
--- a/generator/perl.ml
+++ b/generator/perl.ml
@@ -583,7 +583,7 @@ PREINIT:
);
pr "\n"
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
and generate_perl_struct_list_code typ cols name style n pr " if
(r == NULL)\n";
@@ -923,7 +923,7 @@ C<$g-E<gt>feature-available>.\n\n" opt
pr "=pod\n";
pr "\n";
) non_c_aliases
- ) documented_functions_sorted;
+ ) (actions |> documented_functions |> sort);
pr "=cut\n\n";
@@ -989,7 +989,7 @@ C<$g-E<gt>feature-available>.\n\n" opt
pr " name => \"%s\",\n" name;
pr " description => %S,\n" shortdesc;
pr " },\n";
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr ");\n\n";
pr "# Add aliases to the introspection hash.\n";
@@ -1002,7 +1002,7 @@ C<$g-E<gt>feature-available>.\n\n" opt
pr "$guestfs_introspection{%s} = \\%%ielem%d;\n" alias !i;
incr i
) non_c_aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\n";
(* End of file. *)
diff --git a/generator/php.ml b/generator/php.ml
index 5f06c0f..415c463 100644
--- a/generator/php.ml
+++ b/generator/php.ml
@@ -55,7 +55,7 @@ PHP_FUNCTION (guestfs_last_error);
List.iter (
fun { name = name } -> pr "PHP_FUNCTION (guestfs_%s);\n" name
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\
@@ -199,7 +199,7 @@ static zend_function_entry guestfs_php_functions[] = {
List.iter (
fun { name = name } -> pr " PHP_FE (guestfs_%s, NULL)\n" name
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr " { NULL, NULL, NULL }
};
@@ -585,7 +585,7 @@ PHP_FUNCTION (guestfs_last_error)
pr "}\n";
pr "\n"
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
and generate_php_struct_code typ cols pr " array_init
(return_value);\n";
diff --git a/generator/python.ml b/generator/python.ml
index 31b0875..3bd9c48 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -247,7 +247,7 @@ put_table (char * const * const argv)
(* generate the function for typ *)
emit_put_list_function typ
| typ, _ -> () (* empty *)
- ) (rstructs_used_by external_functions);
+ ) (rstructs_used_by (actions |> external_functions));
(* Python wrapper functions. *)
List.iter (
@@ -548,7 +548,7 @@ put_table (char * const * const argv)
pr "}\n";
pr "#endif\n";
pr "\n"
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
(* Table of functions. *)
pr "static PyMethodDef methods[] = {\n";
@@ -566,7 +566,7 @@ put_table (char * const * const argv)
pr " { (char *) \"%s\", guestfs_int_py_%s, METH_VARARGS,
NULL },\n"
name name;
pr "#endif\n"
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr " { NULL, NULL, 0, NULL }\n";
pr "};\n";
pr "\n";
@@ -901,7 +901,7 @@ class GuestFS(object):
fun alias ->
pr " %s = %s\n\n" alias f.name
) f.non_c_aliases
- ) external_functions_sorted
+ ) (actions |> external_functions |> sort)
and indent_python str indent columns let rec loop str endpos diff --git
a/generator/ruby.ml b/generator/ruby.ml
index 56a387e..3bbdbc9 100644
--- a/generator/ruby.ml
+++ b/generator/ruby.ml
@@ -760,7 +760,7 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn)
pr "}\n";
pr "\n"
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "\
extern void Init__guestfs (void); /* keep GCC warnings happy */
@@ -824,7 +824,7 @@ Init__guestfs (void)
pr " rb_define_method (c_guestfs, \"%s\",\n"
alias;
pr " guestfs_int_ruby_%s, %d);\n" name
nr_args
) non_c_aliases
- ) external_functions_sorted;
+ ) (actions |> external_functions |> sort);
pr "}\n"
diff --git a/generator/tests_c_api.ml b/generator/tests_c_api.ml
index 635a4a6..21ef6e3 100644
--- a/generator/tests_c_api.ml
+++ b/generator/tests_c_api.ml
@@ -76,13 +76,13 @@ let rec generate_c_api_tests () ) tests in
let cmds_tested = List.map List.hd (List.concat seqs) in
List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
- ) all_functions;
+ ) actions;
List.iter (
fun { name = name } ->
if not (Hashtbl.mem hash name) then
pr " \"%s\",\n" name
- ) all_functions_sorted;
+ ) (actions |> sort);
pr " NULL\n";
pr " };\n";
@@ -102,7 +102,7 @@ let rec generate_c_api_tests () List.map (
fun { name = name; optional = optional; tests = tests } ->
mapi (generate_one_test name optional) tests
- ) (List.rev all_functions) in
+ ) (List.rev actions) in
let test_names = List.concat test_names in
let nr_tests = List.length test_names in
@@ -382,7 +382,7 @@ and generate_test_command_call ?(expect_error = false)
?(do_return = true) ?test
(* Look up the function. *)
let f - try List.find (fun { name = n } -> n = name) all_functions
+ try List.find (fun { name = n } -> n = name) actions
with Not_found ->
failwithf "%s: in test, command %s was not found" test_name
name in
diff --git a/generator/xdr.ml b/generator/xdr.ml
index 60ccbf9..8bd168d 100644
--- a/generator/xdr.ml
+++ b/generator/xdr.ml
@@ -169,7 +169,7 @@ let generate_xdr () pr " opaque
%s<>;\n" n;
pr "};\n\n"
);
- ) daemon_functions;
+ ) (actions |> daemon_functions);
pr "/* Table of procedure numbers. */\n";
pr "enum guestfs_procedure {\n";
@@ -182,7 +182,7 @@ let generate_xdr () pr " GUESTFS_PROC_%s =
%d,\n" (String.uppercase shortname) proc_nr;
loop rest
in
- loop daemon_functions;
+ loop (actions |> daemon_functions);
pr "};\n";
pr "\n";
--
2.9.3
Richard W.M. Jones
2016-Sep-02 14:21 UTC
[Libguestfs] [PATCH 3/4] generator: Generalize the code used to split actions across files.
Previously we used an awkward hack to split up the large src/actions.c
into smaller files (which can benefit from being compiled in
parallel). This commit generalizes that code, so that we pass a
subsetted actions list to certain generator functions.
The output of the generator is identical after this commit and the
previous commit, except for the UUID encoded into tests/c-api/tests.c
since that is derived from the MD5 hash of generator/actions.ml.
---
generator/c.ml | 16 +++-------------
generator/c.mli | 4 +---
generator/main.ml | 21 +++++++++++++++------
3 files changed, 19 insertions(+), 22 deletions(-)
diff --git a/generator/c.ml b/generator/c.ml
index 35e08e3..6f5a517 100644
--- a/generator/c.ml
+++ b/generator/c.ml
@@ -33,16 +33,6 @@ let generate_header = generate_header
~inputs:["generator/c.ml"]
(* Generate C API. *)
-(* The actions are split across this many C files. You can increase
- * this number in order to reduce the number of lines in each file
- * (hence making compilation faster), but you also have to modify
- * src/Makefile.am.
- *)
-let nr_actions_files = 7
-let hash_matches h { name = name } - let h' = Hashtbl.hash name mod
nr_actions_files in
- h = h'
-
type optarg_proto = Dots | VA | Argv
let is_public { visibility = v } = match v with
@@ -1335,7 +1325,7 @@ and generate_client_structs_print_h () "
(* Generate the client-side dispatch stubs. *)
-and generate_client_actions hash () +and generate_client_actions actions ()
generate_header CStyle LGPLv2plus;
pr "\
@@ -1782,7 +1772,7 @@ and generate_client_actions hash () List.iter (
function
| { wrapper = true } as f ->
- if hash_matches hash f then generate_non_daemon_wrapper f
+ generate_non_daemon_wrapper f
| { wrapper = false } ->
() (* no wrapper *)
) (actions |> non_daemon_functions);
@@ -2082,7 +2072,7 @@ and generate_client_actions hash ()
List.iter (
fun f ->
- if hash_matches hash f then generate_daemon_stub f
+ generate_daemon_stub f
) (actions |> daemon_functions)
(* Functions which have optional arguments have two or three
diff --git a/generator/c.mli b/generator/c.mli
index 156b244..8c4e86c 100644
--- a/generator/c.mli
+++ b/generator/c.mli
@@ -22,11 +22,9 @@ val generate_prototype : ?extern:bool -> ?static:bool
-> ?semicolon:bool -> ?sin
val generate_c_call_args : ?handle:string -> ?implicit_size_ptr:string ->
?in_daemon:bool -> Types.ret * Types.args * Types.optargs -> unit
-val nr_actions_files : int
-
val generate_actions_pod : unit -> unit
val generate_availability_pod : unit -> unit
-val generate_client_actions : int -> unit -> unit
+val generate_client_actions : Types.action list -> unit -> unit
val generate_client_actions_variants : unit -> unit
val generate_client_structs_cleanup : unit -> unit
val generate_client_structs_compare : unit -> unit
diff --git a/generator/main.ml b/generator/main.ml
index 69c625b..edf106a 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -54,6 +54,20 @@ let perror msg = function
| exn ->
eprintf "%s: %s\n" msg (Printexc.to_string exn)
+(* In some directories the actions are split across this many C
+ * files. You can increase this number in order to reduce the number
+ * of lines in each file (hence making compilation faster), but you
+ * also have to modify .../Makefile.am.
+ *)
+let nr_actions_files = 7
+let actions_subsets + let h i { name = name } = i = Hashtbl.hash name mod
nr_actions_files in
+ Array.init nr_actions_files (fun i -> List.filter (h i) actions)
+let output_to_subset fs f + for i = 0 to nr_actions_files-1 do
+ ksprintf (fun filename -> output_to filename (f actions_subsets.(i))) fs
i
+ done
+
(* Main program. *)
let () let lock_fd @@ -103,12 +117,7 @@ Run it from the top source directory
using the command
output_to "src/structs-print.c" generate_client_structs_print_c;
output_to "src/structs-print.h" generate_client_structs_print_h;
output_to "src/actions-variants.c"
generate_client_actions_variants;
-
- for i = 0 to nr_actions_files-1 do
- let filename = sprintf "src/actions-%d.c" i in
- output_to filename (generate_client_actions i)
- done;
-
+ output_to_subset "src/actions-%d.c" generate_client_actions;
output_to "daemon/actions.h" generate_daemon_actions_h;
output_to "daemon/stubs.c" generate_daemon_actions;
output_to "daemon/names.c" generate_daemon_names;
--
2.9.3
Richard W.M. Jones
2016-Sep-02 14:21 UTC
[Libguestfs] [PATCH 4/4] fish: Split up the very large fish/cmds.c file.
Make parallel compiles faster in this directory (about 8s down to 3s).
---
.gitignore | 3 +
fish/Makefile.am | 17 ++-
generator/fish.ml | 348 ++++++++++++++++++++++++++++++-----------------------
generator/fish.mli | 3 +
generator/main.ml | 3 +
5 files changed, 220 insertions(+), 154 deletions(-)
diff --git a/.gitignore b/.gitignore
index fc0d065..8312d99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -204,6 +204,7 @@ Makefile.in
/fish/cmds-gperf.c
/fish/cmds-gperf.gperf
/fish/completion.c
+/fish/entries-?.c
/fish/event-names.c
/fish/fish-cmds.h
/fish/guestfish
@@ -216,6 +217,8 @@ Makefile.in
/fish/prepopts.h
/fish/rc_protocol.c
/fish/rc_protocol.h
+/fish/run-?.c
+/fish/run.h
/fish/stamp-guestfish.pod
/fish/stamp-libguestfs-tools.conf.pod
/fish/stamp-virt-copy-in.pod
diff --git a/fish/Makefile.am b/fish/Makefile.am
index a6de568..e1bc210 100644
--- a/fish/Makefile.am
+++ b/fish/Makefile.am
@@ -23,13 +23,28 @@ generator_built = \
cmds.c \
cmds-gperf.gperf \
completion.c \
+ entries-0.c \
+ entries-1.c \
+ entries-2.c \
+ entries-3.c \
+ entries-4.c \
+ entries-5.c \
+ entries-6.c \
event-names.c \
fish-cmds.h \
guestfish-actions.pod \
guestfish-commands.pod \
guestfish-prepopts.pod \
prepopts.h \
- prepopts.c
+ prepopts.c \
+ run-0.c \
+ run-1.c \
+ run-2.c \
+ run-3.c \
+ run-4.c \
+ run-5.c \
+ run-6.c \
+ run.h
BUILT_SOURCES = \
$(generator_built) \
diff --git a/generator/fish.ml b/generator/fish.ml
index 2acd484..b16326b 100644
--- a/generator/fish.ml
+++ b/generator/fish.ml
@@ -76,11 +76,10 @@ let c_quoted_indented ~indent str let str = replace_str
str "\\n" ("\\n\"\n" ^ indent ^ "\"") in
str
-(* Generate a lot of different functions for guestfish. *)
-let generate_fish_cmds () +(* Generate run_* functions and header for
libguestfs API functions. *)
+let generate_fish_run_cmds actions () generate_header CStyle GPLv2plus;
-
pr "#include <config.h>\n";
pr "\n";
pr "/* It is safe to call deprecated functions from this file.
*/\n";
@@ -93,7 +92,6 @@ let generate_fish_cmds () pr "#include
<libintl.h>\n";
pr "#include <errno.h>\n";
pr "\n";
- pr "#include \"c-ctype.h\"\n";
pr "#include \"full-write.h\"\n";
pr "#include \"xstrtol.h\"\n";
pr "\n";
@@ -102,157 +100,16 @@ let generate_fish_cmds () pr "#include
\"structs-print.h\"\n";
pr "\n";
pr "#include \"fish.h\"\n";
- pr "#include \"fish-cmds.h\"\n";
pr "#include \"options.h\"\n";
- pr "#include \"cmds-gperf.h\"\n";
+ pr "#include \"fish-cmds.h\"\n";
+ pr "#include \"run.h\"\n";
pr "\n";
pr "/* Valid suffixes allowed for numbers. See Gnulib xstrtol function.
*/\n";
pr "static const char xstrtol_suffixes[] =
\"0kKMGTPEZY\";\n";
pr "\n";
- pr "/* Return these errors from run_* functions. */\n";
- pr "#define RUN_ERROR -1\n";
- pr "#define RUN_WRONG_ARGS -2\n";
- pr "\n";
-
- List.iter (
- fun { name = name } ->
- pr "static int run_%s (const char *cmd, size_t argc, char
*argv[]);\n"
- name
- ) (actions |> fish_functions |> sort);
-
- pr "\n";
-
- (* List of command_entry structs. *)
- List.iter (
- fun ({ name = name; shortdesc = shortdesc; longdesc = longdesc } as f)
->
- let aliases = get_aliases f in
-
- let name2 = replace_char name '_' '-' in
- let describe_alias - if aliases <> [] then
- sprintf "\n\nYou can use %s as an alias for this command."
- (String.concat " or " (List.map (fun s ->
"'" ^ s ^ "'") aliases))
- else "" in
-
- let pod - sprintf "%s - %s\n\n=head1
DESCRIPTION\n\n%s\n\n%s"
- name2 shortdesc longdesc describe_alias in
- let text - String.concat "\n" (pod2text ~trim:false
~discard:false "NAME" pod)
- ^ "\n" in
-
- pr "struct command_entry %s_cmd_entry = {\n" name;
- pr " .name = \"%s\",\n" name2;
- pr " .help = \"%s\",\n" (c_quoted_indented
~indent:" " text);
- pr " .synopsis = NULL,\n";
- pr " .run = run_%s\n" name;
- pr "};\n";
- pr "\n";
- ) fish_commands;
-
- List.iter (
- fun ({ name = name; style = _, args, optargs;
- shortdesc = shortdesc; longdesc = longdesc } as f) ->
- let aliases = get_aliases f in
-
- let name2 = replace_char name '_' '-' in
-
- let longdesc = replace_str longdesc "C<guestfs_"
"C<" in
- let synopsis - match args with
- | [] -> name2
- | args ->
- let args = List.filter (function Key _ -> false | _ -> true)
args in
- sprintf "%s%s%s"
- name2
- (String.concat ""
- (List.map (fun arg -> " " ^ name_of_argt arg)
args))
- (String.concat ""
- (List.map (fun arg ->
- sprintf " [%s:%s]" (name_of_optargt arg)
(doc_opttype_of arg)
- ) optargs)) in
-
- let warnings - if List.exists (function Key _ -> true | _ ->
false) args then
- "\n\nThis command has one or more key or passphrase parameters.
-Guestfish will prompt for these separately."
- else "" in
-
- let warnings - warnings ^
- if f.protocol_limit_warning then
- "\n\n" ^ protocol_limit_warning
- else "" in
-
- let warnings - warnings ^
- match deprecation_notice ~replace_underscores:true f with
- | None -> ""
- | Some txt -> "\n\n" ^ txt in
-
- let describe_alias - if aliases <> [] then
- sprintf "\n\nYou can use %s as an alias for this command."
- (String.concat " or " (List.map (fun s ->
"'" ^ s ^ "'") aliases))
- else "" in
-
- let pod - sprintf "%s - %s\n\n=head1 SYNOPSIS\n\n
%s\n\n=head1 DESCRIPTION\n\n%s%s%s"
- name2 shortdesc synopsis longdesc warnings describe_alias in
- let text - String.concat "\n" (pod2text ~trim:false
~discard:false "NAME" pod)
- ^ "\n" in
-
- pr "struct command_entry %s_cmd_entry = {\n" name;
- pr " .name = \"%s\",\n" name2;
- pr " .help = \"%s\",\n" (c_quoted_indented
~indent:" " text);
- pr " .synopsis = \"%s\",\n" (c_quote synopsis);
- pr " .run = run_%s\n" name;
- pr "};\n";
- pr "\n";
- ) (actions |> fish_functions |> sort);
-
- (* list_commands function, which implements guestfish -h *)
- pr "void\n";
- pr "list_commands (void)\n";
- pr "{\n";
- pr " printf (\" %%-16s %%s\\n\",
_(\"Command\"), _(\"Description\"));\n";
- pr " list_builtin_commands ();\n";
- List.iter (
- fun (name, f) ->
- let name = replace_char name '_' '-' in
- match f with
- | Function shortdesc ->
- pr " printf (\"%%-20s %%s\\n\", \"%s\",
_(\"%s\"));\n"
- name shortdesc
- | Alias f ->
- let f = replace_char f '_' '-' in
- pr " printf (\"%%-20s \", \"%s\");\n"
name;
- pr " printf (_(\"alias for '%%s'\"),
\"%s\");\n" f;
- pr " putchar ('\\n');\n"
- ) all_functions_commands_and_aliases_sorted;
- pr " printf (\" %%s\\n\",";
- pr " _(\"Use -h <cmd> / help <cmd> to show
detailed help for a command.\"));\n";
- pr "}\n";
- pr "\n";
-
- (* display_command function, which implements guestfish -h cmd *)
- pr "int\n";
- pr "display_command (const char *cmd)\n";
- pr "{\n";
- pr " const struct command_table *ct;\n";
- pr "\n";
- pr " ct = lookup_fish_command (cmd, strlen (cmd));\n";
- pr " if (ct) {\n";
- pr " fputs (ct->entry->help, stdout);\n";
- pr " return 0;\n";
- pr " }\n";
- pr " else\n";
- pr " return display_builtin_command (cmd);\n";
- pr "}\n";
- pr "\n";
let emit_print_list_function typ + pr "\n";
pr "static void\n";
pr "print_%s_list (struct guestfs_%s_list *%ss)\n"
typ typ typ;
@@ -266,7 +123,6 @@ Guestfish will prompt for these separately."
pr " printf (\"}\\n\");\n";
pr " }\n";
pr "}\n";
- pr "\n";
in
(* Emit a print_TYPE_list function definition only if that function is used.
*)
@@ -282,22 +138,22 @@ Guestfish will prompt for these separately."
List.iter (
function
| typ, (RStructOnly | RStructAndList) ->
+ pr "\n";
pr "static void\n";
pr "print_%s (struct guestfs_%s *%s)\n" typ typ typ;
pr "{\n";
pr " guestfs_int_print_%s_indent (%s, stdout, \"\\n\",
\"\");\n"
typ typ;
pr "}\n";
- pr "\n";
| typ, _ -> () (* empty *)
) (rstructs_used_by (actions |> fish_functions));
- (* run_<action> actions *)
List.iter (
fun { name = name; style = (ret, args, optargs as style);
fish_output = fish_output; c_function = c_function;
c_optarg_prefix = c_optarg_prefix } ->
- pr "static int\n";
+ pr "\n";
+ pr "int\n";
pr "run_%s (const char *cmd, size_t argc, char *argv[])\n"
name;
pr "{\n";
pr " int ret = RUN_ERROR;\n";
@@ -642,9 +498,195 @@ Guestfish will prompt for these separately."
pr " out_noargs:\n";
pr " return ret;\n";
pr "}\n";
- pr "\n"
+ ) (actions |> fish_functions |> sort)
+
+let generate_fish_run_header () + generate_header CStyle GPLv2plus;
+
+ pr "#ifndef FISH_RUN_H\n";
+ pr "#define FISH_RUN_H\n";
+ pr "\n";
+
+ pr "/* Return these errors from run_* functions. */\n";
+ pr "#define RUN_ERROR -1\n";
+ pr "#define RUN_WRONG_ARGS -2\n";
+ pr "\n";
+
+ List.iter (
+ fun { name = name } ->
+ pr "extern int run_%s (const char *cmd, size_t argc, char
*argv[]);\n"
+ name
) (actions |> fish_functions |> sort);
+ pr "\n";
+ pr "#endif /* FISH_RUN_H */\n"
+
+let generate_fish_cmd_entries actions () + generate_header CStyle GPLv2plus;
+
+ pr "#include <config.h>\n";
+ pr "\n";
+ pr "#include <stdio.h>\n";
+ pr "#include <stdlib.h>\n";
+ pr "\n";
+ pr "#include \"cmds-gperf.h\"\n";
+ pr "#include \"run.h\"\n";
+ pr "\n";
+
+ List.iter (
+ fun ({ name = name; style = _, args, optargs;
+ shortdesc = shortdesc; longdesc = longdesc } as f) ->
+ let aliases = get_aliases f in
+
+ let name2 = replace_char name '_' '-' in
+
+ let longdesc = replace_str longdesc "C<guestfs_"
"C<" in
+ let synopsis + match args with
+ | [] -> name2
+ | args ->
+ let args = List.filter (function Key _ -> false | _ -> true)
args in
+ sprintf "%s%s%s"
+ name2
+ (String.concat ""
+ (List.map (fun arg -> " " ^ name_of_argt arg)
args))
+ (String.concat ""
+ (List.map (fun arg ->
+ sprintf " [%s:%s]" (name_of_optargt arg)
(doc_opttype_of arg)
+ ) optargs)) in
+
+ let warnings + if List.exists (function Key _ -> true | _ ->
false) args then
+ "\n\nThis command has one or more key or passphrase parameters.
+Guestfish will prompt for these separately."
+ else "" in
+
+ let warnings + warnings ^
+ if f.protocol_limit_warning then
+ "\n\n" ^ protocol_limit_warning
+ else "" in
+
+ let warnings + warnings ^
+ match deprecation_notice ~replace_underscores:true f with
+ | None -> ""
+ | Some txt -> "\n\n" ^ txt in
+
+ let describe_alias + if aliases <> [] then
+ sprintf "\n\nYou can use %s as an alias for this command."
+ (String.concat " or " (List.map (fun s ->
"'" ^ s ^ "'") aliases))
+ else "" in
+
+ let pod + sprintf "%s - %s\n\n=head1 SYNOPSIS\n\n
%s\n\n=head1 DESCRIPTION\n\n%s%s%s"
+ name2 shortdesc synopsis longdesc warnings describe_alias in
+ let text + String.concat "\n" (pod2text ~trim:false
~discard:false "NAME" pod)
+ ^ "\n" in
+
+ pr "struct command_entry %s_cmd_entry = {\n" name;
+ pr " .name = \"%s\",\n" name2;
+ pr " .help = \"%s\",\n" (c_quoted_indented
~indent:" " text);
+ pr " .synopsis = \"%s\",\n" (c_quote synopsis);
+ pr " .run = run_%s\n" name;
+ pr "};\n";
+ pr "\n";
+ ) (actions |> fish_functions |> sort)
+
+(* Generate a lot of different functions for guestfish. *)
+let generate_fish_cmds () + generate_header CStyle GPLv2plus;
+
+ pr "#include <config.h>\n";
+ pr "\n";
+ pr "#include <stdio.h>\n";
+ pr "#include <stdlib.h>\n";
+ pr "#include <string.h>\n";
+ pr "#include <inttypes.h>\n";
+ pr "#include <libintl.h>\n";
+ pr "#include <errno.h>\n";
+ pr "\n";
+ pr "#include \"guestfs.h\"\n";
+ pr "#include \"guestfs-internal-frontend.h\"\n";
+ pr "#include \"structs-print.h\"\n";
+ pr "\n";
+ pr "#include \"fish.h\"\n";
+ pr "#include \"fish-cmds.h\"\n";
+ pr "#include \"options.h\"\n";
+ pr "#include \"cmds-gperf.h\"\n";
+ pr "#include \"run.h\"\n";
+ pr "\n";
+
+ (* List of command_entry structs for pure guestfish commands. *)
+ List.iter (
+ fun ({ name = name; shortdesc = shortdesc; longdesc = longdesc } as f)
->
+ let aliases = get_aliases f in
+
+ let name2 = replace_char name '_' '-' in
+ let describe_alias + if aliases <> [] then
+ sprintf "\n\nYou can use %s as an alias for this command."
+ (String.concat " or " (List.map (fun s ->
"'" ^ s ^ "'") aliases))
+ else "" in
+
+ let pod + sprintf "%s - %s\n\n=head1
DESCRIPTION\n\n%s\n\n%s"
+ name2 shortdesc longdesc describe_alias in
+ let text + String.concat "\n" (pod2text ~trim:false
~discard:false "NAME" pod)
+ ^ "\n" in
+
+ pr "struct command_entry %s_cmd_entry = {\n" name;
+ pr " .name = \"%s\",\n" name2;
+ pr " .help = \"%s\",\n" (c_quoted_indented
~indent:" " text);
+ pr " .synopsis = NULL,\n";
+ pr " .run = run_%s\n" name;
+ pr "};\n";
+ pr "\n";
+ ) fish_commands;
+
+ (* list_commands function, which implements guestfish -h *)
+ pr "void\n";
+ pr "list_commands (void)\n";
+ pr "{\n";
+ pr " printf (\" %%-16s %%s\\n\",
_(\"Command\"), _(\"Description\"));\n";
+ pr " list_builtin_commands ();\n";
+ List.iter (
+ fun (name, f) ->
+ let name = replace_char name '_' '-' in
+ match f with
+ | Function shortdesc ->
+ pr " printf (\"%%-20s %%s\\n\", \"%s\",
_(\"%s\"));\n"
+ name shortdesc
+ | Alias f ->
+ let f = replace_char f '_' '-' in
+ pr " printf (\"%%-20s \", \"%s\");\n"
name;
+ pr " printf (_(\"alias for '%%s'\"),
\"%s\");\n" f;
+ pr " putchar ('\\n');\n"
+ ) all_functions_commands_and_aliases_sorted;
+ pr " printf (\" %%s\\n\",";
+ pr " _(\"Use -h <cmd> / help <cmd> to show
detailed help for a command.\"));\n";
+ pr "}\n";
+ pr "\n";
+
+ (* display_command function, which implements guestfish -h cmd *)
+ pr "int\n";
+ pr "display_command (const char *cmd)\n";
+ pr "{\n";
+ pr " const struct command_table *ct;\n";
+ pr "\n";
+ pr " ct = lookup_fish_command (cmd, strlen (cmd));\n";
+ pr " if (ct) {\n";
+ pr " fputs (ct->entry->help, stdout);\n";
+ pr " return 0;\n";
+ pr " }\n";
+ pr " else\n";
+ pr " return display_builtin_command (cmd);\n";
+ pr "}\n";
+ pr "\n";
+
(* run_action function *)
pr "int\n";
pr "run_action (const char *cmd, size_t argc, char *argv[])\n";
diff --git a/generator/fish.mli b/generator/fish.mli
index bb4376a..ed52d90 100644
--- a/generator/fish.mli
+++ b/generator/fish.mli
@@ -17,6 +17,9 @@
*)
val generate_fish_actions_pod : unit -> unit
+val generate_fish_run_cmds : Types.action list -> unit -> unit
+val generate_fish_run_header : unit -> unit
+val generate_fish_cmd_entries : Types.action list -> unit -> unit
val generate_fish_cmds : unit -> unit
val generate_fish_cmds_gperf : unit -> unit
val generate_fish_cmds_h : unit -> unit
diff --git a/generator/main.ml b/generator/main.ml
index edf106a..52b77b4 100644
--- a/generator/main.ml
+++ b/generator/main.ml
@@ -126,6 +126,9 @@ Run it from the top source directory using the command
output_to "tests/c-api/tests.c" generate_c_api_tests;
output_to "fish/cmds-gperf.gperf" generate_fish_cmds_gperf;
output_to "fish/cmds.c" generate_fish_cmds;
+ output_to_subset "fish/entries-%d.c" generate_fish_cmd_entries;
+ output_to_subset "fish/run-%d.c" generate_fish_run_cmds;
+ output_to "fish/run.h" generate_fish_run_header;
output_to "fish/completion.c" generate_fish_completion;
output_to "fish/event-names.c" generate_fish_event_names;
output_to "fish/fish-cmds.h" generate_fish_cmds_h;
--
2.9.3
Pino Toscano
2016-Sep-02 15:52 UTC
Re: [Libguestfs] [PATCH 0/4] generator: Some work to split large C files
On Friday, 2 September 2016 15:21:25 CEST Richard W.M. Jones wrote:> By splitting up large C files we can make parallel compiles > a bit faster.Seems ok, ACK. -- Pino Toscano
Richard W.M. Jones
2016-Sep-02 22:13 UTC
Re: [Libguestfs] [PATCH 0/4] generator: Some work to split large C files
On Fri, Sep 02, 2016 at 05:52:22PM +0200, Pino Toscano wrote:> On Friday, 2 September 2016 15:21:25 CEST Richard W.M. Jones wrote: > > By splitting up large C files we can make parallel compiles > > a bit faster. > > Seems ok, ACK.Thanks - pushed with a few more subdirectories split up. Unfortunately the biggest problems -- perl/ & gobject/ -- are the ones which is hardest to fix. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html