diff options
| author | Julian Andres Klode <julian.klode@canonical.com> | 2025-01-07 17:39:32 +0100 |
|---|---|---|
| committer | Julian Andres Klode <jak@debian.org> | 2025-10-25 18:42:14 +0000 |
| commit | 9d62eef571ffd1fd2df8b97884d3689fced27fb1 (patch) | |
| tree | 100d5321f364b389100928e927639e852c52ff48 /apt-pkg/aptconfiguration.cc | |
| parent | 50d8703c785898d06463513896e37cbe7cedd471 (diff) | |
Implement architecture variants
Architecture variants are children of an architecture that share
the same ABI but are optimized for different ISA levels. They
are available in Ubuntu 25.10 and newer, and not supported in
Debian or other distributions.
A deb built for a variant contains the Architecture-Variant field,
and the Architecture field points to the baseline, for example:
Architecture: amd64
Architecture-Variant: amd64v3
However, the apt-get indextargets command reports the variant in the
Architecture: field, and most of the code in APT presents the variant
as the architecture.
There are two types of variants:
1. Standalone variants are recorded in the Architectures field of the
Release file as if they were a real architecture:
Architectures: amd64 amd64v3
Standalone architecture variants only fetch the standalone
architecture variant's Packages file. To do this, this patch
changes the code such that the variants indextargets "supplant"
the base targets.
This may have complicated outcomes on the apt-get indextargets
command.
2. Other variants can only be identified by their files being recorded
with hashes in the Release file.
APT fetches both the base architecture's as well as the variant's
Packages file.
Variants are configured in the
APT::Architecture-Variants
list.
Image builders may want to build specific variant images using
APT::Architecture-Variants { "amd64v3"; }
But this commit also implements an automatic discovery mechanism
using the varianttable and /proc/cpuinfo.
APT::Architecture-Variants "auto";
Diffstat (limited to 'apt-pkg/aptconfiguration.cc')
| -rw-r--r-- | apt-pkg/aptconfiguration.cc | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc index 96ff8b285..a0164c6c3 100644 --- a/apt-pkg/aptconfiguration.cc +++ b/apt-pkg/aptconfiguration.cc @@ -24,6 +24,8 @@ #include <cstdio> #include <cstdlib> #include <cstring> +#include <fstream> +#include <optional> #include <string> #include <vector> #include <dirent.h> @@ -313,6 +315,117 @@ bool Configuration::checkLanguage(std::string Lang, bool const All) { return (std::find(langs.begin(), langs.end(), Lang) != langs.end()); } /*}}}*/ + +// getArchitectures - Return Vector of preferred Architectures /*{{{*/ + +static std::set<std::string> const &getCpuFlags() +{ + static std::set<std::string> flags; + if (not flags.empty()) + return flags; + + std::ifstream table(_config->FindFile("Dir::proc::cpuinfo", "/proc/cpuinfo")); + for (std::string line; std::getline(table, line);) + { + if (not APT::String::Startswith(line, "flags\t")) + continue; + + line = line.substr(line.find(':')); + line = line.substr(line.find_first_not_of(": ")); + if (flags.empty()) + for (auto &&flag : APT::String::Split(line)) + flags.insert(std::move(flag)); + else + { + // Remove flags not present in this CPU + auto split = APT::String::Split(line); + std::set<std::string> newSet{split.begin(), split.end()}; + for (auto it = flags.begin(); it != flags.end();) + if (newSet.find(*it) == newSet.end()) + it = flags.erase(it); + else + ++it; + } + } + return flags; +} +std::vector<Configuration::ArchitectureVariant> Configuration::getArchitectureVariants(bool cached) +{ + std::optional<std::vector<ArchitectureVariant>> static variants; + if (likely(cached) && variants) + return *variants; + + variants.emplace(); + + auto const configuredVariants = _config->FindVector("APT::Architecture-Variants"); + auto const architectures = getArchitectures(cached); + auto const autoDetect = configuredVariants.size() == 1 && configuredVariants.front() == "auto"; + auto const autoCpuFlags = getCpuFlags(); + auto tablepath = _config->FindFile("Dir::dpkg::varianttable", DPKG_DATADIR "/varianttable"); + std::ifstream table(tablepath); + auto isAutoVariant = [&](auto &var) + { + bool res = true; + for (auto want : var.cpuflags) + if (autoCpuFlags.find(want) == autoCpuFlags.end()) + { + if (_config->FindB("Debug::Acquire::Variants", false)) + std::clog << "variant auto: " << var.name << ": missing: " << want << "\n"; + res = false; + } + return res; + }; + for (std::string line; std::getline(table, line);) + { + if (line[0] == '#' || line[0] == '\0') + continue; + auto cols = APT::String::Split(line); + ArchitectureVariant var{cols[0], cols[1], VectorizeString(cols[2], ',')}; + // Skip disabled architectures. + if (std::find(architectures.begin(), architectures.end(), var.base) == architectures.end()) + { + continue; + } + // See if this variant is configured or we detect it as auto + bool enabled = std::find(configuredVariants.begin(), configuredVariants.end(), cols[0]) != configuredVariants.end() || (autoDetect && isAutoVariant(var)); + if (enabled) + variants->push_back(std::move(var)); + } + + if (not autoDetect) + for (auto &var : configuredVariants) + if (std::find_if(variants->begin(), variants->end(), [var](auto &v) + { return v.name == var; }) == variants->end()) + { + if (var == "auto") + _error->Warning("Invalid value for APT::Architecture-Variants: auto cannot be combined with explicit variants"); + else + _error->Warning("Invalid value for APT::Architecture-Variants: %s", var.c_str()); + } + + // Build the supplants table + for (auto var = variants->begin(); var != variants->end(); ++var) + { + var->supplants.push_back(var->base); + for (auto var2 = var + 1; var2 != variants->end(); ++var2) + if (var2->base == var->base) + var->supplants.push_back(var2->name); + } + + // Order variants by preference + std::sort(variants->begin(), variants->end(), [&](auto &a, auto &b) + { return std::find(configuredVariants.begin(), configuredVariants.end(), a.name) < std::find(configuredVariants.begin(), configuredVariants.end(), b.name); }); + if (_config->FindB("Debug::Acquire::Variants", false)) + { + std::clog << "Variants enabled:"; + for (auto &var : *variants) + std::clog << " " << var.name; + std::clog << std::endl; + } + + return *variants; +} + /*}}}*/ // getArchitectures - Return Vector of preferred Architectures /*{{{*/ std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) { std::vector<std::string> static archs; |
