diff --git a/ChangeLog b/ChangeLog index 4da4ed9..2083a72 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2001-10-25 Tor Lillqvist + + Improve Windows behaviour: Make it even easier to install + developer packages in random locations, without having to modify + the .pc files. Don't set "prefix" globally, instead override it + for each .pc file parsed, if the path where the .pc file is seems + to be the standard .../lib/pkgconfig. + + * main.c (main): Add search directories also from two Registry + keys, in addition to the PKG_CONFIG_PATH environment + variable. Don't define prefix globally. + + * parse.c (parse_line): Instead, if a .pc file is in + /foo/bar/lib/pkgconfig, define prefix as /foo/bar for that package + only. + + * pkg.c: Case-fold file names on Windows, in case they have been + uppercasified by some tool. + + * pkg-config.1: Document Windows behaviour. + 2001-10-21 Tor Lillqvist * Makefile.am (EXTRA_DIST): Distribute README.win32. diff --git a/main.c b/main.c index e2985f4..6a6b357 100644 --- a/main.c +++ b/main.c @@ -11,6 +11,12 @@ #include #include +#ifdef G_OS_WIN32 +#define STRICT +#include +#undef STRICT +#endif + static int want_debug_spew = 0; static int want_verbose_errors = 0; static int want_stdout_errors = 0; @@ -144,14 +150,12 @@ main (int argc, char **argv) static int want_list = 0; static int result; static int want_uninstalled = 0; - static int dont_define_prefix = 0; static char *variable_name = NULL; static int want_exists = 0; static char *required_atleast_version = NULL; static char *required_exact_version = NULL; static char *required_max_version = NULL; static char *required_pkgconfig_version = NULL; - static char *prefix_variable = NULL; static int want_silence_errors = 0; GString *str; GSList *packages = NULL; @@ -208,7 +212,8 @@ main (int argc, char **argv) "print errors from --print-errors to stdout not stderr" }, #ifdef G_OS_WIN32 { "dont-define-prefix", 0, POPT_ARG_NONE, &dont_define_prefix, 0, - "don't set the value of prefix based on where pkg-config.exe is installed" }, + "don't try to override the value of prefix for each .pc file found with " + "a guesstimated value based on the location of the .pc file" }, { "prefix-variable", 0, POPT_ARG_STRING, &prefix_variable, 0, "set the name of the variable that pkg-config automatically sets", "PREFIX" }, #endif @@ -248,6 +253,57 @@ main (int argc, char **argv) g_strfreev (search_dirs); } +#ifdef G_OS_WIN32 + { + /* Add search directories from the Registry */ + + HKEY roots[] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; + gchar *root_names[] = { "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE" }; + HKEY key; + int i; + gulong max_value_name_len, max_value_len; + + for (i = 0; i < G_N_ELEMENTS (roots); i++) + { + key = NULL; + if (RegOpenKeyEx (roots[i], "Software\\" PACKAGE "\\PKG_CONFIG_PATH", 0, + KEY_QUERY_VALUE, &key) == ERROR_SUCCESS && + RegQueryInfoKey (key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &max_value_name_len, &max_value_len, + NULL, NULL) == ERROR_SUCCESS) + { + int index = 0; + gchar *value_name = g_malloc (max_value_name_len + 1); + gchar *value = g_malloc (max_value_len + 1); + + while (TRUE) + { + gulong type; + gulong value_name_len = max_value_name_len + 1; + gulong value_len = max_value_len + 1; + + if (RegEnumValue (key, index++, value_name, &value_name_len, + NULL, &type, + value, &value_len) != ERROR_SUCCESS) + break; + + if (type != REG_SZ) + continue; + + value_name[value_name_len] = '\0'; + value[value_len] = '\0'; + debug_spew ("Adding directory '%s' from %s\\Software\\" + PACKAGE "\\PKG_CONFIG_PATH\\%s\n", + value, root_names[i], value_name); + add_search_dir (value); + } + } + if (key != NULL) + RegCloseKey (key); + } + } +#endif + pcbuilddir = getenv ("PKG_CONFIG_TOP_BUILD_DIR"); if (pcbuilddir) { @@ -329,26 +385,6 @@ main (int argc, char **argv) return 1; } -#ifdef G_OS_WIN32 - if (!dont_define_prefix) - { - gchar *prefix = g_win32_get_package_installation_directory (PACKAGE " " VERSION, NULL); - gchar *p = prefix; - - /* Turn backslashes into slashes or poptParseArgvString() will eat - * them when ${prefix} has been expanded in parse_libs(). - */ - while (*p) - { - if (*p == '\\') - *p = '/'; - p++; - } - define_global_variable (prefix_variable ? prefix_variable : "prefix", - prefix); - } -#endif - package_init (); if (want_list) diff --git a/parse.c b/parse.c index 481bc40..370043f 100644 --- a/parse.c +++ b/parse.c @@ -14,6 +14,11 @@ #endif #include +#ifdef G_OS_WIN32 +int dont_define_prefix = FALSE; +char *prefix_variable = "prefix"; +#endif + /** * Read an entire line from a file into a buffer. Lines may * be delimited with '\n', '\r', '\n\r', or '\r\n'. The delimiter @@ -817,6 +822,51 @@ parse_line (Package *pkg, const char *untrimmed, const char *path) if (pkg->vars == NULL) pkg->vars = g_hash_table_new (g_str_hash, g_str_equal); +#ifdef G_OS_WIN32 + if (!dont_define_prefix && strcmp (tag, prefix_variable) == 0) + { + /* This is the prefix variable. Try to guesstimate a value for it + * for this package from the location of the .pc file. + */ + + gchar *prefix = pkg->pcfiledir; + const int prefix_len = strlen (prefix); + const char *const lib_pkgconfig = "\\lib\\pkgconfig"; + const int lib_pkgconfig_len = strlen (lib_pkgconfig); + + if (strlen (prefix) > lib_pkgconfig_len && + g_ascii_strcasecmp (prefix + prefix_len - lib_pkgconfig_len, + lib_pkgconfig) == 0) + { + /* It ends in lib\pkgconfig. Good. */ + + gchar *p; + + prefix = g_strdup (prefix); + prefix[prefix_len - lib_pkgconfig_len] = '\0'; + + /* Turn backslashes into slashes or + * poptParseArgvString() will eat them when ${prefix} + * has been expanded in parse_libs(). + */ + p = prefix; + while (*p) + { + if (*p == '\\') + *p = '/'; + p++; + } + varname = g_strdup (tag); + debug_spew (" Variable declaration, '%s' overridden with '%s'\n", + tag, prefix); + g_hash_table_insert (pkg->vars, varname, prefix); + g_free (str); + g_free (tag); + return; + } + } +#endif + if (g_hash_table_lookup (pkg->vars, tag)) { verbose_error ("Duplicate definition of variable '%s' in '%s'\n", diff --git a/pkg-config.1 b/pkg-config.1 index e6a94d6..19549d6 100644 --- a/pkg-config.1 +++ b/pkg-config.1 @@ -34,7 +34,8 @@ program: program.c special metadata files. These files are named after the package, with the extension \fI.pc\fP. By default, pkg-config looks in the directory \fIprefix\fP/lib/pkgconfig for these files; it will also -look in the colon-separated list of directories specified by the +look in the colon-separated (on Windows, semicolon-separated) +list of directories specified by the PKG_CONFIG_PATH environment variable. .PP @@ -170,23 +171,20 @@ Remember to use \-\-print-errors if you want error messages. .TP .I "--dont-define-prefix" This option is available only on Windows. It prevents \fIpkg-config\fP -from automatically setting the value of the variable "prefix" to the -directory where \fIpkg-config\fP was installed. (This directory is -determined by asking the system where \fIpkg-config.exe\fP is located, -and if that directory is called \fIbin\fP or \fIlib\fP, using its -parent directory, otherwise itself.) +from automatically trying to override the value of the variable +"prefix" in each .pc file. .TP .I "--prefix-variable=PREFIX" Also this option is available only on Windows. It sets the name of the -variable that \fIpkg-config\fP automatically sets to its own -installation prefix. +variable that \fIpkg-config\fP automatically sets as described above. .SH ENVIRONMENT VARIABLES .TP .I "PKG_CONFIG_PATH" -A colon-separated list of directories to search for .pc files. +A colon-separated (on Windows, semicolon-separated) +list of directories to search for .pc files. The default directory will always be searched after searching the path; the default is \fIlibdir\fP/pkgconfig where \fIlibdir\fP is the libdir where \fIpkg-config\fP was installed. @@ -214,6 +212,20 @@ Normally if you request the package "foo" and the package uninstalled packages. If this environment variable is set, it disables said behavior. +.SH WINDOWS SPECIALITIES +If a .pc file is found in a path that corresponds to the usual +conventions (i.e., ends with lib\\pkgconfig), the prefix for that +package is assumed to be the grandparent of the directory where the .pc file +was found. + +In addition to the \fIPKG_CONFIG_PATH\fP environment variable, the +Registry keys +\fIHKEY_CURRENT_USER\\Software\\pkgconfig\\PKG_CONFIG_PATH\fP and +\fIHKEY_LOCAL_MACHINE\\Software\\pkgconfig\\PKG_CONFIG_PATH\fP can be +used to specify dorectories to search for .pc files. Each (string) +value in these keys is treated as a directory where to look for .pc +files. + .SH AUTOCONF MACROS .TP diff --git a/pkg.c b/pkg.c index 1686db5..686aced 100644 --- a/pkg.c +++ b/pkg.c @@ -22,12 +22,13 @@ #include #endif #include +#include #ifdef G_OS_WIN32 /* No hardcoded paths in the binary, thanks */ #undef PKGLIBDIR /* It's OK to leak this, as PKGLIBDIR is invoked only once */ -#define PKGLIBDIR g_strconcat (g_win32_get_package_installation_directory (PACKAGE " " VERSION, NULL), "\\lib\\pkgconfig", NULL) +#define PKGLIBDIR g_strconcat (g_win32_get_package_installation_directory (PACKAGE, NULL), "\\lib\\pkgconfig", NULL) #endif static void verify_package (Package *pkg); @@ -45,6 +46,15 @@ add_search_dir (const char *path) search_dirs = g_slist_prepend (search_dirs, g_strdup (path)); } +#ifdef G_OS_WIN32 +/* Guard against .pc file being installed with UPPER CASE name */ +# define FOLD(x) tolower(x) +# define FOLDCMP(a, b) g_ascii_strcasecmp (a, b) +#else +# define FOLD(x) (x) +# define FOLDCMP(a, b) strcmp (a, b) +#endif + #define EXT_LEN 3 static gboolean @@ -54,8 +64,8 @@ ends_in_dotpc (const char *str) if (len > EXT_LEN && str[len - 3] == '.' && - str[len - 2] == 'p' && - str[len - 1] == 'c') + FOLD (str[len - 2]) == 'p' && + FOLD (str[len - 1]) == 'c') return TRUE; else return FALSE; @@ -70,7 +80,7 @@ name_ends_in_uninstalled (const char *str) int len = strlen (str); if (len > UNINSTALLED_LEN && - strcmp ((str + len - UNINSTALLED_LEN), "uninstalled") == 0) + FOLDCMP ((str + len - UNINSTALLED_LEN), "uninstalled") == 0) return TRUE; else return FALSE; diff --git a/pkg.h b/pkg.h index 74a1340..587f6d6 100644 --- a/pkg.h +++ b/pkg.h @@ -93,5 +93,13 @@ gboolean name_ends_in_uninstalled (const char *str); /* If TRUE, do not automatically prefer uninstalled versions */ extern gboolean disable_uninstalled; +#ifdef G_OS_WIN32 +/* If TRUE, do not automatically define "prefix" while + * parsing each .pc file */ +extern int dont_define_prefix; +/* The name of the variable that acts as prefix, unless it is "prefix" */ +extern char *prefix_variable; +#endif + #endif