build-basic-autotools: bgo #727637 - Autotools plugin should be able to find the...
[anjuta.git] / plugins / build-basic-autotools / build.c
blobe7120ccf123b8f9f320d1280f7d8db2c5ff969d4
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 build.c
4 Copyright (C) 2000 Naba Kumar
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program 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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <config.h>
23 #include "build.h"
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <stdlib.h>
29 #include <libanjuta/interfaces/ianjuta-project-manager.h>
30 #include <libanjuta/interfaces/ianjuta-language.h>
31 #include <libanjuta/anjuta-utils.h>
33 #include "program.h"
34 #include "build-options.h"
36 /* Types
37 *---------------------------------------------------------------------------*/
39 typedef struct
41 gchar *args;
42 GFile *file;
43 BuildFunc func;
44 IAnjutaBuilderCallback callback;
45 gpointer user_data;
46 } BuildConfigureAndBuild;
48 /* Constants
49 *---------------------------------------------------------------------------*/
51 #define PREF_INSTALL_ROOT "install-root"
52 #define PREF_INSTALL_ROOT_COMMAND "install-root-command"
54 #define DEFAULT_COMMAND_COMPILE "make"
55 #define DEFAULT_COMMAND_BUILD "make"
56 #define DEFAULT_COMMAND_IS_BUILT "make -q"
57 #define DEFAULT_COMMAND_BUILD_TARBALL "make dist"
58 #define DEFAULT_COMMAND_INSTALL "make install"
59 #define DEFAULT_COMMAND_CONFIGURE "configure"
60 #define DEFAULT_COMMAND_GENERATE "autogen.sh"
61 #define DEFAULT_COMMAND_CLEAN "make clean"
62 #define DEFAULT_COMMAND_DISTCLEAN "make distclean"
63 #define DEFAULT_COMMAND_CHECK "make check"
64 #define DEFAULT_COMMAND_AUTORECONF "autoreconf -i --force"
66 #define RUN_PROGRAM_URI "run_program_uri"
68 #define CHOOSE_COMMAND(plugin,command) \
69 ((plugin->commands[(IANJUTA_BUILDABLE_COMMAND_##command)]) ? \
70 (plugin->commands[(IANJUTA_BUILDABLE_COMMAND_##command)]) \
71 : \
72 (DEFAULT_COMMAND_##command))
74 /* Helper functions
75 *---------------------------------------------------------------------------*/
77 /* Normalize a file to use project directory if it is a child */
78 GFile *
79 normalize_project_file (GFile *file, GFile *root)
81 gchar *path;
82 gchar *root_path;
83 gchar *file_path;
84 guint i;
85 GFile *new_file;
87 path = g_file_get_path (root);
88 root_path = anjuta_util_get_real_path (path);
89 g_free (path);
91 path = g_file_get_path (file);
92 file_path = anjuta_util_get_real_path (path);
93 g_free (path);
95 if ((file_path != NULL) && (root_path != NULL))
97 for (i = 0; (file_path[i] == root_path[i]) && (file_path[i] != '\0') && (root_path[i] != '\0'); i++);
98 if ((root_path[i] == '\0') && (file_path[i] == '\0'))
100 new_file = g_object_ref (root);
102 else if ((root_path[i] == '\0') && (file_path[i] == G_DIR_SEPARATOR))
104 new_file = g_file_resolve_relative_path (root, &file_path[i + 1]);
106 else
108 new_file = g_object_ref (file);
111 else
113 new_file = g_object_ref (file);
116 g_free (root_path);
117 g_free (file_path);
119 return new_file;
122 gboolean
123 directory_has_makefile_am (BasicAutotoolsPlugin *bb_plugin, GFile *dir)
125 GFile *file;
126 gboolean exists;
128 /* We need configure.ac or configure.in too */
129 if (bb_plugin->project_root_dir == NULL) return FALSE;
131 exists = TRUE;
132 file = g_file_get_child (bb_plugin->project_root_dir, "configure.ac");
133 if (!g_file_query_exists (file, NULL))
135 g_object_unref (file);
136 file = g_file_get_child (bb_plugin->project_root_dir, "configure.in");
137 if (!g_file_query_exists (file, NULL))
139 exists = FALSE;
142 g_object_unref (file);
144 /* Check for Makefile.am or GNUmakefile.am */
145 if (g_file_has_prefix (dir, bb_plugin->project_build_dir))
147 /* Check for Makefile.am in source directory not build directory */
148 gchar *relative;
149 GFile *src_dir;
151 relative = g_file_get_relative_path (bb_plugin->project_build_dir, dir);
152 src_dir = g_file_get_child (bb_plugin->project_root_dir, relative);
153 file = g_file_get_child (src_dir, "Makefile.am");
154 g_object_unref (src_dir);
155 g_free (relative);
157 else if (g_file_equal (dir, bb_plugin->project_build_dir))
159 file = g_file_get_child (bb_plugin->project_root_dir, "Makefile.am");
161 else
163 file = g_file_get_child (dir, "Makefile.am");
166 if (!g_file_query_exists (file, NULL))
168 g_object_unref (file);
169 file = g_file_get_child (dir, "GNUmakefile.am");
170 if (!g_file_query_exists (file, NULL))
172 exists = FALSE;
175 g_object_unref (file);
177 return exists;
180 gboolean
181 directory_has_makefile (GFile *dir)
183 GFile *file;
184 gboolean exists;
186 exists = TRUE;
187 file = g_file_get_child (dir, "Makefile");
188 if (!g_file_query_exists (file, NULL))
190 g_object_unref (file);
191 file = g_file_get_child (dir, "makefile");
192 if (!g_file_query_exists (file, NULL))
194 g_object_unref (file);
195 file = g_file_get_child (dir, "MAKEFILE");
196 if (!g_file_query_exists (file, NULL))
198 exists = FALSE;
202 g_object_unref (file);
204 return exists;
207 static gboolean
208 directory_has_file (GFile *dir, const gchar *filename)
210 GFile *file;
211 gboolean exists;
213 file = g_file_get_child (dir, filename);
214 exists = g_file_query_exists (file, NULL);
215 g_object_unref (file);
217 return exists;
220 static gchar*
221 shell_quotef (const gchar *format,...)
223 va_list args;
224 gchar *str;
225 gchar *quoted_str;
227 va_start (args, format);
228 str = g_strdup_vprintf (format, args);
229 va_end (args);
231 quoted_str = g_shell_quote (str);
232 g_free (str);
234 return quoted_str;
237 /* Get target relative to current configuration if existing or NULL if the current
238 * target is not relative to the current configuration */
239 gchar *
240 get_configuration_relative_target (BasicAutotoolsPlugin *plugin)
242 gchar *relative_target = NULL;
243 gchar *uri;
245 anjuta_shell_get (ANJUTA_PLUGIN (plugin)->shell, RUN_PROGRAM_URI, G_TYPE_STRING, &uri, NULL);
246 if (uri != NULL)
248 GFile *target;
249 GFile *file;
251 target = g_file_new_for_uri (uri);
252 file = build_configuration_list_get_build_file (plugin->configurations, build_configuration_list_get_selected (plugin->configurations));
253 relative_target = g_file_get_relative_path (file, target);
254 g_object_unref (file);
255 g_object_unref (target);
256 g_free (uri);
259 return relative_target;
262 /* Set target relative to current configuration if relative_target is not NULL*/
263 void
264 set_configuration_relative_target (BasicAutotoolsPlugin *plugin, const gchar* relative_target)
266 if (relative_target != NULL)
268 GFile *file;
269 GFile *target;
270 gchar *uri;
271 GValue value = {0,};
273 file = build_configuration_list_get_build_file (plugin->configurations, build_configuration_list_get_selected (plugin->configurations));
274 target = g_file_get_child (file, relative_target);
275 uri = g_file_get_uri (target);
276 g_value_init (&value, G_TYPE_STRING);
277 g_value_set_static_string (&value, uri);
278 anjuta_shell_add_value (ANJUTA_PLUGIN (plugin)->shell, RUN_PROGRAM_URI, &value, NULL);
279 g_value_unset (&value);
280 g_object_unref (target);
281 g_object_unref (file);
286 /* Return FALSE if Makefile is missing and we have both a Makefile.am and a project
287 * open, meaning that we need to configure the project to get a Makefile */
288 static gboolean
289 is_configured (BasicAutotoolsPlugin *plugin, GFile *file)
291 GFile *build_dir;
292 gboolean has_makefile;
293 gboolean has_makefile_am;
295 /* Get build directory and check for makefiles */
296 build_dir = build_file_from_file (plugin, file, NULL);
297 has_makefile = directory_has_makefile (build_dir);
298 has_makefile_am = directory_has_makefile_am (plugin, build_dir);
299 g_object_unref (build_dir);
301 return has_makefile || !has_makefile_am || (plugin->project_root_dir == NULL);
304 /* Return build path from a source directory */
305 static GFile *
306 build_file_from_directory (BasicAutotoolsPlugin *plugin, GFile *directory)
308 GFile *build_file;
310 if ((plugin->project_root_dir == NULL) || (plugin->project_build_dir == NULL))
312 /* No change if there is no project or no build directory */
313 build_file = g_object_ref (directory);
315 else if (g_file_has_prefix (directory, plugin->project_build_dir) || g_file_equal (directory, plugin->project_build_dir))
317 /* No change, already in build directory */
318 build_file = g_object_ref (directory);
320 else if (g_file_equal (directory, plugin->project_root_dir))
322 /* Use build directory instead of source directory */
323 build_file = g_object_ref (plugin->project_build_dir);
325 else if (g_file_has_prefix (directory, plugin->project_root_dir))
327 /* Get corresponding file in build directory */
328 gchar *relative;
330 relative = g_file_get_relative_path (plugin->project_root_dir, directory);
331 build_file = g_file_resolve_relative_path (plugin->project_build_dir, relative);
332 g_free (relative);
334 else
336 /* File outside the project directory */
337 build_file = g_object_ref (directory);
340 return build_file;
343 /* Return build path and target from a GFile */
344 GFile *
345 build_file_from_file (BasicAutotoolsPlugin *plugin, GFile *file, gchar **target)
348 if (target != NULL) *target = NULL;
350 if (file == NULL)
352 /* Use project root directory */
353 return build_file_from_directory (plugin, plugin->project_root_dir);
355 else if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
357 return build_file_from_directory (plugin, file);
359 else
361 GFile *parent = NULL;
362 GFile *build_file;
363 IAnjutaProjectManager* projman;
365 projman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
366 IAnjutaProjectManager,
367 NULL);
369 if (projman != NULL)
371 /* Use the project manager to find the group file */
372 GFile *child;
374 for (child = normalize_project_file (file, plugin->project_root_dir); child != NULL;)
376 GFile *group;
377 AnjutaProjectNodeType type;
379 type = ianjuta_project_manager_get_target_type (projman, child, NULL);
380 if (type == ANJUTA_PROJECT_GROUP) break;
381 group = ianjuta_project_manager_get_parent (projman, child, NULL);
382 g_object_unref (child);
383 child = group;
385 parent = child;
388 if (parent == NULL)
390 /* Fallback use parent directory */
391 parent = g_file_get_parent (file);
394 if (parent != NULL)
396 if (target != NULL) *target = g_file_get_relative_path (parent, file);
397 build_file = build_file_from_directory (plugin, parent);
398 g_object_unref (parent);
400 return build_file;
402 else
404 return NULL;
409 GFile *
410 build_object_from_file (BasicAutotoolsPlugin *plugin, GFile *file)
412 GFile *object = NULL;
413 IAnjutaProjectManager* projman;
415 /* Check that the GFile is a regular file */
416 if ((file == NULL) || (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY))
418 return NULL;
421 projman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
422 IAnjutaProjectManager,
423 NULL);
424 if ((projman != NULL) && ianjuta_project_manager_is_open (projman, NULL))
426 /* Use the project manager to find the object file */
427 GFile *norm_file;
429 norm_file = normalize_project_file (file, plugin->project_root_dir);
430 object = ianjuta_project_manager_get_parent (projman, norm_file, NULL);
431 if (object != NULL)
433 if (ianjuta_project_manager_get_target_type (projman, object, NULL) != ANJUTA_PROJECT_OBJECT)
435 g_object_unref (object);
436 object = NULL;
439 g_object_unref (norm_file);
441 else
443 /* Use language plugin trying to find an object file */
444 IAnjutaLanguage* langman = anjuta_shell_get_interface (ANJUTA_PLUGIN (plugin)->shell,
445 IAnjutaLanguage,
446 NULL);
448 if (langman != NULL)
450 GFileInfo* file_info;
452 file_info = g_file_query_info (file,
453 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
454 G_FILE_QUERY_INFO_NONE,
455 NULL,
456 NULL);
457 if (file_info)
459 gint id = ianjuta_language_get_from_mime_type (langman,
460 g_file_info_get_content_type (file_info),
461 NULL);
462 if (id > 0)
464 const gchar *obj_ext = ianjuta_language_get_make_target (langman, id, NULL);
465 gchar *basename;
466 gchar *ext;
467 gchar *targetname;
468 GFile *parent;
470 basename = g_file_get_basename (file);
471 ext = strrchr (basename, '.');
472 if ((ext != NULL) && (ext != basename)) *ext = '\0';
473 targetname = g_strconcat (basename, obj_ext, NULL);
474 g_free (basename);
475 parent = g_file_get_parent (file);
476 object = g_file_get_child (parent, targetname);
477 g_object_unref (parent);
478 g_free (targetname);
481 g_object_unref (file_info);
485 return object;
488 /* Save & Build
489 *---------------------------------------------------------------------------*/
491 static BuildContext*
492 build_execute_command (BasicAutotoolsPlugin* bplugin, BuildProgram *prog,
493 gboolean with_view, GError **err)
495 BuildContext *context;
496 gboolean ok;
498 context = build_get_context (bplugin, prog->work_dir, with_view, FALSE);
500 build_set_command_in_context (context, prog);
501 ok = build_execute_command_in_context (context, err);
503 if (ok)
505 return context;
507 else
509 build_context_destroy (context);
511 return NULL;
515 static BuildContext*
516 build_save_and_execute_command (BasicAutotoolsPlugin* bplugin, BuildProgram *prog,
517 gboolean with_view, gboolean check_password, GError **err)
519 BuildContext *context;
521 context = build_get_context (bplugin, prog->work_dir, with_view, check_password);
523 build_set_command_in_context (context, prog);
524 if (!build_save_and_execute_command_in_context (context, err))
526 build_context_destroy (context);
527 context = NULL;
530 return context;
533 static void
534 build_execute_after_command (GObject *sender,
535 IAnjutaBuilderHandle handle,
536 GError *error,
537 gpointer user_data)
539 BuildProgram *prog = (BuildProgram *)user_data;
540 BuildContext *context = (BuildContext *)handle;
542 /* Try next command even if the first one fail (make distclean return an error) */
543 if ((error == NULL) || (error->code != IANJUTA_BUILDER_ABORTED))
545 build_set_command_in_context (context, prog);
546 build_execute_command_in_context (context, NULL);
548 else
550 build_program_free (prog);
554 static BuildContext*
555 build_save_distclean_and_execute_command (BasicAutotoolsPlugin* bplugin, BuildProgram *prog,
556 gboolean with_view, GError **err)
558 BuildContext *context;
559 gchar *root_path;
560 gboolean same;
561 BuildConfiguration *config;
562 GList *vars;
564 context = build_get_context (bplugin, prog->work_dir, with_view, FALSE);
565 root_path = g_file_get_path (bplugin->project_root_dir);
566 same = strcmp (prog->work_dir, root_path) == 0;
567 g_free (root_path);
569 config = build_configuration_list_get_selected (bplugin->configurations);
570 vars = build_configuration_get_variables (config);
572 if (!same && directory_has_file (bplugin->project_root_dir, "config.status"))
574 BuildProgram *new_prog;
576 // Need to run make clean before
577 if (!anjuta_util_dialog_boolean_question (GTK_WINDOW (ANJUTA_PLUGIN (bplugin)->shell), FALSE,
578 _("Before using this new configuration, the default one needs to be removed. Do you want to do that ?"), NULL))
580 if (err)
581 *err = g_error_new (ianjuta_builder_error_quark (),
582 IANJUTA_BUILDER_CANCELED,
583 _("Command canceled by user"));
585 return NULL;
587 new_prog = build_program_new_with_command (bplugin->project_root_dir,
588 "%s",
589 CHOOSE_COMMAND (bplugin, DISTCLEAN));
590 build_program_set_callback (new_prog, build_execute_after_command, prog);
591 prog = new_prog;
593 build_program_add_env_list (prog, vars);
595 build_set_command_in_context (context, prog);
597 build_save_and_execute_command_in_context (context, NULL);
599 return context;
603 /* Build commands
604 *---------------------------------------------------------------------------*/
606 BuildContext*
607 build_build_file_or_dir (BasicAutotoolsPlugin *plugin,
608 GFile *file,
609 IAnjutaBuilderCallback callback, gpointer user_data,
610 GError **err)
612 GFile *build_dir;
613 gchar *target;
614 BuildProgram *prog;
615 BuildContext *context;
616 BuildConfiguration *config;
617 GList *vars;
619 config = build_configuration_list_get_selected (plugin->configurations);
620 vars = build_configuration_get_variables (config);
622 build_dir = build_file_from_file (plugin, file, &target);
623 prog = build_program_new_with_command (build_dir,
624 "%s %s",
625 CHOOSE_COMMAND (plugin, BUILD),
626 target ? target : "");
627 build_program_set_callback (prog, callback, user_data);
628 build_program_add_env_list (prog, vars);
630 context = build_save_and_execute_command (plugin, prog, TRUE, FALSE, err);
631 g_free (target);
632 g_object_unref (build_dir);
634 return context;
639 BuildContext*
640 build_is_file_built (BasicAutotoolsPlugin *plugin, GFile *file,
641 IAnjutaBuilderCallback callback, gpointer user_data,
642 GError **err)
644 GFile *build_dir;
645 gchar *target;
646 BuildProgram *prog;
647 BuildContext *context;
648 BuildConfiguration *config;
649 GList *vars;
652 config = build_configuration_list_get_selected (plugin->configurations);
654 if (!config)
656 return NULL;
659 vars = build_configuration_get_variables (config);
661 build_dir = build_file_from_file (plugin, file, &target);
662 prog = build_program_new_with_command (build_dir,
663 "%s %s",
664 CHOOSE_COMMAND (plugin, IS_BUILT),
665 target ? target : "");
666 build_program_set_callback (prog, callback, user_data);
667 build_program_add_env_list (prog, vars);
669 context = build_save_and_execute_command (plugin, prog, FALSE, FALSE, err);
671 g_free (target);
672 g_object_unref (build_dir);
674 return context;
679 static gchar*
680 get_root_install_command(BasicAutotoolsPlugin *bplugin)
682 GSettings* settings = bplugin->settings;
683 if (g_settings_get_boolean (settings, PREF_INSTALL_ROOT))
685 gchar* command = g_settings_get_string (settings, PREF_INSTALL_ROOT_COMMAND);
686 return command;
688 else
689 return g_strdup("");
692 BuildContext*
693 build_install_dir (BasicAutotoolsPlugin *plugin, GFile *dir,
694 IAnjutaBuilderCallback callback, gpointer user_data,
695 GError **err)
697 BuildContext *context;
698 gchar* root = get_root_install_command(plugin);
699 gboolean use_root = FALSE;
700 GFile *build_dir;
701 BuildProgram *prog;
702 GString *command;
703 BuildConfiguration *config;
704 GList *vars;
706 if ((root != NULL) && (*root != '\0'))
708 gchar *first = root;
709 gchar *ptr = root;
711 /* Replace %s or %q by respectively, the install command or the
712 * quoted install command. % character can be escaped by using two %. */
713 command = g_string_new (NULL);
714 while (*ptr)
716 if (*ptr++ == '%')
718 if (*ptr == 's')
720 /* Not quoted command */
721 g_string_append_len (command, first, ptr - 1 - first);
722 g_string_append (command, CHOOSE_COMMAND (plugin, INSTALL));
723 first = ptr + 1;
725 else if (*ptr == 'q')
727 /* quoted command */
728 gchar *quoted;
730 quoted = g_shell_quote (CHOOSE_COMMAND (plugin, INSTALL));
731 g_string_append_len (command, first, ptr - 1 - first);
732 g_string_append (command, quoted);
733 g_free (quoted);
734 first = ptr + 1;
736 else if (*ptr == '%')
738 /* escaped % */
739 g_string_append_len (command, first, ptr - 1 - first);
740 first = ptr;
742 ptr++;
745 g_string_append (command, first);
746 use_root = TRUE;
748 else
750 command = g_string_new (CHOOSE_COMMAND (plugin, INSTALL));
754 config = build_configuration_list_get_selected (plugin->configurations);
755 vars = build_configuration_get_variables (config);
757 build_dir = build_file_from_file (plugin, dir, NULL);
758 prog = build_program_new_with_command (build_dir,
759 "%s",
760 command->str);
761 build_program_set_callback (prog, callback, user_data);
762 build_program_add_env_list (prog, vars);
764 context = build_save_and_execute_command (plugin, prog, TRUE, use_root, err);
766 g_string_free (command, TRUE);
767 g_object_unref (build_dir);
768 g_free (root);
770 return context;
775 BuildContext*
776 build_clean_dir (BasicAutotoolsPlugin *plugin, GFile *dir,
777 GError **err)
779 BuildContext *context = NULL;
780 BuildProgram *prog;
781 GFile *build_dir;
782 BuildConfiguration *config;
783 GList *vars;
785 if (is_configured (plugin, dir))
787 config = build_configuration_list_get_selected (plugin->configurations);
788 vars = build_configuration_get_variables (config);
790 build_dir = build_file_from_file (plugin, dir, NULL);
792 prog = build_program_new_with_command (build_dir,
793 "%s",
794 CHOOSE_COMMAND (plugin, CLEAN)),
795 build_program_add_env_list (prog, vars);
797 context = build_execute_command (plugin, prog, TRUE, err);
798 g_object_unref (build_dir);
801 return context;
804 BuildContext*
805 build_check_dir (BasicAutotoolsPlugin *plugin, GFile *dir,
806 IAnjutaBuilderCallback callback, gpointer user_data,
807 GError **err)
809 BuildContext *context = NULL;
810 BuildProgram *prog;
811 GFile *build_dir;
812 BuildConfiguration *config;
813 GList *vars;
815 config = build_configuration_list_get_selected (plugin->configurations);
816 vars = build_configuration_get_variables (config);
818 build_dir = build_file_from_file (plugin, dir, NULL);
820 prog = build_program_new_with_command (build_dir,
821 "%s",
822 CHOOSE_COMMAND (plugin, CHECK)),
823 build_program_set_callback (prog, callback, user_data);
824 build_program_add_env_list (prog, vars);
826 context = build_execute_command (plugin, prog, TRUE, err);
827 g_object_unref (build_dir);
829 return context;
832 static void
833 build_remove_build_dir (GObject *sender,
834 IAnjutaBuilderHandle context,
835 GError *error,
836 gpointer user_data)
838 /* FIXME: Should we remove build dir on distclean ? */
841 BuildContext*
842 build_distclean (BasicAutotoolsPlugin *plugin)
844 BuildContext *context;
845 BuildProgram *prog;
846 BuildConfiguration *config;
847 GList *vars;
850 config = build_configuration_list_get_selected (plugin->configurations);
851 vars = build_configuration_get_variables (config);
853 prog = build_program_new_with_command (plugin->project_build_dir,
854 "%s",
855 CHOOSE_COMMAND (plugin, DISTCLEAN));
856 build_program_set_callback (prog, build_remove_build_dir, plugin);
857 build_program_add_env_list (prog, vars);
859 context = build_execute_command (plugin, prog, TRUE, NULL);
861 return context;
866 BuildContext*
867 build_tarball (BasicAutotoolsPlugin *plugin)
869 BuildContext *context;
870 BuildProgram *prog;
871 BuildConfiguration *config;
872 GList *vars;
874 config = build_configuration_list_get_selected (plugin->configurations);
875 vars = build_configuration_get_variables (config);
877 prog = build_program_new_with_command (plugin->project_build_dir,
878 "%s",
879 CHOOSE_COMMAND (plugin, BUILD_TARBALL)),
880 build_program_add_env_list (prog, vars);
882 context = build_save_and_execute_command (plugin, prog, TRUE, FALSE, NULL);
884 return context;
887 BuildContext*
888 build_compile_file (BasicAutotoolsPlugin *plugin, GFile *file)
890 BuildContext *context = NULL;
891 BuildProgram *prog;
892 GFile *object;
893 gchar *target_name;
895 g_return_val_if_fail (file != NULL, FALSE);
897 object = build_object_from_file (plugin, file);
898 if (object != NULL)
900 GFile *build_dir;
901 BuildConfiguration *config;
902 GList *vars;
904 config = build_configuration_list_get_selected (plugin->configurations);
905 vars = build_configuration_get_variables (config);
907 /* Find target directory */
908 build_dir = build_file_from_file (plugin, object, &target_name);
910 prog = build_program_new_with_command (build_dir, "%s %s",
911 CHOOSE_COMMAND(plugin, COMPILE),
912 (target_name == NULL) ? "" : target_name);
913 g_free (target_name);
914 g_object_unref (build_dir);
916 build_program_add_env_list (prog, vars);
918 context = build_save_and_execute_command (plugin, prog, TRUE, FALSE, NULL);
919 g_object_unref (object);
921 else
923 /* FIXME: Prompt the user to create a Makefile with a wizard
924 (if there is no Makefile in the directory) or to add a target
925 rule in the above hash table, eg. editing the preferences, if
926 there is target extension defined for that file extension.
928 GtkWindow *window;
929 gchar *filename;
931 filename = g_file_get_path (file);
932 window = GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell);
933 anjuta_util_dialog_error (window, _("Cannot compile \"%s\": No compile rule defined for this file type."), filename);
934 g_free (filename);
937 return context;
941 void
942 build_project_configured (GObject *sender,
943 IAnjutaBuilderHandle handle,
944 GError *error,
945 gpointer user_data)
947 BuildConfigureAndBuild *pack = (BuildConfigureAndBuild *)user_data;
949 if (error == NULL)
951 BuildContext *context = (BuildContext *)handle;
952 BasicAutotoolsPlugin *plugin = (BasicAutotoolsPlugin *)(context == NULL ? (void *)sender : (void *)build_context_get_plugin (context));
953 GFile *file;
955 /* FIXME: check if build directory correspond, configuration could have changed */
957 file = build_configuration_list_get_build_file (plugin->configurations, build_configuration_list_get_selected (plugin->configurations));
958 if (file)
960 GValue value = G_VALUE_INIT;
961 gchar *uri;
963 uri = g_file_get_uri (file);
964 g_value_init (&value, G_TYPE_STRING);
965 g_value_set_string (&value, uri);
966 g_free (uri);
967 g_object_unref (file);
969 anjuta_shell_add_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_BUILDER_ROOT_URI, &value, NULL);
970 g_value_unset (&value);
972 /* Call build function if necessary */
973 if ((pack) && (pack->func != NULL)) pack->func (plugin, pack->file, pack->callback, pack->user_data, NULL);
975 else
976 anjuta_shell_remove_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_BUILDER_ROOT_URI, NULL);
978 build_update_configuration_menu (plugin);
981 if (pack)
983 g_free (pack->args);
984 if (pack->file != NULL) g_object_unref (pack->file);
985 g_free (pack);
989 BuildContext*
990 build_configure_dir (BasicAutotoolsPlugin *plugin, GFile *dir, const gchar *args,
991 BuildFunc func, GFile *file,
992 IAnjutaBuilderCallback callback, gpointer user_data, GError **error)
994 BuildContext *context;
995 BuildProgram *prog;
996 BuildConfiguration *config;
997 GList *vars;
998 BuildConfigureAndBuild *pack = g_new0 (BuildConfigureAndBuild, 1);
999 gchar *quote;
1000 gchar *root_path;
1002 config = build_configuration_list_get_selected (plugin->configurations);
1003 vars = build_configuration_get_variables (config);
1005 // Make sure the build directory is here
1006 g_file_make_directory_with_parents (dir, NULL, NULL);
1008 root_path = g_file_get_path (plugin->project_root_dir);
1009 quote = shell_quotef ("%s%s%s",
1010 root_path,
1011 G_DIR_SEPARATOR_S,
1012 CHOOSE_COMMAND (plugin, CONFIGURE));
1014 prog = build_program_new_with_command (dir,
1015 "%s %s",
1016 quote,
1017 args);
1018 g_free (quote);
1019 g_free (root_path);
1021 pack->args = NULL;
1022 pack->func = func;
1023 pack->file = (file != NULL) ? g_object_ref (file) : NULL;
1024 pack->callback = callback;
1025 pack->user_data = user_data;
1026 build_program_set_callback (prog, build_project_configured, pack);
1027 build_program_add_env_list (prog, vars);
1029 context = build_save_distclean_and_execute_command (plugin, prog, TRUE, NULL);
1031 return context;
1036 static void
1037 build_configure_after_autogen (GObject *sender,
1038 IAnjutaBuilderHandle handle,
1039 GError *error,
1040 gpointer user_data)
1042 BuildConfigureAndBuild *pack = (BuildConfigureAndBuild *)user_data;
1044 if (error == NULL)
1046 BuildContext *context = (BuildContext *)handle;
1047 BuildConfiguration *config;
1048 GList *vars;
1049 BasicAutotoolsPlugin *plugin = (BasicAutotoolsPlugin *)build_context_get_plugin (context);
1050 struct stat conf_stat, log_stat;
1051 gchar *root_path;
1052 gchar *filename;
1053 gboolean has_configure;
1055 root_path = g_file_get_path (plugin->project_root_dir);
1056 filename = g_build_filename (root_path, "configure", NULL);
1057 has_configure = stat (filename, &conf_stat) == 0;
1058 g_free (filename);
1060 if (has_configure)
1062 gboolean older;
1064 config = build_configuration_list_get_selected (plugin->configurations);
1065 vars = build_configuration_get_variables (config);
1067 filename = g_build_filename (build_context_get_work_dir (context), "config.status", NULL);
1068 older =(stat (filename, &log_stat) != 0) || (log_stat.st_mtime < conf_stat.st_mtime);
1069 g_free (filename);
1071 if (older)
1073 /* configure has not be run, run it */
1074 BuildProgram *prog;
1075 gchar *quote;
1076 GFile *work_file;
1078 quote = shell_quotef ("%s%s%s",
1079 root_path,
1080 G_DIR_SEPARATOR_S,
1081 CHOOSE_COMMAND (plugin, CONFIGURE));
1083 work_file = g_file_new_for_path (build_context_get_work_dir (context));
1084 prog = build_program_new_with_command (work_file,
1085 "%s %s",
1086 quote,
1087 pack != NULL ? pack->args : NULL);
1088 g_object_unref (work_file);
1089 g_free (quote);
1090 build_program_set_callback (prog, build_project_configured, pack);
1091 build_program_add_env_list (prog, vars);
1093 build_set_command_in_context (context, prog);
1094 build_execute_command_in_context (context, NULL);
1096 else
1098 /* run next command if needed */
1099 build_project_configured (sender, handle, NULL, pack);
1102 g_free (root_path);
1103 return;
1105 else
1107 anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell), _("Cannot configure project: Missing configure script in %s."), root_path);
1108 g_free (root_path);
1112 if (pack)
1114 g_free (pack->args);
1115 if (pack->file != NULL) g_object_unref (pack->file);
1116 g_free (pack);
1120 BuildContext*
1121 build_generate_dir (BasicAutotoolsPlugin *plugin, GFile *dir, const gchar *args,
1122 BuildFunc func, GFile *file,
1123 IAnjutaBuilderCallback callback, gpointer user_data, GError **error)
1125 BuildContext *context;
1126 BuildProgram *prog;
1127 BuildConfiguration *config;
1128 GList *vars;
1129 BuildConfigureAndBuild *pack = g_new0 (BuildConfigureAndBuild, 1);
1132 config = build_configuration_list_get_selected (plugin->configurations);
1133 vars = build_configuration_get_variables (config);
1135 // Make sure the build directory is here
1136 g_file_make_directory_with_parents (dir, NULL, NULL);
1138 if (directory_has_file (plugin->project_root_dir, "autogen.sh"))
1140 gchar *quote;
1141 gchar *root_path = g_file_get_path (plugin->project_root_dir);
1143 quote = shell_quotef ("%s%s%s",
1144 root_path,
1145 G_DIR_SEPARATOR_S,
1146 CHOOSE_COMMAND (plugin, GENERATE));
1147 prog = build_program_new_with_command (dir,
1148 "%s %s",
1149 quote,
1150 args);
1151 g_free (quote);
1152 g_free (root_path);
1154 else
1156 prog = build_program_new_with_command (dir,
1157 "%s %s",
1158 CHOOSE_COMMAND (plugin, AUTORECONF),
1159 args);
1161 pack->args = g_strdup (args);
1162 pack->func = func;
1163 pack->file = (file != NULL) ? g_object_ref (file) : NULL;
1164 pack->callback = callback;
1165 pack->user_data = user_data;
1166 build_program_set_callback (prog, build_configure_after_autogen, pack);
1167 build_program_add_env_list (prog, vars);
1169 context = build_save_distclean_and_execute_command (plugin, prog, TRUE, NULL);
1171 return context;
1174 BuildContext*
1175 build_configure_dialog (BasicAutotoolsPlugin *plugin, BuildFunc func, GFile *file, IAnjutaBuilderCallback callback, gpointer user_data, GError **error)
1177 GtkWindow *parent;
1178 gboolean run_autogen = FALSE;
1179 const gchar *project_root;
1180 GValue value = {0,};
1181 const gchar *old_config_name;
1182 gchar *relative_target;
1183 BuildContext* context = NULL;
1185 run_autogen = !directory_has_file (plugin->project_root_dir, "configure");
1187 anjuta_shell_get_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI, &value, NULL);
1189 /* In case, a project is not loaded */
1190 if (!G_VALUE_HOLDS_STRING (&value)) return NULL;
1192 project_root = g_value_get_string (&value);
1193 parent = GTK_WINDOW (ANJUTA_PLUGIN(plugin)->shell);
1195 old_config_name = build_configuration_get_name (build_configuration_list_get_selected (plugin->configurations));
1196 relative_target = get_configuration_relative_target (plugin);
1197 if (build_dialog_configure (parent, project_root, plugin->configurations, &run_autogen))
1199 BuildConfiguration *config;
1200 GFile *build_file;
1201 const gchar *args;
1203 config = build_configuration_list_get_selected (plugin->configurations);
1204 build_file = build_configuration_list_get_build_file (plugin->configurations, config);
1206 args = build_configuration_get_args (config);
1208 if (run_autogen)
1210 context = build_generate_dir (plugin, build_file, args, func, file, callback, user_data, error);
1212 else
1214 context = build_configure_dir (plugin, build_file, args, func, file, callback, user_data, error);
1216 g_object_unref (build_file);
1218 if (context == NULL)
1220 /* Restore previous configuration */
1221 build_configuration_list_select (plugin->configurations, old_config_name);
1223 else
1225 set_configuration_relative_target (plugin, relative_target);
1228 g_free (relative_target);
1230 return context;
1233 /* Run configure if needed and then the build command */
1234 BuildContext*
1235 build_configure_and_build (BasicAutotoolsPlugin *plugin, BuildFunc func, GFile *file, IAnjutaBuilderCallback callback, gpointer user_data, GError **error)
1237 if (!is_configured (plugin, file))
1239 /* Run configure first */
1240 return build_configure_dialog (plugin, func, file, callback, user_data, error);
1242 else
1244 /* Some build functions have less arguments but
1245 * it is not a problem in C */
1246 return func (plugin, file, callback, user_data, error);
1250 /* Configuration commands
1251 *---------------------------------------------------------------------------*/
1253 GList*
1254 build_list_configuration (BasicAutotoolsPlugin *plugin)
1256 BuildConfiguration *cfg;
1257 GList *list = NULL;
1259 for (cfg = build_configuration_list_get_first (plugin->configurations); cfg != NULL; cfg = build_configuration_next (cfg))
1261 const gchar *name = build_configuration_get_name (cfg);
1263 if (name != NULL) list = g_list_prepend (list, (gpointer)name);
1266 return list;
1269 const gchar*
1270 build_get_uri_configuration (BasicAutotoolsPlugin *plugin, const gchar *uri)
1272 BuildConfiguration *cfg;
1273 BuildConfiguration *uri_cfg = NULL;
1274 GFile *file = g_file_new_for_uri (uri);
1276 /* Check all configurations as other configuration directories are
1277 * normally child of default configuration directory */
1278 for (cfg = build_configuration_list_get_first (plugin->configurations); cfg != NULL; cfg = build_configuration_next (cfg))
1280 GFile *root = build_configuration_list_get_build_file (plugin->configurations, cfg);
1282 if ((root != NULL) && g_file_has_prefix (file, root)) uri_cfg = cfg;
1284 g_object_unref (file);
1286 return uri_cfg != NULL ? build_configuration_get_name (uri_cfg) : NULL;