Support constructor chain up to GObject using Object (...)
[vala-lang.git] / vapigen / valavapigen.vala
blobd56a59261858191adbc5173b8afb3692df973ff3
1 /* valavapigen.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 class Vala.VAPIGen : Object {
26 static string directory;
27 static bool version;
28 static bool quiet_mode;
29 [CCode (array_length = false, array_null_terminated = true)]
30 [NoArrayLength]
31 static string[] sources;
32 [CCode (array_length = false, array_null_terminated = true)]
33 [NoArrayLength]
34 static string[] vapi_directories;
35 static string library;
36 [CCode (array_length = false, array_null_terminated = true)]
37 [NoArrayLength]
38 static string[] packages;
39 static string metadata_filename;
40 CodeContext context;
42 const OptionEntry[] options = {
43 { "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings in DIRECTORY", "DIRECTORY..." },
44 { "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", "PACKAGE..." },
45 { "library", 0, 0, OptionArg.STRING, ref library, "Library name", "NAME" },
46 { "metadata", 0, 0, OptionArg.FILENAME, ref metadata_filename, "Metadata filename", "FILE" },
47 { "directory", 'd', 0, OptionArg.FILENAME, ref directory, "Output directory", "DIRECTORY" },
48 { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null },
49 { "quiet", 'q', 0, OptionArg.NONE, ref quiet_mode, "Do not print messages to the console", null },
50 { "", 0, 0, OptionArg.FILENAME_ARRAY, ref sources, null, "FILE..." },
51 { null }
54 private int quit () {
55 if (context.report.get_errors () == 0) {
56 if (!quiet_mode) {
57 stdout.printf ("Generation succeeded - %d warning(s)\n", context.report.get_warnings ());
59 return 0;
60 } else {
61 if (!quiet_mode) {
62 stdout.printf ("Generation failed: %d error(s), %d warning(s)\n", context.report.get_errors (), context.report.get_warnings ());
64 return 1;
68 /* TODO: this is duplicated between here and the compiler. its should go somewhere on its own */
69 private bool add_package (string pkg) {
70 if (context.has_package (pkg)) {
71 // ignore multiple occurences of the same package
72 return true;
75 var package_path = context.get_package_path (pkg, vapi_directories);
77 if (package_path == null) {
78 return false;
81 context.add_package (pkg);
83 context.add_source_file (new SourceFile (context, package_path, true));
85 var deps_filename = Path.build_filename (Path.get_dirname (package_path), "%s.deps".printf (pkg));
86 if (FileUtils.test (deps_filename, FileTest.EXISTS)) {
87 try {
88 string deps_content;
89 ulong deps_len;
90 FileUtils.get_contents (deps_filename, out deps_content, out deps_len);
91 foreach (string dep in deps_content.split ("\n")) {
92 dep = dep.strip ();
93 if (dep != "") {
94 if (!add_package (dep)) {
95 Report.error (null, "%s, dependency of %s, not found in specified Vala API directories".printf (dep, pkg));
99 } catch (FileError e) {
100 Report.error (null, "Unable to read dependency file: %s".printf (e.message));
104 return true;
107 private static string[]? get_packages_from_depsfile (string depsfile) {
108 try {
109 string contents;
110 FileUtils.get_contents (depsfile, out contents);
111 return contents.strip ().split ("\n");
112 } catch (FileError e) {
113 // deps files are optional
114 return null;
118 private int run () {
119 context = new CodeContext ();
120 context.profile = Profile.GOBJECT;
121 CodeContext.push (context);
123 /* default package */
124 if (!add_package ("glib-2.0")) {
125 Report.error (null, "glib-2.0 not found in specified Vala API directories");
127 if (!add_package ("gobject-2.0")) {
128 Report.error (null, "gobject-2.0 not found in specified Vala API directories");
131 /* load packages from .deps file */
132 foreach (string source in sources) {
133 if (!source.has_suffix (".gi")) {
134 continue;
137 var depsfile = source.substring (0, source.len () - "gi".len ()) + "deps";
139 if (!FileUtils.test (depsfile, FileTest.EXISTS)) continue;
141 string[] deps = get_packages_from_depsfile (depsfile);
143 foreach (string dep in deps) {
144 if (!add_package (dep)) {
145 Report.error (null, "%s not found in specified Vala API directories".printf (dep));
150 // depsfile for gir case
151 if (library != null) {
152 var depsfile = library + ".deps";
153 if (FileUtils.test (depsfile, FileTest.EXISTS)) {
155 string[] deps = get_packages_from_depsfile (depsfile);
157 foreach (string dep in deps) {
158 if (!add_package (dep)) {
159 Report.error (null, "%s not found in specified Vala API directories".printf (dep));
165 if (packages != null) {
166 foreach (string package in packages) {
167 if (!add_package (package)) {
168 Report.error (null, "%s not found in specified Vala API directories".printf (package));
171 packages = null;
174 if (context.report.get_errors () > 0) {
175 return quit ();
178 foreach (string source in sources) {
179 if (FileUtils.test (source, FileTest.EXISTS)) {
180 context.add_source_file (new SourceFile (context, source, true));
181 } else {
182 Report.error (null, "%s not found".printf (source));
185 sources = null;
187 if (context.report.get_errors () > 0) {
188 return quit ();
191 var parser = new Parser ();
192 parser.parse (context);
194 if (context.report.get_errors () > 0) {
195 return quit ();
198 var girparser = new GirParser ();
199 if (metadata_filename != null) {
200 girparser.parse_metadata (metadata_filename);
202 girparser.parse (context);
204 if (context.report.get_errors () > 0) {
205 return quit ();
208 var gidlparser = new GIdlParser ();
209 gidlparser.parse (context);
211 if (context.report.get_errors () > 0) {
212 return quit ();
215 var resolver = new SymbolResolver ();
216 resolver.resolve (context);
218 if (context.report.get_errors () > 0) {
219 return quit ();
222 var analyzer = new SemanticAnalyzer ();
223 analyzer.analyze (context);
225 if (context.report.get_errors () > 0) {
226 return quit ();
229 if (library == null && girparser.get_package_names () != null) {
230 var names = girparser.get_package_names ();
232 if (names.length != 1) {
233 Report.error (null, "multiple packages encountered and no library name given");
234 return quit ();
237 library = names[0];
240 if (library != null) {
241 // interface writer ignores external packages
242 foreach (SourceFile file in context.get_source_files ()) {
243 if (!file.filename.has_suffix (".vapi")) {
244 file.external_package = false;
248 var interface_writer = new CodeWriter ();
249 interface_writer.write_file (context, "%s.vapi".printf (library));
251 library = null;
254 return quit ();
257 static int main (string[] args) {
258 try {
259 var opt_context = new OptionContext ("- Vala API Generator");
260 opt_context.set_help_enabled (true);
261 opt_context.add_main_entries (options, null);
262 opt_context.parse (ref args);
263 } catch (OptionError e) {
264 stdout.printf ("%s\n", e.message);
265 stdout.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
266 return 1;
269 if (version) {
270 stdout.printf ("Vala API Generator %s\n", Config.PACKAGE_VERSION);
271 return 0;
274 if (sources == null) {
275 stderr.printf ("No source file specified.\n");
276 return 1;
279 var vapigen = new VAPIGen ();
280 return vapigen.run ();