3
* Copyright (C) 2005 Eric Greveson
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program 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
* General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this program; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
20
* Author: Eric Greveson
21
* Based on the Autotools GBF backend (libgbf-am) by
37
#include "gbf-mkfile-build.h"
39
#ifdef NATIVE_GNU_REGEX
42
GbfMkfileProject *project;
47
/* Regex structures. */
48
struct re_pattern_buffer dir_buf;
49
struct re_pattern_buffer warn_buf;
50
struct re_pattern_buffer err_buf;
51
struct re_registers reg;
59
build_info_free (BuildInfo *info)
64
g_free (info->build_dir);
65
if (info->dir_buf.fastmap)
66
g_free (info->dir_buf.fastmap);
67
if (info->warn_buf.fastmap)
68
g_free (info->warn_buf.fastmap);
69
if (info->err_buf.fastmap)
70
g_free (info->err_buf.fastmap);
75
build_msg (BuildInfo *info,
81
for (l = info->callbacks; l; l = l->next) {
82
GbfMkfileBuildCallback *cb = l->data;
83
(* cb->callback) (GBF_PROJECT (info->project),
90
parse_output (BuildInfo *info,
93
int line_length = strlen (line);
95
/* Check for directory changes. */
96
if (re_search (&info->dir_buf, line, line_length, 0,
97
line_length, &info->reg) != -1) {
98
if (info->reg.num_regs >= 2) {
100
g_free (info->build_dir);
101
info->build_dir = g_strndup (line + info->reg.start[1],
102
info->reg.end[1] - info->reg.start[1]);
106
/* Check for warnings & errors. */
107
if (re_search (&info->warn_buf, line, line_length, 0,
108
line_length, &info->reg) != -1) {
109
GbfBuildWarning *warn;
112
/* Create new warning. */
113
warn = g_new0 (GbfBuildWarning, 1);
114
text = g_strndup (line + info->reg.start[1],
115
info->reg.end[1] - info->reg.start[1]);
116
if (text[0] != '/') { /* only prepend build_dir if path not absolute */
117
warn->filename = g_strconcat (info->build_dir, "/", text, NULL);
120
warn->filename = text;
123
text = g_strndup (line + info->reg.start[2],
124
info->reg.end[2] - info->reg.start[2]);
125
warn->line = atoi (text);
127
warn->warning = g_strndup (line + info->reg.start[3],
128
info->reg.end[3] - info->reg.start[3]);
129
warn->output = g_strdup (line);
131
build_msg (info, GBF_BUILD_WARNING, warn);
132
/* FIXME: We should free warn here, and make copy in gbf-build-info.c. */
133
} else if (re_search (&info->err_buf, line, line_length, 0,
134
line_length, &info->reg) != -1) {
138
/* Create new error. */
139
err = g_new0 (GbfBuildError, 1);
140
text = g_strndup (line + info->reg.start[1],
141
info->reg.end[1] - info->reg.start[1]);
142
if (text[0] != '/') { /* only prepend build_dir if path not absolute */
143
err->filename = g_strconcat (info->build_dir, "/", text, NULL);
146
err->filename = text;
149
text = g_strndup (line + info->reg.start[2],
150
info->reg.end[2] - info->reg.start[2]);
151
err->line = atoi (text);
153
err->error = g_strndup (line + info->reg.start[3],
154
info->reg.end[3] - info->reg.start[3]);
155
err->output = g_strdup (line);
157
build_msg (info, GBF_BUILD_ERROR, err);
158
/* FIXME: We should free err here, and make copy in gbf-build-info.c. */
160
build_msg (info, GBF_BUILD_OUTPUT, (gpointer)line);
165
build_output_cb (GIOChannel *chan,
169
BuildInfo *info = user_data;
176
status = g_io_channel_read_line (chan, &line, &len, &term, &err);
177
if (status != G_IO_STATUS_NORMAL || line == NULL || err != NULL) {
179
g_warning ("Error reading io channel: %s", err->message);
182
info->num_channels--;
183
if (info->num_channels == 0) {
184
build_msg (info, GBF_BUILD_END, _("Build ended"));
186
g_signal_emit_by_name (G_OBJECT (info->project),
189
build_info_free (info);
195
parse_output (info, line);
202
compile_pattern (struct re_pattern_buffer *buf,
205
memset (buf, 0, sizeof (struct re_pattern_buffer));
206
buf->translate = NULL;
207
buf->fastmap = g_malloc (256);
210
buf->can_be_null = 0;
213
if (!re_compile_pattern (pattern, strlen (pattern), buf)) {
214
if (re_compile_fastmap (buf) != 0) {
215
g_warning ("IMPORTANT REGEX FAILED TO CREASTE FASTMAP");
216
g_free (buf->fastmap);
220
g_warning ("IMPORTANT REGEX FAILED TO COMPILE");
228
gbf_build_run (GbfMkfileProject *project,
230
const char *project_dir,
233
static const char *dir_regex = "Entering directory `([^']+)'";
234
static const char *warn_regex = "^([^:]+):([0-9]+): warning: (.+)$";
235
static const char *err_regex = "^([^:]+):([0-9]+): (.+)$";
237
static int buildid = 0;
242
int output, err, pid;
243
GIOChannel *out_channel, *err_channel;
244
reg_syntax_t old_options;
245
GError *error = NULL;
250
/* default targets */
251
if ( 0 == strcmp (id, GBF_MKFILE_BUILD_ID_ALL) ||
252
0 == strcmp (id, GBF_BUILD_ID_DEFAULT) ) {
253
argv[0] = g_strdup (project->make_command);
254
argv[1] = g_strdup ("all");
256
build_dir = g_strdup (project_dir);
257
} else if ( 0 == strcmp (id, GBF_MKFILE_BUILD_ID_CLEAN) ) {
258
argv[0] = g_strdup (project->make_command);
259
argv[1] = g_strdup ("clean");
261
build_dir = g_strdup (project_dir);
262
} else if ( 0 == strcmp (id, GBF_MKFILE_BUILD_ID_INSTALL) ) {
263
argv[0] = g_strdup (project->make_command);
264
argv[1] = g_strdup ("install");
266
build_dir = g_strdup (project_dir);
269
/* id is like: "USER:real_id" */
270
g_node = g_hash_table_lookup (project->targets, id+strlen (GBF_MKFILE_BUILD_ID_USER_PREFIX) );
272
g_warning ("Invalid build: %s", id);
275
node = GBF_MKFILE_NODE (g_node);
277
if ( 0 == strcmp (node->detail, "program") ||
278
0 == strcmp (node->detail, "static_lib") ||
279
0 == strcmp (node->detail, "shared_lib") ) {
280
/* find the right build dir and make argument */
281
/* FIXME: durty ?? */
283
cur = id+strlen (GBF_MKFILE_BUILD_ID_USER_PREFIX);
285
while( *cur != '\0' && *cur != ':') {
293
build_dir = g_strdup_printf ("%s%s", project_dir,
294
id+strlen (GBF_MKFILE_BUILD_ID_USER_PREFIX));
296
argv[0] = g_strdup (project->make_command);
297
argv[1] = g_strdup (last+1);
300
g_warning ("Invalid build type : %s", node->detail);
305
if (!g_spawn_async_with_pipes (build_dir,
312
g_warning ("Couldn't spawn '%s'", argv[0]);
322
out_channel = g_io_channel_unix_new (output);
323
g_io_channel_set_close_on_unref (out_channel, TRUE);
324
err_channel = g_io_channel_unix_new (err);
325
g_io_channel_set_close_on_unref (err_channel, TRUE);
327
/* Set io channel encoding if current locale is not utf-8. */
328
if (!g_get_charset (&charset)) {
329
if (G_IO_STATUS_NORMAL != g_io_channel_set_encoding (out_channel, charset, &error) ||
330
G_IO_STATUS_NORMAL != g_io_channel_set_encoding (err_channel, charset, &error)) {
331
g_io_channel_unref (out_channel);
332
g_io_channel_unref (err_channel);
333
g_warning ("Failed to set encodings: %s", error->message);
334
g_error_free (error);
339
info = g_new0 (BuildInfo, 1);
340
info->project = project;
341
info->id = ++buildid;
342
info->num_channels = 2;
343
info->callbacks = callbacks;
344
info->build_dir = NULL;
346
/* Intialize regexs. */
347
old_options = re_syntax_options;
348
re_syntax_options = RE_SYNTAX_EGREP;
350
if (!compile_pattern (&info->dir_buf, dir_regex) ||
351
!compile_pattern (&info->warn_buf, warn_regex) ||
352
!compile_pattern (&info->err_buf, err_regex)) {
353
g_io_channel_unref (out_channel);
354
g_io_channel_unref (err_channel);
355
build_info_free (info);
356
g_warning ("failed to compile regexs necessary for build output parsing");
360
re_syntax_options = old_options;
362
g_signal_emit_by_name (G_OBJECT (project), "build_start");
364
tmp = g_strjoinv (" ", (char **) argv);
365
msg = g_strconcat (tmp, "\n", NULL);
367
build_msg (info, GBF_BUILD_START, msg);
370
g_io_add_watch (out_channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
373
g_io_channel_unref (out_channel);
374
g_io_add_watch (err_channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
377
g_io_channel_unref (err_channel);
382
#else /* NATIVE_GNU_REGEX */
385
gbf_build_run (GbfMkfileProject *project,
387
const char *project_dir,
393
#endif /* NATIVE_GNU_REGEX */
396
gbf_build_cancel (int build_id)