[PATCH] Detect strongly connected components in package chains to handle cycles
yvvaibhav at gmail.com
yvvaibhav at gmail.com
Tue Feb 26 13:12:22 UTC 2019
From: Vaibhav Yenamandra <vyenamandra at bloomberg.net>
We introduce the ability to detect strongly connected components to
pkg-config based on the previously added cycle detection and breaking
feature.
Interface changes include:
* The command line interface to pkg-config will have the following
new flags:
- `--emit-groups` to control when pkg-config emits groups
- `--group-prefix`, `--group-suffix` to control the archive
group delimiters used on the link-line generated. These two
flags MUST occur together, when specified
* The emitted link line changes if cycles are present and
`--emit-groups` was provided
The changes of this commit can be summarized by the following:
* Packages that do not have cycles will not generate new link-lines
* To enable archive groups on the link line, packages with cyclic
dependency graphs must use `--emit-groups` on the CLI
* The output interface of pkg-config will change as follows:
_ The changes only occur if a cycle is detected with both the
`--emit-groups --static --libs` provided
- The change is only to the link-line emitted. CFLAGS and `-L`
flags are not affected.
- The value of `--group-prefix` defaults to '--start-group'
- The value of `--group-suffix` defaults to '--end-group'
- pkg-config will assume that the group delimiters when
provided, are valid for the target system
The effects of this commit on the link line will be that non-trivial
strongly-connected components (i.e. those comprised of more than one
package) will be surrounded by `--start-group` and `--end-group` on
platforms with linkers that support them.
Examples (in the presence of `--emit-groups`)
1. if `-lin -la -lcycle` was part of a cycle that was broken before
this change will cause it to be emitted as:
`--start-group -lin -la -lcycle --end-group`.
2. if `--group-prefix="-(" --group-suffix="-)"` was also provided, then
the generated link-line becomes:
`-( -lin -la -lcycle -)`.
---
check/Makefile.am | 8 ++
check/check-archive-groups | 58 ++++++++
check/circular-group-1.pc | 11 ++
check/circular-group-2.pc | 11 ++
check/circular-group-3.pc | 11 ++
check/head-line-1.pc | 11 ++
check/head-line-2.pc | 11 ++
check/tail-line-1.pc | 11 ++
check/tail-line-2.pc | 10 ++
main.c | 47 ++++++
parse.c | 2 +
pkg.c | 284 +++++++++++++++++++++++++++++++++++--
pkg.h | 30 ++++
13 files changed, 497 insertions(+), 8 deletions(-)
create mode 100755 check/check-archive-groups
create mode 100644 check/circular-group-1.pc
create mode 100644 check/circular-group-2.pc
create mode 100644 check/circular-group-3.pc
create mode 100644 check/head-line-1.pc
create mode 100644 check/head-line-2.pc
create mode 100644 check/tail-line-1.pc
create mode 100644 check/tail-line-2.pc
diff --git a/check/Makefile.am b/check/Makefile.am
index 68c6d84..214e728 100644
--- a/check/Makefile.am
+++ b/check/Makefile.am
@@ -31,6 +31,7 @@ TESTS = \
check-variables \
check-dependencies \
check-system-flags \
+ check-archive-groups \
$(NULL)
EXTRA_DIST = \
@@ -118,4 +119,11 @@ EXTRA_DIST = \
dependencies/j_dep_k.pc \
dependencies/k_dep.pc \
system.pc \
+ head-line-1.pc \
+ head-line-2.pc \
+ circular-group-1.pc \
+ circular-group-2.pc \
+ circular-group-3.pc \
+ tail-line-1.pc \
+ tail-line-2.pc \
$(NULL)
diff --git a/check/check-archive-groups b/check/check-archive-groups
new file mode 100755
index 0000000..a9977cd
--- /dev/null
+++ b/check/check-archive-groups
@@ -0,0 +1,58 @@
+#! /bin/sh
+
+set -e
+
+. ${srcdir}/common
+
+
+CIRCULAR_FLAGS="-lcirc1 -lcirc2 -lcirc3";
+CIRCULAR_GRP_FLAGS="-lcircgrp1 -lcircgrp2 -lcircgrp3";
+GRP_START="--start-group";
+GRP_END="--end-group"
+
+# Case 1: Whole package chain is a cycle
+RESULT="${CIRCULAR_FLAGS}";
+run_test --libs --static circular-1
+
+RESULT="${GRP_START} ${CIRCULAR_FLAGS} ${GRP_END}";
+run_test --emit-groups --libs --static circular-1
+
+# Case 2: There is one cycle within a linear chain
+RESULT="-lhline1 -lhline2 ${GRP_START} ${CIRCULAR_GRP_FLAGS} ${GRP_END} -ltline1 -ltline2";
+run_test --emit-groups --libs --static head-line-1
+
+RESULT="-lhline1 -lhline2 ${CIRCULAR_GRP_FLAGS} -ltline1 -ltline2";
+run_test --libs --static head-line-1
+
+# Case 3: Two disjoint cycles on separate chains
+RESULT="-lhline1 -lhline2 ${GRP_START} ${CIRCULAR_GRP_FLAGS} ${GRP_END} -ltline1 -ltline2 ${GRP_START} ${CIRCULAR_FLAGS} ${GRP_END}";
+run_test --emit-groups --libs --static head-line-1 circular-1
+
+RESULT="-lhline1 -lhline2 ${CIRCULAR_GRP_FLAGS} -ltline1 -ltline2 ${CIRCULAR_FLAGS}";
+run_test --libs --static head-line-1 circular-1
+
+RESULT="${GRP_START} ${CIRCULAR_FLAGS} ${GRP_END} -lhline1 -lhline2 ${GRP_START} ${CIRCULAR_GRP_FLAGS} ${GRP_END} -ltline1 -ltline2";
+run_test --emit-groups --libs --static circular-1 head-line-1
+
+RESULT="${CIRCULAR_FLAGS} -lhline1 -lhline2 ${CIRCULAR_GRP_FLAGS} -ltline1 -ltline2";
+run_test --libs --static circular-1 head-line-1
+
+# Case 4: Alternative group delimiters passed
+RESULT="-( ${CIRCULAR_FLAGS} -)";
+run_test --emit-groups \
+ --group-prefix="-(" --group-suffix="-)" \
+ --libs --static circular-1
+
+# Case 5: group delimiters not provided in pairs
+EXPECT_RETURN=1
+RESULT="--group-prefix must be accompanied by a --group-suffix"
+run_test --group-prefix="-(" circular-1
+
+EXPECT_RETURN=1
+RESULT="--group-prefix must be accompanied by a --group-suffix"
+run_test --group-suffix="-(" circular-1
+
+unset CIRCULAR_FLAGS;
+unset CIRCULAR_GRP_FLAGS;
+unset GRP_START;
+unset GRP_END;
diff --git a/check/circular-group-1.pc b/check/circular-group-1.pc
new file mode 100644
index 0000000..527c979
--- /dev/null
+++ b/check/circular-group-1.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/circgrp1
+
+Name: Circular Requires test 1
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-group-2
+Libs: -lcircgrp1
+Cflags: -I${includedir}
diff --git a/check/circular-group-2.pc b/check/circular-group-2.pc
new file mode 100644
index 0000000..228dddd
--- /dev/null
+++ b/check/circular-group-2.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/circgrp2
+
+Name: Circular Requires test 2
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-group-3
+Libs: -lcircgrp2
+Cflags: -I${includedir}
diff --git a/check/circular-group-3.pc b/check/circular-group-3.pc
new file mode 100644
index 0000000..3ce5f22
--- /dev/null
+++ b/check/circular-group-3.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/circgrp3
+
+Name: Circular Requires test 3
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-group-1 tail-line-1
+Libs: -lcircgrp3
+Cflags: -I${includedir}
diff --git a/check/head-line-1.pc b/check/head-line-1.pc
new file mode 100644
index 0000000..b90fe3d
--- /dev/null
+++ b/check/head-line-1.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/headline1
+
+Name: Archive Group test, linear-link head 1
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: head-line-2
+Libs: -lhline1
+Cflags: -I${includedir}
diff --git a/check/head-line-2.pc b/check/head-line-2.pc
new file mode 100644
index 0000000..add366e
--- /dev/null
+++ b/check/head-line-2.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/headline2
+
+Name: Archive Group test, linear-link head 2
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: circular-group-1
+Libs: -lhline2
+Cflags: -I${includedir}
diff --git a/check/tail-line-1.pc b/check/tail-line-1.pc
new file mode 100644
index 0000000..276aa3e
--- /dev/null
+++ b/check/tail-line-1.pc
@@ -0,0 +1,11 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/headline1
+
+Name: Archive Group test, linear-link tail 1
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Requires: tail-line-2
+Libs: -ltline1
+Cflags: -I${includedir}
diff --git a/check/tail-line-2.pc b/check/tail-line-2.pc
new file mode 100644
index 0000000..7bbcaac
--- /dev/null
+++ b/check/tail-line-2.pc
@@ -0,0 +1,10 @@
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include/headline2
+
+Name: Archive Group test, linear-link tail 2
+Description: Dummy package for testing circular Requires
+Version: 1.0.0
+Libs: -ltline2
+Cflags: -I${includedir}
diff --git a/main.c b/main.c
index 9b27d9a..e0361e6 100644
--- a/main.c
+++ b/main.c
@@ -62,6 +62,11 @@ static gboolean want_verbose_errors = FALSE;
static gboolean want_stdout_errors = FALSE;
static gboolean output_opt_set = FALSE;
+/* Required by get_components */
+gboolean want_groups = FALSE;
+char *group_prefix = NULL;
+char *group_suffix = NULL;
+
void
debug_spew (const char *format, ...)
{
@@ -475,6 +480,17 @@ static const GOptionEntry options_table[] = {
{ "prefix-variable", 0, 0, G_OPTION_ARG_STRING, &prefix_variable,
"set the name of the variable that pkg-config automatically sets",
"PREFIX" },
+ { "emit-groups", 0, 0, G_OPTION_ARG_NONE, &want_groups,
+ "enable emitting link lines with cycles surrounded in archive group flags"
+ , NULL },
+ { "group-prefix", 0, 0, G_OPTION_ARG_STRING, &group_prefix,
+ "complete flag to be used as an archive group suffix, "
+ "defaults to '--start-group'",
+ "GROUP_PREFIX"},
+ { "group-suffix", 0, 0, G_OPTION_ARG_STRING, &group_suffix,
+ "complete flag to be used as an archive group suffix, "
+ "defaults to '--end-group'",
+ "GROUP_SUFFIX"},
#ifdef G_OS_WIN32
{ "msvc-syntax", 0, 0, G_OPTION_ARG_NONE, &msvc_syntax,
"output -l and -L flags for the Microsoft compiler (cl)", NULL },
@@ -651,6 +667,37 @@ main (int argc, char **argv)
return 0;
}
+ gboolean saw_group_start = group_prefix != NULL;
+ gboolean saw_group_end = group_suffix != NULL;
+ /* Ensure that --group-prefix and --group-suffix flags occur in pairs
+ * if they are present. Fail fatally if not */
+ if (saw_group_start ^ saw_group_end)
+ {
+ fprintf (stderr,
+ "--group-prefix must be accompanied by a "
+ "--group-suffix\n");
+ exit (1);
+ }
+
+ /* Assign default values to the the group prefix, suffix if both were
+ * unspecified */
+ if (!saw_group_start && !saw_group_end)
+ {
+ if (want_groups)
+ {
+
+ debug_spew ("Using defaults for archive group delimiters:\n"
+ " group_prefix = '--start-group'\n"
+ " group_suffix = '--end-group'\n");
+ group_prefix = "--start-group";
+ group_suffix = "--end-group";
+ }
+ else
+ {
+ group_prefix = "";
+ group_suffix = "";
+ }
+ }
/* Collect packages from remaining args */
str = g_string_new ("");
while (argc > 1)
diff --git a/parse.c b/parse.c
index 6e9907c..9d2f5d2 100644
--- a/parse.c
+++ b/parse.c
@@ -1110,6 +1110,8 @@ parse_package_file (const char *key, const char *path,
pkg = g_new0 (Package, 1);
pkg->key = g_strdup (key);
+ pkg->cycle_edge_destination_count = 0;
+ pkg->cycle_edge_source_count = 0;
if (path)
{
diff --git a/pkg.c b/pkg.c
index f29ecc7..d08a742 100644
--- a/pkg.c
+++ b/pkg.c
@@ -51,6 +51,21 @@ gboolean ignore_requires = FALSE;
gboolean ignore_requires_private = TRUE;
gboolean ignore_private_libs = TRUE;
+static void
+print_package(gpointer pkg_, gpointer prefix)
+{
+ Package *pkg = pkg_;
+ debug_spew ("%sPackage{%s, U: %d, D: %d}\n",
+ (char *) prefix, pkg->key, pkg->cycle_edge_source_count,
+ pkg->cycle_edge_destination_count);
+}
+
+static void
+free_component(gpointer component_ptr)
+{
+ g_free (component_ptr);
+}
+
void
add_search_dir (const char *path)
{
@@ -541,6 +556,171 @@ recursive_fill_list (Package *pkg, gboolean include_private,
*listp = g_list_prepend (*listp, pkg);
}
+static void
+print_component(gpointer component, gpointer line_prefix)
+{
+ Component* c = component;
+ char *start = c->start ? ((Package*) c->start->data)->key : "NULL";
+ char *end = c->end ? ((Package*) c->end->data)->key : "NULL";
+ debug_spew ("%sComponent{start: %s, end: %s}\n",
+ (char *) line_prefix, start, end);
+}
+
+static GList*
+get_components(GList* packages)
+{
+ /* Detect cycles in the dependency chain by finding the smallest dep index
+ * for each pacakge. A cycle occurs if any of its requires does not occur
+ * after the package. */
+ GHashTable *earliest_dep = g_hash_table_new(g_str_hash, g_str_equal);
+ GHashTable *pkg_index = g_hash_table_new(g_str_hash, g_str_equal);
+
+ int num_pkgs = g_list_length (packages);
+ int curr_idx = 0;
+
+ /* Containers to hold data referenced by value pointers passed to pkg_index,
+ * earliest_dep respectively.
+ * - indices is an array containing the integer index of each package
+ * - min_dep_idx records the smallest index from a package's requires*/
+ int *indices = g_new0(int, num_pkgs);
+ int *min_dep_idx = g_new(int, num_pkgs);
+
+ /* Default values for smallest dep index, since we only want positive values
+ * when there are cycles */
+ for(int idx = 0; idx < num_pkgs; ++idx)
+ {
+ min_dep_idx[idx] = -1;
+ }
+
+ /* Pre-process to load the index of each key into a table */
+ for (GList *pkg_it = packages; pkg_it != NULL; pkg_it = g_list_next (pkg_it))
+ {
+ indices[curr_idx] = curr_idx;
+ Package *pkg = pkg_it->data;
+ g_hash_table_replace (pkg_index, pkg->key, &indices[curr_idx]);
+ ++curr_idx;
+ }
+
+ /*
+ * Find the index of smallest dependency for each package and
+ * record back edges
+ */
+ curr_idx = 0;
+ for (GList *pkg_it = packages; pkg_it != NULL; pkg_it = g_list_next (pkg_it))
+ {
+ Package *pkg = pkg_it->data;
+ g_hash_table_insert (earliest_dep, pkg->key, &min_dep_idx[curr_idx]);
+ int curr_idx = *( (int *) g_hash_table_lookup (pkg_index, pkg->key));
+
+ for (GList* req_it = pkg->requires_private; req_it != NULL;
+ req_it = g_list_next(req_it))
+ {
+ Package *req = req_it->data;
+ int ridx = *( (int *) g_hash_table_lookup (pkg_index, req->key));
+
+ /*
+ * Back-edges are identified by looking at items in the requires
+ * list that were sorted before the current package, i.e. their
+ * DFS discovery time was earlier than this package's discovery time
+ */
+ if (ridx < curr_idx)
+ {
+ min_dep_idx[curr_idx] = ridx;
+ g_hash_table_replace (earliest_dep,
+ pkg->key, &min_dep_idx[curr_idx]);
+ pkg->cycle_edge_source_count += 1;
+ req->cycle_edge_destination_count += 1;
+ }
+ }
+ ++curr_idx;
+ }
+
+ debug_spew ("List of packages with cycle meta-data:\n");
+ g_list_foreach (packages, print_package, " ");
+
+ /* The current non-trivial component being processed */
+ Component *c_nontrivial = NULL;
+ /* Linked list that records all of the components we saw */
+ GList *components = NULL;
+
+ /* Running tally of up/down edges encounted. Always up to date with the
+ * destination count, lags by 1 iteration on the source count */
+ int cycle_tally = 0;
+
+ /* Current state that we are in. We can either be (IN/ON THE CUSP) of a
+ * cycle or not. */
+ gboolean in_cycle = FALSE;
+
+ /* Incorporate packages into components */
+ for (GList *pkg_it = packages; pkg_it != NULL; pkg_it = g_list_next (pkg_it))
+ {
+ Package *curr = pkg_it->data;
+ Package *prev = pkg_it->prev ? pkg_it->prev->data : NULL;
+ debug_spew("in_cycle: %s ", in_cycle ? "TRUE" : "FALSE");
+ print_package(curr, "processing ");
+ // Re-evaluate what the current state should be before assigning the
+ // current package to a component.
+ if (!in_cycle)
+ {
+ if (curr->cycle_edge_source_count != 0 ||
+ curr->cycle_edge_destination_count != 0)
+ {
+ // Initialize the NT component temporary variable
+ c_nontrivial = g_new0(Component, 1);
+ c_nontrivial->start = pkg_it;
+ c_nontrivial->non_trivial = TRUE;
+ in_cycle = TRUE;
+ }
+ }
+ else
+ {
+ if (prev && cycle_tally == prev->cycle_edge_source_count)
+ {
+ // Reset the NT component temporary variable after adding it
+ // to the components list
+ c_nontrivial->end = pkg_it;
+ components = g_list_prepend(components, c_nontrivial);
+ c_nontrivial = NULL;
+ in_cycle = FALSE;
+ cycle_tally = 0;
+ }
+ }
+
+ if (!in_cycle)
+ {
+ Component *c = g_new0(Component, 1);
+ c->start = pkg_it;
+ c->end = g_list_next(pkg_it);
+ c->non_trivial = FALSE;
+ components = g_list_prepend(components, c);
+ }
+ else
+ {
+ cycle_tally += curr->cycle_edge_destination_count;
+ cycle_tally -= prev ? prev->cycle_edge_source_count : 0;
+ }
+ }
+
+ /* If we end on a cycle, add the current non_trivial component to the
+ * list of components */
+ if (in_cycle)
+ {
+ components = g_list_prepend(components, c_nontrivial);
+ }
+
+ /* Reverse them to match dependency order since we inserted by
+ * prepending */
+ components = g_list_reverse (components);
+ debug_spew ("Identified components:\n");
+ g_list_foreach (components, &print_component, " ");
+ g_hash_table_destroy (pkg_index);
+ g_hash_table_destroy (earliest_dep);
+ g_free(indices);
+ g_free(min_dep_idx);
+
+ return components;
+}
+
/* merge the flags from the individual packages */
static GList *
merge_flag_lists (GList *packages, FlagType type)
@@ -575,9 +755,91 @@ merge_flag_lists (GList *packages, FlagType type)
return merged;
}
+/* merge the flags from the individual packages, incorporating archive groups
+ * if necessary
+ */
+static GList *
+merge_flag_lists_by_component (GList *packages, FlagType type,
+ gboolean repeat_cycles)
+{
+ if (repeat_cycles)
+ {
+ GList *merged = NULL;
+ GList *components = NULL;
+
+ debug_spew ("Merging flags by component\n");
+ components = get_components (packages);
+ for (; components != NULL; components = g_list_next (components))
+ {
+ Component* c = components->data;
+ GList *dashl = NULL;
+ if (c->non_trivial)
+ {
+ debug_spew ("Reading non-trivial component: ");
+ }
+ else
+ {
+ debug_spew ("Reading trivial component: ");
+ }
+ print_component (c, "");
+
+ if (c->non_trivial && want_groups)
+ {
+ Flag *start = g_new0(Flag, 1);
+ start->type = GROUP_DELIM;
+ start->arg = group_prefix;
+
+ dashl = g_list_append(dashl, start);
+ }
+ for (GList* begin = c->start;
+ begin != c->end;
+ begin = g_list_next (begin))
+ {
+ Package* pkg = begin->data;
+ print_package (pkg, " ");
+ GList *flags = (type & LIBS_ANY) ? pkg->libs : pkg->cflags;
+
+ /* manually copy the elements so we can keep track of the end.
+ * This code is duplicated to avoid the quadratic cost
+ * involved in finding the last element for every component chunk.
+ *
+ * SEE: merge_flag_lists(GList *packages, FlagType type)
+ */
+ for (; flags != NULL; flags = g_list_next (flags))
+ {
+ Flag *flag = flags->data;
+
+ if (flag->type & type)
+ {
+ dashl = g_list_append(dashl, flag);
+ }
+ }
+ }
+ if (c->non_trivial && want_groups)
+ {
+ Flag *end = g_new0(Flag, 1);
+ end->type = GROUP_DELIM;
+ end->arg = group_suffix;
+ dashl = g_list_append(dashl, end);
+ }
+
+ /* This is only done for flags matching the mask
+ * (LIBS_l | LIBS_OTHER) */
+ merged = g_list_concat(merged, dashl);
+ }
+ g_list_free_full (components, free_component);
+ return merged;
+ }
+ else
+ {
+ return merge_flag_lists (packages, type);
+ }
+}
+
static GList *
fill_list (GList *packages, FlagType type,
- gboolean in_path_order, gboolean include_private)
+ gboolean in_path_order, gboolean include_private,
+ gboolean capture_cycles)
{
GList *tmp;
GList *expanded = NULL;
@@ -599,7 +861,7 @@ fill_list (GList *packages, FlagType type,
spew_package_list (" sorted", expanded);
}
- flags = merge_flag_lists (expanded, type);
+ flags = merge_flag_lists_by_component (expanded, type, capture_cycles);
g_list_free (expanded);
return flags;
@@ -912,12 +1174,16 @@ verify_package (Package *pkg)
*/
static char *
get_multi_merged (GList *pkgs, FlagType type, gboolean in_path_order,
- gboolean include_private)
+ gboolean include_private, gboolean capture_cycles)
{
GList *list;
char *retval;
- list = fill_list (pkgs, type, in_path_order, include_private);
+ list = fill_list (pkgs,
+ type,
+ in_path_order,
+ include_private,
+ capture_cycles);
list = flag_list_strip_duplicates (list);
retval = flag_list_to_string (list);
g_list_free (list);
@@ -936,21 +1202,21 @@ packages_get_flags (GList *pkgs, FlagType flags)
/* sort packages in path order for -L/-I, dependency order otherwise */
if (flags & CFLAGS_OTHER)
{
- cur = get_multi_merged (pkgs, CFLAGS_OTHER, FALSE, TRUE);
+ cur = get_multi_merged (pkgs, CFLAGS_OTHER, FALSE, TRUE, FALSE);
debug_spew ("adding CFLAGS_OTHER string \"%s\"\n", cur);
g_string_append (str, cur);
g_free (cur);
}
if (flags & CFLAGS_I)
{
- cur = get_multi_merged (pkgs, CFLAGS_I, TRUE, TRUE);
+ cur = get_multi_merged (pkgs, CFLAGS_I, TRUE, TRUE, FALSE);
debug_spew ("adding CFLAGS_I string \"%s\"\n", cur);
g_string_append (str, cur);
g_free (cur);
}
if (flags & LIBS_L)
{
- cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_private_libs);
+ cur = get_multi_merged (pkgs, LIBS_L, TRUE, !ignore_private_libs, FALSE);
debug_spew ("adding LIBS_L string \"%s\"\n", cur);
g_string_append (str, cur);
g_free (cur);
@@ -958,7 +1224,9 @@ packages_get_flags (GList *pkgs, FlagType flags)
if (flags & (LIBS_OTHER | LIBS_l))
{
cur = get_multi_merged (pkgs, flags & (LIBS_OTHER | LIBS_l), FALSE,
- !ignore_private_libs);
+ !ignore_private_libs,
+ (!ignore_requires_private &&
+ !ignore_private_libs));
debug_spew ("adding LIBS_OTHER | LIBS_l string \"%s\"\n", cur);
g_string_append (str, cur);
g_free (cur);
diff --git a/pkg.h b/pkg.h
index c6732bd..01272e3 100644
--- a/pkg.h
+++ b/pkg.h
@@ -29,6 +29,7 @@ typedef guint8 FlagType; /* bit mask for flag types */
#define LIBS_OTHER (1 << 2)
#define CFLAGS_I (1 << 3)
#define CFLAGS_OTHER (1 << 4)
+#define GROUP_DELIM (1 << 5)
#define LIBS_ANY (LIBS_l | LIBS_L | LIBS_OTHER)
#define CFLAGS_ANY (CFLAGS_I | CFLAGS_OTHER)
@@ -47,6 +48,7 @@ typedef enum
typedef struct Flag_ Flag;
typedef struct Package_ Package;
+typedef struct Component_ Component;
typedef struct RequiredVersion_ RequiredVersion;
struct Flag_
@@ -85,6 +87,29 @@ struct Package_
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 */
+ int cycle_edge_source_count; /* The number of times this vertex was the
+ source vertex of an edge that was skipped
+ to maintain acyclicicty */
+ int cycle_edge_destination_count; /* The number of times this vertex was the
+ destination vertex of an edge that was
+ skipped to main acyclicicy */
+};
+
+/* A component is any collection of possibly inter-dependent packages
+* which contains *AT MOST 1* strongly connected component from the original
+* dependency graph.
+*
+* Two components from the same dependency graph *CANNOT* overlap as they are
+* disjoint partitionings of the DAG generated after partitioning the original
+* topologically sorted dependency graph.
+*/
+struct Component_
+{
+ GList* start; /* Iterator to the first package in the component */
+ GList* end; /* Iterator to the last package in the component,
+ can be the same as `start` */
+ gboolean non_trivial; /* A flag that is set if this component contains more
+ than one package */
};
Package *get_package (const char *name);
@@ -142,6 +167,11 @@ extern gboolean define_prefix;
/* The name of the variable that acts as prefix, unless it is "prefix" */
extern char *prefix_variable;
+/* Hold the group prefix and suffix to be used when emitting archive groups */
+extern gboolean want_groups;
+extern char *group_prefix;
+extern char *group_suffix;
+
#ifdef G_OS_WIN32
/* If TRUE, output flags in MSVC syntax. */
extern gboolean msvc_syntax;
--
2.19.1
More information about the pkg-config
mailing list