Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/dev/clang-tidy-fixes-2026-04.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
- [x] [concurrency-mt-unsafe](https://clang.llvm.org/extra/clang-tidy/checks/concurrency/mt-unsafe.html) (1)
- [PR #542](https://github.com/Framework-R-D/phlex/pull/542)
- [ ] [cppcoreguidelines-avoid-const-or-ref-data-members](https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/avoid-const-or-ref-data-members.html) (26)
- [ ] [cppcoreguidelines-avoid-non-const-global-variables](https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/avoid-non-const-global-variables.html) (47)
- [x] [cppcoreguidelines-avoid-non-const-global-variables](https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/avoid-non-const-global-variables.html) (47)
- [PR #544](https://github.com/Framework-R-D/phlex/pull/544)
- [ ] [cppcoreguidelines-explicit-virtual-functions](https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/explicit-virtual-functions.html) (19)
- [ ] [cppcoreguidelines-init-variables](https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/init-variables.html) (9)
- [ ] [cppcoreguidelines-missing-std-forward](https://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines/missing-std-forward.html) (2)
Expand Down
13 changes: 9 additions & 4 deletions phlex/app/load_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ namespace phlex::experimental {

// If factory function goes out of scope, then the library is unloaded...and that's
// bad.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<std::function<detail::module_creator_t>> create_module;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<std::function<detail::source_creator_t>> create_source;
std::function<detail::driver_creator_t> create_driver;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::function<detail::driver_shim_t> create_driver;

template <typename creator_t>
std::function<creator_t> plugin_loader(std::string const& spec, std::string const& symbol_name)
Expand All @@ -49,7 +52,7 @@ namespace phlex::experimental {
// (e.g., NumPy). Load all other plugins with rtld_local (default) to avoid symbol collisions.
auto const load_mode =
(spec == pymodule_name) ? dll::load_mode::rtld_global : dll::load_mode::default_mode;
return dll::import_alias<creator_t>(shared_library_path, symbol_name, load_mode);
return dll::import_symbol<creator_t>(shared_library_path, symbol_name, load_mode);
}
}
throw std::runtime_error("Could not locate library with specification '"s + spec +
Expand Down Expand Up @@ -114,8 +117,10 @@ namespace phlex::experimental {
{
configuration const config{raw_config};
auto const& spec = config.get<std::string>("cpp");
create_driver = plugin_loader<detail::driver_creator_t>(spec, "create_driver");
create_driver = plugin_loader<detail::driver_shim_t>(spec, "create_driver");
driver_proxy const proxy{};
return create_driver(proxy, config);
driver_bundle result;
create_driver(proxy, config, &result);
return result;
}
}
18 changes: 14 additions & 4 deletions phlex/detail/plugin_macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
PHLEX_DETAIL_CREATE_2ARGS) \
(token_type, func_name, __VA_ARGS__)

// Plugin entry-point functions are exported directly with C linkage so boost::dll::import_symbol
// can find them by name without an intermediate alias variable. The func_name parameter is
// retained for API compatibility but is unused in the expansion.
#define PHLEX_DETAIL_REGISTER_PLUGIN(token_type, func_name, dll_alias, ...) \
static PHLEX_DETAIL_SELECT_SIGNATURE(token_type, func_name, __VA_ARGS__); \
BOOST_DLL_ALIAS(func_name, dll_alias) \
PHLEX_DETAIL_SELECT_SIGNATURE(token_type, func_name, __VA_ARGS__)
extern "C" PHLEX_DETAIL_SELECT_SIGNATURE(token_type, dll_alias, __VA_ARGS__)

#define PHLEX_DETAIL_CREATE_DRIVER_1ARG(func_name, d) \
phlex::experimental::driver_bundle func_name(phlex::experimental::driver_proxy const& d, \
Expand All @@ -40,9 +41,18 @@
PHLEX_DETAIL_CREATE_DRIVER_2ARGS) \
(func_name, __VA_ARGS__)

// The driver entry-point cannot use extern "C" directly because driver_bundle is a C++ type.
// Instead we forward-declare the user's C++ implementation, define a thin extern "C" shim that
// writes the result through an out-parameter (which has a void return type, compatible with C
// linkage), and then open the user's implementation definition for the body that follows.
#define PHLEX_DETAIL_REGISTER_DRIVER_PLUGIN(func_name, dll_alias, ...) \
static PHLEX_DETAIL_SELECT_DRIVER_SIGNATURE(func_name, __VA_ARGS__); \
BOOST_DLL_ALIAS(func_name, dll_alias) \
extern "C" void dll_alias(phlex::experimental::driver_proxy const& __phlex_proxy, \
phlex::configuration const& __phlex_config, \
phlex::experimental::driver_bundle* __phlex_out) \
{ \
*__phlex_out = func_name(__phlex_proxy, __phlex_config); \
} \
PHLEX_DETAIL_SELECT_DRIVER_SIGNATURE(func_name, __VA_ARGS__)
// NOLINTEND(bugprone-macro-parentheses)

Expand Down
5 changes: 3 additions & 2 deletions phlex/driver.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef PHLEX_DRIVER_HPP
#define PHLEX_DRIVER_HPP

#include "boost/dll/alias.hpp"

#include "phlex/configuration.hpp"
#include "phlex/core/fwd.hpp"
#include "phlex/detail/plugin_macros.hpp"
Expand All @@ -24,6 +22,9 @@ namespace phlex::experimental {
namespace detail {
using next_index_t = std::function<void(framework_driver&)>;
using driver_creator_t = driver_bundle(driver_proxy const&, configuration const&);
// Shim type for the extern "C" entry-point: out-parameter avoids returning a C++ type
// across a C-linkage boundary.
using driver_shim_t = void(driver_proxy const&, configuration const&, driver_bundle*);
};

/// @brief Bundles the driver function and data hierarchy for the framework.
Expand Down
1 change: 0 additions & 1 deletion phlex/module.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef PHLEX_MODULE_HPP
#define PHLEX_MODULE_HPP

#include "boost/dll/alias.hpp"
#include "phlex/concurrency.hpp"
#include "phlex/configuration.hpp"
#include "phlex/core/graph_proxy.hpp"
Expand Down
1 change: 0 additions & 1 deletion phlex/source.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#ifndef PHLEX_SOURCE_HPP
#define PHLEX_SOURCE_HPP

#include "boost/dll/alias.hpp"
#include "phlex/concurrency.hpp"
#include "phlex/configuration.hpp"
#include "phlex/core/graph_proxy.hpp"
Expand Down
4 changes: 4 additions & 0 deletions plugins/python/src/configwrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,13 @@ static PyObject* pcm_subscript(py_config_map* pycmap, PyObject* pykey)
return pyvalue;
}

// PyMappingMethods must be non-const; tp_as_mapping in PyTypeObject takes a non-const pointer.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static PyMappingMethods pcm_as_mapping = {nullptr, (binaryfunc)pcm_subscript, nullptr};

// clang-format off
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
PyTypeObject phlex::experimental::PhlexConfig_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
(char*) "pyphlex.configuration", // tp_name
Expand Down
4 changes: 4 additions & 0 deletions plugins/python/src/dciwrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ static PyObject* dci_number(py_data_cell_index* pydci)
return PyLong_FromLong((long)pydci->ph_dci->number());
}

// PyMethodDef arrays must be non-const; tp_methods in PyTypeObject takes a non-const pointer.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static PyMethodDef dci_methods[] = {
{(char*)"number", (PyCFunction)dci_number, METH_NOARGS, (char*)"index number"},
{(char*)nullptr, nullptr, 0, nullptr}};

// clang-format off
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
PyTypeObject phlex::experimental::PhlexDataCellIndex_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
(char*) "pyphlex.data_cell_index", // tp_name
Expand Down
2 changes: 2 additions & 0 deletions plugins/python/src/lifelinewrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ static void ll_dealloc(py_lifeline_t* pyobj)
}

// clang-format off
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
PyTypeObject phlex::experimental::PhlexLifeline_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
(char*) "pyphlex.lifeline", // tp_name
Expand Down
8 changes: 8 additions & 0 deletions plugins/python/src/modulewrap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,8 @@ static PyObject* md_observe(py_phlex_module* mod, PyObject* args, PyObject* kwds
Py_RETURN_NONE;
}

// PyMethodDef arrays must be non-const; tp_methods in PyTypeObject takes a non-const pointer.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static PyMethodDef md_methods[] = {{(char*)"transform",
(PyCFunction)md_transform,
METH_VARARGS | METH_KEYWORDS,
Expand All @@ -1088,6 +1090,8 @@ static PyMethodDef md_methods[] = {{(char*)"transform",
{(char*)nullptr, nullptr, 0, nullptr}};

// clang-format off
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
PyTypeObject phlex::experimental::PhlexModule_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
(char*)"pyphlex.module", // tp_name
Expand Down Expand Up @@ -1291,13 +1295,17 @@ static PyObject* sc_provide(py_phlex_source* src, PyObject* args, PyObject* kwds
Py_RETURN_NONE;
}

// PyMethodDef arrays must be non-const; tp_methods in PyTypeObject takes a non-const pointer.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static PyMethodDef sc_methods[] = {{(char*)"provide",
(PyCFunction)sc_provide,
METH_VARARGS | METH_KEYWORDS,
(char*)"register a Python provider"},
{(char*)nullptr, nullptr, 0, nullptr}};

// clang-format off
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
PyTypeObject phlex::experimental::PhlexSource_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
(char*)"pyphlex.source", // tp_name
Expand Down
10 changes: 10 additions & 0 deletions plugins/python/src/wrap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,36 @@ namespace phlex::experimental {

// Create dict-like access to the configuration from Python.
PyObject* wrap_configuration(configuration const& config); // returns new reference
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern PyTypeObject PhlexConfig_Type;
struct py_config_map;

// Phlex' module wrapper to register algorithms
typedef module_graph_proxy<void_tag> phlex_module_t;
PyObject* wrap_module(phlex_module_t& mod); // returns new reference
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern PyTypeObject PhlexModule_Type;
struct py_phlex_module;

// Phlex' source wrapper to register providers
typedef source_graph_proxy<void_tag> phlex_source_t;
PyObject* wrap_source(phlex_source_t& src); // returns new reference
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern PyTypeObject PhlexSource_Type;
struct py_phlex_source;

// Python wrapper for data cell indices (returns a new reference)
PyObject* wrap_dci(data_cell_index const& dci);
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern PyTypeObject PhlexDataCellIndex_Type;

// Python wrapper for Phlex handles
// PyType_Ready() modifies PyTypeObject in-place; the Python C API requires non-const.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
extern PyTypeObject PhlexLifeline_Type;
// clang-format off
struct py_lifeline {
Expand Down
2 changes: 2 additions & 0 deletions test/replicated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ using namespace oneapi::tbb;

namespace {

// std::atomic counter incremented from concurrent callbacks across the entire test; must be mutable.
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::atomic<unsigned int> processed_messages{};
struct thread_unsafe {
std::atomic<unsigned int> counter{};
Expand Down
2 changes: 1 addition & 1 deletion test/type_deduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace {
void only_void_param [[maybe_unused]] (void) {}
std::tuple<> still_no_output [[maybe_unused]] () { return {}; }
std::tuple<int, double> two_output_objects [[maybe_unused]] (int, double) { return {}; }
auto closure [[maybe_unused]] = [](int) -> double { return 2.; };
auto const closure [[maybe_unused]] = [](int) -> double { return 2.; };
}

int main()
Expand Down
Loading