summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2022-09-06 14:30:11 +0800
committerGitHub <[email protected]>2022-09-06 14:30:11 +0800
commit19c45982eecdc1938706517314ba48379145cbb3 (patch)
tree3ffe56e50bed287cd2a39538732198f3f58410eb
parentefe31d55a33fa1f44d0980c069e10aeb82283bca (diff)
parent1fb9ef1571ded01ffe2077edcee0057bf4ced911 (diff)
Merge pull request #2781 from xmake-io/package
Strict compatibility for package linkdeps
-rw-r--r--xmake/actions/package/local/main.lua16
-rw-r--r--xmake/actions/package/remote/main.lua12
-rw-r--r--xmake/core/package/package.lua39
-rw-r--r--xmake/core/project/policy.lua6
-rw-r--r--xmake/modules/private/action/require/impl/actions/install.lua5
-rw-r--r--xmake/modules/private/action/require/impl/install_packages.lua6
-rw-r--r--xmake/modules/private/action/require/impl/package.lua111
-rw-r--r--xmake/modules/private/action/require/impl/register_packages.lua2
-rw-r--r--xmake/modules/private/action/require/install.lua2
9 files changed, 150 insertions, 49 deletions
diff --git a/xmake/actions/package/local/main.lua b/xmake/actions/package/local/main.lua
index 1a51e56f9..e1049419e 100644
--- a/xmake/actions/package/local/main.lua
+++ b/xmake/actions/package/local/main.lua
@@ -26,16 +26,16 @@ import("core.project.config")
import("core.project.project")
import("core.base.bit")
--- get link deps
-function _get_linkdeps(target)
- local linkdeps = {}
+-- get library deps
+function _get_librarydeps(target)
+ local librarydeps = {}
for _, depname in ipairs(target:get("deps")) do
local dep = project.target(depname)
if not ((target:is_binary() or target:is_shared()) and dep:is_static()) then
- table.insert(linkdeps, dep:name())
+ table.insert(librarydeps, dep:name())
end
end
- return linkdeps
+ return librarydeps
end
-- package binary
@@ -55,7 +55,7 @@ function _package_binary(target)
-- generate xmake.lua
local file = io.open(path.join(packagedir, "xmake.lua"), "w")
if file then
- local deps = _get_linkdeps(target)
+ local deps = _get_librarydeps(target)
file:print("package(\"%s\")", packagename)
local homepage = option.get("homepage")
if homepage then
@@ -129,7 +129,7 @@ function _package_library(target)
-- generate xmake.lua
local file = io.open(path.join(packagedir, "xmake.lua"), "w")
if file then
- local deps = _get_linkdeps(target)
+ local deps = _get_librarydeps(target)
file:print("package(\"%s\")", packagename)
local homepage = option.get("homepage")
if homepage then
@@ -193,7 +193,7 @@ function _package_headeronly(target)
-- generate xmake.lua
local file = io.open(path.join(packagedir, "xmake.lua"), "w")
if file then
- local deps = _get_linkdeps(target)
+ local deps = _get_librarydeps(target)
file:print("package(\"%s\")", packagename)
local homepage = option.get("homepage")
if homepage then
diff --git a/xmake/actions/package/remote/main.lua b/xmake/actions/package/remote/main.lua
index f37b1e9ac..d66d53cba 100644
--- a/xmake/actions/package/remote/main.lua
+++ b/xmake/actions/package/remote/main.lua
@@ -26,16 +26,16 @@ import("core.project.config")
import("core.project.project")
import("core.base.bit")
--- get link deps
-function _get_linkdeps(target)
- local linkdeps = {}
+-- get library deps
+function _get_librarydeps(target)
+ local librarydeps = {}
for _, depname in ipairs(target:get("deps")) do
local dep = project.target(depname)
if not ((target:is_binary() or target:is_shared()) and dep:is_static()) then
- table.insert(linkdeps, dep:name())
+ table.insert(librarydeps, dep:name())
end
end
- return linkdeps
+ return librarydeps
end
-- package remote
@@ -48,7 +48,7 @@ function _package_remote(target)
-- generate xmake.lua
local file = io.open(path.join(packagedir, "xmake.lua"), "w")
if file then
- local deps = _get_linkdeps(target)
+ local deps = _get_librarydeps(target)
file:print("package(\"%s\")", packagename)
if target:is_binary() then
file:print(" set_kind(\"binary\")")
diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua
index d812fdc95..5ec14ff0b 100644
--- a/xmake/core/package/package.lua
+++ b/xmake/core/package/package.lua
@@ -364,9 +364,9 @@ function _instance:plaindeps()
return self._PLAINDEPS
end
--- get link deps
-function _instance:linkdeps()
- return self._LINKDEPS
+-- get library deps with correct link order
+function _instance:librarydeps()
+ return self._LIBRARYDEPS
end
-- get parents
@@ -758,16 +758,27 @@ function _instance:manifest_save()
manifest.configs = self:configs()
manifest.envs = self:envs()
- -- save enabled link deps
- if self:linkdeps() then
- manifest.linkdeps = {}
- for _, dep in ipairs(self:linkdeps()) do
+ -- save enabled library deps
+ if self:librarydeps() then
+ manifest.librarydeps = {}
+ for _, dep in ipairs(self:librarydeps()) do
if dep:exists() then
- table.insert(manifest.linkdeps, dep:name())
+ table.insert(manifest.librarydeps, dep:name())
end
end
end
+ -- save deps
+ if self:deps() then
+ manifest.deps = {}
+ for name, dep in pairs(self:deps()) do
+ manifest.deps[name] = {
+ version = dep:version_str(),
+ buildhash = dep:buildhash()
+ }
+ end
+ end
+
-- save variables
local vars = {}
local apis = language.apis()
@@ -1589,16 +1600,16 @@ function _instance:exists()
return self._FETCHINFO ~= nil
end
--- fetch link info of dependencies
-function _instance:fetch_linkdeps()
+-- fetch library dependencies
+function _instance:fetch_librarydeps()
local fetchinfo = self:fetch()
if not fetchinfo then
return
end
fetchinfo = table.copy(fetchinfo) -- avoid the cached fetchinfo be modified
- local linkdeps = self:linkdeps()
- if linkdeps then
- for _, dep in ipairs(linkdeps) do
+ local librarydeps = self:librarydeps()
+ if librarydeps then
+ for _, dep in ipairs(librarydeps) do
local depinfo = dep:fetch()
if depinfo then
for name, values in pairs(depinfo) do
@@ -1745,7 +1756,7 @@ end
-- generate building configs for has_xxx/check_xxx
function _instance:_generate_build_configs(configs, opt)
opt = opt or {}
- configs = table.join(self:fetch_linkdeps(), configs)
+ configs = table.join(self:fetch_librarydeps(), configs)
if self:is_plat("windows") then
local ld = self:build_getenv("ld")
local vs_runtime = self:config("vs_runtime")
diff --git a/xmake/core/project/policy.lua b/xmake/core/project/policy.lua
index ef7851317..b746f6853 100644
--- a/xmake/core/project/policy.lua
+++ b/xmake/core/project/policy.lua
@@ -70,7 +70,11 @@ function policy.policies()
-- use includes as external header files? e.g. -isystem ..
["package.include_external_headers"] = {description = "Use includes as external headers.", type = "boolean"},
-- inherit the configs from the external command arguments, e.g. toolchains, `xmake f --toolchain=`
- ["package.inherit_external_configs"] = {description = "Inherit the configs from the external command arguments.", default = true, type = "boolean"}
+ ["package.inherit_external_configs"] = {description = "Inherit the configs from the external command arguments.", default = true, type = "boolean"},
+ -- set strict compatibility for package dependencies
+ -- if true, then any updates to linked 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 dependencies.", type = "boolean"},
}
policy._POLICIES = policies
end
diff --git a/xmake/modules/private/action/require/impl/actions/install.lua b/xmake/modules/private/action/require/impl/actions/install.lua
index 29725e973..10412c0a9 100644
--- a/xmake/modules/private/action/require/impl/actions/install.lua
+++ b/xmake/modules/private/action/require/impl/actions/install.lua
@@ -49,7 +49,7 @@ function _patch_pkgconfig(package)
vprint("patching %s ..", pcfile)
-- fetch package
- local fetchinfo = package:fetch_linkdeps()
+ local fetchinfo = package:fetch_librarydeps()
if not fetchinfo then
return
end
@@ -274,7 +274,8 @@ function main(package)
else
-- build and install package to the install directory
- if option.get("force") or not package:manifest_load() then
+ local force_reinstall = package:data("force_reinstall") or option.get("force")
+ if force_reinstall or not package:manifest_load() then
-- clean install directory first
os.tryrm(package:installdir())
diff --git a/xmake/modules/private/action/require/impl/install_packages.lua b/xmake/modules/private/action/require/impl/install_packages.lua
index 1e99cf9b8..3e608f671 100644
--- a/xmake/modules/private/action/require/impl/install_packages.lua
+++ b/xmake/modules/private/action/require/impl/install_packages.lua
@@ -76,10 +76,10 @@ function _replace_package(packages, instance, extinstance)
break
end
end
- local linkdeps = rawinstance._LINKDEPS
- for depidx, dep in ipairs(linkdeps) do
+ local librarydeps = rawinstance._LIBRARYDEPS
+ for depidx, dep in ipairs(librarydeps) do
if dep == instance then
- linkdeps[depidx] = extinstance
+ librarydeps[depidx] = extinstance
break
end
end
diff --git a/xmake/modules/private/action/require/impl/package.lua b/xmake/modules/private/action/require/impl/package.lua
index 3a9f4c991..26f608e3d 100644
--- a/xmake/modules/private/action/require/impl/package.lua
+++ b/xmake/modules/private/action/require/impl/package.lua
@@ -266,7 +266,7 @@ end
-- orderdeps: c -> b -> a
--
function _sort_packagedeps(package)
- -- we must use native deps list instead of package:deps() to generate correct linkdeps
+ -- we must use native deps list instead of package:deps() to generate correct librarydeps
local orderdeps = {}
for _, dep in ipairs(package:plaindeps()) do
if dep then
@@ -277,7 +277,7 @@ function _sort_packagedeps(package)
return orderdeps
end
--- sort link deps
+-- sort library deps and generate correct link order
--
-- e.g.
--
@@ -286,13 +286,13 @@ end
--
-- orderdeps: a -> b -> c
--
-function _sort_linkdeps(package)
- -- we must use native deps list instead of package:deps() to generate correct linkdeps
+function _sort_librarydeps(package)
+ -- we must use native deps list instead of package:deps() to generate correct link order
local orderdeps = {}
for _, dep in ipairs(package:plaindeps()) do
if dep and dep:is_library() and not dep:is_private() then
table.insert(orderdeps, dep)
- table.join2(orderdeps, _sort_linkdeps(dep))
+ table.join2(orderdeps, _sort_librarydeps(dep))
end
end
return orderdeps
@@ -883,7 +883,7 @@ function _load_packages(requires, opt)
package._DEPS = packagedeps
package._PLAINDEPS = plaindeps
package._ORDERDEPS = table.unique(_sort_packagedeps(package))
- package._LINKDEPS = table.reverse_unique(_sort_linkdeps(package))
+ package._LIBRARYDEPS = table.reverse_unique(_sort_librarydeps(package))
end
end
@@ -926,7 +926,7 @@ end
--
function _check_package_depconflicts(package)
local packagekeys = {}
- for _, dep in ipairs(package:linkdeps()) do
+ for _, dep in ipairs(package:librarydeps()) do
local key = _get_packagekey(dep:name(), dep:requireinfo())
local prevkey = packagekeys[dep:name()]
if prevkey then
@@ -940,20 +940,101 @@ end
-- must depend on the given package?
function _must_depend_on(package, dep)
local manifest = package:manifest_load()
- if manifest and manifest.linkdeps then
- local linkdeps = hashset.from(manifest.linkdeps)
- return linkdeps:has(dep:name())
+ if manifest and manifest.librarydeps then
+ local librarydeps = hashset.from(manifest.librarydeps)
+ return librarydeps:has(dep:name())
end
end
+-- compatible with all previous link dependencies?
+-- @see https://github.com/xmake-io/xmake/issues/2719
+function _compatible_with_previous_librarydeps(package, opt)
+
+ -- skip to check compatibility?
+ opt = opt or {}
+ if opt.check_compatibility == false then
+ return true
+ end
+
+ -- check strict compatibility for librarydeps?
+ local strict_compatibility = project.policy("package.librarydeps.strict_compatibility")
+ if strict_compatibility == nil then
+ strict_compatibility = package:policy("package.librarydeps.strict_compatibility")
+ end
+ if not strict_compatibility then
+ return true
+ end
+
+ -- has been checked?
+ local compatible_checked = package:data("librarydeps.compatible_checked")
+ if compatible_checked then
+ return
+ end
+
+ -- compute the buildhash for previous librarydeps
+ local depinfos_prev = {}
+ local depnames = hashset.new()
+ local manifest = package:manifest_load()
+ if manifest and manifest.librarydeps then
+ local deps = manifest.deps or {}
+ for _, depname in ipairs(manifest.librarydeps) do
+ local depinfo = deps[depname]
+ if depinfo and depinfo.buildhash then
+ depinfos_prev[depname] = depinfo
+ depnames:insert(depname)
+ end
+ end
+ end
+
+ -- compute the buildhash for current librarydeps
+ local depinfos_curr = {}
+ for _, dep in ipairs(package:librarydeps()) do
+ depinfos_curr[dep:name()] = {
+ version = dep:version_str(),
+ buildhash = dep:buildhash()
+ }
+ depnames:insert(dep:name())
+ end
+
+ -- is compatible?
+ local is_compatible = true
+ local compatible_tips = {}
+ for _, depname in depnames:keys() do
+ local depinfo_prev = depinfos_prev[depname]
+ local depinfo_curr = depinfos_curr[depname]
+ if depinfo_prev and depinfo_curr then
+ if depinfo_prev.buildhash ~= depinfo_curr.buildhash then
+ is_compatible = false
+ table.insert(compatible_tips, ("*%s"):format(depname))
+ end
+ elseif depinfo_prev then
+ is_compatible = false
+ table.insert(compatible_tips, ("-%s"):format(depname))
+ elseif depinfo_curr then
+ is_compatible = false
+ table.insert(compatible_tips, ("+%s"):format(depname))
+ end
+ end
+ if not is_compatible and #compatible_tips > 0 then
+ package:data_set("librarydeps.compatible_tips", compatible_tips)
+ end
+ if not is_compatible then
+ package:data_set("force_reinstall", true)
+ end
+ return is_compatible
+end
+
-- the cache directory
function cachedir()
return path.join(global.directory(), "cache", "packages")
end
-- this package should be install?
-function should_install(package)
- if package:is_template() or package:exists() then
+function should_install(package, opt)
+ if package:is_template() then
+ return false
+ end
+ if package:exists() and _compatible_with_previous_librarydeps(package, opt) then
return false
end
-- we need not install it if this package need only be fetched
@@ -968,7 +1049,7 @@ function should_install(package)
if package:parents() then
-- if all the packages that depend on it already exist, then there is no need to install it
for _, parent in pairs(package:parents()) do
- if should_install(parent) and not parent:exists() then
+ if should_install(parent, opt) and not parent:exists() then
return true
end
@@ -1022,6 +1103,10 @@ function get_configs_str(package)
end
end
end
+ local compatible_tips = package:data("librarydeps.compatible_tips")
+ if compatible_tips then
+ table.insert(configs, "deps:" .. table.concat(compatible_tips, ","))
+ end
local parents_str = _get_parents_str(package)
if parents_str then
table.insert(configs, "from:" .. parents_str)
diff --git a/xmake/modules/private/action/require/impl/register_packages.lua b/xmake/modules/private/action/require/impl/register_packages.lua
index afc84eb98..ecab45b7c 100644
--- a/xmake/modules/private/action/require/impl/register_packages.lua
+++ b/xmake/modules/private/action/require/impl/register_packages.lua
@@ -88,7 +88,7 @@ function _register_required_package(instance, required_package)
_register_required_package_base(instance, required_package)
_register_required_package_libs(instance, required_package)
_register_required_package_envs(instance, envs)
- for _, dep in ipairs(instance:linkdeps()) do
+ for _, dep in ipairs(instance:librarydeps()) do
if instance:is_library() then
_register_required_package_libs(dep, required_package, true)
end
diff --git a/xmake/modules/private/action/require/install.lua b/xmake/modules/private/action/require/install.lua
index c75df8a35..f6d02717e 100644
--- a/xmake/modules/private/action/require/install.lua
+++ b/xmake/modules/private/action/require/install.lua
@@ -35,7 +35,7 @@ function _check_missing_packages(packages)
local packages_missing = {}
local optional_missing = {}
for _, instance in ipairs(packages) do
- if package.should_install(instance) or (instance:is_fetchonly() and not instance:exists()) then
+ if package.should_install(instance, {check_compatibility = false}) or (instance:is_fetchonly() and not instance:exists()) then
if instance:is_optional() then
optional_missing[instance:name()] = instance
else