summaryrefslogtreecommitdiffstats
path: root/libvirt/generator.pl
diff options
context:
space:
mode:
Diffstat (limited to 'libvirt/generator.pl')
-rwxr-xr-xlibvirt/generator.pl524
1 files changed, 524 insertions, 0 deletions
diff --git a/libvirt/generator.pl b/libvirt/generator.pl
new file mode 100755
index 0000000..a54bd94
--- /dev/null
+++ b/libvirt/generator.pl
@@ -0,0 +1,524 @@
+#!/usr/bin/perl -w
+#
+# OCaml bindings for libvirt.
+# (C) Copyright 2007-2008 Richard W.M. Jones, Red Hat Inc.
+# http://libvirt.org/
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This generates libvirt_c.c (the core of the bindings). You don't
+# need to run this program unless you are extending the bindings
+# themselves (eg. because libvirt has been extended).
+
+use strict;
+
+#----------------------------------------------------------------------
+
+# The functions in the libvirt API that we can generate.
+
+my @functions = (
+ { name => "virConnectGetHostname", sig => "conn : string", weak => 1 },
+ { name => "virConnectGetURI", sig => "conn : string", weak => 1 },
+ { name => "virConnectGetType", sig => "conn : static string" },
+ { name => "virConnectNumOfDomains", sig => "conn : int" },
+ { name => "virConnectListDomains", sig => "conn, int : int array" },
+ { name => "virConnectNumOfDefinedDomains", sig => "conn : int" },
+ { name => "virConnectListDefinedDomains",
+ sig => "conn, int : string array" },
+ { name => "virConnectNumOfNetworks", sig => "conn : int" },
+ { name => "virConnectListNetworks", sig => "conn, int : string array" },
+ { name => "virConnectNumOfDefinedNetworks", sig => "conn : int" },
+ { name => "virConnectListDefinedNetworks",
+ sig => "conn, int : string array" },
+ { name => "virConnectNumOfStoragePools", sig => "conn : int", weak => 1 },
+ { name => "virConnectListStoragePools",
+ sig => "conn, int : string array", weak => 1 },
+ { name => "virConnectNumOfDefinedStoragePools",
+ sig => "conn : int", weak => 1 },
+ { name => "virConnectListDefinedStoragePools",
+ sig => "conn, int : string array", weak => 1 },
+ { name => "virConnectGetCapabilities", sig => "conn : string" },
+
+ { name => "virDomainGetName", sig => "dom : static string" },
+ { name => "virDomainGetOSType", sig => "dom : string" },
+ { name => "virDomainGetXMLDesc", sig => "dom, 0 : string" },
+ { name => "virDomainSuspend", sig => "dom : unit" },
+ { name => "virDomainResume", sig => "dom : unit" },
+ { name => "virDomainShutdown", sig => "dom : unit" },
+ { name => "virDomainReboot", sig => "dom, 0 : unit" },
+ { name => "virDomainUndefine", sig => "dom : unit" },
+ { name => "virDomainCreate", sig => "dom : unit" },
+
+ { name => "virNetworkGetName", sig => "net : static string" },
+ { name => "virNetworkGetXMLDesc", sig => "net, 0 : string" },
+ { name => "virNetworkGetBridgeName", sig => "net : string" },
+ { name => "virNetworkUndefine", sig => "net : unit" },
+ { name => "virNetworkCreate", sig => "net : unit" },
+
+ { name => "virStoragePoolGetName",
+ sig => "pool : static string", weak => 1 },
+ { name => "virStoragePoolGetXMLDesc",
+ sig => "pool, 0 : string", weak => 1 },
+ { name => "virStoragePoolUndefine",
+ sig => "pool : string", weak => 1 },
+ { name => "virStoragePoolCreate",
+ sig => "pool : string", weak => 1 },
+ { name => "virStoragePoolShutdown",
+ sig => "pool : string", weak => 1 },
+ { name => "virStoragePoolRefresh",
+ sig => "pool, 0 : string", weak => 1 },
+
+ { name => "virStorageVolGetXMLDesc",
+ sig => "pool, 0 : string", weak => 1 },
+ { name => "virStorageVolGetPath",
+ sig => "pool : string", weak => 1 },
+ { name => "virStorageVolGetKey",
+ sig => "pool : static string", weak => 1 },
+ { name => "virStorageVolGetName",
+ sig => "pool : static string", weak => 1 },
+
+ );
+
+# Functions we haven't implemented anywhere yet.
+# We create stubs for these, but they need to either be moved ^^ so they
+# are auto-generated or implementations written in libvirt_c_oneoffs.c.
+
+my @unimplemented = (
+ "ocaml_libvirt_domain_create_job",
+ "ocaml_libvirt_domain_core_dump_job",
+ "ocaml_libvirt_domain_restore_job",
+ "ocaml_libvirt_domain_save_job",
+ "ocaml_libvirt_connect_create_linux_job",
+ "ocaml_libvirt_network_create_job",
+ "ocaml_libvirt_network_create_xml_job",
+ "ocaml_libvirt_storage_pool_set_autostart",
+ "ocaml_libvirt_storage_pool_get_autostart",
+ "ocaml_libvirt_storage_pool_get_info",
+ "ocaml_libvirt_storage_pool_get_uuid_string",
+ "ocaml_libvirt_storage_pool_get_uuid",
+ "ocaml_libvirt_storage_pool_free",
+ "ocaml_libvirt_storage_pool_destroy",
+ "ocaml_libvirt_storage_pool_define_xml",
+ "ocaml_libvirt_storage_pool_create_xml",
+ "ocaml_libvirt_storage_pool_lookup_by_uuid_string",
+ "ocaml_libvirt_storage_pool_lookup_by_uuid",
+ "ocaml_libvirt_storage_pool_lookup_by_name",
+ "ocaml_libvirt_storage_vol_free",
+ "ocaml_libvirt_storage_vol_destroy",
+ "ocaml_libvirt_storage_vol_create_xml",
+ "ocaml_libvirt_storage_vol_get_info",
+ "ocaml_libvirt_pool_of_volume",
+ "ocaml_libvirt_storage_vol_lookup_by_path",
+ "ocaml_libvirt_storage_vol_lookup_by_key",
+ "ocaml_libvirt_storage_vol_lookup_by_name",
+ "ocaml_libvirt_job_cancel",
+ "ocaml_libvirt_job_get_network",
+ "ocaml_libvirt_job_get_domain",
+ "ocaml_libvirt_job_get_info",
+ );
+
+#----------------------------------------------------------------------
+
+# Open the output file.
+
+my $filename = "libvirt_c.c";
+open F, ">$filename" or die "$filename: $!";
+
+# Write the prologue.
+
+print F <<'END';
+/* WARNING: THIS FILE IS AUTOMATICALLY GENERATED BY 'generator.pl'.
+ * Any changes you make to this file may be overwritten.
+ */
+
+/* OCaml bindings for libvirt.
+ * (C) Copyright 2007-2008 Richard W.M. Jones, Red Hat Inc.
+ * http://libvirt.org/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+
+#include <caml/config.h>
+#include <caml/alloc.h>
+#include <caml/callback.h>
+#include <caml/custom.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/misc.h>
+#include <caml/mlvalues.h>
+#include <caml/signals.h>
+
+#include "libvirt_c_prologue.c"
+
+#include "libvirt_c_oneoffs.c"
+
+END
+
+#----------------------------------------------------------------------
+
+sub camel_case_to_underscores
+{
+ my $name = shift;
+
+ $name =~ s/([A-Z][a-z]+|XML|URI|OS)/$1,/g;
+ my @subs = split (/,/, $name);
+ @subs = map { lc($_) } @subs;
+ join "_", @subs
+}
+
+# Helper functions dealing with signatures.
+
+sub short_name_to_c_type
+{
+ local $_ = shift;
+
+ if ($_ eq "conn") { "virConnectPtr" }
+ elsif ($_ eq "dom") { "virDomainPtr" }
+ elsif ($_ eq "net") { "virNetworkPtr" }
+ elsif ($_ eq "pool") { "virStoragePoolPtr" }
+ elsif ($_ eq "vol") { "virStorageVolPtr" }
+ else {
+ die "unknown short name $_"
+ }
+}
+
+sub gen_c_signature
+{
+ my $sig = shift;
+ my $c_name = shift;
+
+ if ($sig =~ /^(\w+) : string$/) {
+ my $c_type = short_name_to_c_type ($1);
+ "char *$c_name ($c_type $1)"
+ } elsif ($sig =~ /^(\w+) : static string$/) {
+ my $c_type = short_name_to_c_type ($1);
+ "const char *$c_name ($c_type $1)"
+ } elsif ($sig =~ /^(\w+) : int$/) {
+ my $c_type = short_name_to_c_type ($1);
+ "int $c_name ($c_type $1)"
+ } elsif ($sig eq "conn, int : int array") {
+ "int $c_name (virConnectPtr conn, int *ids, int maxids)"
+ } elsif ($sig eq "conn, int : string array") {
+ "int $c_name (virConnectPtr conn, char **const names, int maxnames)"
+ } elsif ($sig =~ /^(\w+), 0 : string$/) {
+ my $c_type = short_name_to_c_type ($1);
+ "char *$c_name ($c_type $1, int flags)"
+ } elsif ($sig =~ /^(\w+), 0 : unit$/) {
+ my $c_type = short_name_to_c_type ($1);
+ "int $c_name ($c_type $1, int flags)"
+ } elsif ($sig =~ /^(\w+) : unit$/) {
+ my $c_type = short_name_to_c_type ($1);
+ "int $c_name ($c_type $1 dom)"
+ } else {
+ die "unknown signature $sig"
+ }
+}
+
+sub gen_arg_names
+{
+ my $sig = shift;
+
+ if ($sig =~ /^(\w+) : string$/) {
+ ( "$1v" )
+ } elsif ($sig =~ /^(\w+) : static string$/) {
+ ( "$1v" )
+ } elsif ($sig =~ /^(\w+) : int$/) {
+ ( "$1v" )
+ } elsif ($sig eq "conn, int : int array") {
+ ( "connv", "iv" )
+ } elsif ($sig eq "conn, int : string array") {
+ ( "connv", "iv" )
+ } elsif ($sig =~ /^(\w+), 0 : string$/) {
+ ( "$1v" )
+ } elsif ($sig =~ /^(\w+), 0 : unit$/) {
+ ( "$1v" )
+ } elsif ($sig =~ /^(\w+) : unit$/) {
+ ( "$1v" )
+ } else {
+ die "unknown signature $sig"
+ }
+}
+
+sub gen_unpack_args
+{
+ local $_ = shift;
+
+ if ($_ eq "conn") {
+ "virConnectPtr conn = Connect_val (connv);"
+ } elsif ($_ eq "dom") {
+ "virDomainPtr dom = Domain_val (domv);\n".
+ " virConnectPtr conn = Connect_domv (domv);"
+ } elsif ($_ eq "net") {
+ "virNetworkPtr net = Network_val (netv);\n".
+ " virConnectPtr conn = Connect_netv (netv);"
+ } elsif ($_ eq "pool") {
+ "virStoragePoolPtr pool = Pool_val (poolv);\n".
+ " virConnectPtr conn = Connect_polv (poolv);"
+ } elsif ($_ eq "vol") {
+ "virStorageVolPtr vol = Volume_val (volv);\n".
+ " virConnectPtr conn = Connect_volv (volv);"
+ } else {
+ die "unknown short name $_"
+ }
+}
+
+sub gen_c_code
+{
+ my $sig = shift;
+ my $c_name = shift;
+
+ if ($sig =~ /^(\w+) : string$/) {
+ "\
+ CAMLlocal1 (rv);
+ " . gen_unpack_args ($1) . "
+ char *r;
+
+ NONBLOCKING (r = $c_name ($1));
+ CHECK_ERROR (!r, conn, \"$c_name\");
+
+ rv = caml_copy_string (r);
+ free (r);
+ CAMLreturn (rv);
+"
+ } elsif ($sig =~ /^(\w+) : static string$/) {
+ "\
+ CAMLlocal1 (rv);
+ " . gen_unpack_args ($1) . "
+ const char *r;
+
+ NONBLOCKING (r = $c_name ($1));
+ CHECK_ERROR (!r, conn, \"$c_name\");
+
+ rv = caml_copy_string (r);
+ CAMLreturn (rv);
+"
+ } elsif ($sig =~ /^(\w+) : int$/) {
+ "\
+ " . gen_unpack_args ($1) . "
+ int r;
+
+ NONBLOCKING (r = $c_name ($1));
+ CHECK_ERROR (r == -1, conn, \"$c_name\");
+
+ CAMLreturn (Val_int (r));
+"
+ } elsif ($sig eq "conn, int : int array") {
+ "\
+ CAMLlocal1 (rv);
+ virConnectPtr conn = Connect_val (connv);
+ int i = Int_val (iv);
+ int ids[i], r;
+
+ NONBLOCKING (r = $c_name (conn, ids, i));
+ CHECK_ERROR (r == -1, conn, \"$c_name\");
+
+ rv = caml_alloc (r, 0);
+ for (i = 0; i < r; ++i)
+ Store_field (rv, i, Val_int (ids[i]));
+
+ CAMLreturn (rv);
+"
+ } elsif ($sig eq "conn, int : string array") {
+ "\
+ CAMLlocal2 (rv, strv);
+ virConnectPtr conn = Connect_val (connv);
+ int i = Int_val (iv);
+ char *names[i];
+ int r;
+
+ NONBLOCKING (r = $c_name (conn, names, i));
+ CHECK_ERROR (r == -1, conn, \"$c_name\");
+
+ rv = caml_alloc (r, 0);
+ for (i = 0; i < r; ++i) {
+ strv = caml_copy_string (names[i]);
+ Store_field (rv, i, strv);
+ free (names[i]);
+ }
+
+ CAMLreturn (rv);
+"
+ } elsif ($sig =~ /^(\w+), 0 : string$/) {
+ "\
+ CAMLlocal1 (rv);
+ " . gen_unpack_args ($1) . "
+ char *r;
+
+ NONBLOCKING (r = $c_name ($1, 0));
+ CHECK_ERROR (!r, conn, \"$c_name\");
+
+ rv = caml_copy_string (r);
+ free (r);
+ CAMLreturn (rv);
+"
+ } elsif ($sig =~ /^(\w+) : unit$/) {
+ "\
+ " . gen_unpack_args ($1) . "
+ int r;
+
+ NONBLOCKING (r = $c_name ($1));
+ CHECK_ERROR (r == -1, conn, \"$c_name\");
+
+ CAMLreturn (Val_unit);
+"
+ } elsif ($sig =~ /^(\w+), 0 : unit$/) {
+ "\
+ " . gen_unpack_args ($1) . "
+ int r;
+
+ NONBLOCKING (r = $c_name ($1, 0));
+ CHECK_ERROR (r == -1, conn, \"$c_name\");
+
+ CAMLreturn (Val_unit);
+"
+ } else {
+ die "unknown signature $sig"
+ }
+}
+
+# Generate each function.
+
+foreach my $function (@functions) {
+ my $c_name = $function->{name};
+ my $is_weak = $function->{weak};
+ my $sig = $function->{sig};
+
+ my $is_pool_func = $c_name =~ /^virStoragePool/;
+ my $is_vol_func = $c_name =~ /^virStorageVol/;
+
+ # Generate an equivalent C-external name for the function, unless
+ # one is defined already.
+ my $c_external_name;
+ if (exists ($function->{c_external_name})) {
+ $c_external_name = $function->{c_external_name};
+ } elsif ($c_name =~ /^vir/) {
+ $c_external_name = substr $c_name, 3;
+ $c_external_name = camel_case_to_underscores ($c_external_name);
+ $c_external_name = "ocaml_libvirt_" . $c_external_name;
+ } else {
+ die "cannot convert c_name $c_name to c_external_name"
+ }
+
+ # Generate a full function prototype if the function is weak.
+ my $have_name = "HAVE_" . uc ($c_name);
+ if ($is_weak) {
+ my $c_sig = gen_c_signature ($sig, $c_name);
+ print F <<END;
+#ifdef HAVE_WEAK_SYMBOLS
+#ifdef $have_name
+extern $c_sig __attribute__((weak));
+#endif
+#endif
+
+END
+ }
+
+ my @arg_names = gen_arg_names ($sig);
+ my $nr_arg_names = scalar @arg_names;
+ my $arg_names = join ", ", @arg_names;
+ my $arg_names_as_values = join (", ", map { "value $_" } @arg_names);
+
+ # Generate the start of the function, arguments.
+ print F <<END;
+CAMLprim value
+$c_external_name ($arg_names_as_values)
+{
+ CAMLparam$nr_arg_names ($arg_names);
+END
+
+ # If weak, check the function exists at compile time or runtime.
+ if ($is_weak) {
+ print F <<END;
+#ifndef $have_name
+ /* Symbol $c_name not found at compile time. */
+ not_supported ("$c_name");
+ /* Suppresses a compiler warning. */
+ (void) caml__frame;
+#else
+ /* Check that the symbol $c_name
+ * is in runtime version of libvirt.
+ */
+ WEAK_SYMBOL_CHECK ($c_name);
+END
+ }
+
+ # Generate the internals of the function.
+ print F (gen_c_code ($sig, $c_name));
+
+ # Finish off weak #ifdef.
+ if ($is_weak) {
+ print F <<END;
+#endif
+END
+ }
+
+ # Finish off the function.
+ print F <<END;
+}
+
+END
+}
+
+#----------------------------------------------------------------------
+
+# Unimplemented functions.
+
+printf "$0: warning: %d unimplemented functions\n", scalar (@unimplemented);
+
+foreach my $c_external_name (@unimplemented) {
+ print F <<END
+CAMLprim value
+$c_external_name ()
+{
+ failwith ("$c_external_name is unimplemented");
+}
+
+END
+}
+
+#----------------------------------------------------------------------
+
+# Write the epilogue.
+
+print F <<'END';
+#include "libvirt_c_epilogue.c"
+
+/* EOF */
+END
+
+close F;
+print "$0: written $filename\n"
+