diff --git a/check/check-sysroot b/check/check-sysroot index 7da415f..1950fad 100755 --- a/check/check-sysroot +++ b/check/check-sysroot @@ -36,3 +36,18 @@ run_test --cflags special-flags RESULT="-L$root/sysroot/foo -L$root/sysroot/bar -framework Foo -lsimple -framework Bar -Wl,-framework -Wl,Baz" run_test --libs special-flags + +# packages from different locations gets the same /sysroot prefix +export PKG_CONFIG_PATH="${srcdir}/sub" +RESULT="-I/sysroot/sub/include -I/sysroot/public-dep/include" +run_test --cflags public-dep sub1 + +# Map sub1 location to another sysroot +if [ "$native_win32" = yes ]; then + export PKG_CONFIG_SYSROOT_MAP="${srcdir}/sub;/subsysroot" +else + export PKG_CONFIG_SYSROOT_MAP="${srcdir}/sub:/subsysroot" +fi + +RESULT="-I/subsysroot/sub/include -I/sysroot/public-dep/include" +run_test --cflags public-dep sub1 diff --git a/main.c b/main.c index 9b27d9a..ed2c2f5 100644 --- a/main.c +++ b/main.c @@ -489,6 +489,7 @@ main (int argc, char **argv) GList *packages = NULL; char *search_path; char *pcbuilddir; + char *pcsysrootmap; gboolean need_newline; FILE *log = NULL; GError *error = NULL; @@ -541,6 +542,12 @@ main (int argc, char **argv) define_global_variable ("pc_sysrootdir", "/"); } + pcsysrootmap = getenv ("PKG_CONFIG_SYSROOT_MAP"); + if (pcsysrootmap) + { + add_sysroot_map (pcsysrootmap, G_SEARCHPATH_SEPARATOR_S); + } + pcbuilddir = getenv ("PKG_CONFIG_TOP_BUILD_DIR"); if (pcbuilddir) { diff --git a/parse.c b/parse.c index 6e9907c..bf8c412 100644 --- a/parse.c +++ b/parse.c @@ -640,6 +640,8 @@ static void _do_parse_libs (Package *pkg, int argc, char **argv) p = arg; g_free(tmp); + flag->pkg = pkg; + if (p[0] == '-' && p[1] == 'l' && /* -lib: is used by the C# compiler for libs; it's not an -l @@ -842,6 +844,8 @@ parse_cflags (Package *pkg, const char *str, const char *path) char *p = arg; g_free(tmp); + flag->pkg = pkg; + if (p[0] == '-' && p[1] == 'I') { diff --git a/pkg-config.1 b/pkg-config.1 index a147fc8..9643822 100644 --- a/pkg-config.1 +++ b/pkg-config.1 @@ -368,6 +368,13 @@ to determine CFLAGS and LDFLAGS. -I and -L are modified to point to the new system root. this means that a -I/usr/include/libfoo will become -I/var/target/usr/include/libfoo with a PKG_CONFIG_SYSROOT_DIR equal to /var/target (same rule apply to -L) +.I "PKG_CONFIG_SYSROOT_MAP" +Similar to PKG_CONFIG_SYSROOT_DIR but allow mapping location where the pc file +was found to a sysroot. A colon-separated (on Windows, semicolon-separated) list +that gets splitted in pairs where the first path is the location of package file +(usually part of PKG_CONFIG_LIBDIR or PKG_CONFIG_PATH) and the second path is +the sysroot. For example: +PKG_CONFIG_SYSROOT_MAP=/sysroot/usr/lib/pkgconfig:/sysroot:/sysroot2/usr/lib/pkgconfig:/sysroot2 .TP .I "PKG_CONFIG_LIBDIR" Replaces the default diff --git a/pkg.c b/pkg.c index f29ecc7..fcd2d60 100644 --- a/pkg.c +++ b/pkg.c @@ -45,6 +45,7 @@ static void verify_package (Package *pkg); static GHashTable *packages = NULL; static GHashTable *globals = NULL; static GList *search_dirs = NULL; +static GHashTable *sysroot_map = NULL; gboolean disable_uninstalled = FALSE; gboolean ignore_requires = FALSE; @@ -78,6 +79,36 @@ add_search_dirs (const char *path, const char *separator) g_strfreev (search_dirs); } +void +add_sysroot_map (const char *path, const char *separator) +{ + char **strv; + char **iter; + + if (sysroot_map == NULL) + sysroot_map = g_hash_table_new (g_str_hash, g_str_equal); + + strv = g_strsplit (path, separator, -1); + + iter = strv; + while (*iter) + { + char *pcfiledir = *iter++; + char *sysroot = *iter++; + + if (sysroot == NULL) { + verbose_error ("PKG_CONFIG_SYSROOT_MAP must contain even number of paths."); + exit (1); + } + + debug_spew ("Adding sysroot map '%s' -> '%s' from PKG_CONFIG_SYSROOT_MAP\n", + pcfiledir, sysroot); + g_hash_table_insert(sysroot_map, pcfiledir, sysroot); + } + + g_free (strv); +} + #ifdef G_OS_WIN32 /* Guard against .pc file being installed with UPPER CASE name */ # define FOLD(x) tolower(x) @@ -393,47 +424,33 @@ get_package_quiet (const char *name) return internal_get_package (name, FALSE); } -/* Strip consecutive duplicate arguments in the flag list. */ -static GList * -flag_list_strip_duplicates (GList *list) -{ - GList *tmp; - - /* Start at the 2nd element of the list so we don't have to check for an - * existing previous element. */ - for (tmp = g_list_next (list); tmp != NULL; tmp = g_list_next (tmp)) - { - Flag *cur = tmp->data; - Flag *prev = tmp->prev->data; - - if (cur->type == prev->type && g_strcmp0 (cur->arg, prev->arg) == 0) - { - /* Remove the duplicate flag from the list and move to the last - * element to prepare for the next iteration. */ - GList *dup = tmp; - - debug_spew (" removing duplicate \"%s\"\n", cur->arg); - tmp = g_list_previous (tmp); - list = g_list_remove_link (list, dup); - } - } - - return list; -} - static char * flag_list_to_string (GList *list) { GList *tmp; GString *str = g_string_new (""); char *retval; - + gsize prev_arg_len = 0; + FlagType prev_type = 0; + + if (sysroot_map == NULL) + sysroot_map = g_hash_table_new (g_str_hash, g_str_equal); + tmp = list; while (tmp != NULL) { Flag *flag = tmp->data; char *tmpstr = flag->arg; + char *sysroot; + char *cur_arg; + char *prev_arg; + gsize cur_arg_len; + gsize old_len = str->len; - if (pcsysrootdir != NULL && flag->type & (CFLAGS_I | LIBS_L)) { + sysroot = g_hash_table_lookup (sysroot_map, flag->pkg->pcfiledir); + if (sysroot == NULL) + sysroot = pcsysrootdir; + + if (sysroot != NULL && flag->type & (CFLAGS_I | LIBS_L)) { /* Handle non-I Cflags like -isystem */ if (flag->type & CFLAGS_I && strncmp (tmpstr, "-I", 2) != 0) { char *space = strchr (tmpstr, ' '); @@ -441,18 +458,33 @@ flag_list_to_string (GList *list) /* Ensure this has a separate arg */ g_assert (space != NULL && space[1] != '\0'); g_string_append_len (str, tmpstr, space - tmpstr + 1); - g_string_append (str, pcsysrootdir); + g_string_append (str, sysroot); g_string_append (str, space + 1); } else { g_string_append_c (str, '-'); g_string_append_c (str, tmpstr[1]); - g_string_append (str, pcsysrootdir); + g_string_append (str, sysroot); g_string_append (str, tmpstr+2); } } else { g_string_append (str, tmpstr); } g_string_append_c (str, ' '); + + /* truncate the string if the arg we added is identical to the previous one */ + cur_arg = str->str + old_len; + cur_arg_len = str->len - old_len; + prev_arg = cur_arg - prev_arg_len; + if (prev_type == flag->type && prev_arg_len == cur_arg_len && strncmp(cur_arg, prev_arg, cur_arg_len) == 0) + { + g_string_truncate (str, old_len); + } + else + { + prev_type = flag->type; + prev_arg_len = cur_arg_len; + } + tmp = g_list_next (tmp); } @@ -918,7 +950,6 @@ get_multi_merged (GList *pkgs, FlagType type, gboolean in_path_order, char *retval; list = fill_list (pkgs, type, in_path_order, include_private); - list = flag_list_strip_duplicates (list); retval = flag_list_to_string (list); g_list_free (list); diff --git a/pkg.h b/pkg.h index c6732bd..c85ddd8 100644 --- a/pkg.h +++ b/pkg.h @@ -53,6 +53,7 @@ struct Flag_ { FlagType type; char *arg; + Package *pkg; }; struct RequiredVersion_ @@ -98,6 +99,7 @@ char * packages_get_var (GList *pkgs, void add_search_dir (const char *path); void add_search_dirs (const char *path, const char *separator); +void add_sysroot_map (const char *path, const char *separator); void package_init (gboolean want_list); int compare_versions (const char * a, const char *b); gboolean version_test (ComparisonType comparison,