FindPlugins.h#
Fully qualified name: carb/FindPlugins.h
File members: carb/FindPlugins.h
// SPDX-FileCopyrightText: Copyright (c) 2020-2025 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 "extras/Library.h"
#include "extras/StringUtils.h"
#include "filesystem/IFileSystem.h"
#include "filesystem/FindFiles.h"
#include "logging/Log.h"
#include "../omni/str/Wildcard.h"
#include <cstring>
namespace carb
{
using FindPluginsOnMatchedFn = void(const char* canonical, bool reloadable, void* context);
struct FindPluginsArgs
{
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;
FindPluginsOnMatchedFn* onMatched;
void* onMatchedContext;
filesystem::FindFilesOnExcludedFn* onExcluded;
void* onExcludedContext;
filesystem::FindFilesOnSkippedFn* onSkipped;
void* onSkippedContext;
filesystem::FindFilesOnSearchPathFn* onSearchPath;
void* onSearchPathContext;
filesystem::IFileSystem* fs;
};
inline bool findPlugins(const FindPluginsArgs& inArgs) noexcept
{
filesystem::FindFilesArgs args{};
args.searchPaths = inArgs.searchPaths;
args.searchPathsCount = uint32_t(inArgs.searchPathCount);
PluginLoadingDesc defaultPluginDesc = PluginLoadingDesc::getDefault();
if (!args.searchPaths || (0 == args.searchPathsCount))
{
// If search path count it not specified, fall back to the default desc search paths
args.searchPaths = defaultPluginDesc.searchPaths;
args.searchPathsCount = uint32_t(defaultPluginDesc.searchPathCount);
}
args.matchWildcards = inArgs.loadedFileWildcards;
args.matchWildcardsCount = uint32_t(inArgs.loadedFileWildcardCount);
args.excludeWildcards = inArgs.excludedFileWildcards;
args.excludeWildcardsCount = uint32_t(inArgs.excludedFileWildcardCount);
#if CARB_PLATFORM_LINUX
constexpr const char* const kIgnorePrefixes[] = { "lib" };
constexpr uint32_t kIgnorePrefixesCount = 1;
#elif CARB_PLATFORM_WINDOWS
constexpr const char* const* kIgnorePrefixes = nullptr;
constexpr uint32_t kIgnorePrefixesCount = 0;
#else
CARB_UNSUPPORTED_PLATFORM();
#endif
args.ignorePrefixes = kIgnorePrefixes;
args.ignorePrefixesCount = kIgnorePrefixesCount;
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 = [](const char* path, void*) {
if (carb::extras::caseInsensitiveEndsWith(carb::cpp::unsafe_length, path, CARB_LIBRARY_EXTENSION))
{
return filesystem::WalkAction::eContinue; // could be a plugin (i.e. correct .ext)
}
else
{
return filesystem::WalkAction::eSkip; // not a plug .ext. skip
}
};
args.onMatched = [](const char* canonical, void* context) {
auto inArgs = static_cast<FindPluginsArgs*>(context);
bool reloadable = false;
if (inArgs->reloadableFileWildcards && inArgs->reloadableFileWildcardCount)
{
extras::Path path(canonical);
auto stemBuffer = path.getStem();
carb::cpp::zstring_view stem = stemBuffer.getZStringView();
reloadable = omni::str::matchWildcards(
stem.c_str(), inArgs->reloadableFileWildcards, uint32_t(inArgs->reloadableFileWildcardCount));
#if CARB_PLATFORM_LINUX
if (!reloadable)
{
if (extras::startsWith(stem, "lib"))
{
stem.remove_prefix(3);
reloadable = omni::str::matchWildcards(
stem.c_str(), inArgs->reloadableFileWildcards, uint32_t(inArgs->reloadableFileWildcardCount));
}
}
#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 = [](const char* canonical, void*) {
CARB_LOG_VERBOSE("Excluding potential plugin file: %s.", canonical);
};
}
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 = [](const char* path, void* context) {
auto inArgs = static_cast<FindPluginsArgs*>(context);
CARB_LOG_VERBOSE("Searching plugins %sin folder: %s", (inArgs->searchRecursive ? "recursively " : ""), path);
};
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