.gear/rules | 2 + .../tags/11f32291d461161676c43a903cab9b9b647f571e | 22 ++ .gear/tags/list | 1 + check/Makefile.am | 4 + check/check-enhanced-ver | 23 ++ check/check-missing | 13 +- check/check-multiline | 11 + check/check-print-options | 6 +- check/enhanced-ver.pc | 9 + check/multiline.pc | 9 + configure.ac | 1 + main.c | 125 ++++++--- parse.c | 241 ++++------------- parse.h | 5 +- pkg-config.spec | 218 +++++++++++++++ pkg.c | 295 ++++++++++++--------- pkg.h | 6 +- 17 files changed, 614 insertions(+), 377 deletions(-) diff --git a/.gear/rules b/.gear/rules new file mode 100644 index 0000000..a315070 --- /dev/null +++ b/.gear/rules @@ -0,0 +1,2 @@ +tar: pkg-config-@version@:. name=@name@-@version@ +diff: pkg-config-@version@:. . name=@name@-@version@-@release@.patch diff --git a/.gear/tags/11f32291d461161676c43a903cab9b9b647f571e b/.gear/tags/11f32291d461161676c43a903cab9b9b647f571e new file mode 100644 index 0000000..c8972a3 --- /dev/null +++ b/.gear/tags/11f32291d461161676c43a903cab9b9b647f571e @@ -0,0 +1,22 @@ +object edf8e6f0ea77ede073f07bff0d2ae1fc7a38103b +type commit +tag pkg-config-0.29.2 +tagger Dan Nicholson 1490029636 -0500 + +Release pkg-config-0.29.2 +-----BEGIN PGP SIGNATURE----- + +iQIcBAABAgAGBQJY0AxJAAoJEAI6RCDH7GkUlrgQAMRp3Pok/Z9OtHR8bRmJ6wbV +snpvku6B+Kv9Q2Jvyz3UFOCnq32YPcYhSLfH0ZbAaAj47cqczZ9Whq7N7bBq50ux +u9BbPy6BIpo8kgAyWoW9xMyp8zrL0zuvb2rsrb1YmmPaN4x89bqiF85oZYEh67uZ +lgydnPieY0QSewfBTbPcovu+H/Ke8VPgAy+iPigBdPNAqpnvXvlx+h1M2EcJvKhF +/PcJZ3IyCk2MvESnKa6XbX7bs20wUA3WVVmhw3iI+bFNppiqsaEusJ24bSIu3hOx +P6J+K/238/2K4PYNTR2o5hRmYbBaKBSlIBqLuPUVCc/Ljp+J0k764Vva3igK90X/ +jVreYJ09DxWnein0Z+RNn3A0eKBXH4px0MuG6bgDbcIVrG8PTrg+PQcjik0rv+bT +7XsWQd32+BmwTNYjCA5pu6cH7uULPGO2QCFeN9kYRFsN1EKP1kIF27PUUDN6fkmy +UnAe8j4uchtpoZMlsJzCokXodmfWUdCBp6ld5F0j24Pk/Is9b4XB4TGTCLWEVGBS +a7U9DykTOKc0k3jM4mFHVFbBOuoi9lEAUhPSOeGlcj0uorJwbdHgdaWrdhtqD23r +xjfQqoBuYDlO8obWaf80Oc0+e76zltBMekmKf7+OVp6aHIiCMJQUA3POEx/nMCYU +cPDEKb4cTdCgcca7z5Bj +=YT+r +-----END PGP SIGNATURE----- diff --git a/.gear/tags/list b/.gear/tags/list new file mode 100644 index 0000000..024356f --- /dev/null +++ b/.gear/tags/list @@ -0,0 +1 @@ +11f32291d461161676c43a903cab9b9b647f571e pkg-config-0.29.2 diff --git a/check/Makefile.am b/check/Makefile.am index 68c6d84..396ab95 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -31,6 +31,8 @@ TESTS = \ check-variables \ check-dependencies \ check-system-flags \ + check-multiline \ + check-enhanced-ver \ $(NULL) EXTRA_DIST = \ @@ -118,4 +120,6 @@ EXTRA_DIST = \ dependencies/j_dep_k.pc \ dependencies/k_dep.pc \ system.pc \ + multiline.pc \ + enhanced-ver.pc \ $(NULL) diff --git a/check/check-enhanced-ver b/check/check-enhanced-ver new file mode 100755 index 0000000..e62b25b --- /dev/null +++ b/check/check-enhanced-ver @@ -0,0 +1,23 @@ +#! /bin/sh + +set -e + +. ${srcdir}/common + +# Check that versioned Requires.private are printed on behalf of Requires. +RESULT="public-dep > 0 +public-dep >= 1" +run_test --print-requires enhanced-ver + +# Also check that Requires.private aren't checked with --print-requires. +run_test --define-variable=private_ver=2 --print-requires enhanced-ver + +# Check that Requires are excluded from Requires.private. +RESULT="private-dep >= 1" +run_test --print-requires-private enhanced-ver + +# Check that versioned Requires.private are actually checked +# on behalf of Requires before being printed. +RESULT="Package 'enhanced-ver' requires 'public-dep >= 2' but version of public-dep is 1.0.0" +EXPECT_RETURN=1 \ +run_test --define-variable=public_ver=2 --print-requires enhanced-ver diff --git a/check/check-missing b/check/check-missing index bb5f79a..2a971ee 100755 --- a/check/check-missing +++ b/check/check-missing @@ -17,7 +17,8 @@ run_test --exists missing-requires # tests below are on an existing package, but with missing Requires.private; # when pkg-config outputs error, the actual error text isn't checked # package exists, but should fail since deps can't be resolved -EXPECT_RETURN=1 +# ALT: actually tolerate missing requires. +EXPECT_RETURN=0 RESULT="" run_test --exists missing-requires-private @@ -36,14 +37,10 @@ if [ "$list_indirect_deps" = yes ]; then fi run_test --silence-errors --static --libs missing-requires-private -# Cflags.private should fail (verbosely, but the output isn't verified) -EXPECT_RETURN=1 -RESULT="" -run_test --silence-errors --static --cflags missing-requires-private - # Cflags should fail (verbosely, but the output isn't verified) -EXPECT_RETURN=1 -RESULT="" +# ALT: actually tolerate missing requires. +EXPECT_RETURN=0 +RESULT="-I/missing-requires-private/include" run_test --silence-errors --cflags missing-requires-private # get includedir var diff --git a/check/check-multiline b/check/check-multiline new file mode 100755 index 0000000..a508abd --- /dev/null +++ b/check/check-multiline @@ -0,0 +1,11 @@ +#! /bin/sh + +set -e + +. ${srcdir}/common + +RESULT="-la -lb -lc -ld -le -lf" +run_test --static --libs multiline + +RESULT="-I/1 -I/2" +run_test --cflags multiline diff --git a/check/check-print-options b/check/check-print-options index 198e5a1..b521d4d 100755 --- a/check/check-print-options +++ b/check/check-print-options @@ -35,9 +35,9 @@ RESULT="private-dep >= 1" run_test --print-requires-private requires-test # --list-all, limit to a subdirectory -RESULT="sub1 Subdirectory package 1 - Test package 1 for subdirectory -sub2 Subdirectory package 2 - Test package 2 for subdirectory -broken Broken package - Module with broken .pc file" +RESULT="broken Broken package - Module with broken .pc file +sub1 Subdirectory package 1 - Test package 1 for subdirectory +sub2 Subdirectory package 2 - Test package 2 for subdirectory" PKG_CONFIG_LIBDIR="$srcdir/sub" run_test --list-all # Check handling when multiple incompatible options are set diff --git a/check/enhanced-ver.pc b/check/enhanced-ver.pc new file mode 100644 index 0000000..03b4a65 --- /dev/null +++ b/check/enhanced-ver.pc @@ -0,0 +1,9 @@ +public_ver=1 +private_ver=1 + +Name: Enhanced version test +Version: 1.0.0 +Description: Dummy package for testing versioned Requires.private on behalf of Requires +Requires: public-dep > 0 +Requires.private: public-dep >= ${public_ver} +Requires.private: private-dep >= ${private_ver} diff --git a/check/multiline.pc b/check/multiline.pc new file mode 100644 index 0000000..ad1e1b7 --- /dev/null +++ b/check/multiline.pc @@ -0,0 +1,9 @@ +Name: Multiline test +Version: 1.0.0 +Description: Dummy package for testing fields spanning multiple lines +Libs.private: -ld -le +Libs.private: -lf +Libs: -la +Libs: -lb -lc +Cflags: -I/1 +Cflags: -I/2 diff --git a/configure.ac b/configure.ac index 5f20721..c05e47d 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,7 @@ AC_CHECK_PROG([LN], [ln], [ln], [cp -Rp]) dnl Check for headers AC_CHECK_HEADERS([dirent.h unistd.h sys/wait.h malloc.h]) +AC_CHECK_FUNCS(getc_unlocked) dnl A POSIX shell is required for the tests. If TEST_SHELL hasn't been dnl set on the command line then we try to find bash or ksh or sh from diff --git a/main.c b/main.c index 9b27d9a..4ec37af 100644 --- a/main.c +++ b/main.c @@ -51,6 +51,7 @@ static gboolean want_provides = FALSE; static gboolean want_requires = FALSE; static gboolean want_requires_private = FALSE; static gboolean want_validate = FALSE; +static gboolean want_recursion = TRUE; static char *required_atleast_version = NULL; static char *required_exact_version = NULL; static char *required_max_version = NULL; @@ -465,6 +466,10 @@ static const GOptionEntry options_table[] = { "linking", NULL }, { "validate", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &output_opt_cb, "validate a package's .pc file", NULL }, + { "disable-recursion", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, + &want_recursion, "disable loading of dependencies", NULL }, + { "enable-recursion", 0, 0, G_OPTION_ARG_NONE, + &want_recursion, "re-enable loading of dependencies", NULL }, { "define-prefix", 0, 0, G_OPTION_ARG_NONE, &define_prefix, "try to override the value of prefix for each .pc file found with a " "guesstimated value based on the location of the .pc file", NULL }, @@ -613,17 +618,45 @@ main (int argc, char **argv) else disable_private_libs(); - /* honor Requires.private if any Cflags are requested or any static - * libs are requested */ - - if (pkg_flags & CFLAGS_ANY || want_requires_private || want_exists || - (want_static_lib_list && (pkg_flags & LIBS_ANY))) - enable_requires_private(); - - /* ignore Requires if no Cflags or Libs are requested */ - - if (pkg_flags == 0 && !want_requires && !want_exists) - disable_requires(); + /* + * Cflags-only dependencies, such as those resulting from #include + * directives, should be listed on behalf of Requires.private rather + * than Requires, the manual says. This is to avoid overlinking. + * But this also makes Requires.private dependencies mandatory, + * even for non-static linking. This leads to ugly dependencies + * like gtk+-3.0 requiring a bunch of wayland-*-devel packages + * simply because it was built with --enable-wayland-backend. + * The following knob suggests one possible way out of this + * predicament: 1) packages should list only Requires and not + * Requires.private; 2) Requires.private dependencies are mandatory + * only for --static --libs, and also for --print-requires-private; + * 3) Requires.private is enabled for --cflags, but missing modules, + * such as wayland-* in the above example, are silently ignored. + * To work smoothly, this solution needs extra support in the + * distro's packaging system, and therefore cannot be enabled + * by default. Specifically, the packaging system needs to use + * an additional dependency generator, known as cpp.req, + * which tracks #include directives in the header files. + */ +#define TOLERATE_MISSING_REQUIRES_PRIVATE TRUE + + /* Loading of dependencies explicitly disabled? */ + if (!want_recursion) + disable_requires (); + /* No need to load Requires; probably in --validate mode. */ + else if (pkg_flags == 0 && !want_exists && + !want_requires && !want_requires_private) + disable_requires (); + /* Need to enable Requires.private unconditinally. */ + else if (want_requires_private || + (want_static_lib_list && (pkg_flags & LIBS_ANY))) + enable_requires_private (FALSE); + /* Conservative --exists needs to check for Requires.private. */ + else if (want_exists && !TOLERATE_MISSING_REQUIRES_PRIVATE) + enable_requires_private (FALSE); + /* Enable Requires.private conditionally for --cflags. */ + else if (pkg_flags & CFLAGS_ANY) + enable_requires_private (TOLERATE_MISSING_REQUIRES_PRIVATE); /* Allow errors in .pc files when listing all. */ if (want_list) @@ -761,54 +794,62 @@ main (int argc, char **argv) } } - if (want_requires) + if (want_requires || want_requires_private) { GList *pkgtmp; for (pkgtmp = packages; pkgtmp != NULL; pkgtmp = g_list_next (pkgtmp)) { Package *pkg = pkgtmp->data; GList *reqtmp; + GHashTable *seen = g_hash_table_new (g_str_hash, g_str_equal); - /* process Requires: */ - for (reqtmp = pkg->requires; reqtmp != NULL; reqtmp = g_list_next (reqtmp)) + /* Process Requires. */ + for (reqtmp = pkg->requires_entries; + reqtmp != NULL; reqtmp = g_list_next (reqtmp)) { - Package *deppkg = reqtmp->data; - RequiredVersion *req; - req = g_hash_table_lookup(pkg->required_versions, deppkg->key); - if ((req == NULL) || (req->comparison == ALWAYS_MATCH)) - printf ("%s\n", deppkg->key); + RequiredVersion *req = reqtmp->data; + g_hash_table_add (seen, req->name); + if (!want_requires) + continue; + if (req->comparison == ALWAYS_MATCH) + printf ("%s\n", req->name); else - printf ("%s %s %s\n", deppkg->key, - comparison_to_str(req->comparison), + printf ("%s %s %s\n", req->name, + comparison_to_str (req->comparison), req->version); } - } - } - if (want_requires_private) - { - GList *pkgtmp; - for (pkgtmp = packages; pkgtmp != NULL; pkgtmp = g_list_next (pkgtmp)) - { - Package *pkg = pkgtmp->data; - GList *reqtmp; - /* process Requires.private: */ - for (reqtmp = pkg->requires_private; reqtmp != NULL; reqtmp = g_list_next (reqtmp)) - { - - Package *deppkg = reqtmp->data; - RequiredVersion *req; - if (g_list_find (pkg->requires, reqtmp->data)) + /* Enhance Requires with versioned Requires.private. */ + if (want_requires) + for (reqtmp = pkg->requires_private_entries; + reqtmp != NULL; reqtmp = g_list_next (reqtmp)) + { + RequiredVersion *req = reqtmp->data; + if (req->comparison == ALWAYS_MATCH) + continue; + if (g_hash_table_lookup (seen, req->name) == NULL) continue; + printf ("%s %s %s\n", req->name, + comparison_to_str (req->comparison), + req->version); + } - req = g_hash_table_lookup(pkg->required_versions, deppkg->key); - if ((req == NULL) || (req->comparison == ALWAYS_MATCH)) - printf ("%s\n", deppkg->key); + /* Print the rest of Requires.private. */ + if (want_requires_private) + for (reqtmp = pkg->requires_private_entries; + reqtmp != NULL; reqtmp = g_list_next (reqtmp)) + { + RequiredVersion *req = reqtmp->data; + if (g_hash_table_lookup (seen, req->name) != NULL) + continue; + if (req->comparison == ALWAYS_MATCH) + printf ("%s\n", req->name); else - printf ("%s %s %s\n", deppkg->key, - comparison_to_str(req->comparison), + printf ("%s %s %s\n", req->name, + comparison_to_str (req->comparison), req->version); } + g_hash_table_destroy (seen); } } diff --git a/parse.c b/parse.c index 7bb666d..15b555e 100644 --- a/parse.c +++ b/parse.c @@ -34,6 +34,11 @@ #endif #include +/* If getc_unlocked is not available, fall back to getc. */ +#if !defined(getc_unlocked) && !defined(HAVE_GETC_UNLOCKED) +#define getc_unlocked getc +#endif + gboolean parse_strict = TRUE; gboolean define_prefix = ENABLE_DEFINE_PREFIX; char *prefix_variable = "prefix"; @@ -64,9 +69,7 @@ read_one_line (FILE *stream, GString *str) while (1) { - int c; - - c = getc (stream); + int c = getc_unlocked (stream); if (c == EOF) { @@ -90,7 +93,7 @@ read_one_line (FILE *stream, GString *str) case '\r': case '\n': { - int next_c = getc (stream); + int next_c = getc_unlocked (stream); if (!(c == EOF || (c == '\r' && next_c == '\n') || @@ -117,7 +120,7 @@ read_one_line (FILE *stream, GString *str) break; case '\n': { - int next_c = getc (stream); + int next_c = getc_unlocked (stream); if (!(c == EOF || (c == '\r' && next_c == '\n') || @@ -316,7 +319,10 @@ split_module_list (const char *str, const char *path) { case OUTSIDE_MODULE: if (!MODULE_SEPARATOR (*p)) - state = IN_MODULE_NAME; + { + state = IN_MODULE_NAME; + start = p; + } break; case IN_MODULE_NAME: @@ -327,11 +333,7 @@ split_module_list (const char *str, const char *path) while (*s && isspace ((guchar)*s)) ++s; - if (*s == '\0') - state = OUTSIDE_MODULE; - else if (MODULE_SEPARATOR (*s)) - state = OUTSIDE_MODULE; - else if (OPERATOR_CHAR (*s)) + if (OPERATOR_CHAR (*s)) state = BEFORE_OPERATOR; else state = OUTSIDE_MODULE; @@ -390,7 +392,7 @@ split_module_list (const char *str, const char *path) ++p; } - if (p != start) + if (state != OUTSIDE_MODULE) { /* get the last module */ char *module = g_strndup (start, p - start); @@ -407,12 +409,12 @@ split_module_list (const char *str, const char *path) return retval; } -GList * -parse_module_list (Package *pkg, const char *str, const char *path) +static void +do_parse_module_list (Package *pkg, GList **listp, + const char *str, const char *path) { GList *split; GList *iter; - GList *retval = NULL; split = split_module_list (str, path); @@ -427,30 +429,20 @@ parse_module_list (Package *pkg, const char *str, const char *path) ver = g_new0 (RequiredVersion, 1); ver->comparison = ALWAYS_MATCH; ver->owner = pkg; - retval = g_list_prepend (retval, ver); - - while (*p && MODULE_SEPARATOR (*p)) - ++p; + *listp = g_list_prepend (*listp, ver); start = p; while (*p && !isspace ((guchar)*p)) ++p; - while (*p && MODULE_SEPARATOR (*p)) + while (*p && isspace ((guchar)*p)) { *p = '\0'; ++p; } - if (*start == '\0') - { - verbose_error ("Empty package name in Requires or Conflicts in file '%s'\n", path); - if (parse_strict) - exit (1); - else - continue; - } + g_assert (*start != '\0'); ver->name = g_strdup (start); @@ -526,65 +518,21 @@ parse_module_list (Package *pkg, const char *str, const char *path) g_list_foreach (split, (GFunc) g_free, NULL); g_list_free (split); - retval = g_list_reverse (retval); - - return retval; } -static void -parse_requires (Package *pkg, const char *str, const char *path) +GList * +parse_module_list (Package *pkg, const char *str, const char *path) { - char *trimmed; - - if (pkg->requires) - { - verbose_error ("Requires field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - - trimmed = trim_and_sub (pkg, str, path); - pkg->requires_entries = parse_module_list (pkg, trimmed, path); - g_free (trimmed); + GList *list = NULL; + do_parse_module_list (pkg, &list, str, path); + return g_list_reverse (list); } static void -parse_requires_private (Package *pkg, const char *str, const char *path) +parse_deps (Package *pkg, GList **listp, const char *str, const char *path) { - char *trimmed; - - if (pkg->requires_private) - { - verbose_error ("Requires.private field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - - trimmed = trim_and_sub (pkg, str, path); - pkg->requires_private_entries = parse_module_list (pkg, trimmed, path); - g_free (trimmed); -} - -static void -parse_conflicts (Package *pkg, const char *str, const char *path) -{ - char *trimmed; - - if (pkg->conflicts) - { - verbose_error ("Conflicts field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - - trimmed = trim_and_sub (pkg, str, path); - pkg->conflicts = parse_module_list (pkg, trimmed, path); + char *trimmed = trim_and_sub (pkg, str, path); + do_parse_module_list (pkg, listp, trimmed, path); g_free (trimmed); } @@ -617,7 +565,8 @@ static char *strdup_escape_shell(const char *s) return r; } -static void _do_parse_libs (Package *pkg, int argc, char **argv) +static void +do_parse_libs (GList **listp, int argc, char **argv) { int i; #ifdef G_OS_WIN32 @@ -652,7 +601,7 @@ static void _do_parse_libs (Package *pkg, int argc, char **argv) flag->type = LIBS_l; flag->arg = g_strconcat (l_flag, p, lib_suffix, NULL); - pkg->libs = g_list_prepend (pkg->libs, flag); + *listp = g_list_prepend (*listp, flag); } else if (p[0] == '-' && p[1] == 'L') @@ -663,7 +612,7 @@ static void _do_parse_libs (Package *pkg, int argc, char **argv) flag->type = LIBS_L; flag->arg = g_strconcat (L_flag, p, NULL); - pkg->libs = g_list_prepend (pkg->libs, flag); + *listp = g_list_prepend (*listp, flag); } else if ((strcmp("-framework", p) == 0 || strcmp("-Wl,-framework", p) == 0) && @@ -679,7 +628,7 @@ static void _do_parse_libs (Package *pkg, int argc, char **argv) framework = strdup_escape_shell(tmp); flag->type = LIBS_OTHER; flag->arg = g_strconcat (arg, " ", framework, NULL); - pkg->libs = g_list_prepend (pkg->libs, flag); + *listp = g_list_prepend (*listp, flag); i++; g_free (framework); g_free (tmp); @@ -688,7 +637,7 @@ static void _do_parse_libs (Package *pkg, int argc, char **argv) { flag->type = LIBS_OTHER; flag->arg = g_strdup (arg); - pkg->libs = g_list_prepend (pkg->libs, flag); + *listp = g_list_prepend (*listp, flag); } else /* flag wasn't used */ @@ -701,33 +650,22 @@ static void _do_parse_libs (Package *pkg, int argc, char **argv) } - static void -parse_libs (Package *pkg, const char *str, const char *path) +parse_libs (Package *pkg, GList **listp, const char *field, + 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 = 0; GError *error = NULL; - if (pkg->libs_num > 0) - { - verbose_error ("Libs field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - trimmed = trim_and_sub (pkg, str, path); if (trimmed && *trimmed && !g_shell_parse_argv (trimmed, &argc, &argv, &error)) { - verbose_error ("Couldn't parse Libs field into an argument vector: %s\n", - error ? error->message : "unknown"); + verbose_error ("Couldn't parse %s field into an argument vector: %s\n", + field, error ? error->message : "unknown"); if (parse_strict) exit (1); else @@ -737,64 +675,10 @@ parse_libs (Package *pkg, const char *str, const char *path) } } - _do_parse_libs(pkg, argc, argv); + do_parse_libs (listp, argc, argv); g_free (trimmed); g_strfreev (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 = 0; - GError *error = NULL; - - if (pkg->libs_private_num > 0) - { - verbose_error ("Libs.private field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - - trimmed = trim_and_sub (pkg, str, path); - - if (trimmed && *trimmed && - !g_shell_parse_argv (trimmed, &argc, &argv, &error)) - { - verbose_error ("Couldn't parse Libs.private field into an argument vector: %s\n", - error ? error->message : "unknown"); - if (parse_strict) - exit (1); - else - { - g_free (trimmed); - return; - } - } - - _do_parse_libs(pkg, argc, argv); - - g_strfreev (argv); - g_free (trimmed); - - pkg->libs_private_num++; } static void @@ -808,15 +692,6 @@ parse_cflags (Package *pkg, const char *str, const char *path) GError *error = NULL; int i; - if (pkg->cflags) - { - verbose_error ("Cflags field occurs twice in '%s'\n", path); - if (parse_strict) - exit (1); - else - return; - } - trimmed = trim_and_sub (pkg, str, path); if (trimmed && *trimmed && @@ -905,9 +780,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, gboolean ignore_private_libs, - gboolean ignore_requires_private) +parse_line (Package *pkg, const char *untrimmed, const char *path) { char *str; char *p; @@ -951,27 +824,18 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, else if (strcmp (tag, "Version") == 0) parse_version (pkg, p, path); else if (strcmp (tag, "Requires.private") == 0) - { - if (!ignore_requires_private) - parse_requires_private (pkg, p, path); - } + parse_deps (pkg, &pkg->requires_private_entries, p, path); else if (strcmp (tag, "Requires") == 0) - { - if (ignore_requires == FALSE) - parse_requires (pkg, p, path); - else - goto cleanup; - } - else if ((strcmp (tag, "Libs.private") == 0) && - ignore_private_libs == FALSE) - parse_libs_private (pkg, p, path); + parse_deps (pkg, &pkg->requires_entries, p, path); + else if (strcmp (tag, "Libs.private") == 0) + parse_libs (pkg, &pkg->libs_private, "Libs.private", p, path); else if (strcmp (tag, "Libs") == 0) - parse_libs (pkg, p, path); + parse_libs (pkg, &pkg->libs, "Libs", p, path); else if (strcmp (tag, "Cflags") == 0 || strcmp (tag, "CFlags") == 0) parse_cflags (pkg, p, path); else if (strcmp (tag, "Conflicts") == 0) - parse_conflicts (pkg, p, path); + parse_deps (pkg, &pkg->conflicts, p, path); else if (strcmp (tag, "URL") == 0) parse_url (pkg, p, path); else @@ -1084,10 +948,7 @@ parse_line (Package *pkg, const char *untrimmed, const char *path, } Package* -parse_package_file (const char *key, const char *path, - gboolean ignore_requires, - gboolean ignore_private_libs, - gboolean ignore_requires_private) +parse_package_file (const char *key, const char *path) { FILE *f; Package *pkg; @@ -1131,8 +992,7 @@ parse_package_file (const char *key, const char *path, { one_line = TRUE; - parse_line (pkg, str->str, path, ignore_requires, ignore_private_libs, - ignore_requires_private); + parse_line (pkg, str->str, path); g_string_truncate (str, 0); } @@ -1143,8 +1003,13 @@ parse_package_file (const char *key, const char *path, g_string_free (str, TRUE); fclose(f); + pkg->requires_entries = g_list_reverse (pkg->requires_entries); + pkg->requires_private_entries = g_list_reverse (pkg->requires_private_entries); + pkg->conflicts = g_list_reverse (pkg->conflicts); + pkg->cflags = g_list_reverse (pkg->cflags); pkg->libs = g_list_reverse (pkg->libs); + pkg->libs_private = g_list_reverse (pkg->libs_private); return pkg; } diff --git a/parse.h b/parse.h index db1bf86..5bbf9fe 100644 --- a/parse.h +++ b/parse.h @@ -22,10 +22,7 @@ #include "pkg.h" -Package *parse_package_file (const char *key, const char *path, - gboolean ignore_requires, - gboolean ignore_private_libs, - gboolean ignore_requires_private); +Package *parse_package_file (const char *key, const char *path); GList *parse_module_list (Package *pkg, const char *str, const char *path); diff --git a/pkg-config.spec b/pkg-config.spec new file mode 100644 index 0000000..20aa507 --- /dev/null +++ b/pkg-config.spec @@ -0,0 +1,218 @@ +Name: pkg-config +Version: 0.29.2 +Release: alt3 + +Summary: Pkgconfig helps make building packages easier +License: GPLv2+ +Group: Development/Other +Url: https://www.freedesktop.org/wiki/Software/pkg-config/ + +Provides: %_libdir/pkgconfig +Provides: %_datadir/pkgconfig + +Provides: pkgconfig-reqprov, pkgconfig-recursion +Provides: pkgconfig-print-requires-private, pkgconfig = 1:%version-%release +Obsoletes: pkgconfig + +# due to pkg.c:add_virtual_pkgconfig_package +Provides: pkgconfig(pkg-config) = %version + +# http://git.altlinux.org/gears/p/pkg-config.git +Source: %name-%version.tar +Patch: %name-%version-%release.patch + +BuildRequires: glib2-devel + +%define docdir %_docdir/%name-%version + +%description +The pkg-config program is used to retrieve information about installed +libraries in the system. It is typically used to compile and link +against one or more libraries. + +%prep +%setup +%patch -p1 +rm -r glib +mkdir glib + +%build +%autoreconf +%configure --docdir=%docdir --without-internal-glib --disable-silent-rules +%make_build + +%install +%makeinstall_std +install -dm755 %buildroot{%_datadir,%_libdir}/pkgconfig +install -pm644 AUTHORS NEWS README %buildroot%docdir/ + +mkdir -p %buildroot%_sysconfdir/buildreqs/files/ignore.d +cat <<\EOF >%buildroot%_sysconfdir/buildreqs/files/ignore.d/%name +# %name buildreq filter. +^(%_libdir|%_datadir)/pkgconfig/[^/]+\.pc$ +EOF + +mkdir -p %buildroot%_rpmlibdir +cat <<\EOF >%buildroot%_rpmlibdir/%name-files.req.list +# %name dirlist for %_rpmlibdir/files.req +/usr/lib/pkgconfig %name +/usr/lib64/pkgconfig %name +/usr/share/pkgconfig %name +EOF + +%check +%make_build -k check + +%set_verify_elf_method strict +%define _unpackaged_files_terminate_build 1 + +%files +%config %_sysconfdir/buildreqs/files/ignore.d/* +%config %_rpmlibdir/* +%_bindir/pkg-config +%_bindir/*-pkg-config +%dir %_libdir/pkgconfig +%dir %_datadir/pkgconfig +%_datadir/aclocal/* +%_man1dir/* +%docdir/ + +%changelog +* Tue Mar 19 2019 Dmitry V. Levin 0.29.2-alt3 +- Made the output of "pkg-config --list-all" sorted. + +* Tue Jun 19 2018 Alexey Tourbin 0.29.2-alt2 +- Re-added --enable-recursion to complement --disable-recursion, for cpp.req. + +* Tue Jun 19 2018 Alexey Tourbin 0.29.2-alt1 +- 0.25 -> 0.29.2, rebased. +- Reimplemented --disable-recursion. +- Reimplemented "Tolerate missing Requires.private in --cflags mode". +- Fields like Cflags/Requires can span multiple lines. +- Some other changes, waiting for the missing upstream maintainer. + +* Mon Feb 28 2011 Alexey Tourbin 0.25-alt2 +- Tolerate missing Requires.private in --cflags mode. + +* Mon Nov 01 2010 Dmitry V. Levin 0.25-alt1 +- Updated to 0.25-6-g03bd4a5. +- Reverted all ALT-specific changes made to recursion algorithm. + More and more freedesktop packages now use Requires.private tag + to specify requirements for --cflags, so we have to revert to + upstream recursion algorithm. It will definitely bring us back + a lot of unneeded requirements among those few really needed + for compilation, but there seems to be no other way. + +* Wed Sep 09 2009 Dmitry V. Levin 0.23-alt4 +- Moved "make check" to %%check section. + +* Tue Dec 09 2008 Alexey Tourbin 0.23-alt3 +- added "Provides: pkgconfig(pkg-config) = %%version" + +* Tue Jun 24 2008 Alexey Tourbin 0.23-alt2 +- added %_rpmlibdir/%name-files.req.list, to make dependencies + on /usr/{lib,lib64,share}/pkgconfig directories + +* Thu Apr 24 2008 Dmitry V. Levin 0.23-alt1 +- Updated to 0.23. + +* Fri Oct 05 2007 Dmitry V. Levin 0.22-alt2 +- Added --enable-recursion and --disable-recursion hidden options. +- Added Provides: pkgconfig-recursion. +- Enabled recursion by default again because disabled recursion + breaks build of many screwed packages. + +* Tue Oct 02 2007 Dmitry V. Levin 0.22-alt1 +- Updated to 0.22. +- Removed dead code. +- Disabled recursion while querying for libraries unless in --static mode. + This change resurrects the behaviour which was introduced + in 0.15.0-alt3 and lost in 0.18. + +* Sun Nov 12 2006 Dmitry V. Levin 0.21-alt1 +- Updated to 0.21. +- Do not package ChangeLog file, NEWS should be enough. +- Do not package COPYING symlink, License tag should be enough. + +* Fri Feb 03 2006 Dmitry V. Levin 0.20-alt3.2 +- Added buildreq ignore rule (#9015). + +* Thu Feb 02 2006 Dmitry V. Levin 0.20-alt3.1 +- Provides: pkgconfig-reqprov. + +* Fri Jan 27 2006 Mikhail Zabaluev 0.20-alt3 +- Patch3: from Fedora CVS, add options for autoreqprov scripts + +* Sun Jan 22 2006 Dmitry V. Levin 0.20-alt2.1 +- Updated package provides. + +* Mon Nov 21 2005 Mikhail Zabaluev 0.20-alt2 +- Patch2: always ignore Requires.private line + unless --static option has been given + +* Mon Nov 21 2005 Mikhail Zabaluev 0.20-alt1 +- 0.20 +- Updated Patch0 and merged in Patch2 to it + +* Sat Sep 10 2005 Mikhail Zabaluev 0.19-alt1 +- 0.19 +- Do not remove /usr/share/pkg-config from the search path [bug #7911] +- Updated Patch1 & Patch2 +- Added NEWS and COPYING do doc list + +* Sun Apr 17 2005 Yuri N. Sedunov 0.17.2-alt1 +- 0.17.2 + +* Tue Apr 12 2005 Yuri N. Sedunov 0.17.1-alt1 +- 0.17.1 +- recursion disabled in upstream. + +* Mon Apr 04 2005 Yuri N. Sedunov 0.16.0-alt1 +- 0.16.0 +- updated patches. +- use only %%_libdir/pkgconfig as a default search path for .pc files. + +* Thu Jan 13 2005 Yuri N. Sedunov 0.15.0-alt4 +- fixed build with latest automake-1.9.4. + +* Fri Mar 05 2004 Yuri N. Sedunov 0.15.0-alt3.2 +- fix pkg.m4 for new automake. + +* Thu Feb 12 2004 Yuri N. Sedunov 0.15.0-alt3.1 +- provides /usr/lib/pkgconfig. + +* Sat Jan 03 2004 Yuri N. Sedunov 0.15.0-alt3 +- disable recursion while output linker flags. New --recursive option + restores former behavior. + +* Wed Dec 17 2003 Yuri N. Sedunov 0.15.0-alt2 +- build with system glib and popt. + +* Wed Jan 22 2003 Yuri N. Sedunov 0.15.0-alt1 +- 0.15.0 + +* Wed Dec 04 2002 Yuri N. Sedunov 0.14.0-alt1 +- 0.14.0, glib2-2.1.3 requires new version. +- removed empty NEWS from %%doc. +- small improvements in description. + +* Mon Sep 23 2002 AEN 0.13.0-alt1 +- new version + +* Wed Mar 27 2002 AEN 0.12.0-alt1 +- new version + +* Tue Feb 12 2002 Stanislav Ievlev 0.10.0-alt1 +- 0.10.0 + +* Thu Jul 26 2001 Stanislav Ievlev 0.8.0-alt1 +- 0.8.0. Cleanup spec. + +* Fri Jun 15 2001 AEN 0.7.0-alt2 +- BuildReq added + +* Fri Jun 15 2001 AEN 0.7.0-alt1 +- new version + +* Thu Apr 19 2001 Stanislav Ievlev 0.5.0-alt1 +- Initial release for ALTLinux. Descriptions to spec from Mandrake package diff --git a/pkg.c b/pkg.c index f29ecc7..6f62f57 100644 --- a/pkg.c +++ b/pkg.c @@ -49,6 +49,7 @@ static GList *search_dirs = NULL; gboolean disable_uninstalled = FALSE; gboolean ignore_requires = FALSE; gboolean ignore_requires_private = TRUE; +gboolean tolerate_missing_requires_private = FALSE; gboolean ignore_private_libs = TRUE; void @@ -219,6 +220,134 @@ package_init (gboolean want_list) add_virtual_pkgconfig_package (); } +static void +verify_info (Package *pkg) +{ + /* Be sure we have the required fields */ + if (pkg->name == NULL) + { + verbose_error ("Package '%s' has no Name: field\n", + pkg->key); + exit (1); + } + + if (pkg->version == NULL) + { + verbose_error ("Package '%s' has no Version: field\n", + pkg->key); + exit (1); + } + + if (pkg->description == NULL) + { + verbose_error ("Package '%s' has no Description: field\n", + pkg->key); + exit (1); + } +} + +static void +verify_req_version (Package *pkg, Package *req, RequiredVersion *ver) +{ + if (version_test (ver->comparison, req->version, ver->version)) + return; + verbose_error ("Package '%s' requires '%s %s %s' but version of %s is %s\n", + pkg->key, req->key, + comparison_to_str (ver->comparison), + ver->version, + req->key, + req->version); + if (req->url) + verbose_error ("You may find new versions of %s at %s\n", + req->name, req->url); + exit (1); +} + +static void +load_requires (Package *pkg, gboolean warn) +{ + GList *iter; + GHashTable *seen = g_hash_table_new (g_str_hash, g_str_equal); + + /* Pull in Requires packages. */ + for (iter = pkg->requires_entries; iter != NULL; iter = g_list_next (iter)) + { + Package *req; + RequiredVersion *ver = iter->data; + + debug_spew ("Searching for '%s' requirement '%s'\n", + pkg->key, ver->name); + req = internal_get_package (ver->name, warn); + if (req == NULL) + { + verbose_error ("Package '%s', required by '%s', not found\n", + ver->name, pkg->key); + exit (1); + } + + verify_req_version (pkg, req, ver); + + g_hash_table_insert (seen, ver->name, req); + + pkg->requires = g_list_prepend (pkg->requires, req); + } + + /* Check enhanced versions. That is, if there are both "Requires: foo" + * and "Requires.private: foo >= ver", the latter is checked on behalf + * of Requires. */ + if (ignore_requires_private) + for (iter = pkg->requires_private_entries; + iter != NULL; iter = g_list_next (iter)) + { + Package *req; + RequiredVersion *ver = iter->data; + + if (ver->comparison == ALWAYS_MATCH) + continue; + + req = g_hash_table_lookup (seen, ver->name); + if (req == NULL) + continue; + + verify_req_version (pkg, req, ver); + } + + g_hash_table_destroy (seen); + + /* Pull in Requires.private packages. */ + if (!ignore_requires_private) + for (iter = pkg->requires_private_entries; + iter != NULL; iter = g_list_next (iter)) + { + Package *req; + RequiredVersion *ver = iter->data; + + debug_spew ("Searching for '%s' private requirement '%s'\n", + pkg->key, ver->name); + req = internal_get_package (ver->name, + tolerate_missing_requires_private ? FALSE : warn); + if (req == NULL) + { + if (tolerate_missing_requires_private) + continue; + verbose_error ("Package '%s', required by '%s', not found\n", + ver->name, pkg->key); + exit (1); + } + + verify_req_version (pkg, req, ver); + + pkg->requires_private = g_list_prepend (pkg->requires_private, req); + } + + /* make requires_private include a copy of the public requires too */ + pkg->requires_private = g_list_concat (g_list_copy (pkg->requires), + pkg->requires_private); + + pkg->requires = g_list_reverse (pkg->requires); + pkg->requires_private = g_list_reverse (pkg->requires_private); +} + static Package * internal_get_package (const char *name, gboolean warn) { @@ -226,7 +355,6 @@ internal_get_package (const char *name, gboolean warn) char *key = NULL; char *location = NULL; unsigned int path_position = 0; - GList *iter; GList *dir_iter; pkg = g_hash_table_lookup (packages, name); @@ -299,8 +427,7 @@ internal_get_package (const char *name, gboolean warn) } debug_spew ("Reading '%s' from file '%s'\n", name, location); - pkg = parse_package_file (key, location, ignore_requires, - ignore_private_libs, ignore_requires_private); + pkg = parse_package_file (key, location); g_free (key); if (pkg != NULL && strstr (location, "uninstalled.pc")) @@ -314,6 +441,8 @@ internal_get_package (const char *name, gboolean warn) return NULL; } + g_assert (pkg->key != NULL); + pkg->path_position = path_position; debug_spew ("Path position of '%s' is %d\n", @@ -322,59 +451,12 @@ internal_get_package (const char *name, gboolean warn) debug_spew ("Adding '%s' to list of known packages\n", pkg->key); g_hash_table_insert (packages, pkg->key, pkg); - /* pull in Requires packages */ - for (iter = pkg->requires_entries; iter != NULL; iter = g_list_next (iter)) - { - Package *req; - RequiredVersion *ver = iter->data; - - debug_spew ("Searching for '%s' requirement '%s'\n", - pkg->key, ver->name); - req = internal_get_package (ver->name, warn); - if (req == NULL) - { - verbose_error ("Package '%s', required by '%s', not found\n", - ver->name, pkg->key); - exit (1); - } - - if (pkg->required_versions == NULL) - pkg->required_versions = g_hash_table_new (g_str_hash, g_str_equal); - - g_hash_table_insert (pkg->required_versions, ver->name, ver); - pkg->requires = g_list_prepend (pkg->requires, req); - } + verify_info (pkg); - /* pull in Requires.private packages */ - for (iter = pkg->requires_private_entries; iter != NULL; - iter = g_list_next (iter)) - { - Package *req; - RequiredVersion *ver = iter->data; - - debug_spew ("Searching for '%s' private requirement '%s'\n", - pkg->key, ver->name); - req = internal_get_package (ver->name, warn); - if (req == NULL) - { - verbose_error ("Package '%s', required by '%s', not found\n", - ver->name, pkg->key); - exit (1); - } - - if (pkg->required_versions == NULL) - pkg->required_versions = g_hash_table_new (g_str_hash, g_str_equal); - - g_hash_table_insert (pkg->required_versions, ver->name, ver); - pkg->requires_private = g_list_prepend (pkg->requires_private, req); - } - - /* make requires_private include a copy of the public requires too */ - pkg->requires_private = g_list_concat (g_list_copy (pkg->requires), - pkg->requires_private); - - pkg->requires = g_list_reverse (pkg->requires); - pkg->requires_private = g_list_reverse (pkg->requires_private); + if (!ignore_requires) + load_requires (pkg, warn); + else /* Requires ignored => Requires.private should also be ignored. */ + g_assert (ignore_requires_private); verify_package (pkg); @@ -656,70 +738,6 @@ verify_package (Package *pkg) const gchar **include_envvars; const gchar **var; - /* Be sure we have the required fields */ - - if (pkg->key == NULL) - { - fprintf (stderr, - "Internal pkg-config error, package with no key, please file a bug report\n"); - exit (1); - } - - if (pkg->name == NULL) - { - verbose_error ("Package '%s' has no Name: field\n", - pkg->key); - exit (1); - } - - if (pkg->version == NULL) - { - verbose_error ("Package '%s' has no Version: field\n", - pkg->key); - exit (1); - } - - if (pkg->description == NULL) - { - verbose_error ("Package '%s' has no Description: field\n", - pkg->key); - exit (1); - } - - /* Make sure we have the right version for all requirements */ - - iter = pkg->requires_private; - - while (iter != NULL) - { - Package *req = iter->data; - RequiredVersion *ver = NULL; - - if (pkg->required_versions) - ver = g_hash_table_lookup (pkg->required_versions, - req->key); - - if (ver) - { - if (!version_test (ver->comparison, req->version, ver->version)) - { - verbose_error ("Package '%s' requires '%s %s %s' but version of %s is %s\n", - pkg->key, req->key, - comparison_to_str (ver->comparison), - ver->version, - req->key, - req->version); - if (req->url) - verbose_error ("You may find new versions of %s at %s\n", - req->name, req->url); - - exit (1); - } - } - - iter = g_list_next (iter); - } - /* Make sure we didn't drag in any conflicts via Requires * (inefficient algorithm, who cares) */ @@ -857,6 +875,12 @@ verify_package (Package *pkg) system_directories = add_env_variable_to_list (system_directories, search_path); + if (ignore_private_libs) + g_list_free (pkg->libs_private); + else + pkg->libs = g_list_concat (pkg->libs, pkg->libs_private); + pkg->libs_private = NULL; + count = 0; for (iter = pkg->libs; iter != NULL; iter = g_list_next (iter)) { @@ -1171,15 +1195,18 @@ max_len_foreach (gpointer key, gpointer value, gpointer data) static void packages_foreach (gpointer key, gpointer value, gpointer data) { - Package *pkg = value; - char *pad; + const Package *pkg = value; - pad = g_strnfill (GPOINTER_TO_INT (data) - strlen (pkg->key), ' '); - - printf ("%s%s%s - %s\n", - pkg->key, pad, pkg->name, pkg->description); + printf ("%-*s%s - %s\n", + GPOINTER_TO_INT (data), pkg->key, pkg->name, pkg->description); +} - g_free (pad); +static int +array_elem_compare(const void *a, const void *b) +{ + const char * const *s_a = a; + const char * const *s_b = b; + return strcmp(*s_a, *s_b); } void @@ -1191,7 +1218,18 @@ print_package_list (void) ignore_requires_private = TRUE; g_hash_table_foreach (packages, max_len_foreach, &mlen); - g_hash_table_foreach (packages, packages_foreach, GINT_TO_POINTER (mlen + 1)); + + guint alen = 0; + gpointer *array = g_hash_table_get_keys_as_array (packages, &alen); + qsort((void *) array, alen, sizeof (array[0]), array_elem_compare); + + for (int i = 0; i < alen; ++i) + { + gpointer value = g_hash_table_lookup (packages, array[i]); + packages_foreach (array[i], value, GINT_TO_POINTER (mlen + 1)); + } + + g_free (array); } void @@ -1219,9 +1257,10 @@ disable_requires(void) } void -enable_requires_private(void) +enable_requires_private(gboolean tolerate_missing) { ignore_requires_private = FALSE; + tolerate_missing_requires_private = tolerate_missing; } void diff --git a/pkg.h b/pkg.h index c6732bd..65fe6f0 100644 --- a/pkg.h +++ b/pkg.h @@ -76,14 +76,12 @@ struct Package_ GList *requires_private_entries; GList *requires_private; GList *libs; + GList *libs_private; GList *cflags; GHashTable *vars; - GHashTable *required_versions; /* hash from name to RequiredVersion */ GList *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 */ char *orig_prefix; /* original prefix value before redefinition */ }; @@ -120,7 +118,7 @@ void enable_private_libs(void); void disable_private_libs(void); void enable_requires(void); void disable_requires(void); -void enable_requires_private(void); +void enable_requires_private(gboolean tolerate_missing); void disable_requires_private(void); /* If TRUE, do not automatically prefer uninstalled versions */