aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/beaver-settings-page.c202
-rw-r--r--src/beaver-settings-page.h2
-rw-r--r--src/beaver-util.c203
-rw-r--r--src/beaver-util.h22
-rw-r--r--src/beaver.h3
-rw-r--r--src/plugin.c516
-rw-r--r--src/plugin.h8
7 files changed, 750 insertions, 206 deletions
diff --git a/src/beaver-settings-page.c b/src/beaver-settings-page.c
index be5f267..0594ec6 100644
--- a/src/beaver-settings-page.c
+++ b/src/beaver-settings-page.c
@@ -152,6 +152,129 @@ radio_toggled_cb (GtkToggleButton *toggle, gpointer userdata)
gtk_toggle_button_get_active (toggle));
}
+/* set_property is a must-to-have call back function used by
+ * Anjuta custom preference registration function for
+ * gtk combo_box component.
+ */
+static void
+set_property (AnjutaProperty *prop, const gchar *value)
+{
+ gchar* values;
+ gchar **vstr;
+ gint i;
+
+ /* AnjutaProperty data structure are protected and must use
+ * its own data field fetch utility functions
+ */
+ GtkWidget *combo_box = anjuta_property_get_widget(prop);
+
+ /* combo_box text values are changed/saved during create_ui,
+ * poky_mode changes, poky_root changes, poky_sdk changes. Its
+ * text values is saved and associated with the target combo_box
+ * component, so that the text values could be fetched and
+ * saved across different functions.
+ */
+ values = g_object_get_data(G_OBJECT(combo_box), OBJ_PROP_TARGET_ARCHS);
+
+ if (!values || strlen(values) <= 0)
+ return;
+
+ vstr = g_strsplit (values, ",", 0);
+ if (vstr)
+ {
+ for (i=0; vstr[i] != NULL; i++)
+ {
+ if (strcmp(value, vstr[i]) == 0)
+ {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), i);
+ break;
+ }
+ }
+ g_strfreev(vstr);
+ }
+}
+
+/* get_property is a must-to-have call back function used by
+ * Anjuta custom preference registration function for gtk
+ * combo_box compnent.
+ */
+static gchar*
+get_property(AnjutaProperty *prop)
+{
+ gchar *values;
+ gchar **vstr;
+ gchar *text_value = NULL;
+ gint idx;
+ GtkWidget *combo_box = anjuta_property_get_widget(prop);
+
+ values = g_object_get_data(G_OBJECT(combo_box), OBJ_PROP_TARGET_ARCHS);
+
+ if (!values || strlen(values) <= 0)
+ return text_value;
+
+ vstr = g_strsplit(values, ",", 0);
+
+ if (vstr)
+ {
+ idx = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
+ if (idx < 0)
+ idx = 0;
+
+ if (vstr[idx] != NULL)
+ text_value = g_strdup(vstr[idx]);
+
+ g_strfreev(vstr);
+ }
+
+ return text_value;
+}
+
+/* Note it's weird that this changed callback function is not implemented
+ * in anjuta preference framework, and property of preference is internal
+ * protected and can't be fetched outside anjuta preference code, so
+ * we have to repeat the implementation of get_property, it seems a little
+ * strange
+ */
+static void
+target_combo_changed (GtkWidget *widget, gpointer user_data)
+{
+ AnjutaPreferences *pr;
+ gchar *text_value = NULL;
+ gint idx;
+ gchar *values = NULL;
+ gchar** vstr;
+
+ pr = ANJUTA_PREFERENCES (g_object_get_data (G_OBJECT (widget),
+ "AnjutaPreferences"));
+ values = g_object_get_data(G_OBJECT(widget), OBJ_PROP_TARGET_ARCHS);
+ if (!values || strlen(values) <= 0)
+ {
+ anjuta_preferences_set (pr, PREFS_PROP_TRIPLET, NULL);
+ return;
+ }
+ vstr = g_strsplit(values, ",", 0);
+ if (vstr)
+ {
+ idx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
+ //if no items selected, select index 0 as default!
+ if (idx < 0)
+ idx = 0;
+ if (vstr[idx] != NULL)
+ text_value = g_strdup(vstr[idx]);
+ g_strfreev(vstr);
+ }
+
+ /* this combo_changed callback will be called before triplet_changed
+ * call back if the combo box text items or selected index have any
+ * changes. We need to update the new triplet value, so that
+ * triplet_changed could get correct new triplet. If the old selected
+ * text value equals the newly selected text value, then
+ * triplet_changed need not be called.
+ */
+ anjuta_preferences_set (pr, PREFS_PROP_TRIPLET, text_value);
+ g_free (text_value);
+}
+
static void
create_ui (BeaverSettingsPage *page)
{
@@ -176,9 +299,14 @@ create_ui (BeaverSettingsPage *page)
GtkWidget *qemu_radio;
GtkWidget *device_radio;
+ GtkWidget *target_combo;
+
gboolean res;
- gchar *filename = NULL;
+ gchar **vstr;
+ gchar *cur_target = NULL;
+ gchar *target_combo_value;
+ int i;
gtk_box_set_spacing (GTK_BOX (page), 6);
gtk_box_set_homogeneous (GTK_BOX (page), FALSE);
@@ -314,27 +442,75 @@ create_ui (BeaverSettingsPage *page)
gtk_box_pack_start (GTK_BOX (inner_vbox), inner_alignment, TRUE, FALSE, 0);
/* label */
- label = gtk_label_new (_("Toolchain triplet: "));
+ label = gtk_label_new (_("Target Architecture: "));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_size_group_add_widget (opts_labels_group, label);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
- /* entry */
- entry = gtk_entry_new ();
- gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
- gtk_size_group_add_widget (opts_fields_group, label);
+ /* available target architecture is stored in a combo_box */
+ target_combo = gtk_combo_box_entry_new_text();
+ gtk_box_pack_start (GTK_BOX(hbox), target_combo, TRUE, TRUE, 0);
+ gtk_size_group_add_widget (opts_fields_group, target_combo);
- /* register prop */
- res = anjuta_preferences_register_property_raw (priv->prefs,
- entry,
+ /* Note: we need to save target_combo box widget pointer in preferences
+ * So event change callback functions outside the UI could get the pointer
+ * and update the combo box related values */
+ g_object_set_data(G_OBJECT(priv->prefs), PREFS_PROP_TARGET_COMBO,
+ target_combo);
+
+ /* Get target arch values from preferences storage, since it's updated
+ * by several actions. And also, previous launching values are saved in
+ * this preference storaget too so that users could save this setting */
+ target_combo_value = anjuta_preferences_get(priv->prefs,
+ PREFS_PROP_TARGET_ARCHS);
+
+ /* Save target arch values and made it associated with combo box, since
+ * get or set combo box property need to use it.*/
+ g_object_set_data(G_OBJECT(target_combo), OBJ_PROP_TARGET_ARCHS,
+ target_combo_value);
+
+ cur_target = anjuta_preferences_get (priv->prefs, PREFS_PROP_TRIPLET);
+
+ g_debug("CUR arch %s of %s when create_ui", cur_target, target_combo_value);
+
+ /* Fill the combo box values according to the available architectures
+ * under current UI selections
+ */
+
+ if (target_combo_value)
+ {
+ vstr = g_strsplit (target_combo_value, ",", 0);
+ if (vstr)
+ {
+ for (i = 0; vstr[i]; i++) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX(target_combo), vstr[i]);
+ if (cur_target && strcmp(cur_target, vstr[i]) == 0)
+ gtk_combo_box_set_active(GTK_COMBO_BOX(target_combo), i);
+ }
+ }
+ g_strfreev (vstr);
+ }
+
+ res = anjuta_preferences_register_property_custom (priv->prefs,
+ target_combo,
PREFS_PROP_TRIPLET,
- NULL,
+ target_combo_value,
0,
- ANJUTA_PROPERTY_OBJECT_TYPE_ENTRY,
- ANJUTA_PROPERTY_DATA_TYPE_TEXT);
+ ANJUTA_PROPERTY_DATA_TYPE_TEXT,
+ set_property,
+ get_property);
if (!res)
- g_warning ("Error adding preference for triplet");
+ g_warning ("Error while adding preference for target triplet");
+
+ /* It's weird that below combo box changed callback registration function
+ * is missing in custom style registration. We need to add it so that when
+ * combo box selection or text changed, we can updated related triplet
+ * in the preference storage
+ */
+
+ g_signal_connect(G_OBJECT(target_combo), "changed",
+ G_CALLBACK(target_combo_changed), NULL);
/* Frame for target */
frame = gtk_frame_new (_("<b>Target Options</b>"));
diff --git a/src/beaver-settings-page.h b/src/beaver-settings-page.h
index 3cced69..b938901 100644
--- a/src/beaver-settings-page.h
+++ b/src/beaver-settings-page.h
@@ -21,6 +21,7 @@
#include <glib-object.h>
#include <gtk/gtk.h>
#include <libanjuta/anjuta-shell.h>
+#include <libanjuta/anjuta-preferences.h>
G_BEGIN_DECLS
@@ -60,4 +61,5 @@ GtkWidget *beaver_settings_page_new (AnjutaShell *shell);
G_END_DECLS
+
#endif /* _BEAVER_SETTINGS_PAGE */
diff --git a/src/beaver-util.c b/src/beaver-util.c
index 96401b9..0461359 100644
--- a/src/beaver-util.c
+++ b/src/beaver-util.c
@@ -106,3 +106,206 @@ beaver_util_strv_joinv (gchar **strv_1, ...)
return res;
}
+
+
+/* Fetch supported target platforms by searching the environment-setup-XXX
+ * files under poky_sdk_root or poky_tree tmpdir directories. it returns
+ * a newly allocated char array which is needed to be freed if caller does
+ * not use it anymore
+ */
+gchar *
+beaver_util_get_archs(gchar *directory)
+{
+ DIR *dirp;
+ struct dirent *entry;
+ gchar *temp = NULL;
+ gchar *support_arch_string = NULL;
+ gchar *archname = NULL;
+
+ errno = 0;//clear errno for catching errors
+ dirp = opendir(directory);
+ if (errno || !dirp)
+ {
+ g_warning("Error while trying to open directory %s: %s!", directory,
+ g_strerror(errno));
+ return NULL;
+ }
+//reset for logging errors
+ errno = 0;
+ while(entry = readdir(dirp))
+ {
+ if (errno)
+ {
+ g_warning("Error while trying to read directory: %s!", g_strerror(errno));
+ goto end;
+ }
+ if (entry->d_type != DT_REG)
+ continue;
+ archname = entry->d_name;
+ /* parse the valid environment script files, all valid platform names
+ * will be connected together with ,
+ */
+ if (g_str_has_prefix(archname, ENV_SCRIPT_FILE_PREFIX))
+ {
+ temp = support_arch_string;
+ if (temp)
+ support_arch_string = g_strconcat(temp, "," , archname + strlen(ENV_SCRIPT_FILE_PREFIX), NULL);
+ else
+ support_arch_string = g_strdup(archname + strlen(ENV_SCRIPT_FILE_PREFIX));
+ g_free(temp);
+ }
+
+ }
+ g_debug("Get supported arch strings %s", support_arch_string);
+end:
+ closedir(dirp);
+ return support_arch_string;
+}
+
+/* when target platform selection changes and if we get valid
+ * corresponding environment script file, we need to update the
+ * ENV storage hash table. Remember, before the first time
+ * updating the environment settings, we need to keep the old
+ * original settings for the conveniences of switching back
+ * the old environment settings before activating this anjuta poky
+ * SDK plugin
+ * Plese Note: This is only a limited parser, if newer script
+ * shell grammar is used, we should be very careful!
+ */
+void
+update_env_hash(gchar *filename, GHashTable *hash_configs,
+ GHashTable **old_hash_configs)
+{
+ FILE *fp;
+ gchar buf[MAX_CONFIG_LENGTH], temp[MAX_CONFIG_LENGTH], value[MAX_CONFIG_LENGTH];
+ gchar *ret_buf, *key;
+ gint i = 0;
+ gboolean save = FALSE;
+ const gchar *env_value;
+
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ {
+ g_warning("Error while opening config file %s!", filename);
+ return;
+ }
+
+ /* the old environment settings are saved into one hash table.
+ * It only needs save once after the poky SDK is activated */
+ if (*old_hash_configs)
+ save = FALSE;
+ else
+ {
+ *old_hash_configs = g_hash_table_new_full
+ (g_str_hash, g_str_equal, g_free, g_free);
+ save = TRUE;
+ }
+
+ while (!feof(fp))
+ {
+ memset(value, 0, MAX_CONFIG_LENGTH);
+ ret_buf = fgets(buf, MAX_CONFIG_LENGTH, fp);
+ if (ret_buf)
+ {
+ //This is the mark of shell script, skip it for convenience!
+ //Otherwise, if user modify scripts, it will be wrong
+ ret_buf = g_strstrip(ret_buf);
+ if (g_str_has_prefix(ret_buf, "#"))
+ continue;
+ if (g_str_has_prefix(ret_buf, "export"))
+ {
+ ret_buf += strlen("export");
+ ret_buf = g_strstrip(ret_buf);
+
+ i = 0;
+ while(ret_buf && (*ret_buf != '='))
+ temp[i++] = *(ret_buf++);
+ temp[i] = '\0';
+ key = g_strdup(temp);
+ key = g_strstrip(key);
+ ret_buf = g_strstrip(ret_buf);
+ while(ret_buf && (*ret_buf == '=' || *ret_buf == '"' ||
+ *ret_buf == '\''))
+ ret_buf++;
+ //we need very carefully deal with special chars...
+ //currently we did it manually. Maybe those special
+ //keys need more processing
+ i = 0;
+ while(ret_buf && (*ret_buf != '"') && (*ret_buf != '\n') &&
+ (*ret_buf != '\r') && (*ret_buf != '\''))
+ value[i++] = *(ret_buf++);
+ value[i] = '\0';
+ g_debug("NEW ENV key %s, val %s, len %d", key, value, strlen(value));
+ /* Please note that hash table key and value must use g_free
+ * destroyer since it used dynamic allocation mechanism, so
+ * that we defined g_free in the g_new_hash_table_full create function
+ */
+ g_hash_table_insert(hash_configs, key, g_strstrip(g_strdup(value)));
+ /* Note: if the old environment variables have never been saved before,
+ * we will save the old env vars to the hash table for later
+ * environment variables restore usage
+ */
+ if (save)
+ {
+ env_value = g_getenv (key);
+ g_debug("Save old ENV: key %s value %s", key, env_value);
+ if (env_value)
+ g_hash_table_insert(*old_hash_configs, g_strdup(key), g_strdup(env_value));
+ }
+ }
+ }
+ }
+ fclose(fp);
+}
+
+/* update_combo_box need to be called when poky mode
+ * selection radio changes, sdk_root directory changes
+ * and poky_root directory changes. It updates the combo
+ * box text items according to the changed directory
+ * environment-setupXXX files.*/
+
+void
+update_combo_box(GtkWidget *p_combo_box, gchar *target_archs)
+{
+ GtkTreeModel *model;
+ gint count, i;
+ gchar **vstr, *active_text;
+
+ if (!p_combo_box)
+ {
+ g_warning("Error while fetching combo_box widget!");
+ return;
+ }
+
+ model = gtk_combo_box_get_model(GTK_COMBO_BOX(p_combo_box));
+ count = gtk_tree_model_iter_n_children(model, NULL);
+
+ //Firstly remove all old text items in the combo_box
+ for(i = count - 1; i >= 0; i--)
+ gtk_combo_box_remove_text(GTK_COMBO_BOX(p_combo_box), i);
+
+ if (!target_archs || strlen(target_archs) <= 0)
+ {
+ gtk_widget_set_sensitive(p_combo_box, FALSE);
+ return;
+ }
+ else {
+ vstr = g_strsplit (target_archs, ",", 0);
+
+ if (vstr)
+ {
+ active_text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(p_combo_box));
+ for (i = 0; vstr[i]; i++)
+ {
+ gtk_combo_box_append_text (GTK_COMBO_BOX(p_combo_box), vstr[i]);
+ //set back old valid selected text for better user experiences
+ if (strcmp(vstr[i], active_text) == 0)
+ gtk_combo_box_set_active(GTK_COMBO_BOX(p_combo_box), i);
+ }
+ gtk_widget_set_sensitive(p_combo_box, TRUE);
+ g_free(active_text);
+ }
+ g_strfreev (vstr);
+ }
+}
diff --git a/src/beaver-util.h b/src/beaver-util.h
index a7c8a61..1cee3d1 100644
--- a/src/beaver-util.h
+++ b/src/beaver-util.h
@@ -21,22 +21,26 @@
#include <config.h>
#include <glib-object.h>
+#include <dirent.h>
+#include <errno.h>
+
#include <libanjuta/libanjuta.h>
#include <libanjuta/interfaces/ianjuta-message-manager.h>
+#define MAX_CONFIG_LENGTH 1000
+#define ENV_SCRIPT_FILE_PREFIX "environment-setup-"
+
void beaver_util_message_view_buffer_flushed_cb (IAnjutaMessageView *view,
gchar *data, gpointer userdata);
gchar **beaver_util_strv_concat (gchar **strv_1, gchar **strv_2);
gchar **beaver_util_strv_joinv (gchar **strv_1, ...);
-#ifdef ANJUTA_CHECK_VERSION
-#if LIBANJUTA_MAJOR_VERSION >= 2 && LIBANJUTA_MINOR_VERSION >= 23
-#if LIBANJUTA_MINOR_VERSION >= 28
-#define ANJUTA_2_28_OR_HIGHER
-#else
-#define ANJUTA_2_23_TO_26
-#endif
-#endif
-#endif
+gchar *beaver_util_get_archs(gchar *directory);
+GHashTable *beaver_util_get_configs(gchar *filename);
+gchar *get_host_triplet(gchar *env_file);
+
+void update_env_hash(gchar *filename, GHashTable *hash_configs,
+ GHashTable **old_hash_configs);
+void update_combo_box(GtkWidget *combo_box, gchar *value);
#endif /* _BEAVER_UTIL */
diff --git a/src/beaver.h b/src/beaver.h
index afa8df9..f5c98af 100644
--- a/src/beaver.h
+++ b/src/beaver.h
@@ -32,5 +32,8 @@
#define PREFS_PROP_ROOTFS "sdk.rootfs"
#define PREFS_PROP_TARGET_IP "sdk.target_ip"
#define PREFS_PROP_TARGET_MODE "sdk.target_mode"
+#define PREFS_PROP_TARGET_ARCHS "sdk.target_archs"
+#define PREFS_PROP_TARGET_COMBO "sdk.target_combo_box"
+#define OBJ_PROP_TARGET_ARCHS "available_archs"
#endif /* _BEAVER */
diff --git a/src/plugin.c b/src/plugin.c
index 3b2e54f..576fa0e 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -45,7 +45,7 @@
#define CONFIGURE_COMMAND "/configure"
#define AUTOGEN_COMMAND "/autogen.sh"
-#define CROSS_COMMAND "--host=%s"
+#define CROSS_COMMAND "CONFIGURE_FLAGS"
#define DEPLOY_COMMAND "rsync " \
"-e 'ssh -o \"CheckHostIP no\" " \
@@ -55,11 +55,14 @@
#define LOCAL_GDB_COMMAND "%s-gdb -x %s %s"
-#define GDB_SCRIPT "set solib-absolute-prefix %s\n" \
+#define GDB_SCRIPT "set solib-search-path %s\n" \
"target remote %s:2345\n"
#define OPROFILEUI_COMMAND "oprofile-viewer -h %s -s %s"
+#define SYSROOT "sysroots"
+#define TMPDIR "tmp/"
+
static gpointer anjuta_plugin_sdk_parent_class;
/* Callback prototypes needed for actions */
@@ -709,7 +712,8 @@ do_local_gdb (AnjutaPluginSdk *sp)
gchar *cmd = NULL;
GError *error = NULL;
gchar *cur_dir = NULL;
- gchar *gdb_prefix = NULL;
+ gchar *gdb_path = NULL;
+ const gchar* env_value;
/*
* create a temporary files and write the client side gdb commands to it,
@@ -723,10 +727,18 @@ do_local_gdb (AnjutaPluginSdk *sp)
return;
}
- gdb_prefix = g_build_filename (sp->sdk_root, sp->triplet, NULL);
- script_contents = g_strdup_printf (GDB_SCRIPT, gdb_prefix,
+ //we use search path here according to latest SDK structure changes.
+ //path is extracted from environment settings PATH! And, ':' should be replaced
+ //with ';'
+ env_value = g_getenv ("PATH");
+ gdb_path = g_strdup(env_value);
+ gdb_path = g_strdelimit(gdb_path, ":", ';');
+
+ script_contents = g_strdup_printf (GDB_SCRIPT, gdb_path,
beaver_target_get_ip_address (sp->target));
+ g_debug("gdb search path %s\n", script_contents);
+
channel = g_io_channel_unix_new (fd);
status = g_io_channel_write_chars (channel, script_contents, -1, NULL, &error);
@@ -747,7 +759,7 @@ do_local_gdb (AnjutaPluginSdk *sp)
g_io_channel_unref (channel);
g_free (script_contents);
- g_free (gdb_prefix);
+ g_free (gdb_path);
terminal = anjuta_shell_get_interface (ANJUTA_PLUGIN (sp)->shell,
IAnjutaTerminal, &error);
@@ -760,7 +772,7 @@ do_local_gdb (AnjutaPluginSdk *sp)
return;
}
- cmd = g_strdup_printf (LOCAL_GDB_COMMAND, sp->triplet,
+ cmd = g_strdup_printf (LOCAL_GDB_COMMAND, sp->target_triplet,
script_name, sp->gdb_local_path);
cur_dir = g_get_current_dir ();
child_pid = ianjuta_terminal_execute_command (terminal, cur_dir, cmd,
@@ -771,7 +783,7 @@ do_local_gdb (AnjutaPluginSdk *sp)
* compatibility
*/
if (child_pid < 0)
- g_warning("Error happned while launching local gdb command\n");
+ g_warning("Error happened while launching local gdb command\n");
else if (error != NULL)
{
g_warning ("Error whilst launching local gdb command: %s", error->message);
@@ -865,6 +877,7 @@ action_remote_profile_activate_cb (GtkAction *action, gpointer userdata)
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata;
gchar *cmd = NULL;
gchar *search_path = NULL;
+ const gchar *env_value;
if (!sp->oprofileui_launcher)
{
@@ -873,7 +886,13 @@ action_remote_profile_activate_cb (GtkAction *action, gpointer userdata)
(GCallback)oprofileui_launcher_child_exited_cb, sp);
}
- search_path = g_build_filename (sp->sdk_root, sp->triplet, NULL);
+ //we use search path here according to latest SDK structure changes.
+ //path is extracted from environment settings PATH! And, ':' should be replaced
+ //with ';'
+ env_value = g_getenv ("PATH");
+ search_path = g_strdup(env_value);
+ search_path = g_strdelimit(search_path, ":", ';');
+
cmd = g_strdup_printf (OPROFILEUI_COMMAND,
beaver_target_get_ip_address (sp->target),
search_path);
@@ -906,7 +925,9 @@ remote_gdb_launcher_child_exited_cb (AnjutaLauncher *launcher, gint child_pid,
{
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata;
- if (sp->triplet && sp->sdk_root &&
+ if (sp->target_triplet &&
+ ((sp->poky_mode == POKY_MODE_TOOLCHAIN && sp->sdk_root) ||
+ (sp->poky_mode == POKY_MODE_FULL && sp->poky_root)) &&
beaver_target_get_state (sp->target) == TARGET_STATE_READY)
{
gtk_action_set_sensitive (sp->remote_debug_action, TRUE);
@@ -947,133 +968,165 @@ message_view_buffer_flushed_cb (IAnjutaMessageView *view, gchar *data,
data, "", NULL);
}
-static gchar *
-get_host_component ()
+/* When new environment variables to be set are stored,
+ * we need to set each one saved in the hash table. Note
+ * one special thing: PATH need to be merged with the old
+ * PATH, otherwise, all useful system paths will be lost!
+ */
+static void
+set_new_env(GHashTable *old_hash_configs, GHashTable *hash_configs)
{
- struct utsname res;
- gchar *os = NULL;
- gchar *host_component = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+ gchar *temp, *oldpath, *newpath;
+ size_t length;
+ const gchar *env_value;
- uname (&res);
- os = g_ascii_strdown (res.sysname, -1);
- host_component = g_strdup_printf("%s-%s", res.machine, os);
+ if (!hash_configs)
+ {
+ g_warning("ERROR while set new environment variables,"
+ "to be set variables are NULL!");
+ return;
+ }
+ if (!old_hash_configs)
+ {
+ g_warning("ERROR while set new environment variables,"
+ "old environment hash table can't be NULL");
+ return;
+ }
- g_free (os);
+ g_hash_table_iter_init (&iter, hash_configs);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ /* do something with key and value */
+ if (key)
+ {
+ /* Do something special for $PATH, we need to
+ * merge the old path before setting the new path!
+ */
+ if (strcmp(key, "PATH") == 0)
+ {
+ temp = g_strrstr((gchar *)value, "$PATH");
+ if (!temp)
+ length = (size_t)(strlen((gchar *)value));
+ else
+ length = (size_t)(strlen((gchar *)value) - strlen(temp));
+ oldpath = (gchar *)g_hash_table_lookup(old_hash_configs, key);
+ if(oldpath && temp)
+ {
+ temp = g_strndup((gchar *)value, length);
+ newpath = g_strconcat(temp, oldpath, NULL);\
+ g_setenv((gchar*)key, newpath, 1);
+ g_debug("SET ENV key %s, value %s", (gchar*)key, (gchar*)newpath);
+ g_free(newpath);
+ g_free(temp);
+ }
+ else
+ g_setenv((gchar*)key, (gchar*)value, 1);
+ }
+ else
+ {
+ g_setenv((gchar*)key, (gchar*)value, 1);
+ g_debug("SET ENV key %s, value %s", (gchar*)key, (gchar*)value);
+ }
- return host_component;
+ }
+ }
}
-/* Update the path to remove or include our sdk bin directory */
-static void
+/* First retrieves new environment variables from the
+ * configuration files, save it to the hash table and
+ * then iterate the hash table and set each of the new
+ * environment variable */
+void
update_path (AnjutaPluginSdk *sp)
{
- const gchar *path;
- gchar *new_path_component = NULL;
- GArray *path_array = NULL;
- char **pathv = NULL;
- int i = 0;
- gchar *poky_scripts_dir = NULL;
- gchar *poky_host_sysroots_bin_dir = NULL;
- gchar *poky_host_sysroots_usr_bin_dir = NULL;
- gchar *host_component = NULL;
-
- /* Create new versions of path bits */
- if (sp->poky_mode == POKY_MODE_TOOLCHAIN)
- {
- if (sp->triplet != NULL && sp->sdk_root != NULL)
- new_path_component = g_build_filename (sp->sdk_root, "bin", NULL);
- } else {
- if (sp->poky_root)
- {
- host_component = get_host_component ();
- poky_scripts_dir = g_build_filename (sp->poky_root, "scripts", NULL);
- poky_host_sysroots_usr_bin_dir = g_build_filename (sp->poky_root, "build", "tmp",
- "sysroots", host_component, "usr", "bin", NULL);
- poky_host_sysroots_bin_dir = g_build_filename (sp->poky_root, "build", "tmp",
- "sysroots", host_component, "bin", NULL);
- g_free (host_component);
- }
- }
-
- /* get current path. do not free */
- path = g_getenv ("PATH");
-
- /* split old path up */
- pathv = g_strsplit (path, ":", -1);
+ gchar *temp, *config_filename;
+
+ temp = g_strconcat(ENV_SCRIPT_FILE_PREFIX, sp->target_triplet, NULL);
+
+ if ((sp->poky_mode == POKY_MODE_TOOLCHAIN) &&
+ sp->target_triplet && sp->sdk_root)
+ config_filename = g_build_filename (sp->sdk_root,temp, NULL);
+ else if ((sp->poky_mode == POKY_MODE_FULL) && sp->poky_root)
+ config_filename = g_build_filename(sp->poky_root, TMPDIR, temp, NULL);
+
+ g_debug("read ENV script, filename %s", config_filename);
+ update_env_hash(config_filename, sp->env_hash, &sp->old_env_hash);
+ g_debug("Set new ENV according to script file!");
+ set_new_env(sp->old_env_hash, sp->env_hash);
+ g_free(temp);
+ g_free(config_filename);
+}
- /* Convert it into a GArray */
- path_array = g_array_sized_new (TRUE, FALSE, sizeof (gchar *),
- g_strv_length (pathv));
- path_array = g_array_insert_vals (path_array, 0, pathv,
- g_strv_length (pathv));
+/* Before restore the environment variables to the
+ * old one before running poky SDK plugins, we need
+ * to unset some newly set environment variables.
+ * PATH need not to be unset since it must exist
+ */
+static void
+unset_env(GHashTable *old_hash_configs)
+{
+ GHashTableIter iter;
+ gpointer key, value;
- /* Remove old versions */
- for (i = 0; i < path_array->len; i++)
+ if (!old_hash_configs || g_hash_table_size (old_hash_configs) <= 0)
{
- gchar *tmp = g_array_index (path_array, gchar *, i);
-
- if ((sp->path_component && g_str_equal (tmp, sp->path_component)) ||
- (sp->poky_scripts_dir && g_str_equal (tmp, sp->poky_scripts_dir)) ||
- (sp->poky_host_sysroots_bin_dir
- && g_str_equal (tmp, sp->poky_host_sysroots_bin_dir)) ||
- (sp->poky_host_sysroots_usr_bin_dir
- && g_str_equal (tmp, sp->poky_host_sysroots_usr_bin_dir)))
- {
- path_array = g_array_remove_index (path_array, i);
- i--; /* because we've deleted something */
- }
+ g_warning("Error while trying to unset environment variables"
+ "old config hash table can't be NULL!");
+ return;
}
- if (sp->poky_mode == POKY_MODE_TOOLCHAIN)
+ g_hash_table_iter_init (&iter, old_hash_configs);
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- /* Add the new path component */
- if (new_path_component)
- path_array = g_array_prepend_val (path_array, new_path_component);
- } else {
- if (poky_scripts_dir)
- path_array = g_array_prepend_val (path_array, poky_scripts_dir);
-
- if (poky_host_sysroots_bin_dir)
- path_array = g_array_prepend_val (path_array, poky_host_sysroots_bin_dir);
-
- if (poky_host_sysroots_usr_bin_dir)
- path_array = g_array_prepend_val (path_array, poky_host_sysroots_usr_bin_dir);
+ /* PATH is always needed */
+ if (key && (strcmp(key, "PATH") != 0))
+ g_unsetenv((gchar*)key);
}
-
- /* Create our new path */
- path = g_strjoinv (":", (gchar **)path_array->data);
- setenv ("PATH", path, 1);
-
- /* Save the components */
- g_free (sp->path_component);
- g_free (sp->poky_scripts_dir);
- g_free (sp->poky_host_sysroots_bin_dir);
- g_free (sp->poky_host_sysroots_usr_bin_dir);
-
- sp->path_component = new_path_component;
- sp->poky_scripts_dir = poky_scripts_dir;
- sp->poky_host_sysroots_bin_dir = poky_host_sysroots_bin_dir;
- sp->poky_host_sysroots_usr_bin_dir = poky_host_sysroots_usr_bin_dir;
-
- g_array_free (path_array, TRUE);
- g_strfreev (pathv);
}
-/*
- * Add/remove/update the environment to reflect changes to the sdk root or
- * triplet
+/* Restore old envrionment variable settings before running
+ * Poky SDK plugin, if anjuta is launching another anjuta
+ * as its sub process, something might be very tricky, yet
+ * seems we have no good solution here. For avoid obvious
+ * mistake, I only restore PATH although all other keys/values
+ * are actually saved for later use.
*/
-static void
cleanup_environment (AnjutaPluginSdk *sp)
{
- update_path (sp);
-
- /* unset environment keys */
- unsetenv ("PKG_CONFIG_SYSROOT_DIR");
- unsetenv ("PKG_CONFIG_PATH");
- unsetenv ("CONFIG_SITE");
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (!sp->old_env_hash || g_hash_table_size (sp->old_env_hash) <= 0)
+ {
+ g_warning("Error while restore ENV: No backup ENV hash created!");
+ return;
+ }
+
+ unset_env(sp->old_env_hash);
+
+ //Note: If anjuta is creating a new project, it is a sub-process.
+ //we might have problem here since the old environment is set-up
+ //by its parent anjuta poky plugin. So that we can only set up
+ //$PATH here for avoid mistakes. Yet I have to say this is not a good
+ //solution since users might set CC, CXXFLAGS...
+ g_hash_table_iter_init (&iter, sp->old_env_hash);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ /* Restore old environment variables */
+ if (key && (strcmp(key, "PATH") == 0))
+ {
+ g_setenv((gchar*)key, (gchar*)value, 1);
+ g_debug("Restore ENV key %s, value %s", (gchar*)key, (gchar*)value);
+ }
+ }
}
+/* When get new valid environment variable settings, set new
+ * env. Otherwise, switch back to the old environment setting
+ * before running Poky SDK Plugin!
+ */
static void
update_environment (AnjutaPluginSdk *sp)
{
@@ -1081,55 +1134,16 @@ update_environment (AnjutaPluginSdk *sp)
gchar *pkg_config_usr_path = NULL;
gchar *pkg_config_path = NULL;
-
- if (sp->triplet == NULL ||
- (sp->poky_mode == POKY_MODE_TOOLCHAIN && sp->sdk_root == NULL) ||
- (sp->poky_mode == POKY_MODE_FULL && sp->poky_root == NULL))
+ if (!sp->target_triplet ||
+ (sp->poky_mode == POKY_MODE_TOOLCHAIN && !sp->sdk_root) ||
+ (sp->poky_mode == POKY_MODE_FULL && !sp->poky_root))
{
+ g_warning("No valid poky environment settings, restore old ENV!");
cleanup_environment (sp);
return;
}
-
+ cleanup_environment (sp);
update_path (sp);
-
- if (sp->poky_mode == POKY_MODE_TOOLCHAIN)
- {
- tmp = g_build_filename (sp->sdk_root, sp->triplet, NULL);
- setenv ("PKG_CONFIG_SYSROOT_DIR", tmp, 1);
- g_free (tmp);
-
- pkg_config_path = g_build_filename (sp->sdk_root, sp->triplet, "lib",
- "pkgconfig", NULL);
- pkg_config_usr_path = g_build_filename (sp->sdk_root, sp->triplet, "usr",
- "lib", "pkgconfig", NULL);
- tmp = g_strdup_printf ("%s:%s", pkg_config_usr_path, pkg_config_path);
-
- setenv ("PKG_CONFIG_PATH", tmp, 1);
- g_free (pkg_config_path);
- g_free (pkg_config_usr_path);
- g_free (tmp);
-
- tmp = g_build_filename (sp->sdk_root, "site-config", NULL);
- setenv ("CONFIG_SITE", tmp, 1);
- g_free (tmp);
- } else {
- tmp = g_build_filename (sp->poky_root, "build", "tmp", "staging",
- sp->triplet, NULL);
- setenv ("PKG_CONFIG_SYSROOT_DIR", tmp, 1);
- g_free (tmp);
-
- pkg_config_usr_path = g_build_filename (sp->poky_root, "build", "tmp",
- "staging", sp->triplet, "usr", "lib", "pkgconfig", NULL);
- pkg_config_path = g_build_filename (sp->poky_root, "build", "tmp",
- "staging", sp->triplet, "lib", "pkgconfig", NULL);
- tmp = g_strdup_printf ("%s:%s", pkg_config_usr_path, pkg_config_path);
- setenv ("PKG_CONFIG_PATH", tmp, 1);
- g_free (pkg_config_path);
- g_free (pkg_config_usr_path);
- g_free (tmp);
-
- unsetenv ("CONFIG_SITE");
- }
}
static void
@@ -1259,28 +1273,71 @@ setup_target (AnjutaPluginSdk *sp)
update_state (sp);
}
+/* GtkWidget combo_box is weird since we can't clear existing
+ * text even if the text items below are all removed and the
+ * active text is actually out-of-date. So sometimes, Anjuta
+ * preference can't sense the text property changes. We need
+ * to manually call the triplet text change callback at the
+ * needed point.
+ * The main task of this callback is to update plugin's target
+ * and host triplet
+ */
+static void
+triplet_changed(AnjutaPluginSdk *sp)
+{
+
+ g_free (sp->target_triplet);
+ sp->target_triplet = NULL;
+
+ sp->target_triplet = anjuta_preferences_get (sp->prefs, PREFS_PROP_TRIPLET);
+ g_debug("New target triplet %s!", sp->target_triplet);
+
+ if (!sp->target_triplet)
+ return;
+
+ /* A NULL value set into anjuta perference will be returned as
+ * empty string */
+ if (strlen(sp->target_triplet) <=0)
+ {
+ sp->target_triplet = NULL;
+ return;
+ }
+}
+
static void
sdk_root_preference_notify_cb (AnjutaPreferences *pref, const gchar *key,
const gchar *value, gpointer userdata)
{
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata;
+ GtkWidget *target_combo;
g_free (sp->sdk_root);
sp->sdk_root = anjuta_preferences_get (sp->prefs, PREFS_PROP_SDK_ROOT);
+ //update target_combo show items
+ g_free(sp->target_archs);
+ sp->target_archs = beaver_util_get_archs(sp->sdk_root);
+ anjuta_preferences_set(pref, PREFS_PROP_TARGET_ARCHS, sp->target_archs);
+
+ target_combo = (GtkWidget *)g_object_get_data(G_OBJECT(pref), PREFS_PROP_TARGET_COMBO);
+ g_object_set_data(G_OBJECT(target_combo), OBJ_PROP_TARGET_ARCHS, sp->target_archs);
+
+ update_combo_box(target_combo, sp->target_archs);
+ triplet_changed(sp);
update_environment (sp);
+
}
+
+
static void
triplet_preference_notify_cb (AnjutaPreferences *pref, const gchar *key,
const gchar *value, gpointer userdata)
{
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata;
-
- g_free (sp->triplet);
- sp->triplet = anjuta_preferences_get (sp->prefs, PREFS_PROP_TRIPLET);
-
+ triplet_changed(sp);
update_environment (sp);
+
}
static void
@@ -1318,10 +1375,29 @@ poky_mode_preference_notify_cb (AnjutaPreferences *pref, const gchar *key,
const gboolean value, gpointer userdata)
{
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata;
+ GtkWidget *target_combo;
+ gchar *dir;
sp->poky_mode = anjuta_preferences_get_bool (sp->prefs, PREFS_PROP_POKY_MODE);
+ g_free(sp->target_archs);
+ if (sp->poky_mode == POKY_MODE_TOOLCHAIN && sp->sdk_root != NULL)
+ sp->target_archs = beaver_util_get_archs(sp->sdk_root);
+ else if (sp->poky_mode == POKY_MODE_FULL && sp->poky_root != NULL)
+ {
+ dir = g_build_filename(sp->poky_root, TMPDIR, NULL);
+ sp->target_archs = beaver_util_get_archs(dir);
+ g_free(dir);
+ }
+ anjuta_preferences_set(pref, PREFS_PROP_TARGET_ARCHS, sp->target_archs);
+
+ target_combo = (GtkWidget *)g_object_get_data(G_OBJECT(pref), PREFS_PROP_TARGET_COMBO);
+ g_object_set_data(G_OBJECT(target_combo), OBJ_PROP_TARGET_ARCHS, sp->target_archs);
+
+ update_combo_box(target_combo, sp->target_archs);
+ triplet_changed(sp);
update_environment (sp);
+
}
static void
@@ -1329,11 +1405,22 @@ poky_root_preference_notify_cb (AnjutaPreferences *pref, const gchar *key,
const gchar *value, gpointer userdata)
{
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)userdata;
+ GtkWidget *target_combo;
g_free (sp->poky_root);
sp->poky_root = anjuta_preferences_get (sp->prefs, PREFS_PROP_POKY_ROOT);
+ g_free(sp->target_archs);
+ sp->target_archs = beaver_util_get_archs(sp->poky_root);
+
+ anjuta_preferences_set(pref, PREFS_PROP_TARGET_ARCHS, sp->target_archs);
+ target_combo = (GtkWidget *)g_object_get_data(G_OBJECT(pref), PREFS_PROP_TARGET_COMBO);
+ g_object_set_data(G_OBJECT(target_combo), OBJ_PROP_TARGET_ARCHS, sp->target_archs);
+
+ update_combo_box(target_combo, sp->target_archs);
+ triplet_changed(sp);
update_environment (sp);
+
}
static void
@@ -1437,7 +1524,11 @@ anjuta_plugin_sdk_activate (AnjutaPlugin *plugin)
GError *error = NULL;
gchar *kernel = NULL;
gchar *rootfs = NULL;
+ gchar *env_filename = NULL;
+ gchar *temp = NULL;
+
+ g_debug("Activate poky SDK plugin");
ui = anjuta_shell_get_ui (ANJUTA_PLUGIN (plugin)->shell, NULL);
sp->action_group = anjuta_ui_add_action_group_entries (ui, "ActionGroupSdk",
@@ -1502,7 +1593,8 @@ anjuta_plugin_sdk_activate (AnjutaPlugin *plugin)
PREFS_PROP_TARGET_IP, target_ip_preference_notify_cb, sp, NULL);
sp->sdk_root = anjuta_preferences_get (sp->prefs, PREFS_PROP_SDK_ROOT);
- sp->triplet = anjuta_preferences_get (sp->prefs, PREFS_PROP_TRIPLET);
+
+ sp->target_triplet = anjuta_preferences_get (sp->prefs, PREFS_PROP_TRIPLET);
sp->poky_root = anjuta_preferences_get (sp->prefs, PREFS_PROP_POKY_ROOT);
@@ -1510,6 +1602,26 @@ anjuta_plugin_sdk_activate (AnjutaPlugin *plugin)
sp->target_mode = anjuta_preferences_get_bool (sp->prefs, PREFS_PROP_TARGET_MODE);
setup_target (sp);
+
+ /* key and value must be freed when destroy the hash table
+ * since they are both dynamically allocated when parsing
+ * config files!
+ */
+
+ sp->env_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+ if (sp->poky_mode == POKY_MODE_TOOLCHAIN && sp->sdk_root != NULL)
+ sp->target_archs = beaver_util_get_archs(sp->sdk_root);
+ else if (sp->poky_mode == POKY_MODE_FULL && sp->poky_root != NULL)
+ {
+ temp = g_build_filename(sp->poky_root, TMPDIR, NULL);
+ sp->target_archs = beaver_util_get_archs(temp);
+ g_free(temp);
+ }
+
+ g_debug("When activate, architecture is %s", sp->target_archs);
+ anjuta_preferences_set(sp->prefs, PREFS_PROP_TARGET_ARCHS, sp->target_archs);
+
update_environment (sp);
sp->project_root_uri_watch = anjuta_plugin_add_watch (plugin,
@@ -1534,6 +1646,7 @@ anjuta_plugin_sdk_deactivate (AnjutaPlugin *plugin)
GError *error = NULL;
IAnjutaMessageManager *msg_manager = NULL;
+ g_warning("begin deactivate!");
cleanup_environment (sp);
ui = anjuta_shell_get_ui (plugin->shell, NULL);
@@ -1620,31 +1733,37 @@ anjuta_plugin_sdk_deactivate (AnjutaPlugin *plugin)
sp->target = NULL;
}
+
/*
* Must set these to NULL because the plugin object might get reused after
* deactivation.
*/
-
g_free (sp->sdk_root);
- g_free (sp->triplet);
+ g_free (sp->target_triplet);
g_free (sp->poky_root);
-
+ g_hash_table_destroy(sp->env_hash);
+ g_hash_table_destroy(sp->old_env_hash);
g_free (sp->project_root_uri);
g_free (sp->path_component);
g_free (sp->gdb_local_path);
g_free (sp->gdb_remote_command);
g_free (sp->remote_command);
+ g_free(sp->target_archs);
sp->sdk_root = NULL;
- sp->triplet = NULL;
+ sp->target_triplet = NULL;
sp->poky_root = NULL;
+ sp->target_archs = NULL;
+ sp->old_env_hash = NULL;
+ sp->env_hash = NULL;
+
+ sp->env_hash = NULL;
sp->project_root_uri = NULL;
sp->path_component = NULL;
sp->gdb_local_path = NULL;
sp->gdb_remote_command = NULL;
sp->remote_command = NULL;
-
return TRUE;
}
@@ -1723,37 +1842,68 @@ static gboolean anjuta_environment_override (IAnjutaEnvironment *obj,
gchar **dirp, gchar ***argvp, gchar ***envp, GError **err)
{
AnjutaPluginSdk *sp = (AnjutaPluginSdk *)obj;
- gchar **new_argv;
+ gchar **new_argv, **vstr;
+ const gchar* configure_flags;
+ gchar* temp;
gsize length = g_strv_length (*argvp);
- int i;
+ gint i, paramcount = 0;
if (length < 1)
return FALSE;
- if (!sp->triplet) // no override for cross command
- return TRUE;
-
+ //we only override autogen and configure related params
if (g_str_has_suffix(*argvp[0], CONFIGURE_COMMAND) ||
- g_str_has_suffix(*argvp[0], AUTOGEN_COMMAND)) {
- new_argv = g_new (gchar*, length + 2);
+ g_str_has_suffix(*argvp[0], AUTOGEN_COMMAND))
+ {
+ configure_flags = g_getenv(CROSS_COMMAND);
+
+ if (!configure_flags)
+ {
+ g_error("Error while getting configuration flags!");
+ return FALSE;
+ }
+
+ //please make sure that configure flags are splited by
+ //only a " ". My parser is not very clever!
+ vstr = g_strsplit(configure_flags, " ", 0);
+ if (!vstr)
+ {
+ g_error("Error while parsing CONFIGURE_FLAGS!");
+ return FALSE;
+ }
+
+ paramcount = g_strv_length (vstr);
+
+ new_argv = g_new (gchar*, length + paramcount + 1);
+
if (!new_argv) {
g_error("Error while allocate args when do environment override!");
+ g_strfreev(vstr);
return FALSE;
}
-
+ /* First copy the command */
new_argv[0] = g_strconcat(*(argvp[0]), NULL);
- new_argv[1] = g_strdup_printf (CROSS_COMMAND, sp->triplet);
+ g_free(*(argvp[0]));
- for (i = 0; i < length; i++) {
- if (i)
- new_argv[1 + i] = g_strconcat(*(*argvp + i), NULL);
- g_free(*(*argvp + i));
+ /* Insert the newly override parameters */
+ for (i = 0; i < paramcount; i++)
+ {
+ new_argv[i + 1] = g_strdup (vstr[i]);
}
+ g_strfreev(vstr);
+ for (i = 1; i < length; i++)
+ {
+ /* copy original parameters, the first one need not to be copied! */
+ new_argv[paramcount + i] = g_strconcat(*(*argvp + i), NULL);
+ g_free(*(*argvp + i));
+ }
/* args must be NULL terminated */
- new_argv[length+1] = NULL;
+ new_argv[length + paramcount] = NULL;
+
g_free (*argvp);
*argvp = new_argv;
+
}
return TRUE;
diff --git a/src/plugin.h b/src/plugin.h
index b0a7a25..bdda406 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -72,8 +72,14 @@ struct _AnjutaPluginSdk
guint remote_gdb_timeout;
- gchar *triplet;
+ gchar *target_triplet;
+ gchar *host_triplet;
+
+ GHashTable *env_hash;
+ GHashTable *old_env_hash;
+
gchar *sdk_root;
+ gchar *target_archs;
gchar *poky_root;
PokyMode poky_mode;