diff options
author | Dan Nicholson <dbn.lists@gmail.com> | 2012-05-09 05:55:47 -0700 |
---|---|---|
committer | Dan Nicholson <dbn.lists@gmail.com> | 2012-10-13 08:14:35 -0700 |
commit | 6d6dd43e75e2bc82cfe6544f8631b1bef6e1cf45 (patch) | |
tree | c779e053af295fb19cfe716f8f79a91ddc7983e9 | |
parent | 3f1f6e79b7ebf246906a6539901571b88bb74067 (diff) | |
download | pkg-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.am | 6 | ||||
-rwxr-xr-x | check/check-circular-requires | 8 | ||||
-rw-r--r-- | check/circular-1.pc | 11 | ||||
-rw-r--r-- | check/circular-2.pc | 11 | ||||
-rw-r--r-- | check/circular-3.pc | 11 | ||||
-rw-r--r-- | pkg.c | 18 |
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} @@ -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 |