summaryrefslogtreecommitdiff
path: root/xmake/modules/package/manager
diff options
context:
space:
mode:
authorruki <[email protected]>2019-01-22 22:39:25 +0800
committerruki <[email protected]>2019-01-22 09:56:36 +0800
commitde29dc88bc3b7d39d4206d6e2bd034d15b232ca2 (patch)
treef247b2624aafd5a30c0a100de93aaeaf50ff7dce /xmake/modules/package/manager
parentc92d87e3b872cd303356112a22190d4858a9fcb3 (diff)
find package from xmake repo and package directories
Diffstat (limited to 'xmake/modules/package/manager')
-rw-r--r--xmake/modules/package/manager/find_package.lua61
-rw-r--r--xmake/modules/package/manager/xmake/find_package.lua271
2 files changed, 326 insertions, 6 deletions
diff --git a/xmake/modules/package/manager/find_package.lua b/xmake/modules/package/manager/find_package.lua
index bcade1f95..4d6cc5299 100644
--- a/xmake/modules/package/manager/find_package.lua
+++ b/xmake/modules/package/manager/find_package.lua
@@ -29,6 +29,12 @@ import("core.project.config")
import("lib.detect.cache")
-- find package
+--
+-- opt.system:
+-- nil: find local or system packages
+-- true: only find system package
+-- false: only find local packages
+--
function _find_package(manager_name, package_name, opt)
-- get managers
@@ -36,22 +42,65 @@ function _find_package(manager_name, package_name, opt)
if manager_name then
table.insert(managers, manager_name)
else
- if not is_host("windows") then
- table.insert(managers, "brew")
+
+ -- we cannot find it from xmake repo and package directories if only find system packages
+ if opt.system ~= true then
+ table.insert(managers, "xmake")
+ end
+
+ -- find system package if be not disabled
+ if opt.system ~= false then
+
+ -- find it from homebrew
+ if not is_host("windows") then
+ table.insert(managers, "brew")
+ end
+
+ -- find it from vcpkg
+ table.insert(managers, "vcpkg")
+
+ -- find it from conan
+ table.insert(managers, "conan")
+
+ -- find it from pkg-config
+ table.insert(managers, "pkg-config")
+
+ -- find it from system
+ table.insert(managers, "system")
end
- table.insert(managers, "vcpkg")
- table.insert(managers, "conan")
end
assert(#managers > 0, "no suitable package manager!")
-- find package from the given package manager
+ local result = nil
for _, manager_name in ipairs(managers) do
dprint("finding %s from %s ..", package_name, manager_name)
- local result = import("package.manager." .. manager_name .. ".find_package", {anonymous = true})(package_name, opt)
+ result = import("package.manager." .. manager_name .. ".find_package", {anonymous = true})(package_name, opt)
if result then
- return result
+ break
+ end
+ end
+
+ -- found?
+ if result then
+
+ -- remove repeat
+ result.linkdirs = table.unique(result.linkdirs)
+ result.includedirs = table.unique(result.includedirs)
+
+ -- check valid version
+ if result.version then
+ local version = semver.new(result.version)
+ if version then
+ result.version = version:rawstr()
+ else
+ result.version = nil
+ end
end
end
+
+ -- ok?
+ return result
end
-- find package using the package manager
diff --git a/xmake/modules/package/manager/xmake/find_package.lua b/xmake/modules/package/manager/xmake/find_package.lua
new file mode 100644
index 000000000..dc0511476
--- /dev/null
+++ b/xmake/modules/package/manager/xmake/find_package.lua
@@ -0,0 +1,271 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2019, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file find_package.lua
+--
+
+-- imports
+import("core.base.global")
+import("core.base.interpreter")
+import("core.project.config")
+import("core.project.option")
+import("core.project.target")
+import("core.language.language")
+import("lib.detect.find_file")
+import("lib.detect.find_library")
+
+-- find package from the repository (maybe only include and no links)
+function _find_package_from_repo(name, opt)
+
+ -- get the prefix directories
+ local prefixdirs = table.wrap(opt.prefixdirs)
+ local platsubdirs = path.join(config.get("plat") or os.host(), config.get("arch") or os.arch())
+ if #prefixdirs == 0 then
+ table.insert(prefixdirs, path.join(opt.islocal and config.directory() or global.directory(), "prefix", platsubdirs, opt.mode or "release"))
+ end
+
+ -- find the prefix info file of package, .e.g prefix/info/z/zlib/1.2.11/info.txt
+ local packagedirs = {}
+ local packagepath = path.join(name:sub(1, 1), name, "*")
+ table.insert(packagedirs, path.join(opt.islocal and config.directory() or global.directory(), "prefix", "info", platsubdirs, opt.mode or "release", packagepath))
+ local prefixfile = find_file("info.txt", packagedirs)
+ if not prefixfile then
+ return
+ end
+
+ -- load prefix info
+ local prefixinfo = io.load(prefixfile)
+ if not prefixinfo then
+ return
+ end
+
+ -- get prefix directory of this package
+ local prefixdir = path.translate(path.directory(path.directory(path.directory(path.directory(prefixfile)))):gsub("[/\\]prefix[/\\]info[/\\]", "/prefix/"))
+
+ -- save includedirs to result (maybe only include and no links)
+ local result = {}
+ local includedirs = {}
+ for _, includedir in ipairs(prefixinfo.includedirs) do
+ table.insert(includedirs, path.join(prefixdir, includedir))
+ end
+ if #includedirs == 0 then
+ table.insert(includedirs, path.join(prefixdir, "include"))
+ end
+ result.includedirs = table.unique(includedirs)
+
+ -- get links and link directories
+ local links = {}
+ local linkdirs = {}
+ for _, linkdir in ipairs(prefixinfo.linkdirs) do
+ table.insert(linkdirs, path.join(prefixdir, linkdir))
+ end
+ if prefixinfo.links then
+ table.join2(links, prefixinfo.links)
+ end
+ if prefixinfo.installed and (not prefixinfo.linkdirs or not prefixinfo.links) then
+ local found = false
+ for _, line in ipairs(prefixinfo.installed) do
+ line = line:trim()
+ if line:endswith(".lib") or line:endswith(".a") then
+ found = true
+ if not prefixinfo.linkdirs then
+ table.insert(linkdirs, path.join(prefixdir, path.directory(line)))
+ end
+ if not prefixinfo.links then
+ table.insert(links, target.linkname(path.filename(line)))
+ end
+ end
+ end
+ if not found then
+ for _, line in ipairs(prefixinfo.installed) do
+ line = line:trim()
+ if line:endswith(".so") or line:endswith(".dylib") then
+ if not prefixinfo.linkdirs then
+ table.insert(linkdirs, path.join(prefixdir, path.directory(line)))
+ end
+ if not prefixinfo.links then
+ table.insert(links, target.linkname(path.filename(line)))
+ end
+ end
+ end
+ end
+ end
+
+ -- add root include and link directories
+ if #linkdirs == 0 then
+ table.insert(linkdirs, path.join(prefixdir, "lib"))
+ end
+
+ -- uses name as links directly .e.g libname.a
+ if #links == 0 then
+ links = table.wrap(name)
+ end
+
+ -- find library
+ for _, link in ipairs(links) do
+ local libinfo = find_library(link, linkdirs)
+ if libinfo then
+ result.links = table.join(result.links or {}, libinfo.link)
+ result.linkdirs = table.join(result.linkdirs or {}, libinfo.linkdir)
+ end
+ end
+ -- make unique links
+ if result.links then
+ result.links = table.unique(result.links)
+ end
+
+ -- inherit the other prefix variables
+ for name, values in pairs(prefixinfo) do
+ if name ~= "links" and name ~= "linkdirs" and name ~= "includedirs" and name ~= "installed" and name ~= "prefixdir" then
+ result[name] = values
+ end
+ end
+
+ -- get version
+ result.version = path.filename(path.directory(prefixfile))
+
+ -- ok
+ return result
+end
+
+-- find package from the package directories
+function _find_package_from_packagedirs(name, opt)
+
+ -- get package path (.e.g name.pkg) in the package directories
+ local packagepath = nil
+ for _, dir in ipairs(table.wrap(opt.packagedirs)) do
+ local p = path.join(dir, name .. ".pkg")
+ if os.isdir(p) then
+ packagepath = p
+ break
+ end
+ end
+ if not packagepath then
+ return
+ end
+
+ -- get package file (.e.g name.pkg/xmake.lua)
+ local packagefile = path.join(packagepath, "xmake.lua")
+ if not os.isfile(packagefile) then
+ return
+ end
+
+ -- init interpreter
+ local interp = interpreter.new()
+
+ -- define apis for option
+ interp:api_define(option.apis())
+
+ -- define apis for language
+ interp:api_define(language.apis())
+
+ -- register filter handler
+ interp:filter():register("find_package", function (variable)
+
+ -- init maps
+ local maps =
+ {
+ arch = opt.arch
+ , plat = opt.plat
+ , mode = opt.mode or config.get("mode")
+ , host = os.host()
+ , tmpdir = function () return os.tmpdir() end
+ , curdir = function () return os.curdir() end
+ , scriptdir = function () return os.scriptdir() end
+ , globaldir = global.directory()
+ , configdir = config.directory()
+ , projectdir = os.projectdir()
+ , programdir = os.programdir()
+ }
+
+ -- get variable
+ return maps[variable]
+ end)
+
+ -- load script
+ local ok, errors = interp:load(packagefile)
+ if not ok then
+ raise(errors)
+ end
+
+ -- load the package from the the package file
+ local packageinfos, errors = interp:make("option", true, true)
+ if not packageinfos then
+ raise(errors)
+ end
+
+ -- get package info
+ local packageinfo = packageinfos[name]
+ if not packageinfo then
+ return
+ end
+
+ -- get linkdirs
+ local linkdirs = {}
+ for _, linkdir in ipairs(packageinfo.linkdirs) do
+ table.insert(linkdirs, path.join(packagepath, linkdir))
+ end
+ if #linkdirs == 0 then
+ return
+ end
+
+ -- find library
+ local result = nil
+ for _, link in ipairs(packageinfo.links) do
+ local libinfo = find_library(link, linkdirs)
+ if libinfo then
+ result = result or {}
+ result.links = table.join(result.links or {}, libinfo.link)
+ result.linkdirs = table.join(result.linkdirs or {}, libinfo.linkdir)
+ end
+ end
+
+ -- inherit other package info
+ if result then
+ result.includedirs = {}
+ for _, includedir in ipairs(packageinfo.includedirs) do
+ table.insert(result.includedirs, path.join(packagepath, includedir))
+ end
+ for _, infoname in ipairs({"defines", "languages", "warnings"}) do
+ result[infoname] = packageinfo[infoname]
+ end
+ end
+
+ -- ok?
+ return result
+end
+
+-- find package using the xmake package manager
+--
+-- @param name the package name
+-- @param opt the options, .e.g {verbose = true, version = "1.12.x")
+--
+function main(name, opt)
+
+ -- find package from repository
+ local result = _find_package_from_repo(name, opt)
+
+ -- find package from the given package directories, e.g. packagedir/xxx.pkg
+ if not result and opt.packagedirs then
+ result = _find_package_from_packagedirs(name, opt)
+ end
+ return result
+end