From fa89323111de3e131620bcfb763ddd56c929d531 Mon Sep 17 00:00:00 2001 From: Martin Belanger Date: Tue, 21 Apr 2026 16:04:02 -0400 Subject: [PATCH] swig: replace hand-written accessor wrappers with auto-generated #defines SWIG generates accessor names as libnvme_STRUCT_MEMBER_get/set() but libnvme exports them as libnvme_STRUCT_get/set_MEMBER(). Previously nvme.i bridged this gap with ~35 hand-written C wrapper functions (~130 lines of boilerplate) that had to be updated manually whenever new accessors were added to the library. Add generate-swig-accessors.py, a post-processing script that reads the accessor header files produced by generate-accessors.py (accessors.h and accessors-fabrics.h, covering both common and fabrics structs) and emits nvme-swig-accessors.i containing one #define per accessor: #define libnvme_ctrl_name_get libnvme_ctrl_get_name Parsing the .h files (not the .ld version scripts) ensures the output is always in sync even before the .ld section labels are manually bumped. Object-like macros are used rather than function-like macros since the call arguments follow naturally after macro expansion. Add a new update-swig-accessors run_target in meson.build and extend the update-accessors alias to include it. Replace the hand-written wrapper blocks in nvme.i with %include "nvme-swig-accessors.i". The four bridges that cannot be auto-generated (virtual member names or !accessors:none annotations) are kept as #defines in a single block next to the %include. Signed-off-by: Martin Belanger Assisted-by: Claude Sonnet 4.6 --- libnvme/libnvme/nvme-swig-accessors.i | 237 ++++++++++++++++++ libnvme/libnvme/nvme.i | 195 +++----------- .../generator/generate-swig-accessors.py | 149 +++++++++++ libnvme/tools/generator/meson.build | 15 +- 4 files changed, 428 insertions(+), 168 deletions(-) create mode 100644 libnvme/libnvme/nvme-swig-accessors.i create mode 100755 libnvme/tools/generator/generate-swig-accessors.py diff --git a/libnvme/libnvme/nvme-swig-accessors.i b/libnvme/libnvme/nvme-swig-accessors.i new file mode 100644 index 0000000000..5800f9a567 --- /dev/null +++ b/libnvme/libnvme/nvme-swig-accessors.i @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* + * This file is part of libnvme. + * + * Copyright (c) 2026, Dell Technologies Inc. or its subsidiaries. + * Authors: Martin Belanger + * + * ____ _ _ ____ _ + * / ___| ___ _ __ ___ _ __ __ _| |_ ___ __| | / ___|___ __| | ___ + * | | _ / _ \ '_ \ / _ \ '__/ _` | __/ _ \/ _` | | | / _ \ / _` |/ _ \ + * | |_| | __/ | | | __/ | | (_| | || __/ (_| | | |__| (_) | (_| | __/ + * \____|\___|_| |_|\___|_| \__,_|\__\___|\__,_| \____\___/ \__,_|\___| + * + * Auto-generated SWIG accessor #define bridges. + * + * To update run: meson compile -C [BUILD-DIR] update-accessors + * Or: make update-accessors + */ + +%{ + /* struct libnvme_fabrics_config */ + #define libnvme_fabrics_config_queue_size_get libnvme_fabrics_config_get_queue_size + #define libnvme_fabrics_config_nr_io_queues_get libnvme_fabrics_config_get_nr_io_queues + #define libnvme_fabrics_config_reconnect_delay_get libnvme_fabrics_config_get_reconnect_delay + #define libnvme_fabrics_config_ctrl_loss_tmo_get libnvme_fabrics_config_get_ctrl_loss_tmo + #define libnvme_fabrics_config_fast_io_fail_tmo_get libnvme_fabrics_config_get_fast_io_fail_tmo + #define libnvme_fabrics_config_keep_alive_tmo_get libnvme_fabrics_config_get_keep_alive_tmo + #define libnvme_fabrics_config_nr_write_queues_get libnvme_fabrics_config_get_nr_write_queues + #define libnvme_fabrics_config_nr_poll_queues_get libnvme_fabrics_config_get_nr_poll_queues + #define libnvme_fabrics_config_tos_get libnvme_fabrics_config_get_tos + #define libnvme_fabrics_config_keyring_id_get libnvme_fabrics_config_get_keyring_id + #define libnvme_fabrics_config_tls_key_id_get libnvme_fabrics_config_get_tls_key_id + #define libnvme_fabrics_config_tls_configured_key_id_get libnvme_fabrics_config_get_tls_configured_key_id + #define libnvme_fabrics_config_duplicate_connect_get libnvme_fabrics_config_get_duplicate_connect + #define libnvme_fabrics_config_disable_sqflow_get libnvme_fabrics_config_get_disable_sqflow + #define libnvme_fabrics_config_hdr_digest_get libnvme_fabrics_config_get_hdr_digest + #define libnvme_fabrics_config_data_digest_get libnvme_fabrics_config_get_data_digest + #define libnvme_fabrics_config_tls_get libnvme_fabrics_config_get_tls + #define libnvme_fabrics_config_concat_get libnvme_fabrics_config_get_concat + #define libnvme_fabrics_config_queue_size_set libnvme_fabrics_config_set_queue_size + #define libnvme_fabrics_config_nr_io_queues_set libnvme_fabrics_config_set_nr_io_queues + #define libnvme_fabrics_config_reconnect_delay_set libnvme_fabrics_config_set_reconnect_delay + #define libnvme_fabrics_config_ctrl_loss_tmo_set libnvme_fabrics_config_set_ctrl_loss_tmo + #define libnvme_fabrics_config_fast_io_fail_tmo_set libnvme_fabrics_config_set_fast_io_fail_tmo + #define libnvme_fabrics_config_keep_alive_tmo_set libnvme_fabrics_config_set_keep_alive_tmo + #define libnvme_fabrics_config_nr_write_queues_set libnvme_fabrics_config_set_nr_write_queues + #define libnvme_fabrics_config_nr_poll_queues_set libnvme_fabrics_config_set_nr_poll_queues + #define libnvme_fabrics_config_tos_set libnvme_fabrics_config_set_tos + #define libnvme_fabrics_config_keyring_id_set libnvme_fabrics_config_set_keyring_id + #define libnvme_fabrics_config_tls_key_id_set libnvme_fabrics_config_set_tls_key_id + #define libnvme_fabrics_config_tls_configured_key_id_set libnvme_fabrics_config_set_tls_configured_key_id + #define libnvme_fabrics_config_duplicate_connect_set libnvme_fabrics_config_set_duplicate_connect + #define libnvme_fabrics_config_disable_sqflow_set libnvme_fabrics_config_set_disable_sqflow + #define libnvme_fabrics_config_hdr_digest_set libnvme_fabrics_config_set_hdr_digest + #define libnvme_fabrics_config_data_digest_set libnvme_fabrics_config_set_data_digest + #define libnvme_fabrics_config_tls_set libnvme_fabrics_config_set_tls + #define libnvme_fabrics_config_concat_set libnvme_fabrics_config_set_concat + + /* struct libnvme_path */ + #define libnvme_path_name_get libnvme_path_get_name + #define libnvme_path_sysfs_dir_get libnvme_path_get_sysfs_dir + #define libnvme_path_ana_state_get libnvme_path_get_ana_state + #define libnvme_path_numa_nodes_get libnvme_path_get_numa_nodes + #define libnvme_path_grpid_get libnvme_path_get_grpid + #define libnvme_path_name_set libnvme_path_set_name + #define libnvme_path_sysfs_dir_set libnvme_path_set_sysfs_dir + #define libnvme_path_ana_state_set libnvme_path_set_ana_state + #define libnvme_path_numa_nodes_set libnvme_path_set_numa_nodes + #define libnvme_path_grpid_set libnvme_path_set_grpid + + /* struct libnvme_ns */ + #define libnvme_ns_nsid_get libnvme_ns_get_nsid + #define libnvme_ns_name_get libnvme_ns_get_name + #define libnvme_ns_sysfs_dir_get libnvme_ns_get_sysfs_dir + #define libnvme_ns_lba_shift_get libnvme_ns_get_lba_shift + #define libnvme_ns_lba_size_get libnvme_ns_get_lba_size + #define libnvme_ns_meta_size_get libnvme_ns_get_meta_size + #define libnvme_ns_lba_count_get libnvme_ns_get_lba_count + #define libnvme_ns_lba_util_get libnvme_ns_get_lba_util + #define libnvme_ns_nsid_set libnvme_ns_set_nsid + #define libnvme_ns_name_set libnvme_ns_set_name + #define libnvme_ns_sysfs_dir_set libnvme_ns_set_sysfs_dir + #define libnvme_ns_lba_shift_set libnvme_ns_set_lba_shift + #define libnvme_ns_lba_size_set libnvme_ns_set_lba_size + #define libnvme_ns_meta_size_set libnvme_ns_set_meta_size + #define libnvme_ns_lba_count_set libnvme_ns_set_lba_count + #define libnvme_ns_lba_util_set libnvme_ns_set_lba_util + + /* struct libnvme_ctrl */ + #define libnvme_ctrl_name_get libnvme_ctrl_get_name + #define libnvme_ctrl_sysfs_dir_get libnvme_ctrl_get_sysfs_dir + #define libnvme_ctrl_firmware_get libnvme_ctrl_get_firmware + #define libnvme_ctrl_model_get libnvme_ctrl_get_model + #define libnvme_ctrl_numa_node_get libnvme_ctrl_get_numa_node + #define libnvme_ctrl_queue_count_get libnvme_ctrl_get_queue_count + #define libnvme_ctrl_serial_get libnvme_ctrl_get_serial + #define libnvme_ctrl_sqsize_get libnvme_ctrl_get_sqsize + #define libnvme_ctrl_transport_get libnvme_ctrl_get_transport + #define libnvme_ctrl_subsysnqn_get libnvme_ctrl_get_subsysnqn + #define libnvme_ctrl_traddr_get libnvme_ctrl_get_traddr + #define libnvme_ctrl_trsvcid_get libnvme_ctrl_get_trsvcid + #define libnvme_ctrl_dhchap_host_key_get libnvme_ctrl_get_dhchap_host_key + #define libnvme_ctrl_dhchap_ctrl_key_get libnvme_ctrl_get_dhchap_ctrl_key + #define libnvme_ctrl_keyring_get libnvme_ctrl_get_keyring + #define libnvme_ctrl_tls_key_identity_get libnvme_ctrl_get_tls_key_identity + #define libnvme_ctrl_tls_key_get libnvme_ctrl_get_tls_key + #define libnvme_ctrl_cntrltype_get libnvme_ctrl_get_cntrltype + #define libnvme_ctrl_cntlid_get libnvme_ctrl_get_cntlid + #define libnvme_ctrl_dctype_get libnvme_ctrl_get_dctype + #define libnvme_ctrl_phy_slot_get libnvme_ctrl_get_phy_slot + #define libnvme_ctrl_host_traddr_get libnvme_ctrl_get_host_traddr + #define libnvme_ctrl_host_iface_get libnvme_ctrl_get_host_iface + #define libnvme_ctrl_discovery_ctrl_get libnvme_ctrl_get_discovery_ctrl + #define libnvme_ctrl_unique_discovery_ctrl_get libnvme_ctrl_get_unique_discovery_ctrl + #define libnvme_ctrl_discovered_get libnvme_ctrl_get_discovered + #define libnvme_ctrl_persistent_get libnvme_ctrl_get_persistent + #define libnvme_ctrl_dhchap_host_key_set libnvme_ctrl_set_dhchap_host_key + #define libnvme_ctrl_dhchap_ctrl_key_set libnvme_ctrl_set_dhchap_ctrl_key + #define libnvme_ctrl_keyring_set libnvme_ctrl_set_keyring + #define libnvme_ctrl_tls_key_identity_set libnvme_ctrl_set_tls_key_identity + #define libnvme_ctrl_tls_key_set libnvme_ctrl_set_tls_key + #define libnvme_ctrl_discovery_ctrl_set libnvme_ctrl_set_discovery_ctrl + #define libnvme_ctrl_unique_discovery_ctrl_set libnvme_ctrl_set_unique_discovery_ctrl + #define libnvme_ctrl_discovered_set libnvme_ctrl_set_discovered + #define libnvme_ctrl_persistent_set libnvme_ctrl_set_persistent + + /* struct libnvme_subsystem */ + #define libnvme_subsystem_name_get libnvme_subsystem_get_name + #define libnvme_subsystem_sysfs_dir_get libnvme_subsystem_get_sysfs_dir + #define libnvme_subsystem_subsysnqn_get libnvme_subsystem_get_subsysnqn + #define libnvme_subsystem_model_get libnvme_subsystem_get_model + #define libnvme_subsystem_serial_get libnvme_subsystem_get_serial + #define libnvme_subsystem_firmware_get libnvme_subsystem_get_firmware + #define libnvme_subsystem_subsystype_get libnvme_subsystem_get_subsystype + #define libnvme_subsystem_application_get libnvme_subsystem_get_application + #define libnvme_subsystem_iopolicy_get libnvme_subsystem_get_iopolicy + #define libnvme_subsystem_application_set libnvme_subsystem_set_application + #define libnvme_subsystem_iopolicy_set libnvme_subsystem_set_iopolicy + + /* struct libnvme_host */ + #define libnvme_host_hostnqn_get libnvme_host_get_hostnqn + #define libnvme_host_hostid_get libnvme_host_get_hostid + #define libnvme_host_dhchap_host_key_get libnvme_host_get_dhchap_host_key + #define libnvme_host_hostsymname_get libnvme_host_get_hostsymname + #define libnvme_host_pdc_enabled_valid_get libnvme_host_get_pdc_enabled_valid + #define libnvme_host_dhchap_host_key_set libnvme_host_set_dhchap_host_key + #define libnvme_host_hostsymname_set libnvme_host_set_hostsymname + #define libnvme_host_pdc_enabled_valid_set libnvme_host_set_pdc_enabled_valid + + /* struct libnvme_fabric_options */ + #define libnvme_fabric_options_cntlid_get libnvme_fabric_options_get_cntlid + #define libnvme_fabric_options_concat_get libnvme_fabric_options_get_concat + #define libnvme_fabric_options_ctrl_loss_tmo_get libnvme_fabric_options_get_ctrl_loss_tmo + #define libnvme_fabric_options_data_digest_get libnvme_fabric_options_get_data_digest + #define libnvme_fabric_options_dhchap_ctrl_secret_get libnvme_fabric_options_get_dhchap_ctrl_secret + #define libnvme_fabric_options_dhchap_secret_get libnvme_fabric_options_get_dhchap_secret + #define libnvme_fabric_options_disable_sqflow_get libnvme_fabric_options_get_disable_sqflow + #define libnvme_fabric_options_discovery_get libnvme_fabric_options_get_discovery + #define libnvme_fabric_options_duplicate_connect_get libnvme_fabric_options_get_duplicate_connect + #define libnvme_fabric_options_fast_io_fail_tmo_get libnvme_fabric_options_get_fast_io_fail_tmo + #define libnvme_fabric_options_hdr_digest_get libnvme_fabric_options_get_hdr_digest + #define libnvme_fabric_options_host_iface_get libnvme_fabric_options_get_host_iface + #define libnvme_fabric_options_host_traddr_get libnvme_fabric_options_get_host_traddr + #define libnvme_fabric_options_hostid_get libnvme_fabric_options_get_hostid + #define libnvme_fabric_options_hostnqn_get libnvme_fabric_options_get_hostnqn + #define libnvme_fabric_options_instance_get libnvme_fabric_options_get_instance + #define libnvme_fabric_options_keep_alive_tmo_get libnvme_fabric_options_get_keep_alive_tmo + #define libnvme_fabric_options_keyring_get libnvme_fabric_options_get_keyring + #define libnvme_fabric_options_nqn_get libnvme_fabric_options_get_nqn + #define libnvme_fabric_options_nr_io_queues_get libnvme_fabric_options_get_nr_io_queues + #define libnvme_fabric_options_nr_poll_queues_get libnvme_fabric_options_get_nr_poll_queues + #define libnvme_fabric_options_nr_write_queues_get libnvme_fabric_options_get_nr_write_queues + #define libnvme_fabric_options_queue_size_get libnvme_fabric_options_get_queue_size + #define libnvme_fabric_options_reconnect_delay_get libnvme_fabric_options_get_reconnect_delay + #define libnvme_fabric_options_tls_get libnvme_fabric_options_get_tls + #define libnvme_fabric_options_tls_key_get libnvme_fabric_options_get_tls_key + #define libnvme_fabric_options_tos_get libnvme_fabric_options_get_tos + #define libnvme_fabric_options_traddr_get libnvme_fabric_options_get_traddr + #define libnvme_fabric_options_transport_get libnvme_fabric_options_get_transport + #define libnvme_fabric_options_trsvcid_get libnvme_fabric_options_get_trsvcid + #define libnvme_fabric_options_cntlid_set libnvme_fabric_options_set_cntlid + #define libnvme_fabric_options_concat_set libnvme_fabric_options_set_concat + #define libnvme_fabric_options_ctrl_loss_tmo_set libnvme_fabric_options_set_ctrl_loss_tmo + #define libnvme_fabric_options_data_digest_set libnvme_fabric_options_set_data_digest + #define libnvme_fabric_options_dhchap_ctrl_secret_set libnvme_fabric_options_set_dhchap_ctrl_secret + #define libnvme_fabric_options_dhchap_secret_set libnvme_fabric_options_set_dhchap_secret + #define libnvme_fabric_options_disable_sqflow_set libnvme_fabric_options_set_disable_sqflow + #define libnvme_fabric_options_discovery_set libnvme_fabric_options_set_discovery + #define libnvme_fabric_options_duplicate_connect_set libnvme_fabric_options_set_duplicate_connect + #define libnvme_fabric_options_fast_io_fail_tmo_set libnvme_fabric_options_set_fast_io_fail_tmo + #define libnvme_fabric_options_hdr_digest_set libnvme_fabric_options_set_hdr_digest + #define libnvme_fabric_options_host_iface_set libnvme_fabric_options_set_host_iface + #define libnvme_fabric_options_host_traddr_set libnvme_fabric_options_set_host_traddr + #define libnvme_fabric_options_hostid_set libnvme_fabric_options_set_hostid + #define libnvme_fabric_options_hostnqn_set libnvme_fabric_options_set_hostnqn + #define libnvme_fabric_options_instance_set libnvme_fabric_options_set_instance + #define libnvme_fabric_options_keep_alive_tmo_set libnvme_fabric_options_set_keep_alive_tmo + #define libnvme_fabric_options_keyring_set libnvme_fabric_options_set_keyring + #define libnvme_fabric_options_nqn_set libnvme_fabric_options_set_nqn + #define libnvme_fabric_options_nr_io_queues_set libnvme_fabric_options_set_nr_io_queues + #define libnvme_fabric_options_nr_poll_queues_set libnvme_fabric_options_set_nr_poll_queues + #define libnvme_fabric_options_nr_write_queues_set libnvme_fabric_options_set_nr_write_queues + #define libnvme_fabric_options_queue_size_set libnvme_fabric_options_set_queue_size + #define libnvme_fabric_options_reconnect_delay_set libnvme_fabric_options_set_reconnect_delay + #define libnvme_fabric_options_tls_set libnvme_fabric_options_set_tls + #define libnvme_fabric_options_tls_key_set libnvme_fabric_options_set_tls_key + #define libnvme_fabric_options_tos_set libnvme_fabric_options_set_tos + #define libnvme_fabric_options_traddr_set libnvme_fabric_options_set_traddr + #define libnvme_fabric_options_transport_set libnvme_fabric_options_set_transport + #define libnvme_fabric_options_trsvcid_set libnvme_fabric_options_set_trsvcid + + /* struct libnvmf_discovery_args */ + #define libnvmf_discovery_args_max_retries_get libnvmf_discovery_args_get_max_retries + #define libnvmf_discovery_args_lsp_get libnvmf_discovery_args_get_lsp + #define libnvmf_discovery_args_max_retries_set libnvmf_discovery_args_set_max_retries + #define libnvmf_discovery_args_lsp_set libnvmf_discovery_args_set_lsp + + /* struct libnvmf_uri */ + #define libnvmf_uri_scheme_get libnvmf_uri_get_scheme + #define libnvmf_uri_protocol_get libnvmf_uri_get_protocol + #define libnvmf_uri_userinfo_get libnvmf_uri_get_userinfo + #define libnvmf_uri_host_get libnvmf_uri_get_host + #define libnvmf_uri_port_get libnvmf_uri_get_port + #define libnvmf_uri_path_segments_get libnvmf_uri_get_path_segments + #define libnvmf_uri_query_get libnvmf_uri_get_query + #define libnvmf_uri_fragment_get libnvmf_uri_get_fragment + #define libnvmf_uri_scheme_set libnvmf_uri_set_scheme + #define libnvmf_uri_protocol_set libnvmf_uri_set_protocol + #define libnvmf_uri_userinfo_set libnvmf_uri_set_userinfo + #define libnvmf_uri_host_set libnvmf_uri_set_host + #define libnvmf_uri_port_set libnvmf_uri_set_port + #define libnvmf_uri_path_segments_set libnvmf_uri_set_path_segments + #define libnvmf_uri_query_set libnvmf_uri_set_query + #define libnvmf_uri_fragment_set libnvmf_uri_set_fragment + +%} diff --git a/libnvme/libnvme/nvme.i b/libnvme/libnvme/nvme.i index 5c7067c13d..053d58058c 100644 --- a/libnvme/libnvme/nvme.i +++ b/libnvme/libnvme/nvme.i @@ -30,6 +30,7 @@ static inline PyObject *Py_NewRef(PyObject *obj) %feature("autodoc", "1"); %include "exception.i" +%include "nvme-swig-accessors.i" %allowexception; @@ -46,6 +47,33 @@ static inline PyObject *Py_NewRef(PyObject *obj) #include "nvme/private.h" #include "nvme/private-fabrics.h" + /* + * These bridges cannot be auto-generated by generate-swig-accessors.py + * and added to "nvme-swig-accessors.i" included above. These are used + * to bridge between SWIG's API naming convention + * "struct_member_[set|get]" and libnvme's API naming convention + * "struct_[set|get]_member. + * + * - libnvme_subsystem_host_get: 'host' is the Python-visible name; the C + * struct member is 's->h' and the hand-written accessor is + * libnvme_subsystem_get_host() in tree.c. + * + * - libnvme_ctrl_state_get: 'state' has !accessors:none in private.h + * (reads from sysfs dynamically); libnvme_ctrl_get_state() is + * hand-written in tree.c. + * + * - libnvme_ctrl_subsystem_get: 'subsystem' is the Python-visible name; + * the C struct member is named 's' and the hand-written accessor is + * libnvme_ctrl_get_subsystem() in tree.c. + * + * - libnvme_ctrl_address_get: 'address' has !accessors:none in private.h + * and maps to libnvme_ctrl_get_traddr(), not libnvme_ctrl_get_address(). + */ + #define libnvme_subsystem_host_get libnvme_subsystem_get_host + #define libnvme_ctrl_state_get libnvme_ctrl_get_state + #define libnvme_ctrl_subsystem_get libnvme_ctrl_get_subsystem + #define libnvme_ctrl_address_get libnvme_ctrl_get_traddr + static int connect_err = 0; static int discover_err = 0; @@ -790,14 +818,6 @@ struct libnvme_ns { %} } -%{ - const char *libnvme_host_dhchap_host_key_get(struct libnvme_host *h) { - return libnvme_host_get_dhchap_host_key(h); - } - void libnvme_host_dhchap_host_key_set(struct libnvme_host *h, char *key) { - libnvme_host_set_dhchap_host_key(h, key); - } -%}; %pythonappend libnvme_subsystem::libnvme_subsystem(struct libnvme_global_ctx *ctx, struct libnvme_host *host, @@ -864,26 +884,6 @@ struct libnvme_ns { struct libnvme_host *host; } -%{ - const char *libnvme_subsystem_name_get(struct libnvme_subsystem *s) { - return libnvme_subsystem_get_name(s); - } - struct libnvme_host *libnvme_subsystem_host_get(struct libnvme_subsystem *s) { - return libnvme_subsystem_get_host(s); - } - const char *libnvme_subsystem_sysfs_dir_get(struct libnvme_subsystem *s) { - return libnvme_subsystem_get_sysfs_dir(s); - } - const char *libnvme_subsystem_iopolicy_get(struct libnvme_subsystem *s) { - return libnvme_subsystem_get_iopolicy(s); - } - const char *libnvme_subsystem_application_get(struct libnvme_subsystem *s) { - return libnvme_subsystem_get_application(s); - } - void libnvme_subsystem_application_set(struct libnvme_subsystem *s, const char *a) { - libnvme_subsystem_set_application(s, a); - } -%}; %pythonappend libnvme_ctrl::connect(struct libnvme_host *h) { self.__host = h # Keep a reference to parent to ensure ctrl obj gets GCed before host} @@ -1103,140 +1103,6 @@ struct libnvme_ns { %} } -%{ - /********************************************************************** - * SWIG automatically generates getter and setter methods using - * the syntax: [class]_[member]_[get|set]. These need to be mapped - * to the matching methods in libnvme (i.e. those that are defined - * publicly in libnvme.map). Typically, we get the following mapping: - * - * SWIG libnvme.map - * ====================== ======================= - * libnvme_ctrl_[member]_get -> libnvme_ctrl_get_[member] - * libnvme_ctrl_[member]_set -> libnvme_ctrl_set_[member] - * - */ - - const char *libnvme_ctrl_name_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_name(c); - } - struct libnvme_subsystem *libnvme_ctrl_subsystem_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_subsystem(c); - } - const char *libnvme_ctrl_state_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_state(c); - } - const char *libnvme_ctrl_dhchap_ctrl_key_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_dhchap_ctrl_key(c); - } - void libnvme_ctrl_dhchap_ctrl_key_set(struct libnvme_ctrl *c, const char *key) { - libnvme_ctrl_set_dhchap_ctrl_key(c, key); - } - const char *libnvme_ctrl_dhchap_host_key_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_dhchap_host_key(c); - } - void libnvme_ctrl_dhchap_host_key_set(struct libnvme_ctrl *c, const char *key) { - libnvme_ctrl_set_dhchap_host_key(c, key); - } - - const char *libnvme_ctrl_cntlid_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_cntlid(c); - } - - bool libnvme_ctrl_persistent_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_persistent(c); - } - void libnvme_ctrl_persistent_set(struct libnvme_ctrl *c, bool persistent) { - libnvme_ctrl_set_persistent(c, persistent); - } - - const char *libnvme_ctrl_phy_slot_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_phy_slot(c); - } - - const char *libnvme_ctrl_trsvcid_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_trsvcid(c); - } - - const char *libnvme_ctrl_traddr_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_traddr(c); - } - - const char *libnvme_ctrl_subsysnqn_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_subsysnqn(c); - } - - const char *libnvme_ctrl_transport_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_transport(c); - } - - const char *libnvme_ctrl_sqsize_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_sqsize(c); - } - - const char *libnvme_ctrl_serial_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_serial(c); - } - - const char *libnvme_ctrl_queue_count_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_queue_count(c); - } - - const char *libnvme_ctrl_numa_node_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_numa_node(c); - } - - const char *libnvme_ctrl_model_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_model(c); - } - - const char *libnvme_ctrl_firmware_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_firmware(c); - } - - const char *libnvme_ctrl_address_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_traddr(c); - } - - const char *libnvme_ctrl_sysfs_dir_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_sysfs_dir(c); - } - - bool libnvme_ctrl_discovery_ctrl_get(struct libnvme_ctrl *c) { - return libnvme_ctrl_get_discovery_ctrl(c); - } - void libnvme_ctrl_discovery_ctrl_set(struct libnvme_ctrl *c, bool discovery) { - libnvme_ctrl_set_discovery_ctrl(c, discovery); - } - - bool libnvme_ctrl_unique_discovery_ctrl_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_unique_discovery_ctrl(c); - } - void libnvme_ctrl_unique_discovery_ctrl_set(libnvme_ctrl_t c, bool unique) { - libnvme_ctrl_set_unique_discovery_ctrl(c, unique); - } - - const char *libnvme_ctrl_keyring_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_keyring(c); - } - void libnvme_ctrl_keyring_set(libnvme_ctrl_t c, const char *keyring) { - libnvme_ctrl_set_keyring(c, keyring); - } - - const char *libnvme_ctrl_tls_key_identity_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_tls_key_identity(c); - } - void libnvme_ctrl_tls_key_identity_set(libnvme_ctrl_t c, const char *identity) { - libnvme_ctrl_set_tls_key_identity(c, identity); - } - - const char *libnvme_ctrl_tls_key_get(libnvme_ctrl_t c) { - return libnvme_ctrl_get_tls_key(c); - } - void libnvme_ctrl_tls_key_set(libnvme_ctrl_t c, const char *key) { - libnvme_ctrl_set_tls_key(c, key); - } -%} %pythonappend libnvme_ns::libnvme_ns(struct libnvme_subsystem *s, unsigned int nsid) { @@ -1262,11 +1128,6 @@ struct libnvme_ns { const char *name; } -%{ - const char *libnvme_ns_name_get(struct libnvme_ns *n) { - return libnvme_ns_get_name(n); - } -%}; /****** NBFT diff --git a/libnvme/tools/generator/generate-swig-accessors.py b/libnvme/tools/generator/generate-swig-accessors.py new file mode 100755 index 0000000000..1e072dca03 --- /dev/null +++ b/libnvme/tools/generator/generate-swig-accessors.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later +""" +generate-swig-accessors.py — Generate SWIG #define accessor name bridges. + +This file is part of libnvme. +Copyright (c) 2026, Dell Technologies Inc. or its subsidiaries. +Authors: Martin Belanger + +Reads accessor header files produced by generate-accessors.py and emits a +SWIG .i file whose %{ %} block contains #define macros that map the +SWIG-generated accessor naming convention to the libnvme C API convention: + + SWIG generated: libnvme_STRUCT_MEMBER_get(obj) + libnvme C API: libnvme_STRUCT_get_MEMBER(obj) + +This is a post-processing step run after generate-accessors.py has refreshed +accessors.h and accessors-fabrics.h. Both files are parsed so that common +and fabrics structs are covered in a single output file. + +Usage: + generate-swig-accessors.py -o nvme-swig-accessors.i accessors.h [accessors-fabrics.h ...] +""" + +import argparse +import os +import re +import sys + +BANNER = """\ +/* + * This file is part of libnvme. + * + * Copyright (c) 2026, Dell Technologies Inc. or its subsidiaries. + * Authors: Martin Belanger + * + * ____ _ _ ____ _ + * / ___| ___ _ __ ___ _ __ __ _| |_ ___ __| | / ___|___ __| | ___ + * | | _ / _ \\ '_ \\ / _ \\ '__/ _` | __/ _ \\/ _` | | | / _ \\ / _` |/ _ \\ + * | |_| | __/ | | | __/ | | (_| | || __/ (_| | | |__| (_) | (_| | __/ + * \\____|\\___|_| |_|\\___|_| \\__,_|\\__\\___|\\__,_| \\____\\___/ \\__,_|\\___| + * + * Auto-generated SWIG accessor #define bridges. + * + * To update run: meson compile -C [BUILD-DIR] update-accessors + * Or: make update-accessors + */""" + +# Non-greedy on the struct-prefix part so that the first occurrence of _get_ +# or _set_ in the function name is used as the split point. +_GET_RE = re.compile(r'\b((?:libnvme|libnvmf)_\w+?)_get_(\w+)\s*\(') +_SET_RE = re.compile(r'\b((?:libnvme|libnvmf)_\w+?)_set_(\w+)\s*\(') + + +def parse_header(text): + """Return ordered dict: struct_prefix -> {'gets': [member, ...], 'sets': [...]}. + + Only function declarations whose names follow the libnvme accessor + convention (PREFIX_get_MEMBER / PREFIX_set_MEMBER) are collected. + Lifecycle functions (new, free, init_defaults) don't match the regex + and are silently ignored. + """ + structs = {} + for line in text.splitlines(): + for m in _GET_RE.finditer(line): + pre, mem = m.group(1), m.group(2) + entry = structs.setdefault(pre, {'gets': [], 'sets': []}) + if mem not in entry['gets']: + entry['gets'].append(mem) + for m in _SET_RE.finditer(line): + pre, mem = m.group(1), m.group(2) + entry = structs.setdefault(pre, {'gets': [], 'sets': []}) + if mem not in entry['sets']: + entry['sets'].append(mem) + return structs + + +def build_content(all_structs): + """Return the full text of the generated .i file.""" + lines = [ + '/* SPDX-License-Identifier: LGPL-2.1-or-later */', + '', + BANNER, + '', + '%{', + ] + for pre, members in all_structs.items(): + pairs = ([(f'{pre}_{m}_get', f'{pre}_get_{m}') for m in members['gets']] + + [(f'{pre}_{m}_set', f'{pre}_set_{m}') for m in members['sets']]) + if not pairs: + continue + width = max(len(swig) for swig, _ in pairs) + lines.append(f'\t/* struct {pre} */') + for swig, c in pairs: + lines.append(f'\t#define {swig:{width}} {c}') + lines.append('') + lines.append('%}') + lines.append('') + return '\n'.join(lines) + + +def main(): + parser = argparse.ArgumentParser( + description='Generate SWIG #define accessor bridges from accessor headers.', + ) + parser.add_argument('-o', '--output', required=True, + metavar='FILE', + help='Output SWIG *.i file.') + parser.add_argument('headers', nargs='+', + help='Accessor header files to parse (e.g. accessors.h).') + args = parser.parse_args() + + all_structs = {} + for hdr in args.headers: + try: + with open(hdr) as f: + text = f.read() + except OSError as e: + print(f'error: cannot read {hdr!r}: {e}', file=sys.stderr) + sys.exit(1) + + for pre, members in parse_header(text).items(): + entry = all_structs.setdefault(pre, {'gets': [], 'sets': []}) + for mem in members['gets']: + if mem not in entry['gets']: + entry['gets'].append(mem) + for mem in members['sets']: + if mem not in entry['sets']: + entry['sets'].append(mem) + + content = build_content(all_structs) + + # Only rewrite when content changes to avoid spurious mtime updates. + try: + with open(args.output) as f: + if f.read() == content: + print(f' unchanged: {os.path.basename(args.output)}') + return + except OSError: + pass + + os.makedirs(os.path.dirname(os.path.abspath(args.output)), exist_ok=True) + with open(args.output, 'w') as f: + f.write(content) + print(f' updated: {os.path.basename(args.output)}') + + +if __name__ == '__main__': + main() diff --git a/libnvme/tools/generator/meson.build b/libnvme/tools/generator/meson.build index b80d6c9b66..dd126da672 100644 --- a/libnvme/tools/generator/meson.build +++ b/libnvme/tools/generator/meson.build @@ -22,8 +22,10 @@ # Generated source files go to src/nvme/ (alongside the library sources). # The generated version script goes to src/ (alongside the other .ld files). +# The generated SWIG include goes to libnvme/ (alongside nvme.i). libnvme_src = libnvme_srcroot / 'src' libnvme_src_nvme = libnvme_src / 'nvme' +libnvme_swig_dir = libnvme_srcroot / 'libnvme' _py3 = find_program('python3', required: true) @@ -53,5 +55,16 @@ _tgt_fabrics = run_target( ], ) +_tgt_swig = run_target( + 'update-swig-accessors', + command: [ + _py3, + files('generate-swig-accessors.py'), + '--output', libnvme_swig_dir / 'nvme-swig-accessors.i', + libnvme_src_nvme / 'accessors.h', + libnvme_src_nvme / 'accessors-fabrics.h', + ], +) + # This alias allows generating all accessors in one shot. -alias_target('update-accessors', _tgt_common, _tgt_fabrics) +alias_target('update-accessors', _tgt_common, _tgt_fabrics, _tgt_swig)