2 // valac TreeBuilder.vala --pkg libvala-0.24 --pkg posix -o /tmp/treebuilder
5 * this only deals with the compiling (when builder is run with different args..)
13 public class ValaSourceReport : Vala.Report {
15 private Project.Project project;
16 public string filepath = "";
18 public string tmpname;
20 //public Gee.ArrayList<ValaSourceNotice> notices;
21 public Json.Object result;
23 //public Gee.HashMap<int,string> line_errors;
25 public void compile_notice(string type, string filename, int line, string message) {
28 GLib.debug("%s %s %d %s", type, filename, line, message);
30 if (!this.result.has_member(type+"-TOTAL")) {
31 this.result.set_int_member(type+"-TOTAL", 1);
33 this.result.set_int_member(type+"-TOTAL",
34 this.result.get_int_member(type+"-TOTAL") +1
39 if (!this.result.has_member(type)) {
40 this.result.set_object_member(type, new Json.Object());
42 var t = this.result.get_object_member(type);
43 if (!t.has_member(filename)) {
44 t.set_object_member(filename, new Json.Object());
46 var tt = t.get_object_member(filename);
47 if (!tt.has_member(line.to_string())) {
48 tt.set_array_member(line.to_string(), new Json.Array());
50 var tl = tt.get_array_member(line.to_string());
51 tl.add_string_element(message);
57 public ValaSourceReport(string filepath, string tmpname, Project.Project project)
60 this.project = project;
61 this.filepath = filepath;
62 this.tmpname = tmpname;
63 this.result = new Json.Object();
64 this.result.set_boolean_member("success", true);
65 this.result.set_string_member("message", "");
69 //this.line_errors = new Gee.HashMap<int,string> ();
70 //this.notices = new Gee.ArrayList<ValaSourceNotice>();
74 public override void note (Vala.SourceReference? source, string message) {
77 //stderr.printf ("My error: %s\n", message);
80 if (source.file.filename != this.tmpname) {
81 this.compile_notice("WARN", source.file.filename , source.begin.line, "Notice: " + message);
84 this.compile_notice("WARN", this.filepath, source.begin.line, "Notice: " + message);
87 public override void warn (Vala.SourceReference? source, string message) {
91 //stderr.printf ("My error: %s\n", message);
94 if (source.file.filename != this.tmpname) {
95 this.compile_notice("WARN", source.file.filename , source.begin.line, message);
98 this.compile_notice("WARN", this.filepath, source.begin.line, message);
101 public override void depr (Vala.SourceReference? source, string message) {
103 if (source == null) {
105 //stderr.printf ("My error: %s\n", message);
108 if (source.file.filename != this.tmpname) {
109 this.compile_notice("DEPR", source.file.filename, source.begin.line, message);
112 this.compile_notice("DEPR", this.filepath, source.begin.line, message);
116 public override void err (Vala.SourceReference? source, string message) {
118 if (source == null) {
120 //stderr.printf ("My error: %s\n", message);
122 if (source.file.filename != this.tmpname) {
123 this.compile_notice("ERR", source.file.filename, source.begin.line, message);
124 GLib.debug ("Other file: Got error error: %d: %s\n", source.begin.line, message);
129 this.compile_notice("ERR", this.filepath, source.begin.line, message);
130 GLib.debug ("Test file: Got error error: %d: %s\n", source.begin.line, message);
135 var iter = this.line_errors.map_iterator();
136 while (iter.next()) {
137 print ("%d : %s\n\n", iter.get_key(), iter.get_value());
144 public class ValaSourceCompiler : Object {
146 public static void jerr(string str)
148 var ret = new Json.Object();
149 ret.set_boolean_member("success", false);
150 ret.set_string_member("message", str);
152 var generator = new Json.Generator ();
153 var root = new Json.Node(Json.NodeType.OBJECT);
154 root.init_object(ret);
155 generator.set_root (root);
157 generator.pretty = true;
158 generator.indent = 4;
161 print("%s\n", generator.to_data (null));
162 GLib.Process.exit(Posix.EXIT_FAILURE);
166 public static void buildApplication()
168 //print("build based on Application settings\n");
170 if (BuilderApplication.opt_compile_target == null) {
171 jerr("missing compile target --target");
174 Project.Project.loadAll();
175 var proj = Project.Project.getProjectByPath(BuilderApplication.opt_compile_project);
179 jerr("could not load test project %s".printf( BuilderApplication.opt_compile_project));
182 if (proj.xtype != "Gtk") {
183 jerr("%s is not a Gtk Project".printf( BuilderApplication.opt_compile_project));
185 var gproj = (Project.Gtk)proj;
188 if (!gproj.compilegroups.has_key(BuilderApplication.opt_compile_target)) {
189 jerr("missing compile target %s".printf(BuilderApplication.opt_compile_target));
192 if (BuilderApplication.opt_compile_skip != null) {
193 skip_file = BuilderApplication.opt_compile_skip;
196 if (BuilderApplication.opt_compile_add != null) {
197 add_file = BuilderApplication.opt_compile_add;
201 var vs = new ValaSourceCompiler(gproj, add_file, BuilderApplication.opt_compile_target, skip_file);
202 if (BuilderApplication.opt_compile_output != null) {
203 vs.output = BuilderApplication.opt_compile_output;
210 Vala.CodeContext context;
211 ValaSourceReport report;
213 public string build_module;
214 public string filepath = "";
215 public string original_filepath;
216 public int line_offset = 0;
217 public string output;
219 // file.project , file.path, file.build_module, ""
220 public ValaSourceCompiler(Project.Gtk project, string filepath, string build_module, string original_filepath) {
223 this.filepath = filepath;
224 this.build_module = build_module;
225 this.original_filepath = original_filepath;
226 this.project = project;
230 public void dumpCode(string str)
232 var ls = str.split("\n");
233 for (var i=0;i < ls.length; i++) {
234 print("%d : %s\n", i+1, ls[i]);
240 public void compile( )
243 var valac = "valac " ;
245 context = new Vala.CodeContext ();
246 Vala.CodeContext.push (context);
248 context.experimental = false;
249 context.experimental_non_null = false;
257 // this is automatic now.. no need to do it manually apparently..
258 //for (int i = 2; i <= ver; i += 2) {
259 // context.add_define ("VALA_0_%d".printf (i));
265 var vapidirs = this.project.vapidirs();
266 // order is important ...
267 vapidirs += Path.get_dirname (context.get_vapi_path("gee-0.8")) ; //usr/share/vala/vapi
268 vapidirs += Path.get_dirname (context.get_vapi_path("glib-2.0")) ; // usr/share/vala-XXX/vapi
270 for(var i =0 ; i < vapidirs.length; i++) {
271 GLib.debug("Add Vapidir = %s" , vapidirs[i]);
273 valac += " --vapidir=" + vapidirs[i];
277 context.vapi_directories = vapidirs;
278 context.report.enable_warnings = true;
279 context.metadata_directories = { };
280 context.gir_directories = {};
281 context.save_temps = true; // keep c sources = is it faster?
282 //context.thread = true;
283 valac += " --thread ";
285 // we should parse the compilegroup to find out the flags..
286 context.debug = true;
289 this.report = new ValaSourceReport(this.original_filepath, this.filepath, this.project);
290 context.report = this.report;
292 valac += " -b " + this.project.path; //."GLib.Environment.get_home_dir() + " ";
293 context.basedir = this.project.path; // GLib.Environment.get_home_dir(); //Posix.realpath (".");
295 this.project.makeProjectSubdir("build");
296 context.directory = this.project.path + "/build"; //null; //??? causes target to end up in the right place at present..
299 // add default packages:
300 //if (settings.profile == "gobject-2.0" || settings.profile == "gobject" || settings.profile == null) {
302 context.set_target_profile (Vala.Profile.GOBJECT);
304 context.profile = Vala.Profile.GOBJECT;
306 var ns_ref = new Vala.UsingDirective (new Vala.UnresolvedSymbol (null, "GLib", null));
307 context.root.add_using_directive (ns_ref);
308 if (this.filepath != "") {
309 var source_file = new Vala.SourceFile (
311 Vala.SourceFileType.SOURCE,
314 source_file.add_using_directive (ns_ref);
315 context.add_source_file (source_file);
317 // add all the files (except the current one) - this.file.path
318 var pr = this.project;
321 if (this.build_module.length > 0) {
322 var cg = pr.compilegroups.get(this.build_module);
323 if (this.output.length < 1) {
324 this.output = cg.name;
328 for (var i = 0; i < cg.sources.size; i++) {
329 var path = cg.sources.get(i);
330 GLib.debug("Try add source file %s", path);
332 if (path.has_suffix(".bjs")) {
333 path = path.splice(path.length -4, path.length, ".vala");
334 GLib.debug("Change source file %s", path);
336 if (!path.has_suffix(".vala") && path.has_suffix(".c") ) {
339 if (!FileUtils.test(pr.path + "/" + path, FileTest.EXISTS)) {
342 // skip thie original
343 if (pr.path + "/" + path == this.original_filepath) {
344 GLib.debug("Add orig source file %s", path);
348 if (FileUtils.test(pr.path + "/" + path, FileTest.IS_DIR)) {
351 GLib.debug("Add source file %s", path);
353 valac += " " + pr.path + "/" + path;
355 if ( path.has_suffix(".c")) {
356 context.add_c_source_file(path);
361 var xsf = new Vala.SourceFile (
363 Vala.SourceFileType.SOURCE,
366 xsf.add_using_directive (ns_ref);
367 context.add_source_file(xsf);
372 // print("%s\n", valac); -
373 // default.. packages..
374 context.add_external_package ("glib-2.0");
375 context.add_external_package ("gobject-2.0");
376 // user defined ones..
379 for (var i = 0; i < pr.packages.size; i++) {
381 var pkg = pr.packages.get(i);
382 // do not add libvala versions except the one that matches the one we are compiled against..
383 if (Regex.match_simple("^libvala", pkg) && pkg != ("libvala-0." + ver.to_string())) {
384 GLib.debug("Skip libvala Package: %s" , pkg);
387 GLib.debug("Add Package: %s" ,pkg);
388 valac += " --pkg " + pr.packages.get(i);
389 if (!this.has_vapi(context.vapi_directories, pkg)) {
390 GLib.debug("Skip vapi '%s' - does not exist", pkg);
394 context.add_external_package(pkg);
397 //Vala.Config.PACKAGE_SUFFIX.substring (1)
399 // add the modules...
401 context.output = this.output == "" ? "/tmp/testrun" : this.output;
402 valac += " -o " + context.output;
403 GLib.debug("%s", valac);
405 context.set_target_glib_version("2.32");
407 context.target_glib_major = 2;
408 context.target_glib_minor = 32;
410 valac += " --target-glib=2.32 ";
412 //add_documented_files (context, settings.source_files);
414 Vala.Parser parser = new Vala.Parser ();
415 parser.parse (context);
416 //gir_parser.parse (context);
417 if (context.report.get_errors () > 0) {
418 Vala.CodeContext.pop ();
419 GLib.debug("parse got errors");
420 //((ValaSourceReport)context.report).dump();
421 this.report.result.set_boolean_member("success", false);
422 this.report.result.set_string_member("message", "Parse failed");
432 if (context.report.get_errors () > 0) {
433 Vala.CodeContext.pop ();
434 GLib.debug("check got errors");
435 //((ValaSourceReport)context.report).dump();
436 this.report.result.set_boolean_member("success", false);
437 this.report.result.set_string_member("message", "Check failed");
443 if (this.output == "") {
444 Vala.CodeContext.pop ();
449 // none of this works on vala-40 as the API is not publicly visible
452 GLib.debug("calling emit");
453 context.codegen = new Vala.GDBusServerModule ();
456 context.codegen.emit (context);
458 if (BuilderApplication.opt_skip_linking) {
459 GLib.debug("skip linking is set = outputing result");
460 Vala.CodeContext.pop ();
462 GLib.Process.exit(Posix.EXIT_SUCCESS);
466 /* --- - only if we are actually doing a full build.- no added benifet for inline complier
467 on my laptop a 5s upto here.. then 40+s doing this.. - no additional warnings really (although if we are using 'C' code it maight be usefull
470 GLib.debug("this.filepath = %s" , this.filepath);
472 if (this.filepath == "") {
473 GLib.debug("calling ccompiler");
474 var ccompiler = new Vala.CCodeCompiler ();
478 var cc_command = Environment.get_variable ("CC");
480 string [] cc_options = { "-lm" , "-pg"};
481 // ccache - would be nice, but we use multiple input files - which causes problems.
482 // would have to modify ccompile a bit, to handle this..
484 if (FileUtils.test("/usr/bin/ccache", FileTest.EXISTS)) {
485 GLib.debug("Using ccache");
486 cc_command = "/usr/bin/ccache " + (cc_command == null ? "cc" : cc_command) ;
488 GLib.debug("Try installing ccache to speed things up");
493 valac += " -X -lm -X -pg";
494 context.verbose_mode = true;
496 ccompiler.compile (context, cc_command, cc_options);
498 var pkg_config_command = Environment.get_variable ("PKG_CONFIG");
499 ccompiler.compile (context, cc_command, cc_options, pkg_config_command);
500 // newer ones got rid fo pkg config command? not sure why.
507 //if (this.filepath != "") {
508 // GLib.FileUtils.unlink(this.filepath);
510 //print("%s\n", valac);
511 Vala.CodeContext.pop ();
515 GLib.Process.exit(Posix.EXIT_SUCCESS);
518 public bool has_vapi(string[] dirs, string vapi)
520 for(var i =0 ; i < dirs.length; i++) {
521 GLib.debug("check VAPI - %s", dirs[i] + "/" + vapi + ".vapi");
522 if (!FileUtils.test( dirs[i] + "/" + vapi + ".vapi", FileTest.EXISTS)) {
531 public void outputResult()
533 var generator = new Json.Generator ();
534 generator.indent = 1;
535 generator.pretty = true;
536 var node = new Json.Node(Json.NodeType.OBJECT);
537 node.set_object(this.report.result);
539 generator.set_root(node);
541 generator.pretty = true;
542 generator.indent = 4;
545 print("%s\n", generator.to_data (null));
546 GLib.Process.exit(Posix.EXIT_SUCCESS);
554 int main (string[] args) {
556 var a = new ValaSource(file);
557 a.create_valac_tree();