Can introspect the whole project in a single batch.
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 814b6bb..58348c0 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -328,6 +328,9 @@
         return env
 
 class Target:
+
+    type_string = 'target'
+
     def __init__(self, name, subdir, subproject, build_by_default):
         if has_path_sep(name):
             # Fix failing test 53 when this becomes an error.
@@ -400,6 +403,7 @@
 
 class BuildTarget(Target):
     known_kwargs = known_build_target_kwargs
+    type_string = 'buildtarget'
 
     def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
         super().__init__(name, subdir, subproject, True)
@@ -1333,6 +1337,7 @@
 
 class Executable(BuildTarget):
     known_kwargs = known_exe_kwargs
+    type_string = 'executable'
 
     def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
         if 'pie' not in kwargs and 'b_pie' in environment.coredata.base_options:
@@ -1422,6 +1427,7 @@
 
 class StaticLibrary(BuildTarget):
     known_kwargs = known_stlib_kwargs
+    type_string = 'static_library'
 
     def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
         if 'pic' not in kwargs and 'b_staticpic' in environment.coredata.base_options:
@@ -1481,6 +1487,7 @@
 
 class SharedLibrary(BuildTarget):
     known_kwargs = known_shlib_kwargs
+    type_string = 'shared_library'
 
     def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
         self.soversion = None
@@ -1788,6 +1795,7 @@
 # into something else.
 class SharedModule(SharedLibrary):
     known_kwargs = known_shmod_kwargs
+    type_string = 'shared_module'
 
     def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
         if 'version' in kwargs:
@@ -1818,6 +1826,7 @@
         'override_options',
         'console',
     ])
+    type_string = 'custom'
 
     def __init__(self, name, subdir, subproject, kwargs, absolute_paths=False):
         super().__init__(name, subdir, subproject, False)
@@ -2060,6 +2069,8 @@
         raise NotImplementedError
 
 class RunTarget(Target):
+    type_string = 'run'
+
     def __init__(self, name, command, args, dependencies, subdir, subproject):
         super().__init__(name, subdir, subproject, False)
         self.command = command
@@ -2093,6 +2104,7 @@
 
 class Jar(BuildTarget):
     known_kwargs = known_jar_kwargs
+    type_string = 'jar'
 
     def __init__(self, name, subdir, subproject, is_cross, sources, objects, environment, kwargs):
         super().__init__(name, subdir, subproject, is_cross, sources, objects, environment, kwargs)
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index b15a608..e6fb736 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -29,6 +29,8 @@
 def add_arguments(parser):
     parser.add_argument('--targets', action='store_true', dest='list_targets', default=False,
                         help='List top level targets.')
+    parser.add_argument('--target-batch', action='store_true', dest='target_batch', default=False,
+                        help='Batch export info on all targets.')
     parser.add_argument('--installed', action='store_true', dest='list_installed', default=False,
                         help='List all installed files and directories.')
     parser.add_argument('--target-files', action='store', dest='target_files', default=None,
@@ -86,19 +88,7 @@
         else:
             fname = os.path.join(target.subdir, fname)
         t['filename'] = fname
-        if isinstance(target, build.Executable):
-            typename = 'executable'
-        elif isinstance(target, build.SharedLibrary):
-            typename = 'shared library'
-        elif isinstance(target, build.StaticLibrary):
-            typename = 'static library'
-        elif isinstance(target, build.CustomTarget):
-            typename = 'custom'
-        elif isinstance(target, build.RunTarget):
-            typename = 'run'
-        else:
-            typename = 'unknown'
-        t['type'] = typename
+        t['type'] = target.type_string
         if installdata and target.should_install():
             t['installed'] = True
             t['install_filename'] = determine_installed_path(target, installdata)
@@ -108,18 +98,31 @@
         tlist.append(t)
     print(json.dumps(tlist))
 
-def list_target_files(target_name, coredata, builddata):
+def batch_targets(coredata, builddata, installdata):
+    batchdata = []
+    for (idname, target) in builddata.get_targets().items():
+        t = {'name': target.get_basename(),
+             'id': idname,
+             'type': target.type_string,
+             'files': get_target_filelist(builddata, idname)}
+        batchdata.append(t)
+    print(json.dumps(batchdata))
+
+def get_target_filelist(builddata, target_id):
     try:
-        t = builddata.targets[target_name]
+        t = builddata.targets[target_id]
         sources = t.sources + t.extra_files
     except KeyError:
-        print("Unknown target %s." % target_name)
-        sys.exit(1)
+        sys.exit("Unknown target %s." % target_id)
     out = []
     for i in sources:
         if isinstance(i, mesonlib.File):
             i = os.path.join(i.subdir, i.fname)
         out.append(i)
+    return out
+
+def list_target_files(target_name, coredata, builddata):
+    out = get_target_filelist(builddata, target_name)
     print(json.dumps(out))
 
 def list_buildoptions(coredata, builddata):
@@ -225,6 +228,8 @@
 
     if options.list_targets:
         list_targets(coredata, builddata, installdata)
+    elif options.target_batch:
+        batch_targets(coredata, builddata, installdata)
     elif options.list_installed:
         list_installed(installdata)
     elif options.target_files is not None: