diff options
| author | ruki <[email protected]> | 2019-01-22 22:39:25 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2019-01-22 09:56:36 +0800 |
| commit | de29dc88bc3b7d39d4206d6e2bd034d15b232ca2 (patch) | |
| tree | f247b2624aafd5a30c0a100de93aaeaf50ff7dce /xmake/modules | |
| parent | c92d87e3b872cd303356112a22190d4858a9fcb3 (diff) | |
find package from xmake repo and package directories
Diffstat (limited to 'xmake/modules')
| -rw-r--r-- | xmake/modules/package/manager/find_package.lua | 61 | ||||
| -rw-r--r-- | xmake/modules/package/manager/xmake/find_package.lua | 271 |
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 |
