[PATCH 09/17] tools/arch/x86/pmtctl: Add libpmtctl Makefile + pc + README

From: David E. Box

Date: Mon May 25 2026 - 21:52:54 EST


Add build infrastructure for libpmtctl_core, allowing the library to be
built standalone and consumed by downstream tools via pkg-config.

Provide separate release and debug build variants so optimized and
development builds can coexist within the same checkout without
overwriting each other.

JSON metric definition support is optional at build time. When built with
HAVE_JANSSON, the JSON metric provider is enabled and linked against
libjansson. Otherwise, JSON-backed metric loading remains unavailable and
pmt_metrics_load() returns PMTCTL_ERR_UNSUPPORTED for non-NULL path
arguments.

Add a pkg-config template for discovering the library's compile and link
flags, along with a README describing the library purpose and build
options.

Assisted-by: GitHub-Copilot:claude-sonnet-4.6
Signed-off-by: David E. Box <david.e.box@xxxxxxxxxxxxxxx>
---
tools/arch/x86/pmtctl/lib/Makefile | 108 +++++++++++++++++++
tools/arch/x86/pmtctl/lib/README | 116 +++++++++++++++++++++
tools/arch/x86/pmtctl/libpmtctl-core.pc.in | 11 ++
3 files changed, 235 insertions(+)
create mode 100644 tools/arch/x86/pmtctl/lib/Makefile
create mode 100644 tools/arch/x86/pmtctl/lib/README
create mode 100644 tools/arch/x86/pmtctl/libpmtctl-core.pc.in

diff --git a/tools/arch/x86/pmtctl/lib/Makefile b/tools/arch/x86/pmtctl/lib/Makefile
new file mode 100644
index 000000000000..e2aeff1935cf
--- /dev/null
+++ b/tools/arch/x86/pmtctl/lib/Makefile
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+CC := gcc
+AR := ar
+RANLIB := ranlib
+
+BUILD ?= release
+
+CPPFLAGS += -I../include -I../../../../include -D_GNU_SOURCE
+CFLAGS += -std=gnu11 -Wall -Wextra
+
+WEXTRA_WARN := -Wpedantic -Wmissing-prototypes -Wstrict-prototypes \
+ -Wunused-function -Wunused-variable -Wunused-parameter \
+ -Wunused-but-set-variable -Wunreachable-code
+
+ifeq ($(BUILD),debug)
+ CFLAGS += -O0 -g3 -fno-omit-frame-pointer
+ CFLAGS += $(WEXTRA_WARN)
+ CPPFLAGS += -DDEBUG
+else ifeq ($(BUILD),release)
+ CFLAGS += -O2 -g0 -DNDEBUG
+else
+ $(error unknown BUILD '$(BUILD)' (use release or debug))
+endif
+
+BUILDDIR := ../build/$(BUILD)/lib
+CORE_TARGET := $(BUILDDIR)/libpmtctl_core.a
+
+CORE_SRC := \
+ log.c \
+ common.c \
+ device_telem.c \
+ metrics_db.c \
+ pmt_guid.c \
+ pmtctl.c \
+ metrics_provider.c \
+ builtin_defs_empty.c
+
+HAVE_JANSSON ?= 0
+ifeq ($(HAVE_JANSSON),1)
+ CORE_SRC += metrics_provider_json.c
+ CPPFLAGS += -DHAVE_JANSSON
+ LDLIBS += -ljansson
+endif
+
+CORE_OBJ := $(patsubst %.c,$(BUILDDIR)/%.o,$(CORE_SRC))
+
+PREFIX ?= /usr/local
+DESTDIR ?=
+INCLUDEDIR ?= $(PREFIX)/include/pmtctl
+LIBINSTALLDIR ?= $(PREFIX)/lib
+PKGCONFIGDIR ?= $(LIBINSTALLDIR)/pkgconfig
+
+PC_CORE := ../libpmtctl-core.pc
+PC_FILES := $(PC_CORE)
+
+PUBLIC_HEADERS := \
+ ../include/lib/pmtctl.h \
+ ../include/lib/metrics_db.h \
+ ../include/lib/pmt_guid.h \
+ ../include/lib/device.h
+
+.PHONY: all clean install install-lib install-headers install-pkgconfig uninstall uninstall-lib uninstall-headers uninstall-pkgconfig
+
+all: $(CORE_TARGET)
+
+$(CORE_TARGET): $(CORE_OBJ)
+ $(AR) rcs $@ $(CORE_OBJ)
+ $(RANLIB) $@
+
+$(PC_CORE): ../libpmtctl-core.pc.in
+ @sed -e 's|@PREFIX@|$(PREFIX)|g' \
+ -e 's|@JANSSON_LIBS@|$(if $(filter 1,$(HAVE_JANSSON)), -ljansson,)|g' \
+ $< > $@
+
+$(BUILDDIR)/%.o: %.c
+ @mkdir -p $(BUILDDIR)
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+install: all install-lib install-headers install-pkgconfig
+
+install-lib: all
+ install -d $(DESTDIR)$(LIBINSTALLDIR)
+ install -m 0644 $(CORE_TARGET) $(DESTDIR)$(LIBINSTALLDIR)
+
+install-headers:
+ install -d $(DESTDIR)$(INCLUDEDIR)
+ install -m 0644 $(PUBLIC_HEADERS) $(DESTDIR)$(INCLUDEDIR)
+
+install-pkgconfig: $(PC_FILES)
+ install -d $(DESTDIR)$(PKGCONFIGDIR)
+ install -m 0644 $(PC_FILES) $(DESTDIR)$(PKGCONFIGDIR)
+
+uninstall: uninstall-lib uninstall-headers uninstall-pkgconfig
+
+uninstall-lib:
+ rm -f $(DESTDIR)$(LIBINSTALLDIR)/libpmtctl_core.a
+
+uninstall-headers:
+ rm -f $(DESTDIR)$(INCLUDEDIR)/pmtctl.h
+ rm -f $(DESTDIR)$(INCLUDEDIR)/metrics_db.h
+ rm -f $(DESTDIR)$(INCLUDEDIR)/device.h
+
+uninstall-pkgconfig:
+ rm -f $(DESTDIR)$(PKGCONFIGDIR)/libpmtctl-core.pc
+
+clean:
+ rm -rf $(BUILDDIR) $(PC_FILES)
diff --git a/tools/arch/x86/pmtctl/lib/README b/tools/arch/x86/pmtctl/lib/README
new file mode 100644
index 000000000000..60f7de8c2256
--- /dev/null
+++ b/tools/arch/x86/pmtctl/lib/README
@@ -0,0 +1,116 @@
+libpmtctl_core usage notes
+==========================
+
+Overview
+--------
+libpmtctl_core provides PMT device enumeration, metric loading, and
+metric-to-device binding services used by pmtctl and other PMT tools.
+
+Public headers installed by lib/Makefile:
+- include/lib/pmtctl.h
+- include/lib/metrics_db.h
+- include/lib/device.h
+
+Typical flow
+------------
+1) Prepare options (struct pmt_global_opts).
+2) Optionally set log verbosity with pmtctl_set_log_level().
+3) Call pmtctl_init(&opts).
+4) Query context/counts and perform selection/reads through public APIs.
+5) Call pmtctl_cleanup() before exit.
+
+API reference
+-------------
+Initialization and lifecycle:
+- int pmtctl_init(const struct pmt_global_opts *gopts)
+ Initializes library-global PMT context. Enumerates devices,
+ and loads metric definitions. Returns 0 on success or a non-zero error code.
+
+- void pmtctl_cleanup(void)
+ Releases library-global resources allocated by pmtctl_init(). Safe to call
+ as part of normal shutdown after successful or partially successful init.
+
+- PMTCTL_SCOPE_GUARD
+ Cleanup helper macro that arranges pmtctl_cleanup() to run automatically
+ when the current scope exits.
+
+Context and counts:
+- const struct pmtctl_context *pmtctl_get_ctx(void)
+ Returns pointer to current library-global context.
+
+- enum pmt_device_type pmtctl_get_device_type(void)
+ Returns selected backend/device type for current context.
+
+- int pmtctl_get_num_devices(void)
+ Returns number of enumerated devices in current context.
+
+- int pmtctl_get_num_metrics(void)
+ Returns number of loaded metric definitions.
+
+- int pmtctl_get_num_bindings(void)
+ Returns number of metric-to-device bindings currently available.
+
+Logging:
+- void pmtctl_set_log_level(enum pmtctl_log_level level)
+ Sets process-global logging verbosity used by libpmtctl_core.
+ Clamp behavior: invalid/out-of-range values are clamped to
+ PMTCTL_LOG_INFO.
+
+Device selection helpers:
+- int pmtctl_parse_ep_selector(const char *s,
+ struct pmt_ep_selector *out)
+ Parses a selector string (for example: guid=27971628, ep=pmt_ep_...)
+ into structured selector fields.
+
+- int pmt_select_devices(const struct pmtctl_context *ctx,
+ const struct pmt_ep_selector *sel,
+ int *out_idx, int max_out)
+ Filters context devices using selector criteria and writes matching device
+ indexes into out_idx. Returns number of matches (0 means no matches).
+
+Log level behavior
+------------------
+pmtctl_set_log_level(enum pmtctl_log_level level)
+- Accepted levels:
+ PMTCTL_LOG_ERROR
+ PMTCTL_LOG_WARN
+ PMTCTL_LOG_INFO
+ PMTCTL_LOG_DEBUG
+- Clamp policy:
+ Invalid/out-of-range values are clamped to PMTCTL_LOG_INFO.
+
+Thread-safety
+-------------
+libpmtctl_core is generally not thread-safe.
+
+In particular, library-global state is used for:
+- PMT context/session ownership
+- logging verbosity
+
+Callers should serialize calls that operate on shared library state,
+including pmtctl_init(), pmtctl_cleanup(), and other APIs that consume
+or mutate global context.
+
+Minimal example
+---------------
+#include "lib/pmtctl.h"
+
+int run(void)
+{
+ struct pmt_global_opts opts = {
+ .json_path = NULL,
+ .device_selector = NULL,
+ .quiet = false,
+ .debug = false,
+ };
+
+ pmtctl_set_log_level(PMTCTL_LOG_INFO);
+
+ if (pmtctl_init(&opts) != 0)
+ return -1;
+
+ /* ... use library APIs ... */
+
+ pmtctl_cleanup();
+ return 0;
+}
diff --git a/tools/arch/x86/pmtctl/libpmtctl-core.pc.in b/tools/arch/x86/pmtctl/libpmtctl-core.pc.in
new file mode 100644
index 000000000000..0cbc9127d686
--- /dev/null
+++ b/tools/arch/x86/pmtctl/libpmtctl-core.pc.in
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+prefix=@PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libpmtctl-core
+Description: Intel PMT core access library (transport/enumeration/bindings)
+Version: 0.1
+Libs: -L${libdir} -lpmtctl_core @JANSSON_LIBS@
+Cflags: -I${includedir}/pmtctl
--
2.43.0