From 20d118d57a9c52bc2d933630d4f833f284593293 Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Thu, 14 Jul 2005 13:07:18 +0000 Subject: [PATCH] 2005-05-21 Tollef Fog Heen Author: tfheen Date: 2005-05-21 09:14:47 GMT 2005-05-21 Tollef Fog Heen * 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. --- ChangeLog | 49 +++++++++++++ NEWS | 21 ++++++ check/Makefile.am | 4 +- check/check-libs-private | 10 +++ check/simple.pc | 1 + configure.in | 6 +- main.c | 13 +++- parse.c | 149 +++++++++++++++++++++++++++------------ parse.h | 3 +- pkg-config.1 | 29 ++++++-- pkg.c | 83 ++++++---------------- pkg.h | 12 ++-- 12 files changed, 254 insertions(+), 126 deletions(-) create mode 100755 check/check-libs-private diff --git a/ChangeLog b/ChangeLog index ec34a57..32e2254 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,52 @@ +2005-05-21 Tollef Fog Heen + + * 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 * main.c (main): Re-add PKG_CONFIG_LIBDIR support which was diff --git a/NEWS b/NEWS index d00f657..bc7046b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,24 @@ +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 diff --git a/check/Makefile.am b/check/Makefile.am index e0f0040..94655f6 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -1,3 +1,3 @@ -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 diff --git a/check/check-libs-private b/check/check-libs-private new file mode 100755 index 0000000..0678fd7 --- /dev/null +++ b/check/check-libs-private @@ -0,0 +1,10 @@ +#! /bin/sh + +set -e + +. ${srcdir}/common + +ARGS="--static --libs simple" +RESULT="-lsimple -lm" + +run_test diff --git a/check/simple.pc b/check/simple.pc index c898313..2daa035 100644 --- a/check/simple.pc +++ b/check/simple.pc @@ -8,4 +8,5 @@ Description: Dummy pkgconfig test package for testing pkgconfig Version: 1.0.0 Requires: Libs: -lsimple +Libs.private: -lm Cflags: -I${includedir} diff --git a/configure.in b/configure.in index 37db25c..316fab6 100644 --- a/configure.in +++ b/configure.in @@ -27,9 +27,9 @@ PKG_CONFIG_FIND_PC_PATH # # 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], diff --git a/main.c b/main.c index 41e5d59..199fd0c 100644 --- a/main.c +++ b/main.c @@ -413,6 +413,11 @@ main (int argc, char **argv) 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); @@ -446,6 +451,8 @@ main (int argc, char **argv) g_string_append (str, " "); } + poptFreeContext (opt_context); + g_strstrip (str->str); { @@ -601,14 +608,14 @@ main (int argc, char **argv) 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; @@ -622,7 +629,7 @@ main (int argc, char **argv) } 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; diff --git a/parse.c b/parse.c index ee0ccaa..5fae5c4 100644 --- a/parse.c +++ b/parse.c @@ -39,7 +39,6 @@ char *prefix_variable = "prefix"; 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 @@ -205,6 +204,7 @@ trim_and_sub (Package *pkg, const char *str, const char *path) g_free (varname); g_string_append (subst, varval); + g_free (varval); } else { @@ -581,15 +581,8 @@ parse_conflicts (Package *pkg, const char *str, const char *path) 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"); @@ -600,25 +593,6 @@ parse_libs (Package *pkg, const char *str, const char *path) 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) @@ -696,14 +670,96 @@ parse_libs (Package *pkg, const char *str, const char *path) ++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) { @@ -797,7 +853,7 @@ parse_url (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; @@ -807,8 +863,11 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean igno str = trim_string (untrimmed); - if (*str == '\0') - return; /* empty line */ + if (*str == '\0') /* empty line */ + { + g_free(str); + return; + } p = str; @@ -816,7 +875,7 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean igno while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || - *p == '_') + *p == '_' || *p == '.') p++; tag = g_strndup (str, p - str); @@ -842,8 +901,11 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean igno 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 || @@ -915,9 +977,7 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean igno 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 @@ -938,13 +998,14 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, gboolean igno 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; @@ -981,7 +1042,7 @@ parse_package_file (const char *path, gboolean ignore_requires) { 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); } @@ -989,7 +1050,7 @@ parse_package_file (const char *path, gboolean ignore_requires) if (!one_line) verbose_error ("Package file '%s' appears to be empty\n", path); - + g_string_free (str, TRUE); fclose(f); return pkg; } diff --git a/parse.h b/parse.h index e538c28..f764f90 100644 --- a/parse.h +++ b/parse.h @@ -22,7 +22,8 @@ #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); diff --git a/pkg-config.1 b/pkg-config.1 index 5bbb57c..35be16e 100644 --- a/pkg-config.1 +++ b/pkg-config.1 @@ -210,15 +210,23 @@ from automatically trying to override the value of the variable 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" @@ -318,6 +326,7 @@ URL: http://www.gtk.org 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 @@ -380,6 +389,12 @@ This line should give the link flags specific to your package. 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. @@ -396,6 +411,6 @@ various hackers in the GNOME team. It was inspired by Owen Taylor's \fIgtk-config\fP program. .SH BUGS -Hah! - +\fIpkg-config\fP does not handle mixing of parameters with and without += well. Stick with one. diff --git a/pkg.c b/pkg.c index 3f895f1..7a3c943 100644 --- a/pkg.c +++ b/pkg.c @@ -55,6 +55,7 @@ static int scanned_dir_count = 0; gboolean disable_uninstalled = FALSE; gboolean ignore_requires = FALSE; +gboolean ignore_private_libs = TRUE; void add_search_dir (const char *path) @@ -145,7 +146,7 @@ scan_dir (const char *dirname) } 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", @@ -196,6 +197,7 @@ scan_dir (const char *dirname) dent->d_name); } } + closedir(dir); } static Package * @@ -320,7 +322,7 @@ internal_get_package (const char *name, gboolean warn, gboolean check_compat) } 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) { @@ -998,10 +1000,8 @@ get_multi_merged_from_back (GSList *pkgs, GetListFunc func, gboolean in_path_ord } 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. */ @@ -1012,41 +1012,14 @@ package_get_l_libs (Package *pkg, gboolean recurse) } 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); @@ -1055,31 +1028,8 @@ package_get_L_libs (Package *pkg, gboolean recurse) } 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); } @@ -1099,7 +1049,7 @@ packages_get_other_libs (GSList *pkgs) } char * -packages_get_all_libs (GSList *pkgs, gboolean recurse) +packages_get_all_libs (GSList *pkgs) { char *l_libs; char *L_libs; @@ -1110,8 +1060,8 @@ packages_get_all_libs (GSList *pkgs, gboolean recurse) 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); @@ -1503,3 +1453,14 @@ print_package_list (void) 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; +} diff --git a/pkg.h b/pkg.h index b5f73df..774d896 100644 --- a/pkg.h +++ b/pkg.h @@ -72,16 +72,18 @@ struct _Package 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); -- 2.39.5