FindPlugins.h#
Fully qualified name: carb/FindPlugins.h
File members: carb/FindPlugins.h
// SPDX-FileCopyrightText: Copyright (c) 2020-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.
#pragma once
#include "Framework.h"
#include "cpp/ZStringView.h"
#include "cpp/Span.h"
#include "extras/Library.h"
#include "extras/StringUtils.h"
#include "filesystem/FileSystemUtils.h"
#include "filesystem/FindFiles.h"
#include "logging/Log.h"
#include "../omni/str/Wildcard.h"
#include <cstring>
namespace carb
{
#if CARB_VERSION_ATLEAST(carb_filesystem_IFileSystem, 2, 0)
using FindPluginsOnMatchedFn = void(cpp::zstring_view canonical, bool reloadable, void* context);
#else
using FindPluginsOnMatchedFn = void(const char* canonical, bool reloadable, void* context);
#endif
struct FindPluginsArgs
{
#if CARB_VERSION_ATLEAST(carb_filesystem_IFileSystem, 2, 0)
cpp::span<const cpp::string_view> searchPaths;
bool searchRecursive;
cpp::span<const cpp::string_view> loadedFileWildcards;
cpp::span<const cpp::string_view> reloadableFileWildcards;
cpp::span<const cpp::string_view> excludedFileWildcards;
#else
const char* const* searchPaths;
size_t searchPathCount;
bool searchRecursive;
const char* const* loadedFileWildcards;
size_t loadedFileWildcardCount;
const char* const* reloadableFileWildcards;
size_t reloadableFileWildcardCount;
const char* const* excludedFileWildcards;
size_t excludedFileWildcardCount;
#endif
FindPluginsOnMatchedFn* onMatched;
void* onMatchedContext;
filesystem::FindFilesOnExcludedFn* onExcluded;
void* onExcludedContext;
filesystem::FindFilesOnSkippedFn* onSkipped;
void* onSkippedContext;
filesystem::FindFilesOnSearchPathFn* onSearchPath;
void* onSearchPathContext;
filesystem::IFileSystem* fs;
};
namespace detail
{
#if CARB_VERSION_ATLEAST(carb_filesystem_IFileSystem, 2, 0)
using StrType = cpp::zstring_view;
using SVType = cpp::string_view;
# define CARBLOCAL_ASSIGN_SPAN(first, second, afirst, asecond) (first) = (afirst)
# define CARBLOCAL_SPAN_SIZE(first, second) ((first).size())
inline filesystem::WalkAction filterNonCanonical(cpp::zstring_view path, void*)
{
return extras::caseInsensitiveEndsWith(path, CARB_LIBRARY_EXTENSION) ? filesystem::WalkAction::eContinue :
filesystem::WalkAction::eSkip;
}
inline void excludeLog(cpp::zstring_view path, void*)
{
CARB_LOG_VERBOSE(CARB_LOG_DEFAULT_CHANNEL, "Excluding potential plugin file: %s", path.c_str());
}
inline void logSearchPaths(cpp::zstring_view path, void* context)
{
auto args = static_cast<FindPluginsArgs*>(context);
CARB_LOG_VERBOSE(CARB_LOG_DEFAULT_CHANNEL, "Searching plugins %sin folder: %s",
args->searchRecursive ? "recursively " : "", path.c_str());
}
#else
using StrType = const char*;
using SVType = cpp::zstring_view;
# define CARBLOCAL_ASSIGN_SPAN(first, second, afirst, asecond) (first) = (afirst), (second) = uint32_t(asecond)
# define CARBLOCAL_SPAN_SIZE(first, second) (second)
inline filesystem::WalkAction filterNonCanonical(const char* path, void*)
{
return extras::caseInsensitiveEndsWith(cpp::unsafe_length, path, CARB_LIBRARY_EXTENSION) ?
filesystem::WalkAction::eContinue :
filesystem::WalkAction::eSkip;
}
inline void excludeLog(const char* path, void*)
{
CARB_LOG_VERBOSE("Excluding potential plugin file: %s", path);
}
inline void logSearchPaths(const char* path, void* context)
{
auto args = static_cast<FindPluginsArgs*>(context);
CARB_LOG_VERBOSE("Searching plugins %sin folder: %s", args->searchRecursive ? "recursively " : "", path);
}
#endif
} // namespace detail
inline bool findPlugins(const FindPluginsArgs& inArgs) noexcept
{
filesystem::FindFilesArgs args{};
CARBLOCAL_ASSIGN_SPAN(args.searchPaths, args.searchPathsCount, inArgs.searchPaths, inArgs.searchPathCount);
PluginLoadingDesc defaultPluginDesc = PluginLoadingDesc::getDefault();
if (CARBLOCAL_SPAN_SIZE(args.searchPaths, args.searchPathsCount) == 0)
{
// If search path count it not specified, fall back to the default desc search paths
#if CARB_VERSION_ATLEAST(carb_filesystem_IFileSystem, 2, 0)
auto stack = CARB_STACK_ALLOC(cpp::string_view, defaultPluginDesc.searchPathCount);
for (size_t i = 0; i != defaultPluginDesc.searchPathCount; ++i)
stack[i] = cpp::string_view(cpp::unsafe_length, defaultPluginDesc.searchPaths[i]);
args.searchPaths = { stack, defaultPluginDesc.searchPathCount };
#else
args.searchPaths = defaultPluginDesc.searchPaths;
args.searchPathsCount = uint32_t(defaultPluginDesc.searchPathCount);
#endif
}
CARBLOCAL_ASSIGN_SPAN(
args.matchWildcards, args.matchWildcardsCount, inArgs.loadedFileWildcards, inArgs.loadedFileWildcardCount);
CARBLOCAL_ASSIGN_SPAN(args.excludeWildcards, args.excludeWildcardsCount, inArgs.excludedFileWildcards,
inArgs.excludedFileWildcardCount);
#if CARB_PLATFORM_LINUX
constexpr static std::array<detail::SVType, 1> kIgnorePrefixes = { detail::SVType("lib") };
#elif CARB_PLATFORM_WINDOWS
constexpr static std::array<detail::SVType, 0> kIgnorePrefixes;
#else
CARB_UNSUPPORTED_PLATFORM();
#endif
#if CARB_VERSION_ATLEAST(carb_filesystem_IFileSystem, 2, 0)
args.ignorePrefixes = kIgnorePrefixes;
#else
{
auto stack = CARB_STACK_ALLOC(const char*, kIgnorePrefixes.size());
for (size_t i = 0; i != kIgnorePrefixes.size(); ++i)
stack[i] = kIgnorePrefixes[i].c_str();
args.ignorePrefixes = stack;
args.ignorePrefixesCount = uint32_t(kIgnorePrefixes.size());
}
#endif
args.fs = inArgs.fs;
// to avoid the expensive filename canonicalization and pattern matching, we do a quick check to make sure the
// extension is for a plugin
args.onFilterNonCanonical = detail::filterNonCanonical;
args.onMatched = [](detail::StrType canonical, void* context) {
auto inArgs = static_cast<FindPluginsArgs*>(context);
bool reloadable = false;
if (CARBLOCAL_SPAN_SIZE(inArgs->reloadableFileWildcards, inArgs->reloadableFileWildcardCount) != 0)
{
extras::Path path(canonical);
auto stemBuffer = path.getStem();
carb::cpp::zstring_view stem = stemBuffer.getZStringView();
#if CARB_VERSION_ATLEAST(carb_filesystem_IFileSystem, 2, 0)
auto reloadableFileWildcards = inArgs->reloadableFileWildcards;
#else
auto stack = CARB_STACK_ALLOC(cpp::string_view, inArgs->reloadableFileWildcardCount);
for (size_t i = 0; i != inArgs->reloadableFileWildcardCount; ++i)
stack[i] = cpp::string_view(cpp::unsafe_length, inArgs->reloadableFileWildcards[i]);
auto reloadableFileWildcards = cpp::span<cpp::string_view>{ stack, inArgs->reloadableFileWildcardCount };
#endif
reloadable = omni::str::matchWildcards(stem, reloadableFileWildcards).has_value();
#if CARB_PLATFORM_LINUX
if (!reloadable)
{
if (extras::startsWith(stem, "lib"))
{
stem.remove_prefix(3);
reloadable = omni::str::matchWildcards(stem, reloadableFileWildcards).has_value();
}
}
#endif
}
inArgs->onMatched(canonical, reloadable, inArgs->onMatchedContext);
};
args.onMatchedContext = const_cast<FindPluginsArgs*>(&inArgs);
args.onExcluded = inArgs.onExcluded;
args.onExcludedContext = inArgs.onExcludedContext;
if (!args.onExcluded && g_carbLogLevel <= carb::logging::kLevelVerbose)
{
args.onExcluded = detail::excludeLog;
}
args.onSkipped = inArgs.onSkipped;
args.onSkippedContext = inArgs.onSkippedContext;
args.onSearchPath = inArgs.onSearchPath;
args.onSearchPathContext = inArgs.onSearchPathContext;
if (!args.onSearchPath && g_carbLogLevel <= carb::logging::kLevelVerbose)
{
args.onSearchPath = detail::logSearchPaths;
args.onSearchPathContext = const_cast<FindPluginsArgs*>(&inArgs);
}
args.flags = (filesystem::kFindFilesFlagMatchStem | filesystem::kFindFilesFlagReplaceEnvironmentVariables);
if (inArgs.searchRecursive)
{
args.flags |= filesystem::kFindFilesFlagRecursive;
}
return filesystem::findFiles(args);
}
} // namespace carb
#undef CARBLOCAL_ASSIGN_SPAN
#undef CARBLOCAL_SPAN_SIZE