From patchwork Mon Jul 28 11:55:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 23998 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 5C72CC3323 for ; Mon, 28 Jul 2025 11:56:12 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7410C69164; Mon, 28 Jul 2025 13:56:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vT2Yu+Ga"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 642F069156 for ; Mon, 28 Jul 2025 13:56:08 +0200 (CEST) Received: from neptunite.hamster-moth.ts.net (unknown [IPv6:2404:7a81:160:2100:5715:34ad:7742:5049]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 29B844A4; Mon, 28 Jul 2025 13:55:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1753703726; bh=35DOxD6u7Y5Ga1b7B3r3AlBZNSJtjpQLnX7zEF8xWOg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vT2Yu+Gaky7Yp7ha3IQl+1FWwsl1EPyZjXHKsavXn0Ct2wzcrxYCkX80fDRQmBguU Np2p3MVlfk/LF4jJdykb0lJaEczCEeyyGFWCBNyYOR+ltU3mz1ECEEA4V6/jds1I8/ E2dW9tmRfef1BpjzLHcZsFXazE87v/uTmzq6yjK4= From: Paul Elder To: libcamera-devel@lists.libcamera.org Cc: Paul Elder , kieran.bingham@ideasonboard.com, barnabas.pocze@ideasonboard.com Subject: [PATCH v3 1/8] libcamera: ipa_manager: Factor out .so file searching Date: Mon, 28 Jul 2025 20:55:48 +0900 Message-ID: <20250728115556.2886082-2-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250728115556.2886082-1-paul.elder@ideasonboard.com> References: <20250728115556.2886082-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 --- 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 | 108 ++++------------------- src/libcamera/meson.build | 1 + src/libcamera/utils.cpp | 107 ++++++++++++++++++++++ 6 files changed, 151 insertions(+), 93 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 a0d448cf9862..6b0ba4b5477f 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -59,10 +59,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 5c80a28c4cbe..690f5c5ec9f6 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -41,6 +41,7 @@ libcamera_internal_headers = files([ 'shared_mem_object.h', 'source_paths.h', 'sysfs.h', + 'utils.h', 'v4l2_device.h', 'v4l2_pixelformat.h', 'v4l2_subdevice.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 830750dcc0fb..1d4de71722df 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -8,9 +8,8 @@ #include "libcamera/internal/ipa_manager.h" #include -#include +#include #include -#include #include #include @@ -19,6 +18,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 @@ -110,6 +110,20 @@ IPAManager::IPAManager() 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 char *modulePaths = utils::secure_getenv("LIBCAMERA_IPA_MODULE_PATH"); if (modulePaths) { @@ -117,7 +131,7 @@ IPAManager::IPAManager() if (dir.empty()) continue; - ipaCount += addDir(dir.c_str()); + ipaCount += utils::findSharedObjects(dir.c_str(), 0, soHandler); } if (!ipaCount) @@ -138,11 +152,11 @@ IPAManager::IPAManager() << "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) @@ -151,90 +165,6 @@ IPAManager::IPAManager() 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 de1eb99b28fd..6a71b2903d27 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -51,6 +51,7 @@ libcamera_internal_sources = files([ 'shared_mem_object.cpp', 'source_paths.cpp', 'sysfs.cpp', + 'utils.cpp', 'v4l2_device.cpp', 'v4l2_pixelformat.cpp', 'v4l2_subdevice.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 */