+2005-05-21 Tollef Fog Heen <tfheen@err.no>
+
+ * check/check-libs-private: New test to check for support for
+ private libraries.
+
+ * check/simple.pc (prefix): Add Libs.private header.
+
+ * check/Makefile.am (TESTS): Add check-libs-private test
+
+ * pkg.h: Adjust function prototypes.
+
+ * pkg.c: Add global ignore_private_libs variable.
+ (scan_dir): Use the correct free function. Stop leaking file
+ descriptors.
+ (package_get_l_libs, packages_get_l_libs, package_get_L_libs,
+ packages_get_L_libs): Stop the recursive silliness and go back to
+ old behaviour.
+ (packages_get_all_libs): Adjust parameters to packages_get_*_libs
+ (enable_private_libs, disable_private_libs): Trivial helper
+ functions.
+
+ * pkg-config.1: Update documentation wrt search path (Debian
+ #308942), update docs for Libs.private and add the problematic
+ handling of mixing = and non-= arguments to the bugs section.
+
+ * parse.h: Adjust parameters for parse_package_file to get private
+ libs or not.
+
+ * parse.c (trim_and_sub): Fix memory leak.
+ (_do_parse_libs): New function including what's common between
+ parse_libs and parse_private_libs.
+ (parse_libs_private): New function. Handle private libraries.
+ (parse_line): Add . to the list of valid characters in headers (so
+ Libs.private works correctly.
+ (parse_line): Fix memory leaks.
+ (parse_line): Handle Libs.private.
+ (parse_package_file): Fix memory leak.
+
+ * main.c (main): Fix memory leak.
+
+ * NEWS: Document changes to inter-library handling.
+
+ * main.c (main): Handle inter-library dependencies old-style, but
+ do private libraries too. Adjust parameters to
+ packages_get_*_libs.
+
+ * configure.in: Change comment wrt inter-library handling to talk
+ about private libraries instead.
+
2005-04-22 Tollef Fog Heen <tfheen@err.no>
* main.c (main): Re-add PKG_CONFIG_LIBDIR support which was
+pkg-config 0.18
+===
+ - The inter-library dependencies check was too tight and caused
+ problems if one used the --no-undefined flag to libtool on Solaris
+ (since it there expands to -Wl,-z,defs which disallows undefined
+ symbols). Add a new name to .pc files: Libs.private which will not
+ be listed in the output of --libs unless --static is also given.
+
+ Private libraries are libraries which are needed in the case of
+ static linking or on platforms not supporting inter-library
+ dependencies. They are not supposed to be used for libraries which
+ are exposed through the library in question. An example of an
+ exposed library is GTK+ exposing Glib. A common example of a private
+ library is libm.
+
+ Generally, if include another library's headers in your own, it's a
+ public dependency and not a private one.
+
+ Thanks a lot to James Henstridge for both the bug and the following
+ discussion.
+
pkg-config 0.17.2
===
- Don't go into an infinite loop allocating more and more memory when
-TESTS = check-cflags check-libs check-define-variable
-EXTRA_DIST = $(TESTS) common simple.pc
\ No newline at end of file
+TESTS = check-cflags check-libs check-define-variable check-libs-private
+EXTRA_DIST = $(TESTS) common simple.pc
--- /dev/null
+#! /bin/sh
+
+set -e
+
+. ${srcdir}/common
+
+ARGS="--static --libs simple"
+RESULT="-lsimple -lm"
+
+run_test
Version: 1.0.0
Requires:
Libs: -lsimple
+Libs.private: -lm
Cflags: -I${includedir}
#
# Code taken from gtk+-2.0's configure.in.
#
-# This causes pkg-config to only list direct dependencies on platforms
-# which support inter-library dependencies.
-#
+# This causes pkg-config to not list private dependencies (a very
+# common example is libm) on platforms which support inter-library
+# dependencies.
AC_ARG_ENABLE(indirect-deps,
[AC_HELP_STRING([--enable-indirect-deps],
else
debug_spew ("Error printing disabled\n");
+ if (want_static_lib_list)
+ enable_private_libs();
+ else
+ disable_private_libs();
+
if (want_my_version)
{
printf ("%s\n", VERSION);
g_string_append (str, " ");
}
+ poptFreeContext (opt_context);
+
g_strstrip (str->str);
{
if (want_l_libs)
{
- char *str = packages_get_l_libs (packages, want_static_lib_list);
+ char *str = packages_get_l_libs (packages);
printf ("%s ", str);
g_free (str);
need_newline = TRUE;
}
else if (want_L_libs)
{
- char *str = packages_get_L_libs (packages, want_static_lib_list);
+ char *str = packages_get_L_libs (packages);
printf ("%s ", str);
g_free (str);
need_newline = TRUE;
}
else if (want_libs)
{
- char *str = packages_get_all_libs (packages, want_static_lib_list);
+ char *str = packages_get_all_libs (packages);
printf ("%s ", str);
g_free (str);
need_newline = TRUE;
int msvc_syntax = FALSE;
#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
g_free (varname);
g_string_append (subst, varval);
+ g_free (varval);
}
else
{
g_free (trimmed);
}
-static void
-parse_libs (Package *pkg, const char *str, const char *path)
+static void _do_parse_libs (Package *pkg, int argc, char **argv)
{
- /* Strip out -l and -L flags, put them in a separate list. */
-
- char *trimmed;
- char **argv = NULL;
- int argc;
- int result;
int i;
#ifdef G_OS_WIN32
char *L_flag = (msvc_syntax ? "/libpath:" : "-L");
char *l_flag = "-l";
char *lib_suffix = "";
#endif
-
- if (pkg->l_libs || pkg->L_libs || pkg->other_libs)
- {
- verbose_error ("Libs field occurs twice in '%s'\n", path);
-
- exit (1);
- }
-
- trimmed = trim_and_sub (pkg, str, path);
-
- result = poptParseArgvString (trimmed, &argc, &argv);
-
- if (result < 0)
- {
- verbose_error ("Couldn't parse Libs field into an argument vector: %s\n",
- poptStrerror (result));
-
- exit (1);
- }
i = 0;
while (i < argc)
++i;
}
- g_free (argv);
- g_free (trimmed);
-
pkg->l_libs = g_slist_reverse (pkg->l_libs);
pkg->L_libs = g_slist_reverse (pkg->L_libs);
pkg->other_libs = g_slist_reverse (pkg->other_libs);
+
}
-
+
+
+static void
+parse_libs (Package *pkg, const char *str, const char *path)
+{
+ /* Strip out -l and -L flags, put them in a separate list. */
+
+ char *trimmed;
+ char **argv = NULL;
+ int argc;
+ int result;
+
+ if (pkg->libs_num > 0)
+ {
+ verbose_error ("Libs field occurs twice in '%s'\n", path);
+
+ exit (1);
+ }
+
+ trimmed = trim_and_sub (pkg, str, path);
+
+ result = poptParseArgvString (trimmed, &argc, &argv);
+
+ if (result < 0)
+ {
+ verbose_error ("Couldn't parse Libs field into an argument vector: %s\n",
+ poptStrerror (result));
+
+ exit (1);
+ }
+
+ _do_parse_libs(pkg, argc, argv);
+
+ g_free (trimmed);
+ g_free (argv);
+ pkg->libs_num++;
+}
+
+static void
+parse_libs_private (Package *pkg, const char *str, const char *path)
+{
+ /*
+ List of private libraries. Private libraries are libraries which
+ are needed in the case of static linking or on platforms not
+ supporting inter-library dependencies. They are not supposed to
+ be used for libraries which are exposed through the library in
+ question. An example of an exposed library is GTK+ exposing Glib.
+ A common example of a private library is libm.
+
+ Generally, if include another library's headers in your own, it's
+ a public dependency and not a private one.
+ */
+
+ char *trimmed;
+ char **argv = NULL;
+ int argc;
+ int result;
+
+ if (pkg->libs_private_num > 0)
+ {
+ verbose_error ("Libs.private field occurs twice in '%s'\n", path);
+
+ exit (1);
+ }
+
+ trimmed = trim_and_sub (pkg, str, path);
+
+ result = poptParseArgvString (trimmed, &argc, &argv);
+
+ if (result < 0)
+ {
+ verbose_error ("Couldn't parse Libs.private field into an argument vector: %s\n",
+ poptStrerror (result));
+
+ exit (1);
+ }
+
+ _do_parse_libs(pkg, argc, argv);
+
+ g_free (argv);
+ g_free (trimmed);
+
+ pkg->libs_private_num++;
+}
+
static void
parse_cflags (Package *pkg, const char *str, const char *path)
{
}
static void
-parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean ignore_requires)
+parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean ignore_requires, gboolean ignore_private_libs)
{
char *str;
char *p;
str = trim_string (untrimmed);
- if (*str == '\0')
- return; /* empty line */
+ if (*str == '\0') /* empty line */
+ {
+ g_free(str);
+ return;
+ }
p = str;
while ((*p >= 'A' && *p <= 'Z') ||
(*p >= 'a' && *p <= 'z') ||
(*p >= '0' && *p <= '9') ||
- *p == '_')
+ *p == '_' || *p == '.')
p++;
tag = g_strndup (str, p - str);
if (ignore_requires == FALSE)
parse_requires (pkg, p, path);
else
- return;
+ goto cleanup;
}
+ else if ((strcmp (tag, "Libs.private") == 0) &&
+ ignore_private_libs == FALSE)
+ parse_libs_private (pkg, p, path);
else if (strcmp (tag, "Libs") == 0)
parse_libs (pkg, p, path);
else if (strcmp (tag, "Cflags") == 0 ||
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;
+ goto cleanup;
}
}
#endif
g_hash_table_insert (pkg->vars, varname, varval);
}
-
+
+ cleanup:
g_free (str);
g_free (tag);
}
Package*
-parse_package_file (const char *path, gboolean ignore_requires)
+parse_package_file (const char *path, gboolean ignore_requires, gboolean ignore_private_libs)
{
FILE *f;
Package *pkg;
{
one_line = TRUE;
- parse_line (pkg, str->str, path, ignore_requires);
+ parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs);
g_string_truncate (str, 0);
}
if (!one_line)
verbose_error ("Package file '%s' appears to be empty\n",
path);
-
+ g_string_free (str, TRUE);
fclose(f);
return pkg;
}
#include "pkg.h"
-Package *parse_package_file (const char *path, gboolean ignore_requires);
+Package *parse_package_file (const char *path, gboolean ignore_requires,
+ gboolean ignore_private_libs);
Package *get_compat_package (const char *name);
Also this option is available only on Windows. It sets the name of the
variable that \fIpkg-config\fP automatically sets as described above.
+.TP
+.I "--static"
+Output libraries suitable for static linking. That means including
+any private libraries in the output. This relies on proper tagging in
+the .pc files, else a too large number of libraries will ordinarily be
+output.
+
.SH ENVIRONMENT VARIABLES
.TP
.I "PKG_CONFIG_PATH"
-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.
+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:\fIdatadir\fP/pkgconfig where \fIlibdir\fP is
+the libdir where \fIpkg-config\fP and \fIdatadir\fP is the datadir
+where \fIpkg-config\fP was installed.
.TP
.I "PKG_CONFIG_DEBUG_SPEW"
Requires: glib-2.0 = 1.3.1
Conflicts: foobar <= 4.5
Libs: -L${libdir} -lgobject-1.3
+Libs.private: -lm
Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib/include
.fi
Don't add any flags for required packages; \fIpkg-config\fP will
add those automatically.
+.TP
+.I "Libs.private:"
+This line should list any private libraries in use. Private libraries
+are libraries which are not exposed through your library, but are
+needed in the case of static linking.
+
.TP
.I "Cflags:"
This line should list the compile flags specific to your package.
\fIgtk-config\fP program.
.SH BUGS
-Hah!
-
+\fIpkg-config\fP does not handle mixing of parameters with and without
+= well. Stick with one.
gboolean disable_uninstalled = FALSE;
gboolean ignore_requires = FALSE;
+gboolean ignore_private_libs = TRUE;
void
add_search_dir (const char *path)
}
dir = opendir (dirname_copy);
- free (dirname_copy);
+ g_free (dirname_copy);
if (!dir)
{
debug_spew ("Cannot open directory '%s' in package search path: %s\n",
dent->d_name);
}
}
+ closedir(dir);
}
static Package *
}
debug_spew ("Reading '%s' from file '%s'\n", name, location);
- pkg = parse_package_file (location, ignore_requires);
+ pkg = parse_package_file (location, ignore_requires, ignore_private_libs);
if (pkg == NULL)
{
}
char *
-package_get_l_libs (Package *pkg, gboolean recurse)
+package_get_l_libs (Package *pkg)
{
- if (!recurse)
- return string_list_to_string (get_l_libs(pkg));
/* We don't want these in search path order, rather in dependency
* order, so static linking works.
*/
}
char *
-packages_get_l_libs (GSList *pkgs, gboolean recurse)
+packages_get_l_libs (GSList *pkgs)
{
- if (!recurse) {
- GSList *tmp;
- GSList *list;
- GSList *dups_list = NULL;
- char *retval;
-
- tmp = pkgs;
- while (tmp != NULL)
- {
- dups_list = g_slist_concat (dups_list, g_slist_copy(get_l_libs(tmp->data)));
- tmp = tmp->next;
- }
-
- list = string_list_strip_duplicates_from_back (dups_list);
- g_slist_free (dups_list);
-
- retval = string_list_to_string (list);
-
- g_slist_free (list);
-
- return retval;
-
- }
-
return get_multi_merged_from_back (pkgs, get_l_libs, FALSE);
}
char *
-package_get_L_libs (Package *pkg, gboolean recurse)
+package_get_L_libs (Package *pkg)
{
- if (!recurse)
- return string_list_to_string (get_L_libs(pkg));
-
/* We want these in search path order so the -L flags don't override PKG_CONFIG_PATH */
if (pkg->L_libs_merged == NULL)
pkg->L_libs_merged = get_merged (pkg, get_L_libs, TRUE);
}
char *
-packages_get_L_libs (GSList *pkgs, gboolean recurse)
+packages_get_L_libs (GSList *pkgs)
{
- if (!recurse) {
- GSList *tmp;
- GSList *list;
- GSList *dups_list = NULL;
- char *retval;
-
- tmp = pkgs;
- while (tmp != NULL)
- {
- dups_list = g_slist_concat (dups_list, g_slist_copy(get_L_libs(tmp->data)));
- tmp = tmp->next;
- }
-
- list = string_list_strip_duplicates_from_back (dups_list);
- g_slist_free (dups_list);
-
- retval = string_list_to_string (list);
-
- g_slist_free (list);
-
- return retval;
- }
-
return get_multi_merged (pkgs, get_L_libs, TRUE);
}
}
char *
-packages_get_all_libs (GSList *pkgs, gboolean recurse)
+packages_get_all_libs (GSList *pkgs)
{
char *l_libs;
char *L_libs;
str = g_string_new ("");
other_libs = packages_get_other_libs (pkgs);
- L_libs = packages_get_L_libs (pkgs, recurse);
- l_libs = packages_get_l_libs (pkgs, recurse);
+ L_libs = packages_get_L_libs (pkgs);
+ l_libs = packages_get_l_libs (pkgs);
if (other_libs)
g_string_append (str, other_libs);
g_hash_table_foreach (locations, packages_foreach, GINT_TO_POINTER (mlen + 1));
}
+void
+enable_private_libs(void)
+{
+ ignore_private_libs = FALSE;
+}
+
+void
+disable_private_libs(void)
+{
+ ignore_private_libs = TRUE;
+}
GSList *conflicts; /* list of RequiredVersion */
gboolean uninstalled; /* used the -uninstalled file */
int path_position; /* used to order packages by position in path of their .pc file, lower number means earlier in path */
+ int libs_num; /* Number of times the "Libs" header has been seen */
+ int libs_private_num; /* Number of times the "Libs.private" header has been seen */
};
Package *get_package (const char *name);
-char * package_get_l_libs (Package *pkg, gboolean recurse);
-char * packages_get_l_libs (GSList *pkgs, gboolean recurse);
-char * package_get_L_libs (Package *pkg, gboolean recurse);
-char * packages_get_L_libs (GSList *pkgs, gboolean recurse);
+char * package_get_l_libs (Package *pkg);
+char * packages_get_l_libs (GSList *pkgs);
+char * package_get_L_libs (Package *pkg);
+char * packages_get_L_libs (GSList *pkgs);
char * package_get_other_libs (Package *pkg);
char * packages_get_other_libs (GSList *pkgs);
-char * packages_get_all_libs (GSList *pkgs, gboolean recurse);
+char * packages_get_all_libs (GSList *pkgs);
char * package_get_I_cflags (Package *pkg);
char * packages_get_I_cflags (GSList *pkgs);
char * package_get_other_cflags (Package *pkg);