This is an automated email from the ASF dual-hosted git repository.

martinzink pushed a commit to branch controller_c_api_requirements
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit a8128b9f81be218adffbdcb3beae16717c1497a5
Author: Adam Debreceni <[email protected]>
AuthorDate: Thu Feb 19 13:52:50 2026 +0100

    MINIFICPP-2715 - Use symbol lookup to check version
---
 Extensions.md                                      | 43 ++++++++++++--
 .../include/utils/ExtensionInitUtils.h             |  4 ++
 extensions/ExtensionInitializer.cpp                |  4 +-
 .../llamacpp/processors/ExtensionInitializer.cpp   |  4 +-
 extensions/opencv/OpenCVLoader.cpp                 |  4 +-
 .../python/pythonlibloader/PythonLibLoader.cpp     |  4 +-
 extensions/python/pythonloader/PyProcLoader.cpp    |  4 +-
 extensions/sftp/SFTPLoader.cpp                     |  4 +-
 libminifi/include/core/extension/Extension.h       | 14 ++++-
 .../include/core/extension/ExtensionManager.h      |  2 +
 libminifi/src/core/extension/Extension.cpp         | 64 ++++++++++++++++-----
 libminifi/src/core/extension/ExtensionManager.cpp  | 22 ++++++--
 libminifi/src/minifi-c.cpp                         | 65 ++++++++++------------
 minifi-api/CMakeLists.txt                          |  2 +-
 minifi-api/include/minifi-c/minifi-c.h             | 19 ++-----
 minifi-api/minifi-c-api.def                        |  2 +-
 16 files changed, 176 insertions(+), 85 deletions(-)

diff --git a/Extensions.md b/Extensions.md
index 3a82e212f..0bfbd5bd9 100644
--- a/Extensions.md
+++ b/Extensions.md
@@ -17,8 +17,41 @@
 To enable all extensions for your platform, you may use -DENABLE_ALL=TRUE OR 
select the option to "Enable all Extensions" in the bootstrap script. 
[ReadMe](https://github.com/apache/nifi-minifi-cpp/#bootstrapping)
 
 # Extension internals
-Extensions are dynamic libraries loaded at runtime by the agent. An extension 
makes its
-capabilities (classes) available to the system through registrars. 
Registration must happen in source files, not headers.
+Extensions are dynamic libraries loaded at runtime by the agent.
+
+## C extensions
+You can build a shared library depending on the C capabilities of the agent as 
given in the `minifi-c.h` file.
+For the shared library to be considered a valid extension, it has to have a 
global symbol with the name `MinifiCApiVersion`
+with its value as a null terminated string (`const char*`) of the macro 
`MINIFI_API_VERSION` from `minifi-c.h`.
+
+Moreover the actual resource registration (processors/controller services) has 
to happen during the `MinifiInitExtension` call.
+One possible example of this is:
+
+```C++
+extern "C" const char* const MinifiApiVersion = MINIFI_API_VERSION;
+
+extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+  MinifiExtension* extension = nullptr;
+  
minifi::api::core::useProcessorClassDescription<minifi::extensions::llamacpp::processors::RunLlamaCppInference>([&]
 (const MinifiProcessorClassDefinition& description) {
+    MinifiExtensionCreateInfo ext_create_info{
+      .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)),
+      .version = 
minifi::api::utils::toStringView(MAKESTRING(EXTENSION_VERSION)),
+      .deinit = nullptr,
+      .user_data = nullptr,
+      .processors_count = 1,
+      .processors_ptr = &description,
+    };
+    extension = MinifiCreateExtension(&ext_create_info);
+  });
+  return extension;
+}
+```
+
+## C++ extensions
+You can utilize the C++ api, linking to `minifi-api` and possibly using the 
helpers in `extension-framework`.
+No compatibilities are guaranteed beyond what extensions are built together 
with the agent at the same time.
+
+An extension makes its capabilities (classes) available to the system through 
registrars. Registration must happen in source files, not headers.
 
 ```C++
 // register user-facing classes as
@@ -33,10 +66,10 @@ REGISTER_RESOURCE(RESTSender, DescriptionOnly);
 ```
 
 Some extensions (e.g. `OpenCVExtension`) require initialization before use.
-You need to define an `MinifiInitExtension` function of type 
`MinifiExtension*(MinifiConfig*)` to be called.
+You need to define an `MinifiInitCppExtension` function of type 
`MinifiExtension*(MinifiConfig*)` to be called.
 
 ```C++
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
   const auto success = 
org::apache::nifi::minifi::utils::Environment::setEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS",
 "rtsp_transport;udp", false /*overwrite*/);
   if (!success) {
     return nullptr;
@@ -49,7 +82,7 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+  return MinifiCreateCppExtension(&ext_create_info);
 }
 ```
 
diff --git a/extension-framework/include/utils/ExtensionInitUtils.h 
b/extension-framework/include/utils/ExtensionInitUtils.h
index 1af7617e5..57f1d063f 100644
--- a/extension-framework/include/utils/ExtensionInitUtils.h
+++ b/extension-framework/include/utils/ExtensionInitUtils.h
@@ -30,4 +30,8 @@ inline MinifiStringView toStringView(std::string_view str) {
 
 using ConfigReader = std::function<std::optional<std::string>(std::string_view 
key)>;
 
+static inline MinifiExtension* MinifiCreateCppExtension(const 
MinifiExtensionCreateInfo* create_info) {
+  return MINIFI_CREATE_EXTENSION_FN(create_info);
+}
+
 }  // namespace org::apache::nifi::minifi::utils
diff --git a/extensions/ExtensionInitializer.cpp 
b/extensions/ExtensionInitializer.cpp
index 3caaaeed0..e735a78e7 100644
--- a/extensions/ExtensionInitializer.cpp
+++ b/extensions/ExtensionInitializer.cpp
@@ -22,7 +22,7 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
   MinifiExtensionCreateInfo ext_create_info{
     .name = minifi::utils::toStringView(MAKESTRING(MODULE_NAME)),
     .version = minifi::utils::toStringView(minifi::AgentBuild::VERSION),
@@ -31,5 +31,5 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
 }
diff --git a/extensions/llamacpp/processors/ExtensionInitializer.cpp 
b/extensions/llamacpp/processors/ExtensionInitializer.cpp
index b90b8b133..29316f8b3 100644
--- a/extensions/llamacpp/processors/ExtensionInitializer.cpp
+++ b/extensions/llamacpp/processors/ExtensionInitializer.cpp
@@ -24,6 +24,8 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
+extern "C" const char* const MinifiApiVersion = MINIFI_API_VERSION;
+
 extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
   MinifiExtension* extension = nullptr;
   
minifi::api::core::useProcessorClassDescription<minifi::extensions::llamacpp::processors::RunLlamaCppInference>([&]
 (const MinifiProcessorClassDefinition& description) {
@@ -35,7 +37,7 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
       .processors_count = 1,
       .processors_ptr = &description,
     };
-    extension = 
MinifiCreateExtension(minifi::api::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+    extension = MinifiCreateExtension(&ext_create_info);
   });
   return extension;
 }
diff --git a/extensions/opencv/OpenCVLoader.cpp 
b/extensions/opencv/OpenCVLoader.cpp
index 3f91395c4..53f61dbca 100644
--- a/extensions/opencv/OpenCVLoader.cpp
+++ b/extensions/opencv/OpenCVLoader.cpp
@@ -24,7 +24,7 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
   // By default in OpenCV, ffmpeg capture is hardcoded to use TCP and this is 
a workaround
   // also if UDP timeout, ffmpeg will retry with TCP
   // Note:
@@ -42,5 +42,5 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
 }
diff --git a/extensions/python/pythonlibloader/PythonLibLoader.cpp 
b/extensions/python/pythonlibloader/PythonLibLoader.cpp
index cdf0356b7..9c9a35d28 100644
--- a/extensions/python/pythonlibloader/PythonLibLoader.cpp
+++ b/extensions/python/pythonlibloader/PythonLibLoader.cpp
@@ -98,7 +98,7 @@ class PythonLibLoader {
   std::shared_ptr<minifi::core::logging::Logger> logger_ = 
minifi::core::logging::LoggerFactory<PythonLibLoader>::getLogger();
 };
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* config) {
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* config) {
   static PythonLibLoader python_lib_loader([&] (std::string_view key) -> 
std::optional<std::string> {
     std::optional<std::string> result;
     MinifiConfigGet(config, minifi::utils::toStringView(key), [] (void* 
user_data, MinifiStringView value) {
@@ -114,5 +114,5 @@ extern "C" MinifiExtension* 
MinifiInitExtension(MinifiConfig* config) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
 }
diff --git a/extensions/python/pythonloader/PyProcLoader.cpp 
b/extensions/python/pythonloader/PyProcLoader.cpp
index 55ad4ebef..cd9cbb998 100644
--- a/extensions/python/pythonloader/PyProcLoader.cpp
+++ b/extensions/python/pythonloader/PyProcLoader.cpp
@@ -33,7 +33,7 @@ static minifi::extensions::python::PythonCreator& 
getPythonCreator() {
 // the symbols of the python library
 extern "C" const int LOAD_MODULE_AS_GLOBAL = 1;
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* config) {
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* config) {
   getPythonCreator().configure([&] (std::string_view key) -> 
std::optional<std::string> {
     std::optional<std::string> result;
     MinifiConfigGet(config, minifi::utils::toStringView(key), [] (void* 
user_data, MinifiStringView value) {
@@ -49,5 +49,5 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
config) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+  return minifi::utils::MinifiCreateCppExtension( &ext_create_info);
 }
diff --git a/extensions/sftp/SFTPLoader.cpp b/extensions/sftp/SFTPLoader.cpp
index bb23e9998..333ab173e 100644
--- a/extensions/sftp/SFTPLoader.cpp
+++ b/extensions/sftp/SFTPLoader.cpp
@@ -25,7 +25,7 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
   if (libssh2_init(0) != 0) {
     return nullptr;
   }
@@ -44,5 +44,5 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
+  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
 }
diff --git a/libminifi/include/core/extension/Extension.h 
b/libminifi/include/core/extension/Extension.h
index e14cb97ed..2a71a6fbc 100644
--- a/libminifi/include/core/extension/Extension.h
+++ b/libminifi/include/core/extension/Extension.h
@@ -17,11 +17,12 @@
 
 #pragma once
 
-#include <memory>
+#include <filesystem>
 #include <map>
+#include <memory>
 #include <string>
-#include <filesystem>
 
+#include "minifi-c/minifi-c.h"
 #include "minifi-cpp/core/logging/Logger.h"
 #include "minifi-cpp/properties/Configure.h"
 
@@ -38,6 +39,12 @@ class Extension {
     void* user_data;
   };
 
+  struct Version {
+    int major{MINIFI_API_MAJOR_VERSION};
+    int minor{MINIFI_API_MINOR_VERSION};
+    int patch{MINIFI_API_PATCH_VERSION};
+  };
+
   Extension(std::string name, std::filesystem::path library_path);
 
   Extension(const Extension&) = delete;
@@ -49,6 +56,8 @@ class Extension {
 
   bool initialize(const std::shared_ptr<minifi::Configure>& configure);
 
+  Version version() const {return version_;}
+
  private:
 #ifdef WIN32
   std::map<void*, std::string> resource_mapping_;
@@ -71,6 +80,7 @@ class Extension {
   std::filesystem::path library_path_;
   gsl::owner<void*> handle_ = nullptr;
 
+  Version version_{};
   std::unique_ptr<Info> info_;
 
   const std::shared_ptr<logging::Logger> logger_;
diff --git a/libminifi/include/core/extension/ExtensionManager.h 
b/libminifi/include/core/extension/ExtensionManager.h
index c610bd70a..7b312ae4b 100644
--- a/libminifi/include/core/extension/ExtensionManager.h
+++ b/libminifi/include/core/extension/ExtensionManager.h
@@ -37,6 +37,8 @@ class ExtensionManager {
   ExtensionManager& operator=(const ExtensionManager&) = delete;
   ExtensionManager& operator=(ExtensionManager&&) = delete;
 
+  static Extension* getExtensionBeingInitialized();
+
  private:
   std::vector<std::unique_ptr<Extension>> extensions_;
 
diff --git a/libminifi/src/core/extension/Extension.cpp 
b/libminifi/src/core/extension/Extension.cpp
index 3034c8a8f..35d0634b9 100644
--- a/libminifi/src/core/extension/Extension.cpp
+++ b/libminifi/src/core/extension/Extension.cpp
@@ -38,6 +38,7 @@
 #include "core/logging/LoggerFactory.h"
 #include "minifi-c/minifi-c.h"
 #include "minifi-cpp/agent/agent_docs.h"
+#include "utils/RegexUtils.h"
 
 namespace org::apache::nifi::minifi::core::extension {
 
@@ -57,10 +58,43 @@ bool Extension::load(bool global) {
   if (!handle_) {
     logger_->log_error("Failed to load extension '{}' at '{}': {}", name_, 
library_path_, dlerror());
     return false;
-  } else {
-    logger_->log_trace("Loaded extension '{}' at '{}'", name_, library_path_);
+  }
+  logger_->log_trace("Dlopen succeeded for extension '{}' at '{}'", name_, 
library_path_);
+  if (findSymbol("MinifiInitCppExtension")) {
+    logger_->log_trace("Loaded cpp extension '{}' at '{}'", name_, 
library_path_);
     return true;
   }
+  if (!findSymbol("MinifiInitExtension")) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': No 
initializer found", name_, library_path_);
+    return false;
+  }
+  auto api_version = reinterpret_cast<const char* 
const*>(findSymbol("MinifiApiVersion"));
+  if (!api_version) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': No 
MinifiApiVersion symbol found", name_, library_path_);
+    return false;
+  }
+  utils::SVMatch match;
+  if (!utils::regexSearch(*api_version, match, 
utils::Regex{R"(^([0-9]+)\.([0-9]+)\.([0-9]+)$)"})) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': Api version 
is in invalid format: '{}'", name_, library_path_, *api_version);
+    return false;
+  }
+  gsl_Assert(match.size() == 4);
+  version_.major = std::stoi(match[1]);
+  version_.minor = std::stoi(match[2]);
+  version_.patch = std::stoi(match[3]);
+  if (version_.major != MINIFI_API_MAJOR_VERSION) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': Api major 
version mismatch, application is '{}' while extension is '{}'",
+        name_, library_path_, MINIFI_API_VERSION, *api_version);
+    return false;
+  }
+  if (version_.minor > MINIFI_API_MINOR_VERSION) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': Extension is 
built for a newer version, application is '{}' while extension is '{}'",
+        name_, library_path_, MINIFI_API_VERSION, *api_version);
+    return false;
+  }
+  logger_->log_debug("Loaded c extension '{}' at '{}': Application version is 
'{}', extension version is '{}'",
+        name_, library_path_, MINIFI_API_VERSION, *api_version);
+  return true;
 }
 
 bool Extension::unload() {
@@ -113,17 +147,21 @@ Extension::~Extension() {
 
 bool Extension::initialize(const std::shared_ptr<minifi::Configure>& 
configure) {
   logger_->log_trace("Initializing extension '{}'", name_);
-  if (void* init_symbol_ptr = findSymbol("MinifiInitExtension")) {
-    logger_->log_debug("Found custom initializer for '{}'", name_);
-    auto init_fn = 
reinterpret_cast<MinifiExtension*(*)(MinifiConfig*)>(init_symbol_ptr);
-    auto config_handle = reinterpret_cast<MinifiConfig*>(configure.get());
-    info_.reset(reinterpret_cast<Info*>(init_fn(config_handle)));
-    if (!info_) {
-      logger_->log_error("Failed to initialize extension '{}'", name_);
-      return false;
-    }
-  } else {
-    logger_->log_debug("No custom initializer for '{}'", name_);
+  void* init_symbol_ptr = findSymbol("MinifiInitCppExtension");
+  if (!init_symbol_ptr) {
+    init_symbol_ptr = findSymbol("MinifiInitExtension");
+  }
+  if (!init_symbol_ptr) {
+    logger_->log_error("No initializer for '{}'", name_);
+    return false;
+  }
+  logger_->log_debug("Found initializer for '{}'", name_);
+  auto init_fn = 
reinterpret_cast<MinifiExtension*(*)(MinifiConfig*)>(init_symbol_ptr);
+  auto config_handle = reinterpret_cast<MinifiConfig*>(configure.get());
+  info_.reset(reinterpret_cast<Info*>(init_fn(config_handle)));
+  if (!info_) {
+    logger_->log_error("Failed to initialize extension '{}'", name_);
+    return false;
   }
   return true;
 }
diff --git a/libminifi/src/core/extension/ExtensionManager.cpp 
b/libminifi/src/core/extension/ExtensionManager.cpp
index 0b144a251..689a6cd42 100644
--- a/libminifi/src/core/extension/ExtensionManager.cpp
+++ b/libminifi/src/core/extension/ExtensionManager.cpp
@@ -30,6 +30,16 @@
 
 namespace org::apache::nifi::minifi::core::extension {
 
+namespace {
+
+std::atomic<Extension*> extension_being_initialized{nullptr};
+
+}  // namespace
+
+Extension* ExtensionManager::getExtensionBeingInitialized() {
+  return extension_being_initialized.load();
+}
+
 ExtensionManager::ExtensionManager(const std::shared_ptr<Configure>& config): 
logger_(logging::LoggerFactory<ExtensionManager>::getLogger()) {
   logger_->log_trace("Initializing extensions");
   if (!config) {
@@ -71,10 +81,14 @@ ExtensionManager::ExtensionManager(const 
std::shared_ptr<Configure>& config): lo
         continue;
       }
     }
-    if (!extension->initialize(config)) {
-      logger_->log_error("Failed to initialize extension '{}' at '{}'", 
library->name, library->getFullPath());
-    } else {
-      extensions_.push_back(std::move(extension));
+    {
+      auto extension_guard = gsl::finally([] {extension_being_initialized = 
nullptr;});
+      extension_being_initialized = extension.get();
+      if (!extension->initialize(config)) {
+        logger_->log_error("Failed to initialize extension '{}' at '{}'", 
library->name, library->getFullPath());
+      } else {
+        extensions_.push_back(std::move(extension));
+      }
     }
   }
 }
diff --git a/libminifi/src/minifi-c.cpp b/libminifi/src/minifi-c.cpp
index 0e4144c33..e670c4415 100644
--- a/libminifi/src/minifi-c.cpp
+++ b/libminifi/src/minifi-c.cpp
@@ -22,6 +22,8 @@
 
 #include "agent/agent_docs.h"
 #include "core/ProcessorMetrics.h"
+#include "core/extension/ExtensionManager.h"
+#include "minifi-cpp/Exception.h"
 #include "minifi-cpp/core/Annotation.h"
 #include "minifi-cpp/core/ClassLoader.h"
 #include "minifi-cpp/core/ProcessContext.h"
@@ -33,10 +35,8 @@
 #include "minifi-cpp/core/PropertyValidator.h"
 #include "minifi-cpp/core/logging/Logger.h"
 #include "minifi-cpp/core/state/PublishedMetricProvider.h"
-#include "minifi-cpp/Exception.h"
-#include "core/extension/ExtensionManager.h"
-#include "utils/PropertyErrors.h"
 #include "utils/CProcessor.h"
+#include "utils/PropertyErrors.h"
 
 namespace minifi = org::apache::nifi::minifi;
 
@@ -146,30 +146,6 @@ class CProcessorFactory : public 
minifi::core::ProcessorFactory {
   minifi::utils::CProcessorClassDescription class_description_;
 };
 
-MinifiExtension* MinifiCreateExtensionImpl(MinifiStringView /*api_version*/, 
const MinifiExtensionCreateInfo* extension_create_info) {
-  gsl_Assert(extension_create_info);
-  auto extension_name = toString(extension_create_info->name);
-  minifi::BundleIdentifier bundle{
-    .name = extension_name,
-    .version = toString(extension_create_info->version)
-  };
-  auto& bundle_components = 
minifi::ClassDescriptionRegistry::getMutableClassDescriptions()[bundle];
-  for (size_t proc_idx = 0; proc_idx < 
extension_create_info->processors_count; ++proc_idx) {
-    
minifi::utils::useCProcessorClassDescription(extension_create_info->processors_ptr[proc_idx],
 [&] (const auto& description, const auto& c_class_description) {
-      
minifi::core::ClassLoader::getDefaultClassLoader().getClassLoader(extension_name).registerClass(
-        c_class_description.name,
-        std::make_unique<CProcessorFactory>(extension_name, 
toString(extension_create_info->processors_ptr[proc_idx].full_name), 
c_class_description));
-      bundle_components.processors.emplace_back(description);
-    });
-  }
-  return reinterpret_cast<MinifiExtension*>(new 
org::apache::nifi::minifi::core::extension::Extension::Info{
-    .name = toString(extension_create_info->name),
-    .version = toString(extension_create_info->version),
-    .deinit = extension_create_info->deinit,
-    .user_data = extension_create_info->user_data
-  });
-}
-
 }  // namespace
 
 namespace org::apache::nifi::minifi::utils {
@@ -249,16 +225,35 @@ void useCProcessorClassDescription(const 
MinifiProcessorClassDefinition& class_d
 
 extern "C" {
 
-MinifiExtension* MINIFI_CREATE_EXTENSION_FN(MinifiStringView api_version, 
const MinifiExtensionCreateInfo* extension_create_info) {
-  return MinifiCreateExtensionImpl(api_version, extension_create_info);
-}
-
-#define REGISTER_C_API_VERSION(major, minor)  \
-  MinifiExtension* MINIFI_PRIVATE_JOIN(MinifiCreateExtension, 
MINIFI_PRIVATE_JOIN(major, minor))(MinifiStringView api_version, const 
MinifiExtensionCreateInfo* extension_create_info) {  \
-    return MinifiCreateExtensionImpl(api_version, extension_create_info);  \
+MinifiExtension* MinifiCreateExtension(const MinifiExtensionCreateInfo* 
extension_create_info) {
+  gsl_Assert(extension_create_info);
+  auto current_extension = 
minifi::core::extension::ExtensionManager::getExtensionBeingInitialized();
+  gsl_Assert(current_extension);
+  auto extension_name = toString(extension_create_info->name);
+  minifi::BundleIdentifier bundle{
+    .name = extension_name,
+    .version = toString(extension_create_info->version)
+  };
+  auto& bundle_components = 
minifi::ClassDescriptionRegistry::getMutableClassDescriptions()[bundle];
+  for (size_t proc_idx = 0; proc_idx < 
extension_create_info->processors_count; ++proc_idx) {
+    
minifi::utils::useCProcessorClassDescription(extension_create_info->processors_ptr[proc_idx],
 [&] (const auto& description, const auto& c_class_description) {
+      
minifi::core::ClassLoader::getDefaultClassLoader().getClassLoader(extension_name).registerClass(
+        c_class_description.name,
+        std::make_unique<CProcessorFactory>(extension_name, 
toString(extension_create_info->processors_ptr[proc_idx].full_name), 
c_class_description));
+      bundle_components.processors.emplace_back(description);
+    });
   }
+  return reinterpret_cast<MinifiExtension*>(new 
org::apache::nifi::minifi::core::extension::Extension::Info{
+    .name = toString(extension_create_info->name),
+    .version = toString(extension_create_info->version),
+    .deinit = extension_create_info->deinit,
+    .user_data = extension_create_info->user_data
+  });
+}
 
-REGISTER_C_API_VERSION(0, 1)
+MinifiExtension* MINIFI_CREATE_EXTENSION_FN(const MinifiExtensionCreateInfo* 
extension_create_info) {
+  return MinifiCreateExtension(extension_create_info);
+}
 
 MinifiStatus MinifiProcessContextGetProperty(MinifiProcessContext* context, 
MinifiStringView property_name, MinifiFlowFile* flowfile,
     void (*result_cb)(void* user_ctx, MinifiStringView result), void* 
user_ctx) {
diff --git a/minifi-api/CMakeLists.txt b/minifi-api/CMakeLists.txt
index 05f78fc99..ebdd239c3 100644
--- a/minifi-api/CMakeLists.txt
+++ b/minifi-api/CMakeLists.txt
@@ -6,7 +6,7 @@ target_compile_definitions(minifi-api-common INTERFACE 
MINIFI_VERSION_STR="${MIN
 add_library(minifi-api INTERFACE)
 target_include_directories(minifi-api INTERFACE include)
 target_link_libraries(minifi-api INTERFACE minifi-api-common)
-target_compile_definitions(minifi-api INTERFACE 
MINIFI_CREATE_EXTENSION_FN=MinifiCreateExtension_${BUILD_IDENTIFIER})
+target_compile_definitions(minifi-api INTERFACE 
MINIFI_CREATE_EXTENSION_FN=MinifiCreateCppExtension_${BUILD_IDENTIFIER})
 
 add_library(minifi-c-api INTERFACE)
 target_include_directories(minifi-c-api INTERFACE include/minifi-c)
diff --git a/minifi-api/include/minifi-c/minifi-c.h 
b/minifi-api/include/minifi-c/minifi-c.h
index d246b773b..5bab74941 100644
--- a/minifi-api/include/minifi-c/minifi-c.h
+++ b/minifi-api/include/minifi-c/minifi-c.h
@@ -39,13 +39,13 @@ extern "C" {
 #define MINIFI_API_PATCH_VERSION 0
 #define MINIFI_API_VERSION MINIFI_PRIVATE_STRINGIFY(MINIFI_API_MAJOR_VERSION) 
"." MINIFI_PRIVATE_STRINGIFY(MINIFI_API_MINOR_VERSION) "." 
MINIFI_PRIVATE_STRINGIFY(MINIFI_API_PATCH_VERSION)
 
-#ifndef MINIFI_CREATE_EXTENSION_FN
-#define MINIFI_CREATE_EXTENSION_FN MINIFI_PRIVATE_JOIN(MinifiCreateExtension, 
MINIFI_PRIVATE_JOIN(MINIFI_API_MAJOR_VERSION, MINIFI_API_MINOR_VERSION))
-#endif
-
 #define MINIFI_NULL nullptr
 #define MINIFI_OWNED
 
+#ifndef MINIFI_CREATE_EXTENSION_FN
+#define MINIFI_CREATE_EXTENSION_FN MinifiCreateExtension
+#endif
+
 typedef bool MinifiBool;
 
 typedef enum MinifiInputRequirement : uint32_t {
@@ -94,7 +94,7 @@ typedef struct MinifiOutputStream MinifiOutputStream;
 typedef struct MinifiConfig MinifiConfig;
 typedef struct MinifiExtension MinifiExtension;
 typedef struct MinifiPublishedMetrics MinifiPublishedMetrics;
-typedef struct MinifiApiVersion MinifiApiVersion;
+typedef struct MinifiAgent MinifiAgent;
 
 typedef enum MinifiStatus : uint32_t {
   MINIFI_STATUS_SUCCESS = 0,
@@ -189,10 +189,7 @@ typedef struct MinifiExtensionCreateInfo {
   const MinifiProcessorClassDefinition* processors_ptr;
 } MinifiExtensionCreateInfo;
 
-// api_version is used to provide backwards compatible changes to the 
MinifiExtensionCreateInfo structure,
-// e.g. if MinifiExtensionCreateInfo gets a new field in version 1.2.0, 
extensions built with api 1.1.0 do not
-// have to be rebuilt
-MinifiExtension* MINIFI_CREATE_EXTENSION_FN(MinifiStringView api_version, 
const MinifiExtensionCreateInfo* create_info);
+MinifiExtension* MINIFI_CREATE_EXTENSION_FN(const MinifiExtensionCreateInfo* 
create_info);
 
 MINIFI_OWNED MinifiPublishedMetrics* MinifiPublishedMetricsCreate(size_t 
count, const MinifiStringView* metric_names, const double* metric_values);
 
@@ -232,8 +229,4 @@ void MinifiFlowFileGetAttributes(MinifiProcessSession* 
session, MinifiFlowFile*
 }  // extern "C"
 #endif  // __cplusplus
 
-static inline MinifiExtension* MinifiCreateExtension(MinifiStringView 
api_version, const MinifiExtensionCreateInfo* create_info) {
-  return MINIFI_CREATE_EXTENSION_FN(api_version, create_info);
-}
-
 #endif  // MINIFI_API_INCLUDE_MINIFI_C_MINIFI_C_H_
diff --git a/minifi-api/minifi-c-api.def b/minifi-api/minifi-c-api.def
index a664bdd2d..fd303daee 100644
--- a/minifi-api/minifi-c-api.def
+++ b/minifi-api/minifi-c-api.def
@@ -1,6 +1,6 @@
 LIBRARY core-minifi.dll
 EXPORTS
-  MinifiCreateExtension_0_1
+  MinifiCreateExtension
   MinifiPublishedMetricsCreate
   MinifiProcessContextGetProperty
   MinifiProcessContextHasNonEmptyProperty

Reply via email to