From patchwork Wed Jan 28 07:49:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 25985 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 84C36C3200 for ; Wed, 28 Jan 2026 07:50:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 47F3C61FCF; Wed, 28 Jan 2026 08:50:14 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MsF6DmAv"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4D27E61A35 for ; Wed, 28 Jan 2026 08:50:10 +0100 (CET) Received: from neptunite.hamster-moth.ts.net (unknown [IPv6:2404:7a81:160:2100:508d:7983:72a6:2eeb]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 90E9AC6F; Wed, 28 Jan 2026 08:49:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1769586573; bh=NI7nfFoKNZxIJ5lFsGWDEIdGS/KLsyCvoZ7z6PZ35wU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MsF6DmAvcYievEn7E6//BkwsHtBS57XQph93f1bzUnUjlA0ItVNUqrpPSBSrvTtwO QDJf56A1iDmFmxMUDJK2JjysSQCADyClmsr1THUkNsz9pMxZYmkjhReKN3CBaGl3Bm z+mvXmNlZF6rAD4lAAPEymjQoObt3oMq0a9CzdhY= From: Paul Elder To: libcamera-devel@lists.libcamera.org Cc: Paul Elder Subject: [PATCH v5 1/8] libcamera: ipa_manager: Factor out .so file searching Date: Wed, 28 Jan 2026 16:49:49 +0900 Message-ID: <20260128074956.760538-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20260128074956.760538-1-paul.elder@ideasonboard.com> References: <20260128074956.760538-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In the near future we will add support for layers/shoes on top of libcamera, which will need to search for shared object files similar to how IPAManager does. To avoid code duplication, move this code out of IPAManager into internal utils. Signed-off-by: Paul Elder --- No change in v4 Changes in v3: - rename addDir to findSharedObjects - make parseDir static No change in v2 --- include/libcamera/internal/ipa_manager.h | 4 - include/libcamera/internal/meson.build | 1 + include/libcamera/internal/utils.h | 23 +++++ src/libcamera/ipa_manager.cpp | 107 ++++------------------- src/libcamera/meson.build | 1 + src/libcamera/utils.cpp | 107 +++++++++++++++++++++++ 6 files changed, 151 insertions(+), 92 deletions(-) create mode 100644 include/libcamera/internal/utils.h create mode 100644 src/libcamera/utils.cpp diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index f8ce780169e6..dcfcf8d69da5 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -68,10 +68,6 @@ public: #endif private: - void parseDir(const char *libDir, unsigned int maxDepth, - std::vector &files); - unsigned int addDir(const char *libDir, unsigned int maxDepth = 0); - IPAModule *module(PipelineHandler *pipe, uint32_t minVersion, uint32_t maxVersion); diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 4d2a09bd7041..ed145a6dd7cd 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -43,6 +43,7 @@ libcamera_internal_headers = files([ 'shared_mem_object.h', 'source_paths.h', 'sysfs.h', + 'utils.h', 'v4l2_device.h', 'v4l2_pixelformat.h', 'v4l2_request.h', diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h new file mode 100644 index 000000000000..5b7957b5d77e --- /dev/null +++ b/include/libcamera/internal/utils.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * Miscellaneous utility functions + */ + +#pragma once + +#include +#include +#include + +namespace libcamera { + +namespace utils { + +unsigned int findSharedObjects(const char *libDir, unsigned int maxDepth, + std::function func); + +} /* namespace utils */ + +} /* namespace libcamera */ diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index 35171d097136..244a8ee67f05 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -8,7 +8,7 @@ #include "libcamera/internal/ipa_manager.h" #include -#include +#include #include #include #include @@ -22,6 +22,7 @@ #include "libcamera/internal/ipa_module.h" #include "libcamera/internal/ipa_proxy.h" #include "libcamera/internal/pipeline_handler.h" +#include "libcamera/internal/utils.h" /** * \file ipa_manager.h @@ -118,6 +119,20 @@ IPAManager::IPAManager(const GlobalConfiguration &configuration) unsigned int ipaCount = 0; + auto &modules = modules_; + std::function soHandler = + [&modules](const std::string &file) { + auto ipaModule = std::make_unique(file); + if (!ipaModule->isValid()) + return 0; + + LOG(IPAManager, Debug) << "Loaded IPA module '" << file << "'"; + + modules.push_back(std::move(ipaModule)); + + return 1; + }; + /* User-specified paths take precedence. */ const auto modulePaths = configuration.envListOption( @@ -127,7 +142,7 @@ IPAManager::IPAManager(const GlobalConfiguration &configuration) if (dir.empty()) continue; - ipaCount += addDir(dir.c_str()); + ipaCount += utils::findSharedObjects(dir.c_str(), 0, soHandler); } if (!modulePaths.empty() && !ipaCount) @@ -148,11 +163,11 @@ IPAManager::IPAManager(const GlobalConfiguration &configuration) << "libcamera is not installed. Adding '" << ipaBuildPath << "' to the IPA search path"; - ipaCount += addDir(ipaBuildPath.c_str(), maxDepth); + ipaCount += utils::findSharedObjects(ipaBuildPath.c_str(), maxDepth, soHandler); } /* Finally try to load IPAs from the installed system path. */ - ipaCount += addDir(IPA_MODULE_DIR); + ipaCount += utils::findSharedObjects(IPA_MODULE_DIR, 0, soHandler); if (!ipaCount) LOG(IPAManager, Warning) @@ -161,90 +176,6 @@ IPAManager::IPAManager(const GlobalConfiguration &configuration) IPAManager::~IPAManager() = default; -/** - * \brief Identify shared library objects within a directory - * \param[in] libDir The directory to search for shared objects - * \param[in] maxDepth The maximum depth of sub-directories to parse - * \param[out] files A vector of paths to shared object library files - * - * Search a directory for .so files, allowing recursion down to sub-directories - * no further than the depth specified by \a maxDepth. - * - * Discovered shared objects are added to the \a files vector. - */ -void IPAManager::parseDir(const char *libDir, unsigned int maxDepth, - std::vector &files) -{ - struct dirent *ent; - DIR *dir; - - dir = opendir(libDir); - if (!dir) - return; - - while ((ent = readdir(dir)) != nullptr) { - if (ent->d_type == DT_DIR && maxDepth) { - if (strcmp(ent->d_name, ".") == 0 || - strcmp(ent->d_name, "..") == 0) - continue; - - std::string subdir = std::string(libDir) + "/" + ent->d_name; - - /* Recursion is limited to maxDepth. */ - parseDir(subdir.c_str(), maxDepth - 1, files); - - continue; - } - - int offset = strlen(ent->d_name) - 3; - if (offset < 0) - continue; - if (strcmp(&ent->d_name[offset], ".so")) - continue; - - files.push_back(std::string(libDir) + "/" + ent->d_name); - } - - closedir(dir); -} - -/** - * \brief Load IPA modules from a directory - * \param[in] libDir The directory to search for IPA modules - * \param[in] maxDepth The maximum depth of sub-directories to search - * - * This function tries to create an IPAModule instance for every shared object - * found in \a libDir, and skips invalid IPA modules. - * - * Sub-directories are searched up to a depth of \a maxDepth. A \a maxDepth - * value of 0 only searches the directory specified in \a libDir. - * - * \return Number of modules loaded by this call - */ -unsigned int IPAManager::addDir(const char *libDir, unsigned int maxDepth) -{ - std::vector files; - - parseDir(libDir, maxDepth, files); - - /* Ensure a stable ordering of modules. */ - std::sort(files.begin(), files.end()); - - unsigned int count = 0; - for (const std::string &file : files) { - auto ipaModule = std::make_unique(file); - if (!ipaModule->isValid()) - continue; - - LOG(IPAManager, Debug) << "Loaded IPA module '" << file << "'"; - - modules_.push_back(std::move(ipaModule)); - count++; - } - - return count; -} - /** * \brief Retrieve an IPA module that matches a given pipeline handler * \param[in] pipe The pipeline handler diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index d15943586300..186d5c48ccd5 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -52,6 +52,7 @@ libcamera_internal_sources = files([ 'shared_mem_object.cpp', 'source_paths.cpp', 'sysfs.cpp', + 'utils.cpp', 'v4l2_device.cpp', 'v4l2_pixelformat.cpp', 'v4l2_request.cpp', diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp new file mode 100644 index 000000000000..2ce62f236cea --- /dev/null +++ b/src/libcamera/utils.cpp @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * Miscellaneous utility functions (internal) + */ + +#include "libcamera/internal/utils.h" + +#include +#include +#include +#include +#include +#include +#include + +/** + * \file internal/utils.h + * \brief Miscellaneous utility functions (internal) + */ + +namespace libcamera { + +namespace utils { + +/** + * \brief Identify shared library objects within a directory + * \param[in] libDir The directory to search for shared objects + * \param[in] maxDepth The maximum depth of sub-directories to parse + * \param[out] files A vector of paths to shared object library files + * + * Search a directory for .so files, allowing recursion down to sub-directories + * no further than the depth specified by \a maxDepth. + * + * Discovered shared objects are added to the \a files vector. + */ +static void parseDir(const char *libDir, unsigned int maxDepth, + std::vector &files) +{ + struct dirent *ent; + DIR *dir; + + dir = opendir(libDir); + if (!dir) + return; + + while ((ent = readdir(dir)) != nullptr) { + if (ent->d_type == DT_DIR && maxDepth) { + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + continue; + + std::string subdir = std::string(libDir) + "/" + ent->d_name; + + /* Recursion is limited to maxDepth. */ + parseDir(subdir.c_str(), maxDepth - 1, files); + + continue; + } + + int offset = strlen(ent->d_name) - 3; + if (offset < 0) + continue; + if (strcmp(&ent->d_name[offset], ".so")) + continue; + + files.push_back(std::string(libDir) + "/" + ent->d_name); + } + + closedir(dir); +} + +/** + * \brief Execute some function on shared object files from a directory + * \param[in] libDir The directory to search for shared objects + * \param[in] maxDepth The maximum depth of sub-directories to search + * \param[in] func The function to execute on every shared object + * + * This function tries to execute the given function \a func for every shared + * object found in \a libDir. + * + * Sub-directories are searched up to a depth of \a maxDepth. A \a maxDepth + * value of 0 only searches the directory specified in \a libDir. + * + * \return Number of shared objects loaded by this call + */ +unsigned int findSharedObjects(const char *libDir, unsigned int maxDepth, + std::function func) +{ + std::vector files; + + parseDir(libDir, maxDepth, files); + + /* Ensure a stable ordering of modules. */ + std::sort(files.begin(), files.end()); + + unsigned int count = 0; + for (const std::string &file : files) + count += func(file); + + return count; +} + +} /* namespace utils */ + +} /* namespace libcamera */