build: rework config generation

So far, we were using a sort operation on the generated .config to
implement precedence of =y packages over =m, and =m over unset.
Unfortunately, this sort not only used for packages, but for all config
lines. This made it impossible to override settings from targets/generic
in a target config when the new setting was sorted before the generic
setting.

To fix this, track configurations by their keys, so we can properly
override config keys that were set before. Value-based precedence is
only preserved for package configuration.

The config() and try_config() calls always take key and value as
separate arguments now. Strings are quoted automatically; the values
true, nil and false map to y, m and unset for tristate options. config()
can take an optional third argument to override the error message to
display when the setting fails to apply.

All existing target configs generate the same .config with the old and the
new code. The new code is also a bit faster on targets with many devices.
This commit is contained in:
Matthias Schiffer 2020-05-26 22:40:12 +02:00
parent 97e5434b32
commit 9e23534ec3
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
11 changed files with 127 additions and 126 deletions

View File

@ -1,24 +1,5 @@
local funcs = {} local lib = dofile('scripts/target_config_lib.lua')()
function funcs.config_message(config, _, ...) for _, config in pairs(lib.configs) do
config(...) io.stdout:write(config:format(), '\n')
end
function funcs.config_package(config, pkg, value)
config('CONFIG_PACKAGE_%s=%s', pkg, value)
end
local lib = dofile('scripts/target_config_lib.lua')(funcs)
local output = {}
for config in pairs(lib.configs) do
table.insert(output, config)
end
-- The sort will make =y entries override =m ones
table.sort(output)
for _, line in ipairs(output) do
io.stdout:write(line, '\n')
end end

View File

@ -1,16 +1,12 @@
local errors = {} local errors = false
local function fail(msg)
local function fail(...) if not errors then
if not next(errors) then errors = true
io.stderr:write('Configuration failed:', '\n') io.stderr:write('Configuration failed:', '\n')
end end
local msg = string.format(...) io.stderr:write(' * ', msg, '\n')
if not errors[msg] then
errors[msg] = true
io.stderr:write(' * ', msg, '\n')
end
end end
local function match_config(f) local function match_config(f)
@ -23,49 +19,21 @@ local function match_config(f)
return false return false
end end
local function check_config(pattern) local function check_config(config)
return match_config(function(line) return line == pattern end) return match_config(function(line) return line == config end)
end
local function check_config_prefix(pattern)
return match_config(function(line) return string.sub(line, 1, -2) == pattern end)
end end
local funcs = {} local lib = dofile('scripts/target_config_lib.lua')()
function funcs.config_message(_, message, ...) for _, config in pairs(lib.configs) do
local pattern = string.format(...) if config.required then
if not check_config(config:format()) then
if not check_config(pattern) then fail(config.required)
fail('%s', message)
end
end
function funcs.config_package(_, pkg, value)
local pattern = string.format('CONFIG_PACKAGE_%s=%s', pkg, value)
local res
if value == 'y' then
res = check_config(pattern)
else
res = check_config_prefix(string.sub(pattern, 1, -2))
end
if not res then
fail("unable to enable package '%s'", pkg)
end
end
local lib = dofile('scripts/target_config_lib.lua')(funcs)
for config, v in pairs(lib.configs) do
if v == 2 then
if not check_config(config) then
fail("unable to set '%s'", config)
end end
end end
end end
if next(errors) then if errors then
os.exit(1) os.exit(1)
end end

View File

@ -40,7 +40,7 @@ local function compact_list(list, keep_neg)
return ret return ret
end end
return function(funcs) return function()
local lib = dofile('scripts/target_lib.lua') local lib = dofile('scripts/target_lib.lua')
local env = lib.env local env = lib.env
@ -102,12 +102,29 @@ END_MAKE
return pkgs return pkgs
end end
local enabled_packages = {}
-- Arguments: package name and config value (true: y, nil: m, false: unset)
-- Ensures precedence of y > m > unset
local function config_package(pkg, v)
if v == false then
if not enabled_packages[pkg] then
lib.try_config('CONFIG_PACKAGE_' .. pkg, false)
end
return
end
if v == true or not enabled_packages[pkg] then
lib.config('CONFIG_PACKAGE_' .. pkg, v, string.format("unable to enable package '%s'", pkg))
enabled_packages[pkg] = true
end
end
local function handle_target_pkgs(pkgs) local function handle_target_pkgs(pkgs)
for _, pkg in ipairs(pkgs) do for _, pkg in ipairs(pkgs) do
if string.sub(pkg, 1, 1) == '-' then if string.sub(pkg, 1, 1) == '-' then
lib.try_config('# CONFIG_PACKAGE_%s is not set', string.sub(pkg, 2)) config_package(string.sub(pkg, 2), false)
else else
funcs.config_package(lib.config, pkg, 'y') config_package(pkg, true)
end end
end end
end end
@ -118,8 +135,8 @@ END_MAKE
lib.check_devices() lib.check_devices()
if not lib.opkg then if not lib.opkg then
lib.config '# CONFIG_SIGNED_PACKAGES is not set' lib.config('CONFIG_SIGNED_PACKAGES', false)
lib.config 'CONFIG_CLEAN_IPKG=y' lib.config('CONFIG_CLEAN_IPKG', true)
lib.packages {'-opkg'} lib.packages {'-opkg'}
end end
@ -133,7 +150,7 @@ END_MAKE
local function handle_pkgs(pkgs) local function handle_pkgs(pkgs)
for _, pkg in ipairs(pkgs) do for _, pkg in ipairs(pkgs) do
if string.sub(pkg, 1, 1) ~= '-' then if string.sub(pkg, 1, 1) ~= '-' then
funcs.config_package(lib.config, pkg, 'm') config_package(pkg, nil)
end end
device_pkgs = append_to_list(device_pkgs, pkg) device_pkgs = append_to_list(device_pkgs, pkg)
end end
@ -144,11 +161,15 @@ END_MAKE
handle_pkgs(dev.options.packages or {}) handle_pkgs(dev.options.packages or {})
handle_pkgs(site_packages(dev.image)) handle_pkgs(site_packages(dev.image))
funcs.config_message(lib.config, string.format("unable to enable device '%s'", profile), lib.config(
'CONFIG_TARGET_DEVICE_%s_DEVICE_%s=y', openwrt_config_target, profile) string.format('CONFIG_TARGET_DEVICE_%s_DEVICE_%s', openwrt_config_target, profile),
lib.config('CONFIG_TARGET_DEVICE_PACKAGES_%s_DEVICE_%s="%s"', true,
openwrt_config_target, profile, string.format("unable to enable device '%s'", profile)
table.concat(device_pkgs, ' ')) )
lib.config(
string.format('CONFIG_TARGET_DEVICE_PACKAGES_%s_DEVICE_%s', openwrt_config_target, profile),
table.concat(device_pkgs, ' ')
)
end end
else else
-- x86 fallback: no devices -- x86 fallback: no devices

View File

@ -150,14 +150,51 @@ local function add_image(image)
table.insert(M.images[device], setmetatable(image, image_mt)) table.insert(M.images[device], setmetatable(image, image_mt))
end end
function F.try_config(...)
M.configs[string.format(...)] = 1 local function format_config(k, v)
local format
if type(v) == 'string' then
format = '%s=%q'
elseif v == true then
format = '%s=y'
elseif v == nil then
format = '%s=m'
elseif v == false then
format = '# %s is not set'
else
format = '%s=%d'
end
return string.format(format, k, v)
end end
function F.config(...) local config_mt = {
M.configs[string.format(...)] = 2 __index = {
format = function(config)
return format_config(config.key, config.value)
end,
}
}
local function do_config(k, v, required)
M.configs[k] = setmetatable({
key = k,
value = v,
required = required,
}, config_mt)
end end
function F.try_config(k, v)
do_config(k, v)
end
function F.config(k, v, message)
if not message then
message = string.format("unable to set '%s'", format_config(k, v))
end
do_config(k, v, message)
end
function F.packages(pkgs) function F.packages(pkgs)
for _, pkg in ipairs(pkgs) do for _, pkg in ipairs(pkgs) do
table.insert(M.target_packages, pkg) table.insert(M.target_packages, pkg)

View File

@ -1,5 +1,5 @@
config 'CONFIG_GLUON_SPECIALIZE_KERNEL=y' config('CONFIG_GLUON_SPECIALIZE_KERNEL', true)
config 'CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=64' config('CONFIG_TARGET_SQUASHFS_BLOCK_SIZE', 64)
local ATH10K_PACKAGES = { local ATH10K_PACKAGES = {
'kmod-ath10k', 'kmod-ath10k',

View File

@ -1,4 +1,4 @@
config 'CONFIG_GLUON_SPECIALIZE_KERNEL=y' config('CONFIG_GLUON_SPECIALIZE_KERNEL', true)
defaults { defaults {
factory = false, factory = false,

View File

@ -1,4 +1,4 @@
config 'CONFIG_GLUON_SPECIALIZE_KERNEL=y' config('CONFIG_GLUON_SPECIALIZE_KERNEL', true)
local ATH10K_PACKAGES = {'kmod-ath10k', '-kmod-ath10k-ct', 'ath10k-firmware-qca988x', '-ath10k-firmware-qca988x-ct'} local ATH10K_PACKAGES = {'kmod-ath10k', '-kmod-ath10k-ct', 'ath10k-firmware-qca988x', '-ath10k-firmware-qca988x-ct'}

View File

@ -1,4 +1,4 @@
config 'CONFIG_GLUON_SPECIALIZE_KERNEL=y' config('CONFIG_GLUON_SPECIALIZE_KERNEL', true)
no_opkg() no_opkg()

View File

@ -1,21 +1,21 @@
assert(env.GLUON_LANGS) assert(env.GLUON_LANGS)
config('CONFIG_GLUON_SITEDIR="%s"', env.GLUON_SITEDIR) config('CONFIG_GLUON_SITEDIR', env.GLUON_SITEDIR)
config('CONFIG_GLUON_RELEASE="%s"', env.GLUON_RELEASE) config('CONFIG_GLUON_RELEASE', env.GLUON_RELEASE)
try_config('CONFIG_GLUON_BRANCH="%s"', env.GLUON_BRANCH or '') try_config('CONFIG_GLUON_BRANCH', env.GLUON_BRANCH or '')
for lang in string.gmatch(env.GLUON_LANGS, '%S+') do for lang in string.gmatch(env.GLUON_LANGS, '%S+') do
try_config('CONFIG_GLUON_WEB_LANG_%s=y', lang) try_config('CONFIG_GLUON_WEB_LANG_' .. lang, true)
end end
config('CONFIG_TARGET_%s=y', env.BOARD) config('CONFIG_TARGET_' .. env.BOARD, true)
if env.SUBTARGET ~= '' then if env.SUBTARGET ~= '' then
config('CONFIG_TARGET_%s_%s=y', env.BOARD, env.SUBTARGET) config(string.format('CONFIG_TARGET_%s_%s', env.BOARD, env.SUBTARGET), true)
end end
-- Disable non-default feeds in distfeeds.conf -- Disable non-default feeds in distfeeds.conf
config('# CONFIG_FEED_gluon_base is not set') config('CONFIG_FEED_gluon_base', false)
local default_feeds = {} local default_feeds = {}
for feed in string.gmatch(exec_capture_raw('. scripts/default_feeds.sh && echo "$DEFAULT_FEEDS"'), '%S+') do for feed in string.gmatch(exec_capture_raw('. scripts/default_feeds.sh && echo "$DEFAULT_FEEDS"'), '%S+') do
@ -24,52 +24,46 @@ end
for feed in string.gmatch(exec_capture_raw('. scripts/modules.sh && echo -n "$FEEDS"'), '%S+') do for feed in string.gmatch(exec_capture_raw('. scripts/modules.sh && echo -n "$FEEDS"'), '%S+') do
if not default_feeds[feed] then if not default_feeds[feed] then
config('# CONFIG_FEED_%s is not set', feed) config('CONFIG_FEED_' .. feed, false)
end end
end end
config '# CONFIG_TARGET_ROOTFS_INITRAMFS is not set' config('CONFIG_TARGET_ROOTFS_INITRAMFS', false)
config 'CONFIG_DEVEL=y' config('CONFIG_DEVEL', true)
config 'CONFIG_ALL_NONSHARED=y' config('CONFIG_ALL_NONSHARED', true)
config '# CONFIG_PACKAGE_usbip is not set' -- fails to build config('CONFIG_PACKAGE_usbip', false) -- fails to build
config '# CONFIG_PACKAGE_kmod-jool is not set' -- fails to build config('CONFIG_PACKAGE_kmod-jool', false) -- fails to build
config 'CONFIG_BUSYBOX_CUSTOM=y' config('CONFIG_BUSYBOX_CUSTOM', true)
config '# CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set' config('CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS', false)
config 'CONFIG_PACKAGE_ATH_DEBUG=y' config('CONFIG_PACKAGE_ATH_DEBUG', true)
try_config 'CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=256' try_config('CONFIG_TARGET_SQUASHFS_BLOCK_SIZE', 256)
config '# CONFIG_KERNEL_IP_MROUTE is not set' config('CONFIG_KERNEL_IP_MROUTE', false)
config '# CONFIG_KERNEL_IPV6_MROUTE is not set' config('CONFIG_KERNEL_IPV6_MROUTE', false)
try_config 'CONFIG_TARGET_MULTI_PROFILE=y' try_config('CONFIG_TARGET_MULTI_PROFILE', true)
try_config 'CONFIG_TARGET_PER_DEVICE_ROOTFS=y' try_config('CONFIG_TARGET_PER_DEVICE_ROOTFS', true)
if istrue(env.GLUON_MULTIDOMAIN) then config('CONFIG_GLUON_MULTIDOMAIN', istrue(env.GLUON_MULTIDOMAIN))
config 'CONFIG_GLUON_MULTIDOMAIN=y'
end
if istrue(env.GLUON_AUTOREMOVE) then config('CONFIG_AUTOREMOVE', istrue(env.GLUON_AUTOREMOVE))
config 'CONFIG_AUTOREMOVE=y'
end
if istrue(env.GLUON_DEBUG) then if istrue(env.GLUON_DEBUG) then
config 'CONFIG_DEBUG=y' config('CONFIG_DEBUG', true)
config 'CONFIG_NO_STRIP=y' config('CONFIG_NO_STRIP', true)
config '# CONFIG_USE_STRIP is not set' config('CONFIG_USE_STRIP', false)
config '# CONFIG_USE_SSTRIP is not set' config('CONFIG_USE_SSTRIP', false)
try_config 'CONFIG_TARGET_ROOTFS_PARTSIZE=500' try_config('CONFIG_TARGET_ROOTFS_PARTSIZE', 500)
end end
if not istrue(env.GLUON_MINIFY) then config('CONFIG_GLUON_MINIFY', istrue(env.GLUON_MINIFY))
config '# CONFIG_GLUON_MINIFY is not set'
end
packages { packages {
'-kmod-ipt-offload', '-kmod-ipt-offload',

View File

@ -1,5 +1,5 @@
config '# CONFIG_KERNEL_KALLSYMS is not set' config('CONFIG_KERNEL_KALLSYMS', false)
config 'CONFIG_GLUON_SPECIALIZE_KERNEL=y' config('CONFIG_GLUON_SPECIALIZE_KERNEL', true)
no_opkg() no_opkg()

View File

@ -1,5 +1,5 @@
config 'CONFIG_VDI_IMAGES=y' config('CONFIG_VDI_IMAGES', true)
config 'CONFIG_VMDK_IMAGES=y' config('CONFIG_VMDK_IMAGES', true)
packages { packages {
'kmod-3c59x', 'kmod-3c59x',