mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-18 21:20:57 +00:00
* Ignore Clipper, libpng, mcut and Boost.Polygon Internals in clang-tidy Each only works through a wrapper or umbrella header: libslic3r/clipper.hpp or clipper_z.hpp configure Clipper before including it, png.h pulls in libpng's config headers, and Boost.Polygon's headers only compile through polygon.hpp or voronoi.hpp. * Ignore minilzo's Config Headers in clang-tidy lzoconf.h and lzodefs.h are internal to minilzo.h, which is what the code includes. * Add Missing Includes Across the Remaining Sources and Tests Covers src/slic3r/Utils, src/slic3r/plugin, src/slic3r/Config, src/libvgcode, src/dev-utils, src/OrcaSlicer.cpp and tests/, the directories left after src/slic3r/GUI and src/libslic3r. Generated with clang-tidy misc-include-cleaner. libvgcode's own headers are included by relative path as in the rest of that library, and Catch2 and pybind11 with angle brackets as elsewhere in the repo. * Make the GUI and Test Headers Compile on Their Own Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Headers that only compile on one platform, or that nothing built includes, are left alone. * Keep Windows and nanosvg Setup Ahead of the Added Includes OrcaSlicer.cpp and several tests set _WIN32_WINNT, WIN32_LEAN_AND_MEAN or NOMINMAX before including Windows.h, and the profile validator defines NANOSVG_IMPLEMENTATION before any libslic3r header. The added includes had landed above those blocks, which broke the Windows build. * Add the GUI Includes the First Pass Missed Covers headers that only became editable once they compiled on their own, and wx symbols whose suggested header changed as the clang-tidy ignore list grew after the src/slic3r/GUI pass. * Keep the Added Test Includes Below the NOMINMAX Guard test_marchingsquares.cpp and test_texture_displacement.cpp had includes inside #ifndef NOMINMAX, which the tests inherit as defined on Windows from libslic3r, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory, as in #16068.
162 lines
6.2 KiB
C++
162 lines
6.2 KiB
C++
#ifndef slic3r_PyPluginTrampoline_hpp_
|
|
#define slic3r_PyPluginTrampoline_hpp_
|
|
|
|
#include "libslic3r/LifecycleEvents.hpp"
|
|
#include <pybind11/embed.h>
|
|
|
|
#include <boost/log/trivial.hpp>
|
|
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
#include "PythonPluginInterface.hpp"
|
|
#include "PythonInterpreter.hpp"
|
|
#include "PluginFsUtils.hpp"
|
|
#include "PluginAuditManager.hpp"
|
|
#include <pybind11/pybind11.h>
|
|
#include <pybind11/gil.h>
|
|
#include <pybind11/pytypes.h>
|
|
|
|
// Trampoline variants of pybind11's override macros. Every C++->Python plugin call crosses a
|
|
// trampoline method, so this single boundary is where we (1) log the full Python traceback and
|
|
// rethrow the exception intact, and (2) open the plugin's filesystem audit scope for the call.
|
|
// We catch ONLY error_already_set (a Python-side raise); other pybind11_fail/runtime_error, such as
|
|
// a pure-virtual-missing failure, must keep their own path and are deliberately not caught here.
|
|
|
|
// Logs (and rethrows) a Python exception from a pybind11 override call, preserving the
|
|
// traceback. Internal helper shared by the public macros below and by trampolines that
|
|
// manage their own audit scope (e.g. the G-code plugin).
|
|
#define ORCA_PY_LOGGED_OVERRIDE_BODY(override_call) \
|
|
try { \
|
|
override_call; \
|
|
} catch (pybind11::error_already_set & err) { \
|
|
const bool _orca_audit_denial = ::Slic3r::PluginAuditManager::instance().audit_denial_pending(); \
|
|
if (_orca_audit_denial) \
|
|
::Slic3r::PluginAuditManager::instance().clear_current_plugin(); \
|
|
::Slic3r::log_python_exception_keep(err); \
|
|
if (_orca_audit_denial) \
|
|
::Slic3r::PluginAuditManager::instance().clear_audit_denial(); \
|
|
throw; \
|
|
}
|
|
|
|
// Opens the plugin's filesystem audit scope for the duration of a C++ -> Python call, and publishes
|
|
// the calling capability's cached name so host APIs invoked from Python can tell which capability
|
|
// they are serving. No-op without an audit plugin key. Declares a local `_orca_audit_scope`.
|
|
#define ORCA_PY_AUDIT_SCOPE() \
|
|
std::optional<::Slic3r::ScopedPluginAuditContext> _orca_audit_scope; \
|
|
if (const std::string& _orca_audit_key = this->audit_plugin_key(); !_orca_audit_key.empty()) \
|
|
_orca_audit_scope.emplace(_orca_audit_key, this->name())
|
|
|
|
#define ORCA_PY_OVERRIDE_AUDITED(audit_setup, override_macro, ret, base, name, ...) \
|
|
do { \
|
|
::Slic3r::PluginCapabilityInterface::RefCounter _orca_ref_counter(*this); \
|
|
::Slic3r::PythonGILState _orca_python_gil; \
|
|
if (!_orca_python_gil) \
|
|
throw std::runtime_error("Python interpreter is shutting down"); \
|
|
ORCA_PY_AUDIT_SCOPE(); \
|
|
if (_orca_audit_scope) \
|
|
audit_setup(); \
|
|
ORCA_PY_LOGGED_OVERRIDE_BODY(override_macro(ret, base, name, ##__VA_ARGS__)); \
|
|
} while (0)
|
|
|
|
namespace Slic3r {
|
|
template<class Base> class PyPluginCommonTrampoline : public Base
|
|
{
|
|
public:
|
|
using Base::Base;
|
|
|
|
std::string get_name() const override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE_PURE, std::string, Base, get_name);
|
|
}
|
|
|
|
// Config UI hooks. Available on every capability type, so they live here rather than in
|
|
// PyPluginInterfaceTrampoline. A Python exception is rethrown; the caller decides the fallback.
|
|
bool has_config_ui() const override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED(
|
|
[] {},
|
|
PYBIND11_OVERRIDE,
|
|
bool,
|
|
Base,
|
|
has_config_ui);
|
|
}
|
|
|
|
std::string get_config_ui() const override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED(
|
|
[] {},
|
|
PYBIND11_OVERRIDE,
|
|
std::string,
|
|
Base,
|
|
get_config_ui);
|
|
}
|
|
|
|
// Hand-rolled rather than PYBIND11_OVERRIDE: the macro casts the Python result to the return
|
|
// type, and nlohmann::json has no pybind caster (config crosses this boundary through the
|
|
// explicit py_to_json/json_to_py helpers). Otherwise identical — same audit scope, same rethrow.
|
|
//
|
|
// The hook is optional, and "not implemented" must mean an EMPTY config: no override, or an
|
|
// override returning None or any non-object (`def get_default_config(self): pass` is the easy
|
|
// mistake), both fall back to the base's empty object rather than writing `"cap_config": null`.
|
|
nlohmann::json get_default_config() const override
|
|
{
|
|
ORCA_PY_AUDIT_SCOPE();
|
|
try {
|
|
pybind11::gil_scoped_acquire gil;
|
|
pybind11::function override = pybind11::get_override(static_cast<const Base*>(this), "get_default_config");
|
|
if (!override)
|
|
return Base::get_default_config();
|
|
|
|
nlohmann::json config = ::Slic3r::py_to_json(override());
|
|
if (!config.is_object()) {
|
|
BOOST_LOG_TRIVIAL(warning)
|
|
<< "Plugin capability '" << this->name() << "' of plugin '" << this->audit_plugin_key()
|
|
<< "': get_default_config() returned " << config.type_name() << ", not an object; restoring an empty config";
|
|
return Base::get_default_config();
|
|
}
|
|
return config;
|
|
} catch (pybind11::error_already_set& err) {
|
|
::Slic3r::log_python_exception_keep(err);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
void on_load() override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_load);
|
|
}
|
|
|
|
void on_unload() override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_unload);
|
|
}
|
|
|
|
void on_cancelled() override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_cancelled);
|
|
}
|
|
|
|
void on_lifecycle_event(LifecycleEvent event, const LifecycleEventContext& ctx) override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED([] {}, PYBIND11_OVERRIDE, void, Base, on_lifecycle_event, event, ctx);
|
|
}
|
|
};
|
|
|
|
class PyPluginInterfaceTrampoline : public PyPluginCommonTrampoline<PluginCapabilityInterface>
|
|
{
|
|
public:
|
|
using PyPluginCommonTrampoline<PluginCapabilityInterface>::PyPluginCommonTrampoline;
|
|
|
|
PluginCapabilityType get_type() const override
|
|
{
|
|
ORCA_PY_OVERRIDE_AUDITED(
|
|
[] {}, PYBIND11_OVERRIDE, PluginCapabilityType, PluginCapabilityInterface,
|
|
get_type);
|
|
}
|
|
};
|
|
} // namespace Slic3r
|
|
|
|
#endif
|