[PATCH 4/4] Support circular Requires loops

Dan Nicholson dbn.lists at gmail.com
Tue May 29 23:05:46 PDT 2012


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
---
 check/Makefile.am             |    8 ++++++--
 check/check-circular-requires |   15 +++++++++++++++
 check/circular-1.pc           |   11 +++++++++++
 check/circular-2.pc           |   11 +++++++++++
 check/circular-3.pc           |   11 +++++++++++
 pkg.c                         |   18 ++++++++++++++++++
 6 files changed, 72 insertions(+), 2 deletions(-)
 create mode 100755 check/check-circular-requires
 create mode 100644 check/circular-1.pc
 create mode 100644 check/circular-2.pc
 create mode 100644 check/circular-3.pc

diff --git a/check/Makefile.am b/check/Makefile.am
index 45fffbc..6cd826a 100644
--- a/check/Makefile.am
+++ b/check/Makefile.am
@@ -11,7 +11,8 @@ TESTS = \
 	check-whitespace \
 	check-cmd-options \
 	check-version \
-	check-non-l-flags
+	check-non-l-flags \
+	check-circular-requires
 
 EXTRA_DIST = \
 	$(TESTS) \
@@ -28,4 +29,7 @@ EXTRA_DIST = \
 	whitespace.pc \
 	fields-blank.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..7991481
--- /dev/null
+++ b/check/check-circular-requires
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+# Make sure we're POSIX
+if [ "$PKG_CONFIG_SHELL_IS_POSIX" != "1" ]; then
+    PKG_CONFIG_SHELL_IS_POSIX=1 PATH=`getconf PATH` exec sh $0 "$@"
+fi
+
+set -e
+
+. ${srcdir}/common
+
+ARGS="--libs circular-1"
+RESULT="-lcirc1 -lcirc2 -lcirc3"
+
+run_test
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 c640dfa..e34997f 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
-- 
1.7.7.6



More information about the pkg-config mailing list