From 95e44833752209b548c1b5e7aa40217d0187909b Mon Sep 17 00:00:00 2001 From: Gigon Bae Date: Tue, 20 Jul 2021 00:46:26 -0700 Subject: [PATCH] Enable additional plugin - cucim.kit.cumed --- cpp/CMakeLists.txt | 4 ++ cpp/include/cucim/config/config.h | 3 + cpp/include/cucim/core/framework.h | 5 +- cpp/include/cucim/cuimage.h | 6 +- cpp/include/cucim/io/format/image_format.h | 3 +- cpp/include/cucim/plugin/image_format.h | 47 ++++++++++++++ cpp/include/cucim/plugin/plugin_config.h | 44 +++++++++++++ .../cucim.kit.cuslide/src/cuslide/cuslide.cpp | 18 +++-- .../src/cuslide/tiff/tiff.cpp | 5 ++ cpp/src/config/config.cpp | 12 ++++ cpp/src/core/cucim_framework.cpp | 38 ++++++++++- cpp/src/core/cucim_framework.h | 5 +- cpp/src/core/cucim_plugin.cpp | 23 +++++-- cpp/src/core/framework.cpp | 9 ++- cpp/src/cuimage.cpp | 65 ++++++++++--------- cpp/src/io/format/image_format.cpp | 2 +- cpp/src/plugin/image_format.cpp | 56 ++++++++++++++++ cpp/src/plugin/plugin_config.cpp | 43 ++++++++++++ run | 46 ++++++++++++- 19 files changed, 384 insertions(+), 50 deletions(-) create mode 100644 cpp/include/cucim/plugin/image_format.h create mode 100644 cpp/include/cucim/plugin/plugin_config.h create mode 100644 cpp/src/plugin/image_format.cpp create mode 100644 cpp/src/plugin/plugin_config.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 804ee3368..2f86a9c4a 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -63,6 +63,8 @@ add_library(${CUCIM_PACKAGE_NAME} include/cucim/macros/defines.h include/cucim/memory/dlpack.h include/cucim/memory/memory_manager.h + include/cucim/plugin/image_format.h + include/cucim/plugin/plugin_config.h include/cucim/util/cuda.h include/cucim/util/file.h include/cucim/util/platform.h @@ -96,6 +98,8 @@ add_library(${CUCIM_PACKAGE_NAME} src/logger/logger.cpp src/logger/timer.cpp src/memory/memory_manager.cu + src/plugin/image_format.cpp + src/plugin/plugin_config.cpp src/util/file.cpp src/util/platform.cpp) diff --git a/cpp/include/cucim/config/config.h b/cpp/include/cucim/config/config.h index bc15aae18..1ec1200fc 100644 --- a/cpp/include/cucim/config/config.h +++ b/cpp/include/cucim/config/config.h @@ -20,6 +20,7 @@ #include "cucim/macros/api_header.h" #include "cucim/cache/cache_type.h" #include "cucim/cache/image_cache_config.h" +#include "cucim/plugin/plugin_config.h" #include #include @@ -38,6 +39,7 @@ class EXPORT_VISIBLE Config Config(); cucim::cache::ImageCacheConfig& cache(); + cucim::plugin::PluginConfig& plugin(); std::string shm_name() const; pid_t pid() const; @@ -52,6 +54,7 @@ class EXPORT_VISIBLE Config std::string source_path_; cucim::cache::ImageCacheConfig cache_; + cucim::plugin::PluginConfig plugin_; }; } // namespace cucim::config diff --git a/cpp/include/cucim/core/framework.h b/cpp/include/cucim/core/framework.h index 9534e6d49..e4411c5ac 100644 --- a/cpp/include/cucim/core/framework.h +++ b/cpp/include/cucim/core/framework.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,7 +63,7 @@ struct PluginLoadingDesc struct Framework { - void load_plugins(const PluginLoadingDesc& desc = PluginLoadingDesc::get_default()); + // void load_plugins(const PluginLoadingDesc& desc = PluginLoadingDesc::get_default()); bool(CUCIM_ABI* register_plugin)(const char* client_name, const PluginRegistrationDesc& desc); void*(CUCIM_ABI* acquire_interface_from_library_with_client)(const char* client_name, InterfaceDesc desc, @@ -74,6 +74,7 @@ struct Framework T* acquire_interface_from_library(const char* library_path); // cuCIM-specific methods + void(CUCIM_ABI* load_plugin)(const char* library_path); const char*(CUCIM_ABI* get_plugin_root)(); void(CUCIM_ABI* set_plugin_root)(const char* path); }; diff --git a/cpp/include/cucim/cuimage.h b/cpp/include/cucim/cuimage.h index 18efc028b..75c49dee2 100644 --- a/cpp/include/cucim/cuimage.h +++ b/cpp/include/cucim/cuimage.h @@ -24,6 +24,7 @@ #include "cucim/io/device.h" #include "cucim/io/format/image_format.h" #include "cucim/memory/dlpack.h" +#include "cucim/plugin/image_format.h" #include #include @@ -106,7 +107,7 @@ class EXPORT_VISIBLE CuImage : public std::enable_shared_from_this operator bool() const { - return !!image_formats_ && !is_loaded_; + return !!image_format_ && !is_loaded_; } static Framework* get_framework(); @@ -181,9 +182,10 @@ class EXPORT_VISIBLE CuImage : public std::enable_shared_from_this // Note: config_ should be placed before cache_manager_ (cache_manager_ depends on config_) static std::unique_ptr config_; static std::unique_ptr cache_manager_; + static std::unique_ptr image_format_plugins_; mutable Mutex mutex_; - cucim::io::format::IImageFormat* image_formats_ = nullptr; + cucim::io::format::ImageFormatDesc* image_format_ = nullptr; CuCIMFileHandle file_handle_{}; io::format::ImageMetadataDesc* image_metadata_ = nullptr; io::format::ImageDataDesc* image_data_ = nullptr; diff --git a/cpp/include/cucim/io/format/image_format.h b/cpp/include/cucim/io/format/image_format.h index ba4dc5ba0..091ea098b 100644 --- a/cpp/include/cucim/io/format/image_format.h +++ b/cpp/include/cucim/io/format/image_format.h @@ -170,9 +170,10 @@ struct ImageCheckerDesc * Returns true if the given file is valid for the format * @param file_name * @param buf + * @param size * @return */ - bool(CUCIM_ABI* is_valid)(const char* file_name, const char* buf); + bool(CUCIM_ABI* is_valid)(const char* file_name, const char* buf, size_t size); }; struct ImageParserDesc diff --git a/cpp/include/cucim/plugin/image_format.h b/cpp/include/cucim/plugin/image_format.h new file mode 100644 index 000000000..98e2fc76d --- /dev/null +++ b/cpp/include/cucim/plugin/image_format.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CUCIM_PLUGIN_IMAGE_FORMAT_H +#define CUCIM_PLUGIN_IMAGE_FORMAT_H + +#include "cucim/filesystem/file_path.h" +#include "cucim/io/format/image_format.h" + + +namespace cucim::plugin +{ + +class ImageFormat +{ +public: + ImageFormat() = default; + ~ImageFormat() = default; + + bool add_interfaces(cucim::io::format::IImageFormat* image_formats); + cucim::io::format::ImageFormatDesc* detect_image_format(const filesystem::Path& path); + + operator bool() const + { + return !image_formats_.empty(); + } + +private: + std::vector image_formats_; +}; + +} // namespace cucim::plugin + +#endif // CUCIM_PLUGIN_IMAGE_FORMAT_H diff --git a/cpp/include/cucim/plugin/plugin_config.h b/cpp/include/cucim/plugin/plugin_config.h new file mode 100644 index 000000000..047f21146 --- /dev/null +++ b/cpp/include/cucim/plugin/plugin_config.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CUCIM_PLUGIN_PLUGIN_CONFIG_H +#define CUCIM_PLUGIN_PLUGIN_CONFIG_H + +#include "cucim/core/framework.h" + +#include +#include + +namespace cucim::plugin +{ + +#define XSTR(x) STR(x) +#define STR(x) #x + +struct EXPORT_VISIBLE PluginConfig +{ + void load_config(const void* json_obj); + + std::vector plugin_names{ std::string("cucim.kit.cuslide@" XSTR(CUCIM_VERSION) ".so"), + std::string("cucim.kit.cumed@" XSTR(CUCIM_VERSION) ".so") }; +}; + +#undef STR +#undef XSTR + +} // namespace cucim::plugin + +#endif // CUCIM_PLUGIN_PLUGIN_CONFIG_H diff --git a/cpp/plugins/cucim.kit.cuslide/src/cuslide/cuslide.cpp b/cpp/plugins/cucim.kit.cuslide/src/cuslide/cuslide.cpp index 055473892..173381239 100644 --- a/cpp/plugins/cucim.kit.cuslide/src/cuslide/cuslide.cpp +++ b/cpp/plugins/cucim.kit.cuslide/src/cuslide/cuslide.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ #include #include #include +#include #include using json = nlohmann::json; @@ -68,12 +69,17 @@ static const char* get_format_name() return "Generic TIFF"; } -static bool CUCIM_ABI checker_is_valid(const char* file_name, const char* buf) // TODO: need buffer size parameter +static bool CUCIM_ABI checker_is_valid(const char* file_name, const char* buf, size_t size) { - // TODO implement this - (void)file_name; (void)buf; - return true; + (void)size; + auto file = std::filesystem::path(file_name); + auto extension = file.extension().string(); + if (extension.compare(".tif") == 0 || extension.compare(".tiff") == 0) + { + return true; + } + return false; } static CuCIMFileHandle CUCIM_ABI parser_open(const char* file_path) @@ -277,7 +283,7 @@ static bool CUCIM_ABI writer_write(const CuCIMFileHandle* handle, void fill_interface(cucim::io::format::IImageFormat& iface) { - static cucim::io::format::ImageCheckerDesc image_checker = { 0, 80, checker_is_valid }; + static cucim::io::format::ImageCheckerDesc image_checker = { 0, 0, checker_is_valid }; static cucim::io::format::ImageParserDesc image_parser = { parser_open, parser_parse, parser_close }; static cucim::io::format::ImageReaderDesc image_reader = { reader_read }; diff --git a/cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp b/cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp index f35e44891..be13f2604 100644 --- a/cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp +++ b/cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp @@ -206,6 +206,11 @@ TIFF::TIFF(const cucim::filesystem::Path& file_path, int mode) : file_path_(file throw std::invalid_argument(fmt::format("Cannot open {}!", file_path)); } tiff_client_ = ::TIFFFdOpen(fd, file_path_cstr, "rm"); // Add 'm' to disable memory-mapped file + if (tiff_client_ == nullptr) + { + cucim_free(file_path_cstr); + throw std::invalid_argument(fmt::format("Cannot load {}!", file_path)); + } // TODO: make file_handle_ object to pointer file_handle_ = CuCIMFileHandle{ fd, nullptr, FileHandleType::kPosix, file_path_cstr, this }; diff --git a/cpp/src/config/config.cpp b/cpp/src/config/config.cpp index 89010673a..dffd30dc7 100644 --- a/cpp/src/config/config.cpp +++ b/cpp/src/config/config.cpp @@ -55,6 +55,11 @@ cucim::cache::ImageCacheConfig& Config::cache() return cache_; } +cucim::plugin::PluginConfig& Config::plugin() +{ + return plugin_; +} + std::string Config::shm_name() const { return fmt::format("cucim-shm.{}", pgid()); @@ -113,11 +118,18 @@ bool Config::parse_config(std::string& path) { std::ifstream ifs(path); json obj = json::parse(ifs, nullptr /*cb*/, true /*allow_exceptions*/, true /*ignore_comments*/); + json cache = obj["cache"]; if (cache.is_object()) { cache_.load_config(&cache); } + + json plugin = obj["plugin"]; + if (plugin.is_object()) + { + plugin_.load_config(&plugin); + } } catch (const json::parse_error& e) { diff --git a/cpp/src/core/cucim_framework.cpp b/cpp/src/core/cucim_framework.cpp index 66be59081..026f32f21 100644 --- a/cpp/src/core/cucim_framework.cpp +++ b/cpp/src/core/cucim_framework.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -131,6 +131,25 @@ bool CuCIMFramework::register_plugin(const std::shared_ptr& plugin) return true; } +size_t CuCIMFramework::get_plugin_count() const +{ + ScopedLock g(mutex_); + return plugin_manager_.get_plugin_indices().size(); +} + +void CuCIMFramework::get_plugins(PluginDesc* out_plugins) const +{ + ScopedLock g(mutex_); + const std::unordered_set& plugins = plugin_manager_.get_plugin_indices(); + size_t i = 0; + for (const auto& plugin_index : plugins) + { + if (out_plugins) + { + out_plugins[i++] = plugin_manager_.get_plugin(plugin_index)->get_plugin_desc(); + } + } +} size_t CuCIMFramework::get_plugin_index(const char* name) const { @@ -603,6 +622,23 @@ bool CuCIMFramework::register_plugin(const std::string& file_path, bool reloadab } // cuCIM-specific methods + +void CuCIMFramework::load_plugin(const char* library_path) +{ + + ScopedLock g(mutex_); + + const std::string canonical_library_path(library_path); + + Plugin* plugin = get_plugin_by_library_path(canonical_library_path); + // Check if plugin with this library path was already loaded + if (!plugin) + { + // It was not loaded, try to register such plugin and get it again + register_plugin(canonical_library_path); + } +} + std::string& CuCIMFramework::get_plugin_root() { return plugin_root_path_; diff --git a/cpp/src/core/cucim_framework.h b/cpp/src/core/cucim_framework.h index 966c33ba8..3f0b56530 100644 --- a/cpp/src/core/cucim_framework.h +++ b/cpp/src/core/cucim_framework.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,12 +58,15 @@ class CuCIMFramework const InterfaceDesc& desc, const char* library_path, bool optional = false); + size_t get_plugin_count() const; + void get_plugins(PluginDesc* out_plugins) const; size_t get_plugin_index(const char* name) const; Plugin* get_plugin(size_t index) const; Plugin* get_plugin(const char* name) const; Plugin* get_plugin_by_library_path(const std::string& library_path); // cuCIM-specific methods; + void load_plugin(const char* library_path); std::string& get_plugin_root(); void set_plugin_root(const char* path); diff --git a/cpp/src/core/cucim_plugin.cpp b/cpp/src/core/cucim_plugin.cpp index 8e6aa11bc..86b75ba5e 100644 --- a/cpp/src/core/cucim_plugin.cpp +++ b/cpp/src/core/cucim_plugin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ #include #include +#include namespace cucim { @@ -49,8 +50,19 @@ Plugin::Plugin() Plugin::Plugin(const std::string& file_path) : Plugin() { + auto file = std::filesystem::path(file_path); + auto filename = file.filename().string(); + std::size_t pivot = filename.find("@"); + if (pivot != std::string::npos) + { + std::string plugin_name = filename.substr(0, pivot); + name_ = std::move(plugin_name); + } + else + { + name_ = "cucim.unknown"; + } library_path_ = file_path; - name_ = "cucim.kit.cuslide"; // TODO: Get plgin name from file_path } Plugin::~Plugin() @@ -257,7 +269,7 @@ bool Plugin::try_load(int version, bool full) { return is_loaded_; } - CUCIM_LOG_VERBOSE("[Plugin: %s] %s", name_cstr(), full ? "Loading..." : "Preloading..."); + // CUCIM_LOG_VERBOSE("[Plugin: %s] %s", name_cstr(), full ? "Loading..." : "Preloading..."); std::string lib_file; if (!prepare_file_to_load(lib_file, version)) @@ -297,11 +309,14 @@ bool Plugin::try_load(int version, bool full) // Register if (!fill_registration_data(version, full, lib_file)) { + CUCIM_LOG_ERROR("[Plugin: %s] Could not load the dynamic library from %s. Error: fill_registration_data() failed!", + name_cstr(), lib_file.c_str()); return false; } // Load was successful - CUCIM_LOG_VERBOSE("[Plugin: %s] %s successfully. Version: %d", name_cstr(), full ? "loaded" : "preloaded", version); + // CUCIM_LOG_VERBOSE("[Plugin: %s] %s successfully. Version: %d", name_cstr(), full ? "loaded" : "preloaded", + // version); is_loaded_ = true; return is_loaded_; } diff --git a/cpp/src/core/framework.cpp b/cpp/src/core/framework.cpp index 15765db68..d3bb409e7 100644 --- a/cpp/src/core/framework.cpp +++ b/cpp/src/core/framework.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,12 @@ static void unload_all_plugins() g_framework->unload_all_plugins(); } +static void load_plugin(const char* library_path) +{ + CUCIM_ASSERT(g_framework); + g_framework->load_plugin(library_path); +} + static const char* get_plugin_root() { CUCIM_ASSERT(g_framework); @@ -77,6 +83,7 @@ static Framework get_framework_impl() register_plugin, acquire_interface_from_library_with_client, unload_all_plugins, + load_plugin, get_plugin_root, set_plugin_root, }; diff --git a/cpp/src/cuimage.cpp b/cpp/src/cuimage.cpp index 8942c557e..044626135 100644 --- a/cpp/src/cuimage.cpp +++ b/cpp/src/cuimage.cpp @@ -135,23 +135,23 @@ DetectedFormat detect_format(filesystem::Path path) Framework* CuImage::framework_ = cucim::acquire_framework("cucim"); std::unique_ptr CuImage::config_ = std::make_unique(); std::unique_ptr CuImage::cache_manager_ = std::make_unique(); +std::unique_ptr CuImage::image_format_plugins_ = std::make_unique(); CuImage::CuImage(const filesystem::Path& path) { // printf("[cuCIM] CuImage::CuImage(filesystem::Path path)\n"); ensure_init(); - (void)path; + image_format_ = image_format_plugins_->detect_image_format(path); // TODO: need to detect available format for the file path - file_handle_ = image_formats_->formats[0].image_parser.open(path.c_str()); + file_handle_ = image_format_->image_parser.open(path.c_str()); // printf("[GB] file_handle: %s\n", file_handle_.path); // fmt::print("[GB] CuImage path char: '{}'\n", file_handle_.path[0]); - io::format::ImageMetadata& image_metadata = *(new io::format::ImageMetadata{}); image_metadata_ = &image_metadata.desc(); - is_loaded_ = image_formats_->formats[0].image_parser.parse(&file_handle_, image_metadata_); + is_loaded_ = image_format_->image_parser.parse(&file_handle_, image_metadata_); dim_indices_ = DimIndices(image_metadata_->dims); auto& associated_image_info = image_metadata_->associated_image_info; @@ -183,7 +183,7 @@ CuImage::CuImage(CuImage&& cuimg) : std::enable_shared_from_this() // printf("[cuCIM] CuImage::CuImage(CuImage&& cuimg) %s\n", cuimg.file_handle_.path); (void)cuimg; std::swap(file_handle_, cuimg.file_handle_); - std::swap(image_formats_, cuimg.image_formats_); + std::swap(image_format_, cuimg.image_format_); std::swap(image_metadata_, cuimg.image_metadata_); std::swap(image_data_, cuimg.image_data_); std::swap(is_loaded_, cuimg.is_loaded_); @@ -201,7 +201,7 @@ CuImage::CuImage(const CuImage* cuimg, // cucim::io::format::ImageDataDesc* image_data)\n"); // file_handle_ = cuimg->file_handle_; ==> Don't do this. it will cause a double free. - image_formats_ = cuimg->image_formats_; + image_format_ = cuimg->image_format_; image_metadata_ = image_metadata; image_data_ = image_data; is_loaded_ = true; @@ -230,7 +230,7 @@ CuImage::~CuImage() { // printf("[cuCIM] CuImage::~CuImage()\n"); close(); - image_formats_ = nullptr; // memory release is handled by the framework + image_format_ = nullptr; // memory release is handled by the framework if (image_metadata_) { // Memory for json_data needs to be manually released if image_metadata_->json_data is not "" @@ -616,7 +616,7 @@ CuImage CuImage::read_region(std::vector&& location, { throw std::runtime_error("[Error] The image file is closed!"); } - if (!image_formats_->formats[0].image_reader.read( + if (!image_format_->image_reader.read( &file_handle_, image_metadata_, &request, image_data, nullptr /*out_metadata*/)) { cucim_free(image_data); @@ -796,7 +796,7 @@ CuImage CuImage::associated_image(const std::string& name, const io::Device& dev io::format::ImageMetadata& out_metadata = *(new io::format::ImageMetadata{}); - if (!image_formats_->formats[0].image_reader.read( + if (!image_format_->image_reader.read( &file_handle_, image_metadata_, &request, out_image_data, &out_metadata.desc())) { cucim_free(out_image_data); @@ -865,7 +865,7 @@ void CuImage::close() { if (file_handle_.client_data) { - image_formats_->formats[0].image_parser.close(&file_handle_); + image_format_->image_parser.close(&file_handle_); } file_handle_.cufile = nullptr; file_handle_.path = nullptr; @@ -880,27 +880,34 @@ void CuImage::ensure_init() { CUCIM_ERROR("Framework is not initialized!"); } - if (!image_formats_) + if (!(*image_format_plugins_)) { - auto plugin_root = framework_->get_plugin_root(); - // TODO: Here 'LINUX' path separator is used. Need to make it generalize once filesystem library is - // available. - std::string plugin_file_path = - (plugin_root && *plugin_root != 0) ? - fmt::format("{}/cucim.kit.cuslide@{}.{}.{}.so", plugin_root, XSTR(CUCIM_VERSION_MAJOR), - XSTR(CUCIM_VERSION_MINOR), XSTR(CUCIM_VERSION_PATCH)) : - fmt::format("cucim.kit.cuslide@{}.{}.{}.so", XSTR(CUCIM_VERSION_MAJOR), XSTR(CUCIM_VERSION_MINOR), - XSTR(CUCIM_VERSION_PATCH)); - if (!cucim::util::file_exists(plugin_file_path.c_str())) - { - plugin_file_path = fmt::format("cucim.kit.cuslide@" XSTR(CUCIM_VERSION) ".so"); - } - image_formats_ = - framework_->acquire_interface_from_library(plugin_file_path.c_str()); - if (image_formats_ == nullptr) + image_format_plugins_ = std::make_unique(); + + const std::vector& plugin_names = get_config()->plugin().plugin_names; + + const char* plugin_root = framework_->get_plugin_root(); + for (auto& plugin_name : plugin_names) { - throw std::runtime_error( - fmt::format("Dependent library 'cucim.kit.cuslide@" XSTR(CUCIM_VERSION) ".so' cannot be loaded!")); + // TODO: Here 'LINUX' path separator is used. Need to make it generalize once filesystem library is + // available. + std::string plugin_file_path = (plugin_root && *plugin_root != 0) ? + fmt::format("{}/{}", plugin_root, plugin_name) : + fmt::format("{}", plugin_name); + if (!cucim::util::file_exists(plugin_file_path.c_str())) + { + plugin_file_path = fmt::format("{}", plugin_name); + } + + const auto& image_formats = + framework_->acquire_interface_from_library(plugin_file_path.c_str()); + + image_format_plugins_->add_interfaces(image_formats); + + if (image_formats == nullptr) + { + throw std::runtime_error(fmt::format("Dependent library '{}' cannot be loaded!", plugin_file_path)); + } } } } diff --git a/cpp/src/io/format/image_format.cpp b/cpp/src/io/format/image_format.cpp index 38009465d..9816f9130 100644 --- a/cpp/src/io/format/image_format.cpp +++ b/cpp/src/io/format/image_format.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. + * Copyright (c) 2020-2021, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cpp/src/plugin/image_format.cpp b/cpp/src/plugin/image_format.cpp new file mode 100644 index 000000000..174c8b414 --- /dev/null +++ b/cpp/src/plugin/image_format.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020-2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "cucim/io/format/image_format.h" +#include "cucim/plugin/image_format.h" + +#include + + +namespace cucim::plugin +{ + +bool ImageFormat::add_interfaces(cucim::io::format::IImageFormat* image_formats) +{ + if (image_formats && image_formats->format_count > 0) + { + for (size_t i = 0; i < image_formats->format_count; ++i) + { + cucim::io::format::ImageFormatDesc* format = &(image_formats->formats[i]); + image_formats_.push_back(format); + } + } + else + { + return false; + } + return true; +} + +cucim::io::format::ImageFormatDesc* ImageFormat::detect_image_format(const cucim::filesystem::Path& path) +{ + for (auto& format : image_formats_) + { + if (format->image_checker.is_valid(path.c_str(), nullptr, 0)) + { + return format; + } + } + throw std::invalid_argument(fmt::format("Cannot find a plugin to handle '{}'!", path)); +} + +} // namespace cucim::plugin diff --git a/cpp/src/plugin/plugin_config.cpp b/cpp/src/plugin/plugin_config.cpp new file mode 100644 index 000000000..c16e009b6 --- /dev/null +++ b/cpp/src/plugin/plugin_config.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cucim/plugin/plugin_config.h" + +#include +#include + +using json = nlohmann::json; + +namespace cucim::plugin +{ + +void PluginConfig::load_config(const void* json_obj) +{ + const json& plugin_config = *(static_cast(json_obj)); + + if (plugin_config["names"].is_array()) + { + std::vector names; + names.reserve(16); + for (const auto& name : plugin_config["names"]) + { + names.push_back(name); + } + plugin_names = std::move(names); + } +} + +} // namespace cucim::plugin diff --git a/run b/run index f87116d0e..e2cd109a3 100755 --- a/run +++ b/run @@ -301,6 +301,27 @@ build_local_cuslide_() { popd } +build_local_cumed_() { + local source_folder=${1:-${TOP}/cpp/plugins/cucim.kit.cumed} + local build_type=${2:-debug} + local build_type_str=${3:-Debug} + local prefix=${4:-} + local build_folder=${source_folder}/build-${build_type} + local CMAKE_CMD=${CMAKE_CMD:-cmake} + + pushd ${source_folder} > /dev/null + + ${CMAKE_CMD} -S ${source_folder} -B ${build_folder} -G "Unix Makefiles" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE \ + -DCMAKE_BUILD_TYPE=${build_type_str} \ + -DCMAKE_PREFIX_PATH=${prefix} \ + -DCMAKE_INSTALL_PREFIX=${source_folder}/install + ${CMAKE_CMD} --build ${build_folder} --config ${build_type_str} --target cucim.kit.cumed -- -j $(nproc) + ${CMAKE_CMD} --build ${build_folder} --config ${build_type_str} --target install -- -j $(nproc) + + popd +} + build_local_cucim_() { local source_folder=${1:-${TOP}/python} local build_type=${2:-debug} @@ -333,7 +354,7 @@ build_local_desc() { echo 'Build locally Compile binaries locally Arguments: - $1 - subcommand [all|clean_cache|clean|libcucim|cuslide|cucim] (default: all) + $1 - subcommand [all|clean_cache|clean|libcucim|cuslide|cumed|cucim] (default: all) $2 - build type [debug|release|rel-debug] (default: debug) ' } @@ -355,6 +376,7 @@ build_local() { if [ "$subcommand" = "clean_cache" ]; then rm -f ${TOP}/build-*/CMakeCache.txt rm -f ${TOP}/cpp/plugins/cucim.kit.cuslide/build-*/CMakeCache.txt + rm -f ${TOP}/cpp/plugins/cucim.kit.cumed/build-*/CMakeCache.txt rm -f ${TOP}/python/build-*/CMakeCache.txt fi @@ -363,6 +385,8 @@ build_local() { rm -rf ${TOP}/install rm -rf ${TOP}/cpp/plugins/cucim.kit.cuslide/build-*/ rm -rf ${TOP}/cpp/plugins/cucim.kit.cuslide/install + rm -rf ${TOP}/cpp/plugins/cucim.kit.cumed/build-*/ + rm -rf ${TOP}/cpp/plugins/cucim.kit.cumed/install rm -rf ${TOP}/python/build-* rm -rf ${TOP}/python/install fi @@ -375,6 +399,10 @@ build_local() { build_local_cuslide_ ${TOP}/cpp/plugins/cucim.kit.cuslide ${build_type} ${build_type_str} ${prefix} fi + if [ "$subcommand" = "all" ] || [ "$subcommand" = "cumed" ]; then + build_local_cumed_ ${TOP}/cpp/plugins/cucim.kit.cumed ${build_type} ${build_type_str} ${prefix} + fi + if [ "$subcommand" = "all" ] || [ "$subcommand" = "cucim" ]; then build_local_cucim_ ${TOP}/python ${build_type} ${build_type_str} ${prefix} fi @@ -385,11 +413,12 @@ build_local() { if [ "$subcommand" = "all" ] || [ "$subcommand" = "cucim" ]; then # We don't need to copy binary if executed by conda-build if [ "${CONDA_BUILD:-}" != "1" ]; then - # Copy .so files from libcucim & cuslide's build folders to cuCIM's Python source folder + # Copy .so files from libcucim & cuslide/cumed's build folders to cuCIM's Python source folder # Since wheel file doesn't support symbolic link (https://github.com/pypa/wheel/issues/203), # we don't need to copy symbolic links. Instead copy only libcucim.so.${major_version} (without symbolic link) cp ${TOP}/build-$build_type/lib*/libcucim.so.${major_version} ${TOP}/python/cucim/src/cucim/clara/ cp -P ${TOP}/cpp/plugins/cucim.kit.cuslide/build-$build_type/lib*/cucim* ${TOP}/python/cucim/src/cucim/clara/ + cp -P ${TOP}/cpp/plugins/cucim.kit.cumed/build-$build_type/lib*/cucim* ${TOP}/python/cucim/src/cucim/clara/ # Copy .so files from pybind's build folder to cuCIM's Python source folder cp ${TOP}/python/build-$build_type/lib/cucim/_cucim.*.so ${TOP}/python/cucim/src/cucim/clara/ @@ -489,6 +518,7 @@ build_python_package_() { # Clear CMakeCache.txt to use the latest options run_command rm -f ${BUILD_ROOT}/libcucim/CMakeCache.txt run_command rm -f ${BUILD_ROOT}/cuslide/CMakeCache.txt + run_command rm -f ${BUILD_ROOT}/cumed/CMakeCache.txt run_command rm -f ${BUILD_ROOT}/cucim/CMakeCache.txt # Create a folder for .whl file that repair_wheel_ is not applied. @@ -513,6 +543,8 @@ build_python_package_() { rm -rf ${BUILD_ROOT}/libcucim/install/lib*/lib* rm -rf ${BUILD_ROOT}/cuslide/lib/* rm -rf ${BUILD_ROOT}/cuslide/install/lib*/cucim* + rm -rf ${BUILD_ROOT}/cumed/lib/* + rm -rf ${BUILD_ROOT}/cumed/install/lib*/cucim* rm -rf ${BUILD_ROOT}/cucim/lib/cucim/*.so* rm -rf ${BUILD_ROOT}/cucim/install/lib/*.so* @@ -531,6 +563,14 @@ build_python_package_() { ${CMAKE_CMD} --build ${BUILD_ROOT}/cuslide --config ${CMAKE_BUILD_TYPE} --target cucim.kit.cuslide -- -j ${NUM_THREADS} ${CMAKE_CMD} --build ${BUILD_ROOT}/cuslide --config ${CMAKE_BUILD_TYPE} --target install -- -j ${NUM_THREADS} + # Build cumed plugin + ${CMAKE_CMD} -S ${SRC_ROOT}/cpp/plugins/cucim.kit.cumed -B ${BUILD_ROOT}/cumed \ + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ + -DCMAKE_INSTALL_PREFIX=${BUILD_ROOT}/cumed/install \ + -DCUCIM_SDK_PATH=${CUCIM_SDK_PATH} + ${CMAKE_CMD} --build ${BUILD_ROOT}/cumed --config ${CMAKE_BUILD_TYPE} --target cucim.kit.cumed -- -j ${NUM_THREADS} + ${CMAKE_CMD} --build ${BUILD_ROOT}/cumed --config ${CMAKE_BUILD_TYPE} --target install -- -j ${NUM_THREADS} + # Build Python bind pybins="$(echo /opt/python/*/bin)" if [ "${pybins}" = "/opt/python/*/bin" ]; then @@ -558,6 +598,7 @@ build_python_package_() { # (it uses -P to copy symbolic links as they are) cp -P ${BUILD_ROOT}/libcucim/install/lib*/lib* ${BUILD_ROOT}/cucim/install/lib/ cp -P ${BUILD_ROOT}/cuslide/install/lib*/cucim* ${BUILD_ROOT}/cucim/install/lib/ + cp -P ${BUILD_ROOT}/cumed/install/lib*/cucim* ${BUILD_ROOT}/cucim/install/lib/ # Copy .so files from pybind's build folder to cucim Python source folder # Since wheel file doesn't support symbolic link (https://github.com/pypa/wheel/issues/203), @@ -604,6 +645,7 @@ build_python_package_() { mkdir -p ${DEST_ROOT}/examples/cpp cp -P -r ${BUILD_ROOT}/libcucim/install ${DEST_ROOT}/ cp -P -r ${BUILD_ROOT}/cuslide/install/lib/*.so ${DEST_ROOT}/install/lib/ + cp -P -r ${BUILD_ROOT}/cumed/install/lib/*.so ${DEST_ROOT}/install/lib/ cp -r ${SRC_ROOT}/examples/cpp/tiff_image ${DEST_ROOT}/examples/cpp/ cp ${BUILD_ROOT}/libcucim/CMakeLists.txt.examples.release ${DEST_ROOT}/examples/cpp/CMakeLists.txt