summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Nicholson <dbn.lists@gmail.com>2012-05-09 05:55:47 -0700
committerDan Nicholson <dbn.lists@gmail.com>2012-10-13 08:14:35 -0700
commit6d6dd43e75e2bc82cfe6544f8631b1bef6e1cf45 (patch)
treec779e053af295fb19cfe716f8f79a91ddc7983e9
parent3f1f6e79b7ebf246906a6539901571b88bb74067 (diff)
downloadpkg-config-6d6dd43e75e2bc82cfe6544f8631b1bef6e1cf45.tar.gz
Support circular Requires loops
After the packages are parsed, pkg-config recurses through all the required packages to generate one list. Before descending another level, check to see if the package has already been handled and skip it. This allows packages to require each other circularly by breaking the loop. A test has been added resolving a two level deep circular dependency. Freedesktop #7331
-rw-r--r--check/Makefile.am6
-rwxr-xr-xcheck/check-circular-requires8
-rw-r--r--check/circular-1.pc11
-rw-r--r--check/circular-2.pc11
-rw-r--r--check/circular-3.pc11
-rw-r--r--pkg.c18
6 files changed, 64 insertions, 1 deletions
diff --git a/check/Makefile.am b/check/Makefile.am
index cd3f8b9..64a6151 100644
--- a/check/Makefile.am
+++ b/check/Makefile.am
@@ -8,6 +8,7 @@ TESTS = \
check-define-variable \
check-libs-private \
check-requires-private \
+ check-circular-requires \
check-includedir \
check-conflicts \
check-missing \
@@ -45,4 +46,7 @@ EXTRA_DIST = \
requires-version-2.pc \
requires-version-3.pc \
non-l.pc \
- non-l-required.pc
+ non-l-required.pc \
+ circular-1.pc \
+ circular-2.pc \
+ circular-3.pc
diff --git a/check/check-circular-requires b/check/check-circular-requires
new file mode 100755
index 0000000..e77370c
--- /dev/null
+++ b/check/check-circular-requires
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+set -e
+
+. ${srcdir}/common
+
+RESULT="-lcirc1 -lcirc2 -lcirc3"
+run_test --libs circular-1
diff --git a/check/circular-1.pc b/check/circular-1.pc
new file mode 100644
index 0000000..3d999a0
--- /dev/null
+++ b/check/circular-1.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/circ1
+
+Name: Circular Requires test 1
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-2
+Libs: -lcirc1
+Cflags: -I${includedir}
diff --git a/check/circular-2.pc b/check/circular-2.pc
new file mode 100644
index 0000000..8d8bd84
--- /dev/null
+++ b/check/circular-2.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/circ2
+
+Name: Circular Requires test 2
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-3
+Libs: -lcirc2
+Cflags: -I${includedir}
diff --git a/check/circular-3.pc b/check/circular-3.pc
new file mode 100644
index 0000000..ad6555a
--- /dev/null
+++ b/check/circular-3.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/circ3
+
+Name: Circular Requires test 3
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-1
+Libs: -lcirc3
+Cflags: -I${includedir}
diff --git a/pkg.c b/pkg.c
index dcbf85e..4ef36b0 100644
--- a/pkg.c
+++ b/pkg.c
@@ -626,6 +626,7 @@ static void
recursive_fill_list (Package *pkg, GetListFunc func, GSList **listp)
{
GSList *tmp;
+ static GSList *chain = NULL;
/*
* This function should only be called to resolve Requires or
@@ -633,10 +634,27 @@ recursive_fill_list (Package *pkg, GetListFunc func, GSList **listp)
*/
g_assert (func == get_requires || func == get_requires_private);
+ /*
+ * If the package is one of the parents, we can skip it. This allows
+ * circular requires loops to be broken.
+ */
+ if (g_slist_find (chain, pkg) != NULL)
+ {
+ debug_spew ("Package %s already in requires chain, skipping\n",
+ pkg->key);
+ return;
+ }
+
+ /* record this package in the dependency chain */
+ chain = g_slist_prepend (chain, pkg);
+
for (tmp = (*func) (pkg); tmp != NULL; tmp = g_slist_next (tmp))
recursive_fill_list (tmp->data, func, listp);
*listp = g_slist_prepend (*listp, pkg);
+
+ /* remove this package from the dependency chain now that we've unwound */
+ chain = g_slist_remove (chain, pkg);
}
static void