1/* valacompiler.vala 2 * 3 * Copyright (C) 2006-2012 Jürg Billeter 4 * Copyright (C) 1996-2002, 2004, 2005, 2006 Free Software Foundation, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 * Author: 21 * Jürg Billeter <j@bitron.ch> 22 */ 23 24using GLib; 25 26class Vala.Compiler { 27 private const string DEFAULT_COLORS = "error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01"; 28 29 static string basedir; 30 static string directory; 31 static bool version; 32 static bool api_version; 33 [CCode (array_length = false, array_null_terminated = true)] 34 static string[] sources; 35 [CCode (array_length = false, array_null_terminated = true)] 36 static string[] vapi_directories; 37 [CCode (array_length = false, array_null_terminated = true)] 38 static string[] gir_directories; 39 [CCode (array_length = false, array_null_terminated = true)] 40 static string[] metadata_directories; 41 static string vapi_filename; 42 static string library; 43 static string shared_library; 44 static string gir; 45 [CCode (array_length = false, array_null_terminated = true)] 46 static string[] packages; 47 [CCode (array_length = false, array_null_terminated = true)] 48 static string[] fast_vapis; 49 static string target_glib; 50 [CCode (array_length = false, array_null_terminated = true)] 51 static string[] gresources; 52 [CCode (array_length = false, array_null_terminated = true)] 53 static string[] gresources_directories; 54 55 static bool ccode_only; 56 static bool abi_stability; 57 static string header_filename; 58 static bool use_header; 59 static string internal_header_filename; 60 static string internal_vapi_filename; 61 static string fast_vapi_filename; 62 static bool vapi_comments; 63 static string symbols_filename; 64 static string includedir; 65 static bool compile_only; 66 static string output; 67 static bool debug; 68 static bool mem_profiler; 69 static bool disable_assert; 70 static bool enable_checking; 71 static bool deprecated; 72 static bool hide_internal; 73 static bool experimental; 74 static bool experimental_non_null; 75 static bool gobject_tracing; 76 static bool disable_since_check; 77 static bool disable_warnings; 78 static bool keep_going; 79 static bool list_sources; 80 static string cc_command; 81 [CCode (array_length = false, array_null_terminated = true)] 82 static string[] cc_options; 83 static string pkg_config_command; 84 static string dump_tree; 85 static bool save_temps; 86 [CCode (array_length = false, array_null_terminated = true)] 87 static string[] defines; 88 static bool quiet_mode; 89 static bool verbose_mode; 90 static string profile; 91 static bool nostdpkg; 92 static bool enable_version_header; 93 static bool disable_version_header; 94 static bool fatal_warnings; 95 static bool disable_colored_output; 96 static Report.Colored colored_output = Report.Colored.AUTO; 97 static string dependencies; 98 static string depfile; 99 100 static string entry_point; 101 102 static bool run_output; 103 static string run_args; 104 105 private CodeContext context; 106 107 const OptionEntry[] options = { 108 { "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings in DIRECTORY", "DIRECTORY..." }, 109 { "girdir", 0, 0, OptionArg.FILENAME_ARRAY, ref gir_directories, "Look for .gir files in DIRECTORY", "DIRECTORY..." }, 110 { "metadatadir", 0, 0, OptionArg.FILENAME_ARRAY, ref metadata_directories, "Look for GIR .metadata files in DIRECTORY", "DIRECTORY..." }, 111 { "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", "PACKAGE..." }, 112 { "vapi", 0, 0, OptionArg.FILENAME, ref vapi_filename, "Output VAPI file name", "FILE" }, 113 { "library", 0, 0, OptionArg.STRING, ref library, "Library name", "NAME" }, 114 { "shared-library", 0, 0, OptionArg.STRING, ref shared_library, "Shared library name used in generated gir", "NAME" }, 115 { "gir", 0, 0, OptionArg.STRING, ref gir, "GObject-Introspection repository file name", "NAME-VERSION.gir" }, 116 { "basedir", 'b', 0, OptionArg.FILENAME, ref basedir, "Base source directory", "DIRECTORY" }, 117 { "directory", 'd', 0, OptionArg.FILENAME, ref directory, "Change output directory from current working directory", "DIRECTORY" }, 118 { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null }, 119 { "api-version", 0, 0, OptionArg.NONE, ref api_version, "Display API version number", null }, 120 { "ccode", 'C', 0, OptionArg.NONE, ref ccode_only, "Output C code", null }, 121 { "header", 'H', 0, OptionArg.FILENAME, ref header_filename, "Output C header file", "FILE" }, 122 { "use-header", 0, 0, OptionArg.NONE, ref use_header, "Use C header file", null }, 123 { "includedir", 0, 0, OptionArg.FILENAME, ref includedir, "Directory used to include the C header file", "DIRECTORY" }, 124 { "internal-header", 'h', 0, OptionArg.FILENAME, ref internal_header_filename, "Output internal C header file", "FILE" }, 125 { "internal-vapi", 0, 0, OptionArg.FILENAME, ref internal_vapi_filename, "Output vapi with internal api", "FILE" }, 126 { "fast-vapi", 0, 0, OptionArg.STRING, ref fast_vapi_filename, "Output vapi without performing symbol resolution", null }, 127 { "use-fast-vapi", 0, 0, OptionArg.STRING_ARRAY, ref fast_vapis, "Use --fast-vapi output during this compile", null }, 128 { "vapi-comments", 0, 0, OptionArg.NONE, ref vapi_comments, "Include comments in generated vapi", null }, 129 { "deps", 0, 0, OptionArg.STRING, ref dependencies, "Write make-style dependency information to this file", null }, 130 { "depfile", 0, 0, OptionArg.STRING, ref depfile, "Write make-style external dependency information for build systems to this file", null }, 131 { "list-sources", 0, 0, OptionArg.NONE, ref list_sources, "Output a list of all source and binding files which are used", null }, 132 { "symbols", 0, 0, OptionArg.FILENAME, ref symbols_filename, "Output symbols file", "FILE" }, 133 { "compile", 'c', 0, OptionArg.NONE, ref compile_only, "Compile but do not link", null }, 134 { "output", 'o', 0, OptionArg.FILENAME, ref output, "Place output in file FILE", "FILE" }, 135 { "debug", 'g', 0, OptionArg.NONE, ref debug, "Produce debug information", null }, 136 { "thread", 0, OptionFlags.OPTIONAL_ARG | OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) option_deprecated, "Enable multithreading support (DEPRECATED AND IGNORED)", null }, 137 { "enable-mem-profiler", 0, 0, OptionArg.NONE, ref mem_profiler, "Enable GLib memory profiler", null }, 138 { "define", 'D', 0, OptionArg.STRING_ARRAY, ref defines, "Define SYMBOL", "SYMBOL..." }, 139 { "main", 0, 0, OptionArg.STRING, ref entry_point, "Use SYMBOL as entry point", "SYMBOL..." }, 140 { "nostdpkg", 0, 0, OptionArg.NONE, ref nostdpkg, "Do not include standard packages", null }, 141 { "disable-assert", 0, 0, OptionArg.NONE, ref disable_assert, "Disable assertions", null }, 142 { "enable-checking", 0, 0, OptionArg.NONE, ref enable_checking, "Enable additional run-time checks", null }, 143 { "enable-deprecated", 0, 0, OptionArg.NONE, ref deprecated, "Enable deprecated features", null }, 144 { "hide-internal", 0, 0, OptionArg.NONE, ref hide_internal, "Hide symbols marked as internal", null }, 145 { "enable-experimental", 0, 0, OptionArg.NONE, ref experimental, "Enable experimental features", null }, 146 { "disable-warnings", 0, 0, OptionArg.NONE, ref disable_warnings, "Disable warnings", null }, 147 { "fatal-warnings", 0, 0, OptionArg.NONE, ref fatal_warnings, "Treat warnings as fatal", null }, 148 { "disable-since-check", 0, 0, OptionArg.NONE, ref disable_since_check, "Do not check whether used symbols exist in local packages", null }, 149 { "keep-going", 'k', 0, OptionArg.NONE, ref keep_going, "Continue as much as possible after an error", null }, 150 { "enable-experimental-non-null", 0, 0, OptionArg.NONE, ref experimental_non_null, "Enable experimental enhancements for non-null types", null }, 151 { "enable-gobject-tracing", 0, 0, OptionArg.NONE, ref gobject_tracing, "Enable GObject creation tracing", null }, 152 { "cc", 0, 0, OptionArg.STRING, ref cc_command, "Use COMMAND as C compiler command", "COMMAND" }, 153 { "Xcc", 'X', 0, OptionArg.STRING_ARRAY, ref cc_options, "Pass OPTION to the C compiler", "OPTION..." }, 154 { "pkg-config", 0, 0, OptionArg.STRING, ref pkg_config_command, "Use COMMAND as pkg-config command", "COMMAND" }, 155 { "dump-tree", 0, 0, OptionArg.FILENAME, ref dump_tree, "Write code tree to FILE", "FILE" }, 156 { "save-temps", 0, 0, OptionArg.NONE, ref save_temps, "Keep temporary files", null }, 157 { "profile", 0, 0, OptionArg.STRING, ref profile, "Use the given profile instead of the default", "PROFILE" }, 158 { "quiet", 'q', 0, OptionArg.NONE, ref quiet_mode, "Do not print messages to the console", null }, 159 { "verbose", 'v', 0, OptionArg.NONE, ref verbose_mode, "Print additional messages to the console", null }, 160 { "no-color", 0, 0, OptionArg.NONE, ref disable_colored_output, "Disable colored output, alias for --color=never", null }, 161 { "color", 0, OptionFlags.OPTIONAL_ARG, OptionArg.CALLBACK, (void*) option_parse_color, "Enable color output, options are 'always', 'never', or 'auto'", "WHEN" }, 162 { "target-glib", 0, 0, OptionArg.STRING, ref target_glib, "Target version of glib for code generation", "'MAJOR.MINOR', or 'auto'" }, 163 { "gresources", 0, 0, OptionArg.FILENAME_ARRAY, ref gresources, "XML of gresources", "FILE..." }, 164 { "gresourcesdir", 0, 0, OptionArg.FILENAME_ARRAY, ref gresources_directories, "Look for resources in DIRECTORY", "DIRECTORY..." }, 165 { "enable-version-header", 0, 0, OptionArg.NONE, ref enable_version_header, "Write vala build version in generated files", null }, 166 { "disable-version-header", 0, 0, OptionArg.NONE, ref disable_version_header, "Do not write vala build version in generated files", null }, 167 { "run-args", 0, 0, OptionArg.STRING, ref run_args, "Arguments passed to directly compiled executable", null }, 168 { "abi-stability", 0, 0, OptionArg.NONE, ref abi_stability, "Enable support for ABI stability", null }, 169 { OPTION_REMAINING, 0, 0, OptionArg.FILENAME_ARRAY, ref sources, null, "FILE..." }, 170 { null } 171 }; 172 173 static bool option_parse_color (string option_name, string? val, void* data) throws OptionError { 174 switch (val) { 175 case "auto": colored_output = Report.Colored.AUTO; break; 176 case "never": colored_output = Report.Colored.NEVER; break; 177 case null: 178 case "always": colored_output = Report.Colored.ALWAYS; break; 179 default: throw new OptionError.FAILED ("Invalid --color argument '%s'", val); 180 } 181 return true; 182 } 183 184 static bool option_deprecated (string option_name, string? val, void* data) throws OptionError { 185 stdout.printf ("Command-line option `%s` is deprecated and will be ignored\n", option_name); 186 return true; 187 } 188 189 private int quit () { 190 if (context.report.get_errors () == 0 && context.report.get_warnings () == 0) { 191 CodeContext.pop (); 192 return 0; 193 } 194 if (context.report.get_errors () == 0 && (!fatal_warnings || context.report.get_warnings () == 0)) { 195 if (!quiet_mode) { 196 stdout.printf ("Compilation succeeded - %d warning(s)\n", context.report.get_warnings ()); 197 } 198 CodeContext.pop (); 199 return 0; 200 } else { 201 if (!quiet_mode) { 202 stdout.printf ("Compilation failed: %d error(s), %d warning(s)\n", context.report.get_errors (), context.report.get_warnings ()); 203 } 204 CodeContext.pop (); 205 return 1; 206 } 207 } 208 209 private int run () { 210 context = new CodeContext (); 211 CodeContext.push (context); 212 213 if (disable_colored_output) { 214 colored_output = Report.Colored.NEVER; 215 } 216 217 if (colored_output != Report.Colored.NEVER) { 218 unowned string env_colors = Environment.get_variable ("VALA_COLORS"); 219 if (env_colors != null) { 220 context.report.set_colors (env_colors, colored_output); 221 } else { 222 context.report.set_colors (DEFAULT_COLORS, colored_output); 223 } 224 } 225 226 227 // default to build executable 228 if (!ccode_only && !compile_only && output == null) { 229 // strip extension if there is one 230 // else we use the default output file of the C compiler 231 if (sources[0].last_index_of_char ('.') != -1) { 232 int dot = sources[0].last_index_of_char ('.'); 233 output = Path.get_basename (sources[0].substring (0, dot)); 234 } 235 } 236 237 context.assert = !disable_assert; 238 context.checking = enable_checking; 239 context.deprecated = deprecated; 240 context.since_check = !disable_since_check; 241 context.hide_internal = hide_internal; 242 context.experimental = experimental; 243 context.experimental_non_null = experimental_non_null; 244 context.gobject_tracing = gobject_tracing; 245 context.keep_going = keep_going; 246 context.report.enable_warnings = !disable_warnings; 247 context.report.set_verbose_errors (!quiet_mode); 248 context.verbose_mode = verbose_mode; 249 context.version_header = !disable_version_header; 250 251 context.ccode_only = ccode_only; 252 if (ccode_only && cc_options != null) { 253 Report.warning (null, "-X has no effect when -C or --ccode is set"); 254 } 255 context.abi_stability = abi_stability; 256 context.compile_only = compile_only; 257 context.header_filename = header_filename; 258 if (header_filename == null && use_header) { 259 Report.error (null, "--use-header may only be used in combination with --header"); 260 } 261 context.use_header = use_header; 262 context.internal_header_filename = internal_header_filename; 263 context.symbols_filename = symbols_filename; 264 context.includedir = includedir; 265 context.output = output; 266 if (output != null && ccode_only) { 267 Report.warning (null, "--output and -o have no effect when -C or --ccode is set"); 268 } 269 if (basedir == null) { 270 context.basedir = CodeContext.realpath ("."); 271 } else { 272 context.basedir = CodeContext.realpath (basedir); 273 } 274 if (directory != null) { 275 context.directory = CodeContext.realpath (directory); 276 } else { 277 context.directory = context.basedir; 278 } 279 context.vapi_directories = vapi_directories; 280 context.vapi_comments = vapi_comments; 281 context.gir_directories = gir_directories; 282 context.metadata_directories = metadata_directories; 283 context.debug = debug; 284 context.mem_profiler = mem_profiler; 285 context.save_temps = save_temps; 286 if (ccode_only && save_temps) { 287 Report.warning (null, "--save-temps has no effect when -C or --ccode is set"); 288 } 289 if (profile == "posix") { 290 context.profile = Profile.POSIX; 291 context.add_define ("POSIX"); 292 } else if (profile == "gobject-2.0" || profile == "gobject" || profile == null) { 293 // default profile 294 context.profile = Profile.GOBJECT; 295 context.add_define ("GOBJECT"); 296 } else { 297 Report.error (null, "Unknown profile %s".printf (profile)); 298 } 299 nostdpkg |= fast_vapi_filename != null; 300 context.nostdpkg = nostdpkg; 301 302 context.entry_point_name = entry_point; 303 304 context.run_output = run_output; 305 306 if (pkg_config_command == null) { 307 pkg_config_command = Environment.get_variable ("PKG_CONFIG") ?? "pkg-config"; 308 } 309 context.pkg_config_command = pkg_config_command; 310 311 if (defines != null) { 312 foreach (string define in defines) { 313 context.add_define (define); 314 } 315 } 316 317 if (context.profile == Profile.POSIX) { 318 if (!nostdpkg) { 319 /* default package */ 320 context.add_external_package ("posix"); 321 } 322 } else if (context.profile == Profile.GOBJECT) { 323 if (target_glib != null) { 324 context.set_target_glib_version (target_glib); 325 } 326 327 if (!nostdpkg) { 328 /* default packages */ 329 context.add_external_package ("glib-2.0"); 330 context.add_external_package ("gobject-2.0"); 331 } 332 } 333 334 if (packages != null) { 335 foreach (string package in packages) { 336 context.add_external_package (package); 337 } 338 packages = null; 339 } 340 341 if (fast_vapis != null) { 342 foreach (string vapi in fast_vapis) { 343 var rpath = CodeContext.realpath (vapi); 344 var source_file = new SourceFile (context, SourceFileType.FAST, rpath); 345 context.add_source_file (source_file); 346 } 347 context.use_fast_vapi = true; 348 } 349 350 context.gresources = gresources; 351 context.gresources_directories = gresources_directories; 352 353 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 354 return quit (); 355 } 356 357 if (context.profile == Profile.GOBJECT) { 358 context.codegen = new GDBusServerModule (); 359 } else { 360 context.codegen = new CCodeDelegateModule (); 361 } 362 363 bool has_c_files = false; 364 bool has_h_files = false; 365 366 foreach (string source in sources) { 367 if (context.add_source_filename (source, run_output, true)) { 368 if (source.has_suffix (".c")) { 369 has_c_files = true; 370 } else if (source.has_suffix (".h")) { 371 has_h_files = true; 372 } 373 } 374 } 375 sources = null; 376 if (ccode_only && (has_c_files || has_h_files)) { 377 Report.warning (null, "C header and source files are ignored when -C or --ccode is set"); 378 } 379 380 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 381 return quit (); 382 } 383 384 if (list_sources) { 385 foreach (SourceFile file in context.get_source_files ()) { 386 print ("%s\n", file.filename); 387 } 388 if (!ccode_only) { 389 foreach (string filename in context.get_c_source_files ()) { 390 print ("%s\n", filename); 391 } 392 } 393 return 0; 394 } 395 396 var parser = new Parser (); 397 parser.parse (context); 398 399 var genie_parser = new Genie.Parser (); 400 genie_parser.parse (context); 401 402 var gir_parser = new GirParser (); 403 gir_parser.parse (context); 404 405 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 406 return quit (); 407 } 408 409 if (fast_vapi_filename != null) { 410 var interface_writer = new CodeWriter (CodeWriterType.FAST); 411 interface_writer.write_file (context, fast_vapi_filename); 412 return quit (); 413 } 414 415 context.check (); 416 417 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 418 return quit (); 419 } 420 421 if (!ccode_only && !compile_only && library == null) { 422 // building program, require entry point 423 if (!has_c_files && context.entry_point == null) { 424 Report.error (null, "program does not contain a static `main' method"); 425 } 426 } 427 428 if (dump_tree != null) { 429 var code_writer = new CodeWriter (CodeWriterType.DUMP); 430 code_writer.write_file (context, dump_tree); 431 } 432 433 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 434 return quit (); 435 } 436 437 context.codegen.emit (context); 438 439 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 440 return quit (); 441 } 442 443 if (vapi_filename == null && library != null) { 444 // keep backward compatibility with --library option 445 vapi_filename = "%s.vapi".printf (library); 446 } 447 448 if (library != null) { 449 if (gir != null) { 450 if (context.profile == Profile.GOBJECT) { 451 string gir_base = Path.get_basename (gir); 452 long gir_len = gir_base.length; 453 int last_hyphen = gir_base.last_index_of_char ('-'); 454 455 if (last_hyphen == -1 || !gir_base.has_suffix (".gir")) { 456 Report.error (null, "GIR file name `%s' is not well-formed, expected NAME-VERSION.gir".printf (gir)); 457 } else { 458 string gir_namespace = gir_base.substring (0, last_hyphen); 459 string gir_version = gir_base.substring (last_hyphen + 1, gir_len - last_hyphen - 5); 460 gir_version.canon ("0123456789.", '?'); 461 if (gir_namespace == "" || gir_version == "" || !gir_version[0].isdigit () || gir_version.contains ("?")) { 462 Report.error (null, "GIR file name `%s' is not well-formed, expected NAME-VERSION.gir".printf (gir)); 463 } else { 464 var gir_writer = new GIRWriter (); 465 466 // put .gir file in current directory unless -d has been explicitly specified 467 string gir_directory = "."; 468 if (directory != null) { 469 gir_directory = context.directory; 470 } 471 472 gir_writer.write_file (context, gir_directory, gir, gir_namespace, gir_version, library, shared_library); 473 } 474 } 475 } 476 477 gir = null; 478 } 479 480 library = null; 481 } else { 482 if (gir != null) { 483 Report.warning (null, "--gir has no effect without --library"); 484 gir = null; 485 } 486 } 487 488 // The GIRWriter places the gir_namespace and gir_version into the top namespace, so write the vapi after that stage 489 if (vapi_filename != null) { 490 var interface_writer = new CodeWriter (); 491 492 // put .vapi file in current directory unless -d has been explicitly specified 493 if (directory != null && !Path.is_absolute (vapi_filename)) { 494 vapi_filename = "%s%c%s".printf (context.directory, Path.DIR_SEPARATOR, vapi_filename); 495 } 496 497 interface_writer.write_file (context, vapi_filename); 498 } 499 500 if (internal_vapi_filename != null) { 501 if (internal_header_filename == null || 502 header_filename == null) { 503 Report.error (null, "--internal-vapi may only be used in combination with --header and --internal-header"); 504 return quit(); 505 } 506 507 var interface_writer = new CodeWriter (CodeWriterType.INTERNAL); 508 509 if (context.includedir != null) { 510 var prefixed_header_filename = Path.build_path ("/", context.includedir, Path.get_basename (header_filename)); 511 var prefixed_internal_header_filename = Path.build_path ("/", context.includedir, Path.get_basename (internal_header_filename)); 512 interface_writer.set_cheader_override (prefixed_header_filename, prefixed_internal_header_filename); 513 } else { 514 interface_writer.set_cheader_override (header_filename, internal_header_filename); 515 } 516 517 string vapi_filename = internal_vapi_filename; 518 519 // put .vapi file in current directory unless -d has been explicitly specified 520 if (directory != null && !Path.is_absolute (vapi_filename)) { 521 vapi_filename = "%s%c%s".printf (context.directory, Path.DIR_SEPARATOR, vapi_filename); 522 } 523 524 interface_writer.write_file (context, vapi_filename); 525 526 internal_vapi_filename = null; 527 } 528 529 if (dependencies != null) { 530 context.write_dependencies (dependencies); 531 } 532 533 if (depfile != null) { 534 context.write_external_dependencies (depfile); 535 } 536 537 if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { 538 return quit (); 539 } 540 541 if (!ccode_only) { 542 var ccompiler = new CCodeCompiler (); 543 if (cc_command == null && Environment.get_variable ("CC") != null) { 544 cc_command = Environment.get_variable ("CC"); 545 } 546 if (cc_options == null) { 547 ccompiler.compile (context, cc_command, new string[] { }); 548 } else { 549 ccompiler.compile (context, cc_command, cc_options); 550 } 551 } 552 553 return quit (); 554 } 555 556 static int run_source (string[] args) { 557 try { 558 var opt_context = new OptionContext ("- Vala Interpreter"); 559 opt_context.set_help_enabled (true); 560 opt_context.add_main_entries (options, null); 561 opt_context.parse (ref args); 562 } catch (OptionError e) { 563 stdout.printf ("%s\n", e.message); 564 stdout.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]); 565 return 1; 566 } 567 568 if (version) { 569 stdout.printf ("Vala %s\n", Vala.BUILD_VERSION); 570 return 0; 571 } else if (api_version) { 572 stdout.printf ("%s\n", Vala.API_VERSION); 573 return 0; 574 } 575 576 if (sources == null) { 577 stderr.printf ("No source file specified.\n"); 578 return 1; 579 } 580 581 output = "%s/%s.XXXXXX".printf (Environment.get_tmp_dir (), Path.get_basename (sources[0])); 582 int outputfd = FileUtils.mkstemp (output); 583 if (outputfd < 0) { 584 return 1; 585 } 586 587 ccode_only = false; 588 compile_only = false; 589 run_output = true; 590 disable_warnings = true; 591 quiet_mode = true; 592 library = null; 593 shared_library = null; 594 595 var compiler = new Compiler (); 596 int ret = compiler.run (); 597 if (ret != 0) { 598 return ret; 599 } 600 601 FileUtils.close (outputfd); 602 if (FileUtils.chmod (output, 0700) != 0) { 603 FileUtils.unlink (output); 604 return 1; 605 } 606 607 string[] target_args = { output }; 608 if (run_args != null) { 609 string[] target_run_args = run_args.split (" "); 610 foreach (string arg in target_run_args) { 611 target_args += arg; 612 } 613 } 614 615 try { 616 Pid pid; 617 var loop = new MainLoop (); 618 int child_status = 0; 619 620 Process.spawn_async (null, target_args, null, SpawnFlags.CHILD_INHERITS_STDIN | SpawnFlags.DO_NOT_REAP_CHILD, null, out pid); 621 622 FileUtils.unlink (output); 623 ChildWatch.add (pid, (pid, status) => { 624 child_status = (status & 0xff00) >> 8; 625 loop.quit (); 626 }); 627 628 loop.run (); 629 630 return child_status; 631 } catch (SpawnError e) { 632 stdout.printf ("%s\n", e.message); 633 return 1; 634 } 635 } 636 637 static int main (string[] args) { 638 // initialize locale 639 Intl.setlocale (LocaleCategory.ALL, ""); 640 641 if (Path.get_basename (args[0]) == "vala" || Path.get_basename (args[0]) == "vala" + Config.PACKAGE_SUFFIX) { 642 return run_source (args); 643 } 644 645 try { 646 var opt_context = new OptionContext ("- Vala Compiler"); 647 opt_context.set_help_enabled (true); 648 opt_context.add_main_entries (options, null); 649 opt_context.parse (ref args); 650 } catch (OptionError e) { 651 stdout.printf ("%s\n", e.message); 652 stdout.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]); 653 return 1; 654 } 655 656 if (version) { 657 stdout.printf ("Vala %s\n", Vala.BUILD_VERSION); 658 return 0; 659 } else if (api_version) { 660 stdout.printf ("%s\n", Vala.API_VERSION); 661 return 0; 662 } 663 664 if (sources == null && fast_vapis == null) { 665 stderr.printf ("No source file specified.\n"); 666 return 1; 667 } 668 669 var compiler = new Compiler (); 670 return compiler.run (); 671 } 672} 673