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 e83dbf2d710de9bf1ee2e9382f63f6956f105f9d
Author: Adam Debreceni <[email protected]>
AuthorDate: Mon Mar 2 17:23:32 2026 +0100

    MINIFICPP-2715 - Use a single integer as c api version
---
 Extensions.md                                      | 10 ++-
 .../include/utils/ExtensionInitUtils.h             |  4 +-
 extensions/ExtensionInitializer.cpp                |  4 +-
 .../llamacpp/processors/ExtensionInitializer.cpp   |  8 +--
 extensions/opencv/OpenCVLoader.cpp                 |  6 +-
 .../python/pythonlibloader/PythonLibLoader.cpp     |  4 +-
 extensions/python/pythonloader/PyProcLoader.cpp    |  4 +-
 extensions/sftp/SFTPLoader.cpp                     |  8 +--
 libminifi/include/core/extension/ApiVersion.h      | 16 ++---
 libminifi/include/core/extension/Extension.h       |  8 +--
 libminifi/src/core/extension/ApiVersion.cpp        | 15 ++++-
 libminifi/src/core/extension/Extension.cpp         | 76 +++++++++++-----------
 libminifi/src/minifi-c.cpp                         | 15 +++--
 .../extension-verification-test/CApiExtension.cpp  |  6 +-
 .../extension-verification-test/CMakeLists.txt     | 18 ++---
 .../CppApiExtension.cpp                            |  4 +-
 .../CreateNotCalled.cpp}                           | 26 ++------
 .../ExtensionVerificationTests.cpp                 | 49 +++++++-------
 minifi-api/include/minifi-c/minifi-c.h             | 11 ++--
 19 files changed, 141 insertions(+), 151 deletions(-)

diff --git a/Extensions.md b/Extensions.md
index 159232f9a..f75c068e6 100644
--- a/Extensions.md
+++ b/Extensions.md
@@ -30,8 +30,7 @@ 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;
+extern "C" void MinifiInitExtension(MinifiExtension* extension, MinifiConfig* 
/*config*/) {
   
minifi::api::core::useProcessorClassDescription<minifi::extensions::llamacpp::processors::RunLlamaCppInference>([&]
 (const MinifiProcessorClassDefinition& description) {
     MinifiExtensionCreateInfo ext_create_info{
       .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)),
@@ -41,9 +40,8 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
       .processors_count = 1,
       .processors_ptr = &description,
     };
-    extension = MinifiCreateExtension(&ext_create_info);
+    MinifiCreateExtension(extension, &ext_create_info);
   });
-  return extension;
 }
 ```
 
@@ -69,7 +67,7 @@ Some extensions (e.g. `OpenCVExtension`) require 
initialization before use.
 You need to define an `MinifiInitCppExtension` function of type 
`MinifiExtension*(MinifiConfig*)` to be called.
 
 ```C++
-extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
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;
@@ -82,7 +80,7 @@ extern "C" MinifiExtension* 
MinifiInitCppExtension(MinifiConfig* /*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
 ```
 
diff --git a/extension-framework/include/utils/ExtensionInitUtils.h 
b/extension-framework/include/utils/ExtensionInitUtils.h
index 57f1d063f..75da5c1ae 100644
--- a/extension-framework/include/utils/ExtensionInitUtils.h
+++ b/extension-framework/include/utils/ExtensionInitUtils.h
@@ -30,8 +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);
+static inline void MinifiCreateCppExtension(MinifiExtension* extension, const 
MinifiExtensionCreateInfo* create_info) {
+  MINIFI_CREATE_EXTENSION_FN(extension, create_info);
 }
 
 }  // namespace org::apache::nifi::minifi::utils
diff --git a/extensions/ExtensionInitializer.cpp 
b/extensions/ExtensionInitializer.cpp
index e735a78e7..47a4c2185 100644
--- a/extensions/ExtensionInitializer.cpp
+++ b/extensions/ExtensionInitializer.cpp
@@ -22,7 +22,7 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
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* 
MinifiInitCppExtension(MinifiConfig* /*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
diff --git a/extensions/llamacpp/processors/ExtensionInitializer.cpp 
b/extensions/llamacpp/processors/ExtensionInitializer.cpp
index 29316f8b3..8c223dc70 100644
--- a/extensions/llamacpp/processors/ExtensionInitializer.cpp
+++ b/extensions/llamacpp/processors/ExtensionInitializer.cpp
@@ -24,10 +24,9 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" const char* const MinifiApiVersion = MINIFI_API_VERSION;
+extern "C" const uint32_t MinifiApiVersion = MINIFI_API_VERSION;
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
-  MinifiExtension* extension = nullptr;
+extern "C" void MinifiInitExtension(MinifiExtension* extension, MinifiConfig* 
/*config*/) {
   
minifi::api::core::useProcessorClassDescription<minifi::extensions::llamacpp::processors::RunLlamaCppInference>([&]
 (const MinifiProcessorClassDefinition& description) {
     MinifiExtensionCreateInfo ext_create_info{
       .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)),
@@ -37,7 +36,6 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
       .processors_count = 1,
       .processors_ptr = &description,
     };
-    extension = MinifiCreateExtension(&ext_create_info);
+    MinifiCreateExtension(extension, &ext_create_info);
   });
-  return extension;
 }
diff --git a/extensions/opencv/OpenCVLoader.cpp 
b/extensions/opencv/OpenCVLoader.cpp
index 53f61dbca..87c6615c5 100644
--- a/extensions/opencv/OpenCVLoader.cpp
+++ b/extensions/opencv/OpenCVLoader.cpp
@@ -24,7 +24,7 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
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:
@@ -32,7 +32,7 @@ extern "C" MinifiExtension* 
MinifiInitCppExtension(MinifiConfig* /*config*/) {
   // 2. The command will not overwrite value if 
"OPENCV_FFMPEG_CAPTURE_OPTIONS" already exists.
   const auto success = 
org::apache::nifi::minifi::utils::Environment::setEnvironmentVariable("OPENCV_FFMPEG_CAPTURE_OPTIONS",
 "rtsp_transport;udp", false /*overwrite*/);
   if (!success) {
-    return nullptr;
+    return;
   }
   MinifiExtensionCreateInfo ext_create_info{
     .name = minifi::utils::toStringView(MAKESTRING(MODULE_NAME)),
@@ -42,5 +42,5 @@ extern "C" MinifiExtension* 
MinifiInitCppExtension(MinifiConfig* /*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
diff --git a/extensions/python/pythonlibloader/PythonLibLoader.cpp 
b/extensions/python/pythonlibloader/PythonLibLoader.cpp
index 9c9a35d28..79ef21556 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* MinifiInitCppExtension(MinifiConfig* config) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
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* 
MinifiInitCppExtension(MinifiConfig* config) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
diff --git a/extensions/python/pythonloader/PyProcLoader.cpp 
b/extensions/python/pythonloader/PyProcLoader.cpp
index d4edf9cf2..e92bbea41 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* MinifiInitCppExtension(MinifiConfig* config) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
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* 
MinifiInitCppExtension(MinifiConfig* config) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
diff --git a/extensions/sftp/SFTPLoader.cpp b/extensions/sftp/SFTPLoader.cpp
index 333ab173e..c8309cc60 100644
--- a/extensions/sftp/SFTPLoader.cpp
+++ b/extensions/sftp/SFTPLoader.cpp
@@ -25,13 +25,13 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
MinifiConfig* /*config*/) {
   if (libssh2_init(0) != 0) {
-    return nullptr;
+    return;
   }
   if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
     libssh2_exit();
-    return nullptr;
+    return;
   }
   MinifiExtensionCreateInfo ext_create_info{
     .name = minifi::utils::toStringView(MAKESTRING(MODULE_NAME)),
@@ -44,5 +44,5 @@ extern "C" MinifiExtension* 
MinifiInitCppExtension(MinifiConfig* /*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
diff --git a/libminifi/include/core/extension/ApiVersion.h 
b/libminifi/include/core/extension/ApiVersion.h
index 01acb82cb..34b917a32 100644
--- a/libminifi/include/core/extension/ApiVersion.h
+++ b/libminifi/include/core/extension/ApiVersion.h
@@ -21,17 +21,9 @@
 
 namespace org::apache::nifi::minifi::core::extension {
 
-struct ApiVersion {
-  int major;
-  int minor;
-  int patch;
-
-  std::string str() const {
-    return std::to_string(major) + "." + std::to_string(minor) + "." + 
std::to_string(patch);
-  }
-};
-
-ApiVersion getAgentApiVersion();
-void setAgentApiVersion(ApiVersion api_version);
+uint32_t getAgentApiVersion();
+uint32_t getMinSupportedApiVersion();
+void test_setAgentApiVersion(uint32_t api_version);
+void test_setMinSupportedApiVersion(uint32_t min_api_version);
 
 }  // namespace org::apache::nifi::minifi::core::extension
diff --git a/libminifi/include/core/extension/Extension.h 
b/libminifi/include/core/extension/Extension.h
index 356efed4c..85cf4fc60 100644
--- a/libminifi/include/core/extension/Extension.h
+++ b/libminifi/include/core/extension/Extension.h
@@ -51,7 +51,7 @@ class Extension {
 
   bool initialize(const std::shared_ptr<minifi::Configure>& configure);
 
-  [[nodiscard]] ApiVersion apiVersion() const {return api_version_;}
+  bool setInfo(Info info);
 
  private:
 #ifdef WIN32
@@ -71,12 +71,12 @@ class Extension {
   bool unload();
   void* findSymbol(const char* name);
 
-  std::string name_;
+  std::string library_name_;
   std::filesystem::path library_path_;
   gsl::owner<void*> handle_ = nullptr;
 
-  ApiVersion api_version_;
-  std::unique_ptr<Info> info_;
+  std::optional<Info> info_;
+  uint32_t api_version_{0};
 
   const std::shared_ptr<logging::Logger> logger_;
 };
diff --git a/libminifi/src/core/extension/ApiVersion.cpp 
b/libminifi/src/core/extension/ApiVersion.cpp
index 1f515b25b..15f59d18b 100644
--- a/libminifi/src/core/extension/ApiVersion.cpp
+++ b/libminifi/src/core/extension/ApiVersion.cpp
@@ -20,14 +20,23 @@
 
 namespace org::apache::nifi::minifi::core::extension {
 
-static ApiVersion agent_api_version{.major = MINIFI_API_MAJOR_VERSION, .minor 
= MINIFI_API_MINOR_VERSION, .patch = MINIFI_API_PATCH_VERSION};
+static uint32_t agent_api_version{MINIFI_API_VERSION};
+static uint32_t min_supported_api_version{MINIFI_API_VERSION};
 
-ApiVersion getAgentApiVersion() {
+uint32_t getAgentApiVersion() {
   return agent_api_version;
 }
 
-void setAgentApiVersion(ApiVersion api_version) {
+void test_setAgentApiVersion(uint32_t api_version) {
   agent_api_version = api_version;
 }
 
+uint32_t getMinSupportedApiVersion() {
+  return min_supported_api_version;
+}
+
+void test_setMinSupportedApiVersion(uint32_t min_api_version) {
+  min_supported_api_version = min_api_version;
+}
+
 }  // namespace org::apache::nifi::minifi::core::extension
\ No newline at end of file
diff --git a/libminifi/src/core/extension/Extension.cpp 
b/libminifi/src/core/extension/Extension.cpp
index 9073b6c9a..9382da9d1 100644
--- a/libminifi/src/core/extension/Extension.cpp
+++ b/libminifi/src/core/extension/Extension.cpp
@@ -42,10 +42,9 @@
 
 namespace org::apache::nifi::minifi::core::extension {
 
-Extension::Extension(std::string name, std::filesystem::path library_path)
-  : name_(std::move(name)),
+Extension::Extension(std::string library_name, std::filesystem::path 
library_path)
+  : library_name_(std::move(library_name)),
     library_path_(std::move(library_path)),
-    api_version_(getAgentApiVersion()),
     logger_(logging::LoggerFactory<Extension>::getLogger()) {
 }
 
@@ -57,59 +56,51 @@ bool Extension::load(bool global) {
     handle_ = dlopen(library_path_.string().c_str(), RTLD_NOW | RTLD_LOCAL);  
// NOLINT(cppcoreguidelines-owning-memory)
   }
   if (!handle_) {
-    logger_->log_error("Failed to load extension '{}' at '{}': {}", name_, 
library_path_, dlerror());
+    logger_->log_error("Failed to load extension '{}' at '{}': {}", 
library_name_, library_path_, dlerror());
     return false;
   }
-  logger_->log_trace("Dlopen succeeded for extension '{}' at '{}'", name_, 
library_path_);
+  logger_->log_trace("Dlopen succeeded for extension '{}' at '{}'", 
library_name_, library_path_);
   if (findSymbol("MinifiInitCppExtension")) {
-    logger_->log_trace("Loaded cpp extension '{}' at '{}'", name_, 
library_path_);
+    logger_->log_trace("Loaded cpp extension '{}' at '{}'", library_name_, 
library_path_);
     return true;
   }
   if (!findSymbol("MinifiInitExtension")) {
-    logger_->log_error("Failed to load as c extension '{}' at '{}': No 
initializer found", name_, library_path_);
+    logger_->log_error("Failed to load as c extension '{}' at '{}': No 
initializer found", library_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_);
+  auto api_version_ptr = reinterpret_cast<const 
uint32_t*>(findSymbol("MinifiApiVersion"));
+  if (!api_version_ptr) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': No 
MinifiApiVersion symbol found", library_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);
+  api_version_ = *api_version_ptr;
+  if (api_version_ < getMinSupportedApiVersion()) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': Api version 
is no longer supported, application supports {}-{} while extension is {}",
+        library_name_, library_path_, getMinSupportedApiVersion(), 
getAgentApiVersion(), api_version_);
     return false;
   }
-  gsl_Assert(match.size() == 4);
-  api_version_.major = std::stoi(match[1]);
-  api_version_.minor = std::stoi(match[2]);
-  api_version_.patch = std::stoi(match[3]);
-  if (api_version_.major != getAgentApiVersion().major) {
-    logger_->log_error("Failed to load c extension '{}' at '{}': Api major 
version mismatch, application is '{}' while extension is '{}'",
-        name_, library_path_, getAgentApiVersion().str(), *api_version);
+  if (api_version_ > getAgentApiVersion()) {
+    logger_->log_error("Failed to load c extension '{}' at '{}': Extension is 
built for a newer version, application supports {}-{} while extension is {}",
+        library_name_, library_path_, getMinSupportedApiVersion(), 
getAgentApiVersion(), api_version_);
     return false;
   }
-  if (api_version_.minor > getAgentApiVersion().minor) {
-    logger_->log_error("Failed to load c extension '{}' at '{}': Extension is 
built for a newer version, application is '{}' while extension is '{}'",
-        name_, library_path_, getAgentApiVersion().str(), *api_version);
-    return false;
-  }
-  logger_->log_debug("Loaded c extension '{}' at '{}': Application version is 
'{}', extension version is '{}'",
-        name_, library_path_, getAgentApiVersion().str(), *api_version);
+  logger_->log_debug("Loaded c extension '{}' at '{}': Application version is 
{}, extension version is {}",
+        library_name_, library_path_, getAgentApiVersion(), api_version_);
   return true;
 }
 
 bool Extension::unload() {
-  logger_->log_trace("Unloading library '{}' at '{}'", name_, library_path_);
+  logger_->log_trace("Unloading library '{}' at '{}'", library_name_, 
library_path_);
   if (!handle_) {
-    logger_->log_error("Extension does not have a handle_ '{}' at '{}'", 
name_, library_path_);
+    logger_->log_error("Extension does not have a handle_ '{}' at '{}'", 
library_name_, library_path_);
     return true;
   }
   dlerror();
   if (dlclose(handle_)) {
-    logger_->log_error("Failed to unload extension '{}' at '{}': {}", name_, 
library_path_, dlerror());
+    logger_->log_error("Failed to unload extension '{}' at '{}': {}", 
library_name_, library_path_, dlerror());
     return false;
   }
-  logger_->log_trace("Unloaded extension '{}' at '{}'", name_, library_path_);
+  logger_->log_trace("Unloaded extension '{}' at '{}'", library_name_, 
library_path_);
   handle_ = nullptr;
   return true;
 }
@@ -146,25 +137,34 @@ Extension::~Extension() {
 #endif
 }
 
+bool Extension::setInfo(Info info) {
+  if (info_) {
+    return false;
+  }
+  info_ = std::move(info);
+  return true;
+}
+
 bool Extension::initialize(const std::shared_ptr<minifi::Configure>& 
configure) {
-  logger_->log_trace("Initializing extension '{}'", name_);
+  logger_->log_trace("Initializing extension '{}'", library_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_);
+    logger_->log_error("No initializer for '{}'", library_name_);
     return false;
   }
-  logger_->log_debug("Found initializer for '{}'", name_);
-  auto init_fn = 
reinterpret_cast<MinifiExtension*(*)(MinifiConfig*)>(init_symbol_ptr);
+  logger_->log_debug("Found initializer for '{}'", library_name_);
+  auto init_fn = reinterpret_cast<void(*)(MinifiExtension*, 
MinifiConfig*)>(init_symbol_ptr);
   auto config_handle = reinterpret_cast<MinifiConfig*>(configure.get());
-  info_.reset(reinterpret_cast<Info*>(init_fn(config_handle)));
+  auto extension_handle = reinterpret_cast<MinifiExtension*>(this);
+  init_fn(extension_handle, config_handle);
   if (!info_) {
-    logger_->log_error("Failed to initialize extension '{}'", name_);
+    logger_->log_error("Failed to initialize extension '{}'", library_name_);
     return false;
   }
-  logger_->log_debug("Initialized extension '{}'", name_);
+  logger_->log_debug("Initialized extension '{}', name = '{}', version = 
'{}'", library_name_, info_->name, info_->version);
   return true;
 }
 
diff --git a/libminifi/src/minifi-c.cpp b/libminifi/src/minifi-c.cpp
index e670c4415..0936f4808 100644
--- a/libminifi/src/minifi-c.cpp
+++ b/libminifi/src/minifi-c.cpp
@@ -225,10 +225,9 @@ void useCProcessorClassDescription(const 
MinifiProcessorClassDefinition& class_d
 
 extern "C" {
 
-MinifiExtension* MinifiCreateExtension(const MinifiExtensionCreateInfo* 
extension_create_info) {
+MinifiStatus MinifiCreateExtension(MinifiExtension* extension, const 
MinifiExtensionCreateInfo* extension_create_info) {
+  gsl_Assert(extension);
   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,
@@ -243,16 +242,20 @@ MinifiExtension* MinifiCreateExtension(const 
MinifiExtensionCreateInfo* extensio
       bundle_components.processors.emplace_back(description);
     });
   }
-  return reinterpret_cast<MinifiExtension*>(new 
org::apache::nifi::minifi::core::extension::Extension::Info{
+  bool success = 
reinterpret_cast<org::apache::nifi::minifi::core::extension::Extension*>(extension)->setInfo(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
   });
+  if (success) {
+    return MINIFI_STATUS_SUCCESS;
+  }
+  return MINIFI_STATUS_UNKNOWN_ERROR;
 }
 
-MinifiExtension* MINIFI_CREATE_EXTENSION_FN(const MinifiExtensionCreateInfo* 
extension_create_info) {
-  return MinifiCreateExtension(extension_create_info);
+MinifiStatus MINIFI_CREATE_EXTENSION_FN(MinifiExtension* extension, const 
MinifiExtensionCreateInfo* extension_create_info) {
+  return MinifiCreateExtension(extension, extension_create_info);
 }
 
 MinifiStatus MinifiProcessContextGetProperty(MinifiProcessContext* context, 
MinifiStringView property_name, MinifiFlowFile* flowfile,
diff --git 
a/libminifi/test/integration/extension-verification-test/CApiExtension.cpp 
b/libminifi/test/integration/extension-verification-test/CApiExtension.cpp
index e6fd7cfbc..bbd51809a 100644
--- a/libminifi/test/integration/extension-verification-test/CApiExtension.cpp
+++ b/libminifi/test/integration/extension-verification-test/CApiExtension.cpp
@@ -24,9 +24,9 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" const char* const MinifiApiVersion = MINIFI_TEST_API_VERSION;
+extern "C" const uint32_t MinifiApiVersion = MINIFI_TEST_API_VERSION;
 
-extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* /*config*/) {
+extern "C" void MinifiInitExtension(MinifiExtension* extension, MinifiConfig* 
/*config*/) {
   MinifiExtensionCreateInfo ext_create_info{
     .name = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_NAME)),
     .version = minifi::api::utils::toStringView(MAKESTRING(EXTENSION_VERSION)),
@@ -35,5 +35,5 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr,
   };
-  return MinifiCreateExtension(&ext_create_info);
+  MinifiCreateExtension(extension, &ext_create_info);
 }
\ No newline at end of file
diff --git 
a/libminifi/test/integration/extension-verification-test/CMakeLists.txt 
b/libminifi/test/integration/extension-verification-test/CMakeLists.txt
index 32c068106..fa428b044 100644
--- a/libminifi/test/integration/extension-verification-test/CMakeLists.txt
+++ b/libminifi/test/integration/extension-verification-test/CMakeLists.txt
@@ -41,7 +41,7 @@ function(create_c_test_extension extension-name 
custom_api_version)
     set(extension-name "test-extension-loading-${extension-name}")
     create_loading_test_extension(${extension-name} CApiExtension.cpp)
     target_link_libraries(${extension-name} minifi-cpp-extension-lib)
-    target_compile_definitions(${extension-name} PRIVATE 
MINIFI_TEST_API_VERSION="${custom_api_version}")
+    target_compile_definitions(${extension-name} PRIVATE 
MINIFI_TEST_API_VERSION=${custom_api_version})
     target_compile_definitions(${extension-name}
             PRIVATE "EXTENSION_NAME=${extension-name}" 
"EXTENSION_VERSION=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
 endfunction()
@@ -69,11 +69,13 @@ 
create_loading_test_extension(test-extension-loading-valid-build-id-cpp CppApiEx
 target_link_libraries(test-extension-loading-valid-build-id-cpp 
dummy-core-minifi)
 target_compile_definitions(test-extension-loading-valid-build-id-cpp PRIVATE 
MINIFI_CREATE_EXTENSION_FN=MinifiCreateCppExtension_${BUILD_IDENTIFIER})
 
-create_c_test_extension(same-version "1.1.1")
-create_c_test_extension(greater-major-version "2.0.0")
-create_c_test_extension(smaller-major-version "0.1.0")
-create_c_test_extension(greater-minor-version "1.2.0")
-create_c_test_extension(smaller-minor-version "1.0.1")
-create_c_test_extension(greater-patch-version "1.1.2")
-create_c_test_extension(smaller-patch-version "1.1.0")
+create_c_test_extension(max-version 10)
+create_c_test_extension(valid-version 7)
+create_c_test_extension(min-version 5)
+create_c_test_extension(greater-version 11)
+create_c_test_extension(smaller-version 4)
 create_loading_test_extension(test-extension-loading-missing-init 
InvalidMissingInitExtension.cpp)
+
+create_loading_test_extension(test-extension-loading-create-not-called 
CreateNotCalled.cpp)
+target_link_libraries(test-extension-loading-create-not-called minifi-c-api)
+target_compile_definitions(test-extension-loading-create-not-called PRIVATE 
MINIFI_TEST_API_VERSION=10)
diff --git 
a/libminifi/test/integration/extension-verification-test/CppApiExtension.cpp 
b/libminifi/test/integration/extension-verification-test/CppApiExtension.cpp
index 0503a8c17..59daee45d 100644
--- a/libminifi/test/integration/extension-verification-test/CppApiExtension.cpp
+++ b/libminifi/test/integration/extension-verification-test/CppApiExtension.cpp
@@ -24,7 +24,7 @@
 
 namespace minifi = org::apache::nifi::minifi;
 
-extern "C" MinifiExtension* MinifiInitCppExtension(MinifiConfig* /*config*/) {
+extern "C" void MinifiInitCppExtension(MinifiExtension* extension, 
MinifiConfig* /*config*/) {
   MinifiExtensionCreateInfo ext_create_info{
     .name = minifi::utils::toStringView(MAKESTRING(MODULE_NAME)),
     .version = minifi::utils::toStringView("1.0.0"),
@@ -33,5 +33,5 @@ extern "C" MinifiExtension* 
MinifiInitCppExtension(MinifiConfig* /*config*/) {
     .processors_count = 0,
     .processors_ptr = nullptr
   };
-  return minifi::utils::MinifiCreateCppExtension(&ext_create_info);
+  minifi::utils::MinifiCreateCppExtension(extension, &ext_create_info);
 }
diff --git a/libminifi/include/core/extension/ApiVersion.h 
b/libminifi/test/integration/extension-verification-test/CreateNotCalled.cpp
similarity index 60%
copy from libminifi/include/core/extension/ApiVersion.h
copy to 
libminifi/test/integration/extension-verification-test/CreateNotCalled.cpp
index 01acb82cb..ec6e5394d 100644
--- a/libminifi/include/core/extension/ApiVersion.h
+++ b/libminifi/test/integration/extension-verification-test/CreateNotCalled.cpp
@@ -1,5 +1,6 @@
 /**
-* Licensed to the Apache Software Foundation (ASF) under one or more
+*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
  * The ASF licenses this file to You under the Apache License, Version 2.0
@@ -15,23 +16,10 @@
  * limitations under the License.
  */
 
-#pragma once
+#include "minifi-c.h"
 
-#include  <string>
+extern "C" const uint32_t MinifiApiVersion = MINIFI_TEST_API_VERSION;
 
-namespace org::apache::nifi::minifi::core::extension {
-
-struct ApiVersion {
-  int major;
-  int minor;
-  int patch;
-
-  std::string str() const {
-    return std::to_string(major) + "." + std::to_string(minor) + "." + 
std::to_string(patch);
-  }
-};
-
-ApiVersion getAgentApiVersion();
-void setAgentApiVersion(ApiVersion api_version);
-
-}  // namespace org::apache::nifi::minifi::core::extension
+extern "C" void MinifiInitExtension(MinifiExtension* extension, MinifiConfig* 
/*config*/) {
+  // NOT CALLING CREATE
+}
\ No newline at end of file
diff --git 
a/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp
 
b/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp
index 6fa304691..a31700bf7 100644
--- 
a/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp
+++ 
b/libminifi/test/integration/extension-verification-test/ExtensionVerificationTests.cpp
@@ -32,7 +32,8 @@ class ExtensionLoadingTestController {
     LogTestController::getInstance().clear();
     
LogTestController::getInstance().setTrace<core::extension::ExtensionManager>();
     LogTestController::getInstance().setTrace<core::extension::Extension>();
-    minifi::core::extension::setAgentApiVersion({.major = 1, .minor = 1, 
.patch = 1});
+    minifi::core::extension::test_setAgentApiVersion(10);
+    minifi::core::extension::test_setMinSupportedApiVersion(5);
     auto config = minifi::Configure::create();
     config->set(minifi::Configuration::nifi_extension_path, pattern);
     return config;
@@ -46,9 +47,9 @@ TEST_CASE("Can load cpp-api extensions with same build id") {
   REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded cpp 
extension 'test-extension-loading-valid-build-id-cpp'"));
 }
 
-TEST_CASE("Can load c-api extensions with same version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-same-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-same-version'"));
+TEST_CASE("Can load c-api extensions with max version") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-max-version*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-max-version'"));
 }
 
 TEST_CASE("Can't load cpp-api extensions with different build id") {
@@ -56,35 +57,35 @@ TEST_CASE("Can't load cpp-api extensions with different 
build id") {
   REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load extension 'test-extension-loading-invalid-build-id-cpp'"));
 }
 
-TEST_CASE("Can't load c-api extensions with greater major version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-greater-major-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load c extension 'test-extension-loading-greater-major-version'"));
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Api major 
version mismatch, application is '1.1.1' while extension is '2.0.0'"));
+TEST_CASE("Can load c-api extensions with min version") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-min-version*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-min-version'"));
 }
 
-TEST_CASE("Can't load c-api extensions with smaller major version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-smaller-major-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load c extension 'test-extension-loading-smaller-major-version'"));
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Api major 
version mismatch, application is '1.1.1' while extension is '0.1.0'"));
+TEST_CASE("Can load c-api extensions with valid version") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-valid-version*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-valid-version'"));
 }
 
-TEST_CASE("Can't load c-api extensions with greater minor version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-greater-minor-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load c extension 'test-extension-loading-greater-minor-version'"));
+TEST_CASE("Can't load c-api extensions with greater version") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-greater-version*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load c extension 'test-extension-loading-greater-version'"));
   REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Extension 
is built for a newer version"));
 }
 
-TEST_CASE("Can load c-api extensions with smaller minor version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-smaller-minor-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-smaller-minor-version'"));
+TEST_CASE("Can't load c-api extensions with smaller version") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-smaller-version*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load c extension 'test-extension-loading-smaller-version'"));
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Api 
version is no longer supported, application supports 5-10 while extension is 
4"));
 }
 
-TEST_CASE("Can load c-api extensions with greater patch version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-greater-patch-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-greater-patch-version'"));
+TEST_CASE("Can't load c-api extensions with no MinifiInitExtension function") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-missing-init*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
load as c extension 'test-extension-loading-missing-init'"));
 }
 
-TEST_CASE("Can load c-api extensions with smaller patch version") {
-  ExtensionLoadingTestController 
controller{"*test-extension-loading-smaller-patch-version*"};
-  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Loaded c 
extension 'test-extension-loading-smaller-patch-version'"));
+TEST_CASE("Can't load c-api extensions with no MinifiCreateExtension call") {
+  ExtensionLoadingTestController 
controller{"*test-extension-loading-create-not-called*"};
+  REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(0s, "Failed to 
initialize extension 'test-extension-loading-create-not-called'"));
 }
+
diff --git a/minifi-api/include/minifi-c/minifi-c.h 
b/minifi-api/include/minifi-c/minifi-c.h
index 5bab74941..9a80b5791 100644
--- a/minifi-api/include/minifi-c/minifi-c.h
+++ b/minifi-api/include/minifi-c/minifi-c.h
@@ -34,11 +34,6 @@ extern "C" {
 #define MINIFI_PRIVATE_JOIN_HELPER(X, Y) X ## _ ## Y
 #define MINIFI_PRIVATE_JOIN(X, Y) MINIFI_PRIVATE_JOIN_HELPER(X, Y)
 
-#define MINIFI_API_MAJOR_VERSION 0
-#define MINIFI_API_MINOR_VERSION 1
-#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)
-
 #define MINIFI_NULL nullptr
 #define MINIFI_OWNED
 
@@ -46,6 +41,10 @@ extern "C" {
 #define MINIFI_CREATE_EXTENSION_FN MinifiCreateExtension
 #endif
 
+enum : uint32_t {
+  MINIFI_API_VERSION = 1
+};
+
 typedef bool MinifiBool;
 
 typedef enum MinifiInputRequirement : uint32_t {
@@ -189,7 +188,7 @@ typedef struct MinifiExtensionCreateInfo {
   const MinifiProcessorClassDefinition* processors_ptr;
 } MinifiExtensionCreateInfo;
 
-MinifiExtension* MINIFI_CREATE_EXTENSION_FN(const MinifiExtensionCreateInfo* 
create_info);
+MinifiStatus MINIFI_CREATE_EXTENSION_FN(MinifiExtension* extension, const 
MinifiExtensionCreateInfo* create_info);
 
 MINIFI_OWNED MinifiPublishedMetrics* MinifiPublishedMetricsCreate(size_t 
count, const MinifiStringView* metric_names, const double* metric_values);
 


Reply via email to