summaryrefslogtreecommitdiff
path: root/gobject/valaccodecompiler.vala
blob: f0273a100eb22fc4dbe4eb5c71dbaaf288747f77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* valaccodecompiler.vala
 *
 * Copyright (C) 2007  Jürg Billeter
 *
 * 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 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
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
 */

using GLib;

/**
 * Interface to the C compiler.
 */
public class Vala.CCodeCompiler : Object {
	public CCodeCompiler () {
	}

	static bool package_exists(string package_name) {
		string pc = "pkg-config --exists " + package_name;
		int exit_status;

		try {
			Process.spawn_command_line_sync (pc, null, null, out exit_status);
			return (0 == exit_status);
		} catch (SpawnError e) {
			Report.error (null, e.message);
			return false;
		}
	}

	/**
	 * Compile generated C code to object code and optionally link object
	 * files.
	 *
	 * @param context a code context
	 */
	[NoArrayLength]
	public void compile (CodeContext! context, string cc_command, string[] cc_options) {
		string pc = "pkg-config --cflags";
		if (!context.compile_only) {
			pc += " --libs";
		}
		pc += " gobject-2.0";
		if (context.thread) {
			pc += " gthread-2.0";
		}
		foreach (string pkg in context.get_packages ()) {
			if (package_exists(pkg))
				pc += " " + pkg;
		}
		string pkgflags;
		int exit_status;
		try {
			Process.spawn_command_line_sync (pc, out pkgflags, null, out exit_status);
			if (exit_status != 0) {
				Report.error (null, "pkg-config exited with status %d".printf (exit_status));
				return;
			}
		} catch (SpawnError e) {
			Report.error (null, e.message);
			return;
		}

		// TODO compile the C code files in parallel

		if (cc_command == null) {
			cc_command = "cc";
		}
		string cmdline = cc_command;
		if (context.debug) {
			cmdline += " -g";
		}
		cmdline += " -O%d".printf (context.optlevel);
		if (context.compile_only) {
			cmdline += " -c";
		} else if (context.output != null) {
			string output = context.output;
			if (context.directory != null && context.directory != "") {
				output = "%s/%s".printf (context.directory, context.output);
			}
			cmdline += " -o " + Shell.quote (output);
		}
		cmdline += " " + pkgflags;
		if (cc_options != null) {
			foreach (string cc_option in cc_options) {
				cmdline += " " + cc_option;
			}
		}

		/* make sure include files can be found if -d is used */
		if (context.directory != null && context.directory != "") {
			cmdline += " -I" + Shell.quote ("%s/..".printf (context.directory));
		}

		/* we're only interested in non-pkg source files */
		var source_files = context.get_source_files ();
		foreach (SourceFile file in source_files) {
			if (!file.pkg) {
				cmdline += " " + Shell.quote (file.get_csource_filename ());
			}
		}
		var c_source_files = context.get_c_source_files ();
		foreach (string file in c_source_files) {
			cmdline += " " + Shell.quote (file);
		}

		try {
			Process.spawn_command_line_sync (cmdline, null, null, out exit_status);
			if (exit_status != 0) {
				Report.error (null, "cc exited with status %d".printf (exit_status));
			}
		} catch (SpawnError e) {
			Report.error (null, e.message);
		}

		/* remove generated C source and header files */
		foreach (SourceFile file in source_files) {
			if (!file.pkg) {
				if (!context.save_csources)
					FileUtils.unlink (file.get_csource_filename ());
				if (!context.save_cheaders)
					FileUtils.unlink (file.get_cheader_filename ());
			}
		}
	}
}