Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve the package configs conflict #5923

Merged
merged 12 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
os: [macos-12]
os: [macos-13]
arch: [x86_64]

runs-on: ${{ matrix.os }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ package_end()
package("bar")
add_deps("zlib 1.2.x")
-- add_deps("libpng dev")
-- add_deps("libpng", {configs = {debug = true}})
-- add_deps("boost", {system = false, configs = {zlib = false}})
set_policy("package.install_locally", true)
on_install(function () end)
package_end()

package("zoo")
-- add_deps("libpng master")
-- add_deps("libpng", {configs = {shared = true}})
-- add_deps("boost", {system = false, configs = {zlib = true}})
set_policy("package.install_locally", true)
on_install(function () end)
package_end()
Expand All @@ -26,6 +26,7 @@ package("test")
package_end()

add_requires("test")
--add_requireconfs("**.boost", {override = true, configs = {zlib = false}})

target("test")
set_kind("binary")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

int main(int argc, char** argv) {
printf("hello world!\n");
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function main(t)
-- freebsd ci is slower
if is_host("bsd") then
return
end
-- only for x86/x64, because it will take too long time on ci with arm/mips
if os.subarch():startswith("x") or os.subarch() == "i386" then
t:build()
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

package("foo")
add_deps("zlib >=1.2.13")
set_policy("package.install_locally", true)
on_install(function () end)
package_end()

package("bar")
add_deps("zlib 1.2.x")
set_policy("package.install_locally", true)
on_install(function () end)
package_end()

package("zoo")
set_policy("package.install_locally", true)
on_install(function () end)
package_end()

package("test")
add_deps("foo", "bar", "zoo")
set_policy("package.install_locally", true)
on_install(function () end)
package_end()

set_policy("package.sync_requires_to_deps", true)

add_requires("test")
add_requires("zlib >=1.2.13", {system = false, configs = {shared = true}})

target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("test")
8 changes: 7 additions & 1 deletion xmake/core/project/policy.lua
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,14 @@ function policy.policies()
-- if true, then any updates to library dependencies, such as buildhash changes due to version changes,
-- will force the installed packages to be recompiled and installed. @see https://github.com/xmake-io/xmake/issues/2719
["package.librarydeps.strict_compatibility"] = {description = "Set strict compatibility for package and it's all library dependencies.", type = "boolean"},
-- Resolve package dependencies conflict automatically
-- @see https://github.com/xmake-io/xmake/issues/5745
["package.resolve_depconflict"] = {description = "Automatically resolve package dependencies conflict.", default = true, type = "boolean"},
-- Synchronize add_requires configuration in toplevel to all package dependencies for this package
-- @see https://github.com/xmake-io/xmake/issues/5745
["package.sync_requires_to_deps"] = {description = "Synchronize requires configuration to all package dependencies.", default = false, type = "boolean"},
-- Automatically passes dependency configuration for inner xmake package
-- https://github.com/xmake-io/xmake/issues/3952
-- @see https://github.com/xmake-io/xmake/issues/3952
["package.xmake.pass_depconfs"] = {description = "Automatically passes dependency configuration for inner xmake package", default = true, type = "boolean"},
-- It will force cmake package use ninja for build
["package.cmake_generator.ninja"] = {description = "Set cmake package use ninja for build", type = "boolean"},
Expand Down
36 changes: 36 additions & 0 deletions xmake/core/project/project.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,42 @@ function project.requireconfs_str()
project.requires_str()
local requireconfs_str = project._memcache():get("requireconfs_str")
local requireconfs_extra = project._memcache():get("requireconfs_extra")
-- synchronize requires configuration to all package dependencies.
-- @see https://github.com/xmake-io/xmake/issues/5745#issuecomment-2513951471
if project.policy("package.sync_requires_to_deps") then
local requires_str = project._memcache():get("requires_str")
local requires_extra = project._memcache():get("requires_extra")
local sync_requires_to_deps = project._memcache():get("package.sync_requires_to_deps")
if requires_str and not sync_requires_to_deps then
requires_extra = requires_extra and table.wrap(requires_extra) or {}
requireconfs_str = requireconfs_str and table.wrap(requireconfs_str) or {}
requireconfs_extra = requireconfs_extra and table.wrap(requireconfs_extra) or {}
for _, require_str in ipairs(table.wrap(requires_str)) do
if not require_str:find("::", 1, true) then
local splitinfo = require_str:split("%s")
local packagename = splitinfo[1]
local packageversion = splitinfo[2]
local requireconf_str = "**." .. packagename
local requireconf_extra = table.clone(requires_extra[require_str])
if requireconf_extra then
requireconf_extra.configs = table.clone(requireconf_extra.configs) or {}
end
if packageversion then
requireconf_extra = requireconf_extra or {configs = {}}
requireconf_extra.configs.version = packageversion
end
if requireconf_extra then
requireconf_extra.override = true
table.insert(requireconfs_str, requireconf_str)
requireconfs_extra[requireconf_str] = requireconf_extra
end
end
end
project._memcache():set("requireconfs_str", requireconfs_str)
project._memcache():set("requireconfs_extra", requireconfs_extra)
project._memcache():set("package.sync_requires_to_deps", true)
end
end
return requireconfs_str, requireconfs_extra
end

Expand Down
118 changes: 91 additions & 27 deletions xmake/modules/private/action/require/impl/package.lua
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,26 @@ function _load_require(require_str, requires_extra, opt)
end
end

-- resolve require info
local resolvedinfo = opt.resolvedinfo
local requirepath = opt.requirepath
if requirepath then
requirepath = requirepath .. "." .. packagename
else
requirepath = packagename
end
resolvedinfo = resolvedinfo and resolvedinfo[requirepath]
if resolvedinfo then
-- resolve the conflict package version
if resolvedinfo.version then
version = resolvedinfo.version
end
-- resolve the conflict package configs
if resolvedinfo.configs then
require_extra.configs = resolvedinfo.configs
end
end

-- get required building configurations
-- we need to clone a new configs object, because the whole requireinfo will be modified later.
-- @see https://github.com/xmake-io/xmake-repo/pull/2067
Expand Down Expand Up @@ -216,22 +236,6 @@ function _load_require(require_str, requires_extra, opt)
require_extra.system = false
end

-- resolve require info
local resolvedinfo = opt.resolvedinfo
local requirepath = opt.requirepath
if requirepath then
requirepath = requirepath .. "." .. packagename
else
requirepath = packagename
end
resolvedinfo = resolvedinfo and resolvedinfo[requirepath]
if resolvedinfo then
-- resolve the conflict package version
if resolvedinfo.version then
version = resolvedinfo.version
end
end

-- init required item
local required = {}
local parentinfo = opt.parentinfo
Expand All @@ -257,7 +261,8 @@ function _load_require(require_str, requires_extra, opt)
verify = require_extra.verify, -- default: true, we can set false to ignore sha256sum and select any version
external = require_extra.external, -- default: true, we use sysincludedirs/-isystem instead of -I/xxx
private = require_extra.private, -- default: false, private package, only for installation, do not export any links/includes and environments
build = require_extra.build -- default: false, always build packages, we do not use the precompiled artifacts
build = require_extra.build, -- default: false, always build packages, we do not use the precompiled artifacts
resolvedinfo = resolvedinfo -- the resolved info for the conflict version/configs
}
return required.packagename, required.requireinfo
end
Expand Down Expand Up @@ -1206,29 +1211,44 @@ function _get_requirepaths(package)
table.insert(requirepaths, requirepath .. "." .. package:name())
end
end
-- we also need to resolve requires conflict in toplevel, if `package.sync_requires_to_deps` policy is enabled.
-- @see https://github.com/xmake-io/xmake/issues/5745#issuecomment-2513951471
if project.policy("package.sync_requires_to_deps") then
table.insert(requirepaths, package:name())
end
else
table.insert(requirepaths, package:name())
end
return requirepaths
end

-- get configs key for compatibility
-- get compatibility key
function _get_package_compatkey(dep)
local key = dep:plat() .. "/" .. dep:arch() .. "/" .. (dep:kind() or "")
if dep:is_system() then
key = key .. "/system"
end
local configs = dep:requireinfo().configs
if configs then
local configs_order = {}
for k, v in pairs(configs) do
if type(v) == "table" then
v = string.serialize(v, {strip = true, indent = false, orderkeys = true})
local resolve_depconflict = project.policy("package.resolve_depconflict")
if resolve_depconflict == nil then
resolve_depconflict = dep:policy("package.resolve_depconflict")
end
if resolve_depconflict == false then
if dep:version_str() then
key = key .. "/" .. dep:version_str()
end
local configs = dep:requireinfo().configs
if configs then
local configs_order = {}
for k, v in pairs(configs) do
if type(v) == "table" then
v = string.serialize(v, {strip = true, indent = false, orderkeys = true})
end
table.insert(configs_order, k .. "=" .. tostring(v))
end
table.insert(configs_order, k .. "=" .. tostring(v))
table.sort(configs_order)
key = key .. ":" .. string.serialize(configs_order, true)
end
table.sort(configs_order)
key = key .. ":" .. string.serialize(configs_order, true)

end
return key
end
Expand Down Expand Up @@ -1298,16 +1318,42 @@ function _check_and_resolve_package_depconflicts_impl(package, name, deps, resol

-- check configs compatibility
local prevkey
local configs
local configs_conflict = false
for _, dep in ipairs(deps) do
local key = _get_package_compatkey(dep)
if prevkey then
if prevkey ~= key then
configs_conflict = true
break
end
else
prevkey = key
end
local depconfigs = dep:requireinfo().configs
if configs and depconfigs then
for k, v in pairs(depconfigs) do
local oldv = configs[k]
if oldv ~= nil then
local v_key = tostring(v)
local oldv_key = tostring(oldv)
if type(v) == "table" then
v_key = string.serialize(v, {strip = true, indent = false, orderkeys = true})
end
if type(oldv) == "table" then
oldv_key = string.serialize(oldv, {strip = true, indent = false, orderkeys = true})
end
if v_key ~= oldv_key then
configs_conflict = true
break
end
else
configs[k] = v
end
end
else
configs = depconfigs
end
end
if configs_conflict then
print("package(%s): add_deps(%s, ...)", package:name(), name)
Expand Down Expand Up @@ -1335,6 +1381,16 @@ function _check_and_resolve_package_depconflicts_impl(package, name, deps, resol
end
end
end

-- resolve configs
if configs then
for _, dep in ipairs(deps) do
for _, requirepath in ipairs(_get_requirepaths(dep)) do
resolvedinfo[requirepath] = resolvedinfo[requirepath] or {}
resolvedinfo[requirepath].configs = configs
end
end
end
end

-- check and resolve dependencies conflicts
Expand Down Expand Up @@ -1573,11 +1629,19 @@ function get_configs_str(package)
if parents_str then
table.insert(configs, "from:" .. parents_str)
end
local license = package:get("license")
if license then
table.insert(configs, "license:" .. license)
end
local configs_str = #configs > 0 and "[" .. table.concat(configs, ", ") .. "]" or ""
local limitwidth = math.floor(os.getwinsize().width * 2 / 3)
if #configs_str > limitwidth then
configs_str = configs_str:sub(1, limitwidth) .. " ..)"
end
local resolvedinfo = requireinfo.resolvedinfo
if resolvedinfo then
configs_str = configs_str .. " " .. "${color.warning}(conflict resolved)${clear}"
end
return configs_str
end

Expand Down
Loading