[RFC PATCH 07/12] build: use recursive addition for enabled libraries option

Bruce Richardson bruce.richardson at intel.com
Fri Oct 16 12:59:45 CEST 2026


When a user configures the build using "--enable_libs" there is no
automatic handling of dependencies for the requested libraries. For
example, if "ipsec" is a requested library, the user must know that
security and cryptodev libs must also be in the enabled set.

Fix this omission by using a python script to parse the previously
generated dependency set for the DPDK components and report out the
necessary libraries. This allows for the automatic addition of extra
libraries if they are needed to enable an explicitly-requested library.
If a dependency of a requested lib is explicitly in the disable list,
then error out.

Signed-off-by: Bruce Richardson <bruce.richardson at intel.com>
---
 buildtools/meson.build     |  1 +
 buildtools/resolve-deps.py | 80 ++++++++++++++++++++++++++++++++++++++
 lib/meson.build            | 18 +++++----
 3 files changed, 91 insertions(+), 8 deletions(-)
 create mode 100644 buildtools/resolve-deps.py

diff --git a/buildtools/meson.build b/buildtools/meson.build
index 02c66a5580..b3aa7197f9 100644
--- a/buildtools/meson.build
+++ b/buildtools/meson.build
@@ -26,6 +26,7 @@ get_deps_cmd = py3 + files('get-deps.py')
 get_numa_count_cmd = py3 + files('get-numa-count.py')
 get_min_meson_version_cmd = py3 + files('get-min-meson-version.py')
 get_test_suites_cmd = py3 + files('get-test-suites.py')
+resolve_deps_cmd = py3 + files('resolve-deps.py')
 header_gen_cmd = py3 + files('gen-header.py')
 has_hugepages_cmd = py3 + files('has-hugepages.py')
 cmdline_gen_cmd = py3 + files('dpdk-cmdline-gen.py')
diff --git a/buildtools/resolve-deps.py b/buildtools/resolve-deps.py
new file mode 100644
index 0000000000..ac2f9c63d9
--- /dev/null
+++ b/buildtools/resolve-deps.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2026 Intel Corporation
+
+"""List everything needed in order to build the given components.
+
+Reads the dependency graph produced by get-deps.py and prints, as a single
+comma-separated list, the named components plus everything they depend on,
+directly or indirectly.
+
+"""
+
+import argparse
+from collections import namedtuple
+
+Component = namedtuple("Component", ["kind", "name", "key", "deps"])
+
+
+def read_graph(filename):
+    """Load every component that can be depended upon.
+
+    Apps are never depended upon and may share a name with a library, e.g. graph
+    and pdump, so they are left out of the graph entirely.
+    """
+    components = []
+    with open(filename) as f:
+        for line in f:
+            kind, name, path, deps, _ = line.strip().split("|")
+            if kind == "app":
+                continue
+            # the option key is the path without its category directory
+            key = path.split("/", 1)[1]
+            components.append(Component(kind, name, key, [d for d in deps.split(",") if d]))
+    return components
+
+
+def needed(components, roots, kinds):
+    """Return the keys, of the wanted kinds, of everything the roots need."""
+    by_name = {c.name: c for c in components}
+    by_key = {c.key: c for c in components}
+
+    pending = []
+    for r in roots:
+        comp = by_key.get(r) or by_name.get(r)
+        if comp is not None:
+            pending.append(comp.name)
+
+    seen = set()
+    while pending:
+        comp = by_name[pending.pop()]
+        if comp.name in seen:
+            continue
+        seen.add(comp.name)
+        pending += [d for d in comp.deps if d in by_name]
+
+    return sorted(c.key for c in components if c.name in seen and c.kind in kinds)
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("graph", help="dependency graph file from get-deps.py")
+    parser.add_argument("--libs", action="store_true", help="report only libraries")
+    parser.add_argument("--drivers", action="store_true", help="report only drivers")
+    parser.add_argument("component", nargs="+", help="components to be built")
+    args = parser.parse_args()
+
+    kinds = []
+    if args.libs:
+        kinds.append("lib")
+    if args.drivers:
+        kinds.append("drv")
+    if not kinds:
+        kinds = ["lib", "drv"]
+
+    components = read_graph(args.graph)
+    print(",".join(needed(components, args.component, kinds)))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/lib/meson.build b/lib/meson.build
index 87bfb914e8..f7705d7ebe 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -100,18 +100,20 @@ endforeach
 
 disable_libs = run_command(list_dir_globs, get_option('disable_libs'), check: true).stdout().split()
 
-enable_libs = run_command(list_dir_globs, get_option('enable_libs'), check: true).stdout().split()
-foreach l:enable_libs
+requested_libs = run_command(list_dir_globs, get_option('enable_libs'), check: true).stdout().split()
+foreach l:requested_libs
     if disable_libs.contains(l)
         error('Library "@0@" is in both "enable_libs" and "disable_libs".'.format(l))
     endif
 endforeach
-require_libs = true
-if enable_libs.length() == 0
-    require_libs = false
-    enable_libs = libraries
-else
-    enable_libs += always_enable
+require_libs = requested_libs.length() != 0
+
+# expand the requested libraries to also include the libraries they depend on,
+# with an empty request meaning every library is wanted
+enable_libs = libraries
+if requested_libs.length() > 0
+    enable_libs = run_command(resolve_deps_cmd, dpdk_deps_graph, '--libs',
+            requested_libs + always_enable, check: true).stdout().strip().split(',')
 endif
 
 default_cflags = machine_args
-- 
2.53.0



More information about the dev mailing list