diff --git a/grust/generators/sys_cargo.py b/grust/generators/sys_cargo.py
new file mode 100644
index 0000000..2c56a6a
--- /dev/null
+++ b/grust/generators/sys_cargo.py
@@ -0,0 +1,62 @@
+# coding: UTF-8
+# grust-gen - Rust binding generator for GObject introspection
+#
+# Copyright (C) 2016  Jonas Ã…dahl <jadahl@gmail.com>
+#
+# 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.1 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
+
+import os
+from ..mapping import sys_crate_name
+from ..output import FileOutput
+
+class SysCargoWriter(object):
+    """Generator for -sys Cargo build files."""
+
+    def __init__(self, mapper, transformer, tmpl_lookup, path):
+        self._mapper = mapper
+        self._transformer = transformer
+        self._cargo_template = tmpl_lookup.get_template('cargo/cargo.tmpl')
+        self._build_rs_template = tmpl_lookup.get_template('cargo/build.rs.tmpl')
+        self._cargo_file = os.path.join(path, 'Cargo.toml')
+        self._build_rs_file = os.path.join(path, 'build.rs')
+
+    def _write_cargo(self, output):
+        pkgname = sys_crate_name(self._transformer.namespace)
+        version = self._transformer.namespace.version
+        result = self._cargo_template.render_unicode(mapper=self._mapper,
+                                                     pkgname=pkgname,
+                                                     version=version)
+        output.write(result)
+
+    def _write_build_rs(self, output):
+        pkgconfig_packages = self._transformer.namespace.exported_packages
+        result = self._build_rs_template.render_unicode(packages=pkgconfig_packages)
+        output.write(result)
+
+    def write(self):
+        cargo_output = FileOutput(self._cargo_file, encoding='utf-8')
+        with cargo_output as output:
+            try:
+                self._write_cargo(output)
+            except Exception:
+                raise SystemExit(1)
+
+        build_rs_output = FileOutput(self._build_rs_file, encoding='utf-8')
+        with build_rs_output as output:
+            try:
+                self._write_build_rs(output)
+            except Exception:
+                raise SystemExit(1)
diff --git a/grust/generators/sys_crate.py b/grust/generators/sys_crate.py
index 9ddb8e1..667ca41 100644
--- a/grust/generators/sys_crate.py
+++ b/grust/generators/sys_crate.py
@@ -29,7 +29,7 @@ def __init__(self,
                  template,
                  options,
                  gir_filename=None):
-        self._mapper = RawMapper(transformer)
+        self._mapper = RawMapper(transformer, options)
         self._template = template
         self._options = options
         if gir_filename:
@@ -55,3 +55,6 @@ def _prepare_walk(self, node, chain):
                                context=node)
             return False
         return True
+
+    def get_mapper(self):
+        return self._mapper
diff --git a/grust/genmain.py b/grust/genmain.py
index 744baa8..1ecbea7 100644
--- a/grust/genmain.py
+++ b/grust/genmain.py
@@ -29,8 +29,11 @@
 from .giscanner import message
 from .giscanner import utils
 from .generators.sys_crate import SysCrateWriter
+from .generators.sys_cargo import SysCargoWriter
 from .output import FileOutput, DirectOutput
 from . import __version__ as version
+from .mapping import sys_crate_name
+from .mapping import RawMapper
 
 def output_file(name):
     if name == '-':
@@ -53,6 +56,14 @@ def _create_arg_parser():
                         help='add directory to include search path')
     parser.add_argument('-t', '--template',
                         help='name of the custom template file')
+    parser.add_argument('-c', '--cargo', dest='gen_cargo', action='store_true',
+                        help='generate a Cargo build description')
+    parser.add_argument('--exclude', action='append',
+                        dest='excluded_crates', metavar='DEP',
+                        help='exclude mapping functions relating to this crate')
+    parser.add_argument('--include', action='append',
+                        dest='included_crates', metavar='DEP',
+                        help='include mapping functions relating to this crate')
     return parser
 
 def generator_main():
@@ -112,4 +123,16 @@ def generator_main():
         if error_count > 0:
             raise SystemExit(2)
 
+    if opts.gen_cargo:
+        if opts.template is not None:
+            sys.exit('can only generate cargo build description without custom template')
+        if not isinstance(output, FileOutput):
+            sys.exit('can only generate cargo build description with file output')
+        cargo_path = os.path.dirname(output.filename())
+        cargo_gen = SysCargoWriter(mapper=gen.get_mapper(),
+                                   transformer=transformer,
+                                   tmpl_lookup=tmpl_lookup,
+                                   path=cargo_path)
+
+        cargo_gen.write()
     return 0
diff --git a/grust/mapping.py b/grust/mapping.py
index 9172d41..9ed1213 100644
--- a/grust/mapping.py
+++ b/grust/mapping.py
@@ -476,6 +476,7 @@ def _unwrap_call_signature_ctype(type_container):
     if ctype is None:
         raise MappingError('parameter {}: C type attribute is missing'.format(type_container.argname))
     if (isinstance(type_container, ast.Parameter)
+        and not isinstance(type_container.type, ast.Array)
         and type_container.direction in (ast.PARAM_DIRECTION_OUT,
                                          ast.PARAM_DIRECTION_INOUT)
         and not type_container.caller_allocates):
@@ -514,11 +515,21 @@ class RawMapper(object):
     names resolved in the Rust code generated using the mapping methods.
     """
 
-    def __init__(self, transformer):
+    def __init__(self, transformer, options):
         self.transformer = transformer
         self.crate = self._create_crate(transformer.namespace)
         self._extern_crates = {}  # namespace name -> Crate
         self._crate_libc = None
+        self._excluded_crates = options.excluded_crates
+        self._included_crates = options.included_crates
+
+    def is_excluded(self, crate):
+        if not self._included_crates and not self._excluded_crates:
+            return False
+        if not self._included_crates:
+            return crate.local_name in self._excluded_crates
+        else:
+            return not crate.local_name in self._included_crates
 
     def _create_crate(self, namespace):
         # This is a method, to allow per-namespace configuration
@@ -872,6 +883,66 @@ def map_field_type(self, field):
                 .format(field.name, typenode))
         return self._map_type(field.type, nullable=True)
 
+    def _struct_field_type_is_valid(self, field_type):
+        if field_type is None:
+            return False
+        if isinstance(field_type, ast.Union):
+            return False
+        if isinstance(field_type, ast.Array):
+            return self._struct_field_type_is_valid(field_type.element_type)
+        if isinstance(field_type, ast.Record):
+            return self.struct_is_valid(field_type)
+        if isinstance(field_type, ast.Type) and field_type.target_giname:
+            if not self.node_is_mappable(field_type):
+                return False
+            if field_type.ctype is None or not field_type.ctype.endswith('*'):
+                crate,name = self._lookup_giname(field_type.target_giname)
+                return self._struct_field_type_is_valid(crate.namespace.names[name])
+        return True
+
+    def struct_is_valid(self, node):
+        if isinstance(node, ast.Union):
+            return False
+        for field in node.fields:
+            if field.bits is not None:
+                return False
+            if not self._struct_field_type_is_valid(field.type):
+                return False
+        return True
+
+    def node_is_mappable(self, node):
+        if isinstance(node, ast.Type) and node == ast.TYPE_VALIST:
+            return False
+        if isinstance(node, ast.Type) and node.target_giname:
+            crate,name = self._lookup_giname(node.target_giname)
+            if self.is_excluded(crate):
+                return False
+        if isinstance(node, ast.TypeContainer):
+            return self.node_is_mappable(node.type)
+        if isinstance(node, ast.Alias):
+            return self.node_is_mappable(node.target)
+        if isinstance(node, ast.Callable):
+            # Throwing maps to GError, which is in the glib crate
+            if self.crate.local_name != 'glib' and node.throws:
+                glib_crate = self._extern_crates.get('GLib')
+                if self.is_excluded(glib_crate):
+                    return False
+            if any([not self.node_is_mappable(param) for param in node.parameters]):
+                return False
+            return self.node_is_mappable(node.retval)
+        if isinstance(node, ast.List) and self.crate.local_name != 'glib':
+            # Lists are always GList or GSList, which are in the glib crate
+            glib_crate = self._extern_crates.get('GLib')
+            if self.is_excluded(glib_crate):
+                return False
+            return self.node_is_mappable(node.element_type)
+        if isinstance(node, ast.Array):
+            return self.node_is_mappable(node.element_type)
+        if isinstance(node, ast.Type) and node.target_giname:
+            crate,name = self._lookup_giname(node.target_giname)
+            return self.node_is_mappable(crate.namespace.names[name])
+        return True
+
     def map_parameter_type(self, parameter):
         """Return the Rust FFI type syntax for a function parameter.
 
diff --git a/grust/output.py b/grust/output.py
index 22fbdab..2cf3889 100644
--- a/grust/output.py
+++ b/grust/output.py
@@ -51,6 +51,9 @@ def __init__(self, filename, mode='w', encoding=None, newline=None):
                 'newline': newline
             }
 
+    def filename(self):
+        return self._filename
+
     def __enter__(self):
         dirname, basename = os.path.split(self._filename)
         if sys.version_info.major >= 3:
diff --git a/grust/templates/cargo/build.rs.tmpl b/grust/templates/cargo/build.rs.tmpl
new file mode 100644
index 0000000..fb1851b
--- /dev/null
+++ b/grust/templates/cargo/build.rs.tmpl
@@ -0,0 +1,13 @@
+extern crate pkg_config;
+
+const PACKAGES: &'static [ &'static str ] = &[
+%    for package in packages:
+    "${package}",
+%    endfor
+];
+
+fn main() {
+    for package in PACKAGES {
+        pkg_config::probe_library(package).unwrap();
+    }
+}
diff --git a/grust/templates/cargo/cargo.tmpl b/grust/templates/cargo/cargo.tmpl
new file mode 100644
index 0000000..d5490af
--- /dev/null
+++ b/grust/templates/cargo/cargo.tmpl
@@ -0,0 +1,26 @@
+[package]
+name = "${pkgname}"
+version = "0.0.1"
+build = "build.rs"
+
+[lib]
+path = "lib.rs"
+
+[build-dependencies]
+pkg-config = "0.3.7"
+
+[dependencies.libc]
+git = "https://github.com/rust-lang/libc.git"
+
+[dependencies.grust]
+git = "https://github.com/gi-rust/grust.git"
+
+[dependencies.gtypes]
+git = "https://github.com/gi-rust/gtypes.git"
+
+%   for xc in mapper.extern_crates():
+%       if xc.name is not 'libc' and not mapper.is_excluded(xc):
+[dependencies.${xc.name}]
+path = "../${xc.name}"
+%       endif
+%   endfor
diff --git a/grust/templates/sys/crate.tmpl b/grust/templates/sys/crate.tmpl
index 3dbb979..3ed4de1 100644
--- a/grust/templates/sys/crate.tmpl
+++ b/grust/templates/sys/crate.tmpl
@@ -57,6 +57,7 @@ def indenter(amount):
         ast.Constant: constant,
         ast.Record: struct,
         ast.Class: struct,
+        ast.Union: struct,
         ast.Interface: interface,
         ast.Enum: enum,
         ast.Bitfield: flags
@@ -93,8 +94,7 @@ def indenter(amount):
             continue
         if node.name in self.attr.ignore_names:
             continue
-        if any(param.type == ast.TYPE_VALIST for param in node.parameters):
-            # Functions with a va_list parameter are usable only in C
+        if not mapper.node_is_mappable(node):
             continue
         functions.append(node)
 
@@ -117,7 +117,7 @@ extern crate gtypes;
 %   for xc in mapper.extern_crates():
 %       if xc.name == xc.local_name:
 extern crate ${xc.name};
-%       else:
+%       elif not mapper.is_excluded(xc):
 extern crate ${xc.name} as ${xc.local_name};
 %       endif
 %   endfor
@@ -180,12 +180,16 @@ extern {
         raise ConsistencyError(
             'C type name {} conflicts with a fundamental type'
             .format(node.ctype))
+    if not mapper.node_is_mappable(node):
+        return ''
 %>
 pub type ${node.ctype} = ${mapper.map_aliased_type(node)};
 </%def>\
 ##
 <%def name="callback(node)">
+%    if mapper.node_is_mappable(node):
 pub type ${node.ctype} = ${mapper.map_callback(node)};
+%    endif
 </%def>\
 ##
 <%def name="constant(node)">
@@ -203,11 +207,15 @@ pub struct ${node.ctype}(gpointer);
 pub enum ${node.ctype} { }
 %   else:
 #[repr(C)]
+%       if not mapper.struct_is_valid(node):
+pub struct ${node.ctype};
+%       else:
 pub struct ${node.ctype} {
-%       for field in node.fields:
+%           for field in node.fields:
     ${'' if field.private else 'pub '}${sanitize_ident(field.name)}: ${mapper.map_field_type(field)},
-%       endfor
+%           endfor
 }
+%       endif
 %   endif
 </%def>\
 ##
@@ -307,11 +315,13 @@ extern {
                         type=mapper.map_parameter_type(param))
                       for param in parameters]
 %>\
+%    if mapper.node_is_mappable(node):
 pub fn ${node.symbol}(${', '.join(param_list)})\
-%   if node.retval.type != ast.TYPE_NONE:
+%       if node.retval.type != ast.TYPE_NONE:
  -> ${mapper.map_return_type(node.retval)}\
-%   endif
+%       endif
 ;
+%   endif
 </%def>\
 ##
 <%def name="cfg_attr(cfg)">\