@@ -77,7 +77,22 @@ foreach app:apps
endif
if build
+ # call into subdir may update name so record it here
+ display_name = name
+
subdir(name)
+ app_name = 'dpdk-' + name
+
+ # log mandatory dependencies
+ cmds = ['--type', 'app']
+ cmds += ['--display-name', display_name]
+ run_command([log_deps_cmd, cmds, app_name, deps], check: false)
+
+ # log optional dependencies, if any
+ if optional_deps.length() > 0
+ cmds += ['--optional']
+ run_command([log_deps_cmd, cmds, app_name, optional_deps], check: false)
+ endif
if not build and require_apps
error('Cannot build explicitly requested app "@0@".\n'.format(name)
+ '\tReason: ' + reason)
@@ -125,7 +140,7 @@ foreach app:apps
link_libs = dpdk_static_libraries + dpdk_drivers
endif
- exec = executable('dpdk-' + name,
+ exec = executable(app_name,
[ sources, resources ],
c_args: cflags,
link_args: ldflags,
new file mode 100644
@@ -0,0 +1,94 @@
+#! /usr/bin/env python3
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2024 Intel Corporation
+
+"""Utility script to build up a list of dependencies from meson."""
+
+import os
+import sys
+import argparse
+import typing as T
+
+
+def file_to_list(filename: str) -> T.List[str]:
+ """Read file into a list of strings."""
+ with open(filename, encoding="utf-8") as f:
+ return f.readlines()
+
+
+def list_to_file(filename: str, lines: T.List[str]):
+ """Write a list of strings out to a file."""
+ with open(filename, "w", encoding="utf-8") as f:
+ f.writelines(lines)
+
+
+def gen_deps(
+ component_type: str,
+ optional: bool,
+ component: str,
+ display_name: T.Optional[str],
+ deps: T.List[str],
+) -> str:
+ """Generate a dependency graph for meson."""
+ dep_list_str = '", "'.join(deps)
+ deps_str = "" if not deps else f' -> {{ "{dep_list_str}" }}'
+ # we define custom attributes for the nodes
+ attr_str = f'dpdk_componentType="{component_type}"'
+ if optional:
+ # we use a dotted line to represent optional dependencies
+ attr_str += ',style="dotted"'
+ if display_name is not None:
+ attr_str += f',dpdk_displayName="{display_name}"'
+ return f'"{component}"{deps_str} [{attr_str}]\n'
+
+
+def _main():
+ depsfile = f'{os.environ["MESON_BUILD_ROOT"]}/deps.dot'
+
+ # to reset the deps file on each build, the script is called without any params
+ if len(sys.argv) == 1:
+ os.remove(depsfile)
+ sys.exit(0)
+
+ # we got arguments, parse them
+ parser = argparse.ArgumentParser(
+ description="Generate a dependency graph for meson."
+ )
+ # type is required
+ parser.add_argument(
+ "--type", required=True, help="Type of dependency (lib, examples, etc.)"
+ )
+ parser.add_argument(
+ "--optional", action="store_true", help="Whether the dependency is optional"
+ )
+ parser.add_argument(
+ "--display-name",
+ help="Component name as it is used in the build system",
+ )
+ # component is required
+ parser.add_argument("component", help="The component to add to the graph")
+ parser.add_argument("deps", nargs="*", help="The dependencies of the component")
+
+ parsed = parser.parse_args()
+
+ try:
+ contents = file_to_list(depsfile)
+ except FileNotFoundError:
+ contents = ["digraph {\n", "}\n"]
+
+ # occasionally, component binary name may be different from what it appears in Meson.
+ display_name = parsed.display_name
+
+ c_type = parsed.type
+ optional = parsed.optional
+ component = parsed.component
+ deps = parsed.deps
+ contents[-1] = gen_deps(c_type, optional, component, display_name, deps)
+
+ contents.append("}\n")
+
+ list_to_file(depsfile, contents)
+
+
+if __name__ == "__main__":
+ _main()
@@ -26,6 +26,8 @@ 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')
check_dts_requirements = py3 + files('check-dts-requirements.py')
+log_deps_cmd = py3 + files('log-deps.py')
+run_command(log_deps_cmd, check: false) # call with no parameters to reset the file
# install any build tools that end-users might want also
install_data([
@@ -157,6 +157,8 @@ foreach subpath:subdirs
endif
if build
+ # call into subdir may update name so record it here
+ display_name = '@0@/@1@'.format(class, name)
# pull in driver directory which should update all the local variables
subdir(drv_path)
@@ -171,6 +173,18 @@ foreach subpath:subdirs
+'\tReason: ' + reason)
endif
+ # log mandatory dependencies
+ cmds = ['--type', 'drivers']
+ cmds += ['--display-name', display_name]
+ drv_name = class + '_' + name
+ run_command([log_deps_cmd, cmds, drv_name, deps], check: false)
+
+ # log optional dependencies, if any
+ if optional_deps.length() > 0
+ cmds += ['--optional']
+ run_command([log_deps_cmd, cmds, drv_name, optional_deps], check: false)
+ endif
+
# get dependency objs from strings
shared_deps = ext_deps
static_deps = ext_deps
@@ -99,11 +99,27 @@ foreach example: examples
includes = [include_directories(example, 'common')]
deps = ['eal', 'mempool', 'net', 'mbuf', 'ethdev', 'cmdline']
optional_deps = []
+
+ # call into subdir may update name so record it here
+ display_name = example
+
subdir(example)
+ example_name = 'dpdk-' + name
if build
dep_objs = ext_deps
+ # log mandatory dependencies
+ cmds = ['--type', 'examples']
+ cmds += ['--display-name', display_name]
+ run_command([log_deps_cmd, cmds, example_name, deps], check: false)
+
+ # log optional dependencies, if any
+ if optional_deps.length() > 0
+ cmds += ['--optional']
+ run_command([log_deps_cmd, cmds, example_name, optional_deps], check: false)
+ endif
+
# resolve any optional internal dependencies
def_lib = get_option('default_library')
foreach d: optional_deps
@@ -135,7 +151,7 @@ foreach example: examples
if allow_experimental_apis
cflags += '-DALLOW_EXPERIMENTAL_API'
endif
- executable('dpdk-' + name, sources,
+ executable(example_name, sources,
include_directories: includes,
link_whole: link_whole_libs,
link_args: ldflags,
@@ -160,7 +160,21 @@ foreach l:libraries
endif
if build
+ # as per warning below, directory name should match library name but it is not considered an error
+ display_name = name
+
subdir(l)
+
+ # log mandatory dependencies
+ cmds = ['--type', 'lib']
+ cmds += ['--display-name', display_name]
+ run_command([log_deps_cmd, cmds, name, deps], check: false)
+
+ # log optional dependencies, if any
+ if optional_deps.length() > 0
+ cmds += ['--optional']
+ run_command([log_deps_cmd, cmds, name, optional_deps], check: false)
+ endif
if not build and require_libs
error('Cannot build explicitly requested lib "@0@".\n'.format(name)
+'\tReason: ' + reason)