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