~ubuntu-branches/ubuntu/raring/vala-0.16/raring

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
141
142
143
144
145
146
147
/* valaccodecompiler.vala
 *
 * Copyright (C) 2007-2009  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.1 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 {
	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
	 */
	public void compile (CodeContext context, string? cc_command, string[] cc_options) {
		bool use_pkgconfig = false;

		string pc = "pkg-config --cflags";
		if (!context.compile_only) {
			pc += " --libs";
		}
		if (context.profile == Profile.GOBJECT) {
			use_pkgconfig = true;
			pc += " gobject-2.0";
			if (context.thread) {
				pc += " gthread-2.0";
			}
		}
		foreach (string pkg in context.get_packages ()) {
			if (package_exists (pkg)) {
				use_pkgconfig = true;
				pc += " " + pkg;
			}
		}
		string pkgflags = "";
		if (use_pkgconfig) {
			try {
				int exit_status;
				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";
		}
		if (context.compile_only) {
			cmdline += " -c";
		} else if (context.output != null) {
			string output = context.output;
			if (context.directory != null && context.directory != "" && !Path.is_absolute (context.output)) {
				output = "%s%c%s".printf (context.directory, Path.DIR_SEPARATOR, context.output);
			}
			cmdline += " -o " + Shell.quote (output);
		}

		/* we're only interested in non-pkg source files */
		var source_files = context.get_source_files ();
		foreach (SourceFile file in source_files) {
			if (file.file_type == SourceFileType.SOURCE) {
				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);
		}

		// add libraries after source files to fix linking
		// with --as-needed and on Windows
		cmdline += " " + pkgflags.strip ();
		foreach (string cc_option in cc_options) {
			cmdline += " " + Shell.quote (cc_option);
		}

		if (context.verbose_mode) {
			stdout.printf ("%s\n", cmdline);
		}

		try {
			int exit_status;
			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.file_type == SourceFileType.SOURCE) {
				if (!context.save_csources) {
					FileUtils.unlink (file.get_csource_filename ());
				}
			}
		}
	}
}