[{"id":35928,"web_url":"https://patchwork.libcamera.org/comment/35928/","msgid":"<20250919164348.GA8038@pendragon.ideasonboard.com>","date":"2025-09-19T16:43:48","subject":"Re: [PATCH v18 01/12] config: Introduce global runtime configuration","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"(CC'ing Nicholas Roth)\n\nOn Fri, Sep 12, 2025 at 04:29:02PM +0200, Milan Zamazal wrote:\n> Currently, libcamera can be configured in runtime using several\n> environment variables.  With introducing more and more variables, this\n> mechanism reaches its limits.  It would be simpler and more flexible if\n> it was possible to configure libcamera in a single file.\n> \n> For example, there was a request to define pipeline precedence in\n> runtime.  We want to compile in multiple pipelines, in order to have\n> them accessible within single packages in distributions.  And then being\n> able to select among the pipelines manually as needed based on the\n> particular hardware or operating system environment.  Having the\n> configuration file then allows easy switching between hardware, GPU or\n> CPU IPAs.  The configuration file can also be used to enable or disable\n> experimental features and avoid the need to track local patches changing\n> configuration options hard-wired in the code when working on new\n> features.\n> \n> This patch introduces basic support for configuration files.\n> GlobalConfiguration class reads and stores the configuration.  Its\n> instance can be used by other libcamera objects to access the\n> configuration.  A GlobalConfiguration instance is supposed to be stored\n> in a well-defined place, e.g. a CameraManager instance.  It is possible\n> to have multiple GlobalConfiguration instances, which may or may not\n> make sense.\n> \n> libcamera configuration can be specified using a system-wide\n> configuration file or a user configuration file.  The user configuration\n> file takes precedence if present.  There is currently no way to merge\n> multiple configuration files, the one found is used as the only\n> configuration file.  If no configuration file is present, nothing\n> changes to the current libcamera behavior (except for some log\n> messages related to configuration file lookup).\n> \n> The configuration file is a YAML file.  We already have a mechanism for\n> handling YAML configuration files in libcamera and the given\n> infrastructure can be reused for the purpose.  However, the\n> configuration type is abstracted to make contingent future change of the\n> underlying class easier while retaining (most of) the original API.\n> \n> The configuration is versioned.  This has currently no particular\n> meaning but is likely to have its purpose in future, especially once\n> configuration validation is introduced.\n> \n> The configuration YAML file looks as follows:\n> \n>   ---\n>   version: 1\n>   configuration:\n>     WHATEVER CONFIGURATION NEEDED\n> \n> This patch introduces just the basic idea.  Actually using the\n> configuration in the corresponding places (everything what is currently\n> configurable via environment variables should be configurable in the\n> file configuration) and other enhancements are implemented in the\n> followup patches.\n> \n> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>  .../libcamera/internal/global_configuration.h |  34 ++++\n>  include/libcamera/internal/meson.build        |   1 +\n>  src/libcamera/global_configuration.cpp        | 148 ++++++++++++++++++\n>  src/libcamera/meson.build                     |   1 +\n>  4 files changed, 184 insertions(+)\n>  create mode 100644 include/libcamera/internal/global_configuration.h\n>  create mode 100644 src/libcamera/global_configuration.cpp\n> \n> diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h\n> new file mode 100644\n> index 000000000..f695498c4\n> --- /dev/null\n> +++ b/include/libcamera/internal/global_configuration.h\n> @@ -0,0 +1,34 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024-2025 Red Hat, inc.\n> + *\n> + * Global configuration handling\n> + */\n> +\n> +#pragma once\n> +\n> +#include <filesystem>\n\nWe removed all usage of std::filesystem in\n\ncommit 6a2f971035c2df711b10200f9c8c011d9a420e58\nAuthor: Nicholas Roth <nicholas@rothemail.net>\nDate:   Thu Oct 27 22:17:21 2022 -0500\n\n    android: remove references to std::filesystem\n\nbecause the Android 11 (and older) toolchain didn't support it. Android\n12 has been released 4 years ago, in October 2021. The virtual pipeline\nhandler has reintroduced usage of std::filesystem in November 2024 and\nnobody has screamed. I supposed it's fine. If someone complains, we can\naddress the issue on top.\n\n> +\n> +#include \"libcamera/internal/yaml_parser.h\"\n> +\n> +namespace libcamera {\n> +\n> +class GlobalConfiguration\n> +{\n> +public:\n> +\tusing Configuration = const YamlObject &;\n> +\n> +\tGlobalConfiguration();\n> +\n> +\tunsigned int version() const;\n> +\tConfiguration configuration() const;\n> +\n> +private:\n> +\tbool loadFile(const std::filesystem::path &fileName);\n> +\tvoid load();\n> +\n> +\tstd::unique_ptr<YamlObject> yamlConfiguration_ =\n> +\t\tstd::make_unique<YamlObject>();\n> +};\n> +\n> +} /* namespace libcamera */\n> diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\n> index 5c80a28c4..45c299f6a 100644\n> --- a/include/libcamera/internal/meson.build\n> +++ b/include/libcamera/internal/meson.build\n> @@ -23,6 +23,7 @@ libcamera_internal_headers = files([\n>      'dma_buf_allocator.h',\n>      'formats.h',\n>      'framebuffer.h',\n> +    'global_configuration.h',\n>      'ipa_data_serializer.h',\n>      'ipa_manager.h',\n>      'ipa_module.h',\n> diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\n> new file mode 100644\n> index 000000000..d02668111\n> --- /dev/null\n> +++ b/src/libcamera/global_configuration.cpp\n> @@ -0,0 +1,148 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2024-2025 Red Hat, inc.\n> + *\n> + * Global configuration handling\n> + */\n> +\n> +#include \"libcamera/internal/global_configuration.h\"\n> +\n> +#include <filesystem>\n> +#include <string_view>\n> +#include <sys/types.h>\n> +\n> +#include <libcamera/base/file.h>\n> +#include <libcamera/base/log.h>\n> +#include <libcamera/base/utils.h>\n> +\n> +#include \"libcamera/internal/yaml_parser.h\"\n> +\n> +namespace libcamera {\n> +\n> +namespace {\n> +const std::vector<std::filesystem::path> globalConfigurationFiles = {\n> +\tstd::filesystem::path(LIBCAMERA_SYSCONF_DIR) / \"configuration.yaml\",\n> +\tstd::filesystem::path(LIBCAMERA_DATA_DIR) / \"configuration.yaml\",\n> +};\n> +}\n> +\n> +LOG_DEFINE_CATEGORY(Configuration)\n> +\n> +/**\n> + * \\class GlobalConfiguration\n> + * \\brief Support for global libcamera configuration\n> + *\n> + * The configuration file is a YAML file and the configuration itself is stored\n> + * under `configuration' top-level item.\n> + *\n> + * The configuration file is looked up in user's home directory first and if it\n> + * is not found then in system-wide configuration directories. If multiple\n> + * configuration files exist then only the first one found is used and no\n> + * configuration merging is performed.\n> + *\n> + * If the first found configuration file cannot be opened or parsed, an error is\n> + * reported and no configuration file is used. This is to prevent libcamera from\n> + * using an unintended configuration file.\n> + */\n> +\n> +bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName)\n> +{\n> +\tFile file(fileName);\n> +\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> +\t\tif (file.error() == -ENOENT)\n> +\t\t\treturn false;\n> +\n> +\t\tLOG(Configuration, Error)\n> +\t\t\t<< \"Failed to open configuration file \" << fileName;\n> +\t\treturn true;\n> +\t}\n> +\n> +\tstd::unique_ptr<YamlObject> configuration = YamlParser::parse(file);\n> +\tif (!configuration) {\n> +\t\tLOG(Configuration, Error)\n> +\t\t\t<< \"Failed to parse configuration file \" << fileName;\n> +\t\treturn true;\n> +\t}\n> +\n> +\tyamlConfiguration_ = std::move(configuration);\n> +\treturn true;\n> +}\n> +\n> +void GlobalConfiguration::load()\n> +{\n> +\tstd::filesystem::path userConfigurationDirectory;\n> +\tconst char *xdgConfigHome = utils::secure_getenv(\"XDG_CONFIG_HOME\");\n> +\tif (xdgConfigHome) {\n> +\t\tuserConfigurationDirectory = xdgConfigHome;\n> +\t} else {\n> +\t\tconst char *home = utils::secure_getenv(\"HOME\");\n> +\t\tif (home)\n> +\t\t\tuserConfigurationDirectory =\n> +\t\t\t\tstd::filesystem::path(home) / \".config\";\n> +\t}\n> +\n> +\tif (!userConfigurationDirectory.empty()) {\n> +\t\tstd::filesystem::path user_configuration_file =\n> +\t\t\tuserConfigurationDirectory / \"libcamera\" / \"configuration.yaml\";\n> +\t\tif (loadFile(user_configuration_file))\n> +\t\t\treturn;\n> +\t}\n> +\n> +\tfor (const auto &path : globalConfigurationFiles) {\n> +\t\tif (loadFile(path))\n> +\t\t\treturn;\n> +\t}\n> +}\n> +\n> +/**\n> + * \\brief Initialize the global configuration\n> + */\n> +GlobalConfiguration::GlobalConfiguration()\n> +{\n> +\tload();\n> +}\n> +\n> +/**\n> + * \\typedef GlobalConfiguration::Configuration\n> + * \\brief Type representing global libcamera configuration\n> + *\n> + * All code outside GlobalConfiguration must use this type declaration and not\n> + * the underlying type.\n> + */\n> +\n> +/**\n> + * \\brief Return configuration version\n> + *\n> + * The version is (optionally) declared in the configuration file in the\n\nThe version is not optional, parsing returns an error if it's not\npresent. I'll drop \"(optionally)\".\n\n> + * top-level section `version', alongside `configuration'. This has currently no\n> + * real use but may be needed in future if configuration incompatibilities\n> + * occur.\n> + *\n> + * \\return Configuration version as declared in the configuration file or 0 if\n> + * no version is declared there\n\nAnd here I'll use\n\n * \\return Configuration version as declared in the configuration file or 0 if\n * no global configuration is available\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> + */\n> +unsigned int GlobalConfiguration::version() const\n> +{\n> +\treturn (*yamlConfiguration_)[\"version\"].get<unsigned int>().value_or(0);\n> +}\n> +\n> +/**\n> + * \\brief Return libcamera global configuration\n> + *\n> + * This returns the whole configuration stored in the top-level section\n> + * `configuration' of the YAML configuration file.\n> + *\n> + * The requested part of the configuration can be accessed using \\a YamlObject\n> + * methods.\n> + *\n> + * \\note \\a YamlObject type itself shouldn't be used in type declarations to\n> + * avoid trouble if we decide to change the underlying data objects in future.\n> + *\n> + * \\return The whole configuration section\n> + */\n> +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const\n> +{\n> +\treturn (*yamlConfiguration_)[\"configuration\"];\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index b3ca27f21..5b9b86f21 100644\n> --- a/src/libcamera/meson.build\n> +++ b/src/libcamera/meson.build\n> @@ -31,6 +31,7 @@ libcamera_internal_sources = files([\n>      'device_enumerator_sysfs.cpp',\n>      'dma_buf_allocator.cpp',\n>      'formats.cpp',\n> +    'global_configuration.cpp',\n>      'ipa_controls.cpp',\n>      'ipa_data_serializer.cpp',\n>      'ipa_interface.cpp',","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 0EAC3C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 19 Sep 2025 16:44:23 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9F7096B597;\n\tFri, 19 Sep 2025 18:44:21 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 84FA662C35\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 19 Sep 2025 18:44:19 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id AD5143A2;\n\tFri, 19 Sep 2025 18:42:58 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"SS6kJDXl\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758300178;\n\tbh=Quy8N+LdWYkOQeEMSIs2qepk3HhuL5Z17AM50pIyaOc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=SS6kJDXlo1dinzw642HSuJ1+ojpDvgNYgchOvOmmlLOT3OmJShWg60dSbgubnHsUS\n\tkg0zwwlm/6QD6OhPZEWSXKgJl0nsZBfUYVLwdSIB6zi7Qh6lmiReOOJfOcYItYFnIe\n\t1jYoQkpxiWUvZB0htzfLGtTfLcI1oagNEg4JBVGY=","Date":"Fri, 19 Sep 2025 19:43:48 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>,  Nicholas Roth <nicholas@rothemail.net>","Subject":"Re: [PATCH v18 01/12] config: Introduce global runtime configuration","Message-ID":"<20250919164348.GA8038@pendragon.ideasonboard.com>","References":"<20250912142915.53949-1-mzamazal@redhat.com>\n\t<20250912142915.53949-2-mzamazal@redhat.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20250912142915.53949-2-mzamazal@redhat.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35939,"web_url":"https://patchwork.libcamera.org/comment/35939/","msgid":"<20250921045532.GG30137@pendragon.ideasonboard.com>","date":"2025-09-21T04:55:32","subject":"Re: [PATCH v18 01/12] config: Introduce global runtime configuration","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Fri, Sep 19, 2025 at 07:43:48PM +0300, Laurent Pinchart wrote:\n> (CC'ing Nicholas Roth)\n> \n> On Fri, Sep 12, 2025 at 04:29:02PM +0200, Milan Zamazal wrote:\n> > Currently, libcamera can be configured in runtime using several\n> > environment variables.  With introducing more and more variables, this\n> > mechanism reaches its limits.  It would be simpler and more flexible if\n> > it was possible to configure libcamera in a single file.\n> > \n> > For example, there was a request to define pipeline precedence in\n> > runtime.  We want to compile in multiple pipelines, in order to have\n> > them accessible within single packages in distributions.  And then being\n> > able to select among the pipelines manually as needed based on the\n> > particular hardware or operating system environment.  Having the\n> > configuration file then allows easy switching between hardware, GPU or\n> > CPU IPAs.  The configuration file can also be used to enable or disable\n> > experimental features and avoid the need to track local patches changing\n> > configuration options hard-wired in the code when working on new\n> > features.\n> > \n> > This patch introduces basic support for configuration files.\n> > GlobalConfiguration class reads and stores the configuration.  Its\n> > instance can be used by other libcamera objects to access the\n> > configuration.  A GlobalConfiguration instance is supposed to be stored\n> > in a well-defined place, e.g. a CameraManager instance.  It is possible\n> > to have multiple GlobalConfiguration instances, which may or may not\n> > make sense.\n> > \n> > libcamera configuration can be specified using a system-wide\n> > configuration file or a user configuration file.  The user configuration\n> > file takes precedence if present.  There is currently no way to merge\n> > multiple configuration files, the one found is used as the only\n> > configuration file.  If no configuration file is present, nothing\n> > changes to the current libcamera behavior (except for some log\n> > messages related to configuration file lookup).\n> > \n> > The configuration file is a YAML file.  We already have a mechanism for\n> > handling YAML configuration files in libcamera and the given\n> > infrastructure can be reused for the purpose.  However, the\n> > configuration type is abstracted to make contingent future change of the\n> > underlying class easier while retaining (most of) the original API.\n> > \n> > The configuration is versioned.  This has currently no particular\n> > meaning but is likely to have its purpose in future, especially once\n> > configuration validation is introduced.\n> > \n> > The configuration YAML file looks as follows:\n> > \n> >   ---\n> >   version: 1\n> >   configuration:\n> >     WHATEVER CONFIGURATION NEEDED\n> > \n> > This patch introduces just the basic idea.  Actually using the\n> > configuration in the corresponding places (everything what is currently\n> > configurable via environment variables should be configurable in the\n> > file configuration) and other enhancements are implemented in the\n> > followup patches.\n> > \n> > Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n> > Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> > ---\n> >  .../libcamera/internal/global_configuration.h |  34 ++++\n> >  include/libcamera/internal/meson.build        |   1 +\n> >  src/libcamera/global_configuration.cpp        | 148 ++++++++++++++++++\n> >  src/libcamera/meson.build                     |   1 +\n> >  4 files changed, 184 insertions(+)\n> >  create mode 100644 include/libcamera/internal/global_configuration.h\n> >  create mode 100644 src/libcamera/global_configuration.cpp\n> > \n> > diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h\n> > new file mode 100644\n> > index 000000000..f695498c4\n> > --- /dev/null\n> > +++ b/include/libcamera/internal/global_configuration.h\n> > @@ -0,0 +1,34 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2024-2025 Red Hat, inc.\n> > + *\n> > + * Global configuration handling\n> > + */\n> > +\n> > +#pragma once\n> > +\n> > +#include <filesystem>\n> \n> We removed all usage of std::filesystem in\n> \n> commit 6a2f971035c2df711b10200f9c8c011d9a420e58\n> Author: Nicholas Roth <nicholas@rothemail.net>\n> Date:   Thu Oct 27 22:17:21 2022 -0500\n> \n>     android: remove references to std::filesystem\n> \n> because the Android 11 (and older) toolchain didn't support it. Android\n> 12 has been released 4 years ago, in October 2021. The virtual pipeline\n> handler has reintroduced usage of std::filesystem in November 2024 and\n> nobody has screamed. I supposed it's fine. If someone complains, we can\n> address the issue on top.\n> \n> > +\n> > +#include \"libcamera/internal/yaml_parser.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +class GlobalConfiguration\n> > +{\n> > +public:\n> > +\tusing Configuration = const YamlObject &;\n> > +\n> > +\tGlobalConfiguration();\n> > +\n> > +\tunsigned int version() const;\n> > +\tConfiguration configuration() const;\n> > +\n> > +private:\n> > +\tbool loadFile(const std::filesystem::path &fileName);\n> > +\tvoid load();\n> > +\n> > +\tstd::unique_ptr<YamlObject> yamlConfiguration_ =\n> > +\t\tstd::make_unique<YamlObject>();\n> > +};\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\n> > index 5c80a28c4..45c299f6a 100644\n> > --- a/include/libcamera/internal/meson.build\n> > +++ b/include/libcamera/internal/meson.build\n> > @@ -23,6 +23,7 @@ libcamera_internal_headers = files([\n> >      'dma_buf_allocator.h',\n> >      'formats.h',\n> >      'framebuffer.h',\n> > +    'global_configuration.h',\n> >      'ipa_data_serializer.h',\n> >      'ipa_manager.h',\n> >      'ipa_module.h',\n> > diff --git a/src/libcamera/global_configuration.cpp b/src/libcamera/global_configuration.cpp\n> > new file mode 100644\n> > index 000000000..d02668111\n> > --- /dev/null\n> > +++ b/src/libcamera/global_configuration.cpp\n> > @@ -0,0 +1,148 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2024-2025 Red Hat, inc.\n> > + *\n> > + * Global configuration handling\n> > + */\n> > +\n> > +#include \"libcamera/internal/global_configuration.h\"\n> > +\n> > +#include <filesystem>\n> > +#include <string_view>\n> > +#include <sys/types.h>\n> > +\n> > +#include <libcamera/base/file.h>\n> > +#include <libcamera/base/log.h>\n> > +#include <libcamera/base/utils.h>\n> > +\n> > +#include \"libcamera/internal/yaml_parser.h\"\n> > +\n> > +namespace libcamera {\n> > +\n> > +namespace {\n> > +const std::vector<std::filesystem::path> globalConfigurationFiles = {\n> > +\tstd::filesystem::path(LIBCAMERA_SYSCONF_DIR) / \"configuration.yaml\",\n> > +\tstd::filesystem::path(LIBCAMERA_DATA_DIR) / \"configuration.yaml\",\n> > +};\n> > +}\n> > +\n> > +LOG_DEFINE_CATEGORY(Configuration)\n> > +\n> > +/**\n> > + * \\class GlobalConfiguration\n> > + * \\brief Support for global libcamera configuration\n> > + *\n> > + * The configuration file is a YAML file and the configuration itself is stored\n> > + * under `configuration' top-level item.\n> > + *\n> > + * The configuration file is looked up in user's home directory first and if it\n\ns/user/the user/\n\n> > + * is not found then in system-wide configuration directories. If multiple\n> > + * configuration files exist then only the first one found is used and no\n> > + * configuration merging is performed.\n> > + *\n> > + * If the first found configuration file cannot be opened or parsed, an error is\n> > + * reported and no configuration file is used. This is to prevent libcamera from\n> > + * using an unintended configuration file.\n> > + */\n> > +\n> > +bool GlobalConfiguration::loadFile(const std::filesystem::path &fileName)\n> > +{\n> > +\tFile file(fileName);\n> > +\tif (!file.open(File::OpenModeFlag::ReadOnly)) {\n> > +\t\tif (file.error() == -ENOENT)\n> > +\t\t\treturn false;\n> > +\n> > +\t\tLOG(Configuration, Error)\n> > +\t\t\t<< \"Failed to open configuration file \" << fileName;\n> > +\t\treturn true;\n> > +\t}\n> > +\n> > +\tstd::unique_ptr<YamlObject> configuration = YamlParser::parse(file);\n> > +\tif (!configuration) {\n> > +\t\tLOG(Configuration, Error)\n> > +\t\t\t<< \"Failed to parse configuration file \" << fileName;\n> > +\t\treturn true;\n> > +\t}\n> > +\n> > +\tyamlConfiguration_ = std::move(configuration);\n> > +\treturn true;\n> > +}\n> > +\n> > +void GlobalConfiguration::load()\n> > +{\n> > +\tstd::filesystem::path userConfigurationDirectory;\n> > +\tconst char *xdgConfigHome = utils::secure_getenv(\"XDG_CONFIG_HOME\");\n> > +\tif (xdgConfigHome) {\n> > +\t\tuserConfigurationDirectory = xdgConfigHome;\n> > +\t} else {\n> > +\t\tconst char *home = utils::secure_getenv(\"HOME\");\n> > +\t\tif (home)\n> > +\t\t\tuserConfigurationDirectory =\n> > +\t\t\t\tstd::filesystem::path(home) / \".config\";\n> > +\t}\n> > +\n> > +\tif (!userConfigurationDirectory.empty()) {\n> > +\t\tstd::filesystem::path user_configuration_file =\n> > +\t\t\tuserConfigurationDirectory / \"libcamera\" / \"configuration.yaml\";\n> > +\t\tif (loadFile(user_configuration_file))\n> > +\t\t\treturn;\n> > +\t}\n> > +\n> > +\tfor (const auto &path : globalConfigurationFiles) {\n> > +\t\tif (loadFile(path))\n> > +\t\t\treturn;\n> > +\t}\n> > +}\n> > +\n> > +/**\n> > + * \\brief Initialize the global configuration\n> > + */\n> > +GlobalConfiguration::GlobalConfiguration()\n> > +{\n> > +\tload();\n> > +}\n> > +\n> > +/**\n> > + * \\typedef GlobalConfiguration::Configuration\n> > + * \\brief Type representing global libcamera configuration\n> > + *\n> > + * All code outside GlobalConfiguration must use this type declaration and not\n> > + * the underlying type.\n> > + */\n> > +\n> > +/**\n> > + * \\brief Return configuration version\n> > + *\n> > + * The version is (optionally) declared in the configuration file in the\n> \n> The version is not optional, parsing returns an error if it's not\n> present. I'll drop \"(optionally)\".\n> \n> > + * top-level section `version', alongside `configuration'. This has currently no\n> > + * real use but may be needed in future if configuration incompatibilities\n> > + * occur.\n> > + *\n> > + * \\return Configuration version as declared in the configuration file or 0 if\n> > + * no version is declared there\n> \n> And here I'll use\n> \n>  * \\return Configuration version as declared in the configuration file or 0 if\n>  * no global configuration is available\n> \n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> \n> > + */\n> > +unsigned int GlobalConfiguration::version() const\n> > +{\n> > +\treturn (*yamlConfiguration_)[\"version\"].get<unsigned int>().value_or(0);\n> > +}\n> > +\n> > +/**\n> > + * \\brief Return libcamera global configuration\n> > + *\n> > + * This returns the whole configuration stored in the top-level section\n> > + * `configuration' of the YAML configuration file.\n> > + *\n> > + * The requested part of the configuration can be accessed using \\a YamlObject\n> > + * methods.\n> > + *\n> > + * \\note \\a YamlObject type itself shouldn't be used in type declarations to\n> > + * avoid trouble if we decide to change the underlying data objects in future.\n> > + *\n> > + * \\return The whole configuration section\n> > + */\n> > +GlobalConfiguration::Configuration GlobalConfiguration::configuration() const\n> > +{\n> > +\treturn (*yamlConfiguration_)[\"configuration\"];\n> > +}\n> > +\n> > +} /* namespace libcamera */\n> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > index b3ca27f21..5b9b86f21 100644\n> > --- a/src/libcamera/meson.build\n> > +++ b/src/libcamera/meson.build\n> > @@ -31,6 +31,7 @@ libcamera_internal_sources = files([\n> >      'device_enumerator_sysfs.cpp',\n> >      'dma_buf_allocator.cpp',\n> >      'formats.cpp',\n> > +    'global_configuration.cpp',\n> >      'ipa_controls.cpp',\n> >      'ipa_data_serializer.cpp',\n> >      'ipa_interface.cpp',","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A763AC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 21 Sep 2025 04:56:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4B5866B59C;\n\tSun, 21 Sep 2025 06:56:05 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C778662C35\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 21 Sep 2025 06:56:03 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 2492B1838; \n\tSun, 21 Sep 2025 06:54:42 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"AZqBAScr\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758430482;\n\tbh=CPBBzIIr8+g41ew/oWvwe1C8/9Omo0EyDqxoz8bnScw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=AZqBAScrJykM+perh4CEqVD5h/7xNO1bNynfza9LuxtuvbzkJPGFOe00+qn0O7wMB\n\t7KI736Jl8QsasQm4pR8JxyMWJ0eC8mNs9cb/2xM2gLNxNU2dS0mkFIlWMPoAg0v9TH\n\ts/dZGGOiBIzeWm0ybc7K/Kg753muQY1++2nkhfCE=","Date":"Sun, 21 Sep 2025 07:55:32 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>,  Nicholas Roth <nicholas@rothemail.net>","Subject":"Re: [PATCH v18 01/12] config: Introduce global runtime configuration","Message-ID":"<20250921045532.GG30137@pendragon.ideasonboard.com>","References":"<20250912142915.53949-1-mzamazal@redhat.com>\n\t<20250912142915.53949-2-mzamazal@redhat.com>\n\t<20250919164348.GA8038@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20250919164348.GA8038@pendragon.ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]