diff options
| author | ruki <[email protected]> | 2019-01-24 00:48:14 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2019-01-23 22:49:27 +0800 |
| commit | dae284b933cea7f3717a5a0dee3f18304b3fb1e0 (patch) | |
| tree | 4c8e23bb698b570ff5d150f9004106384ff1c359 | |
| parent | 7d9fe778c235da802039bf46c62cd4142f4719e4 (diff) | |
improve lib.detect.find_package
| -rw-r--r-- | xmake/core/sandbox/modules/import/lib/detect/find_package.lua | 528 | ||||
| -rw-r--r-- | xmake/modules/detect/packages/find_libxml2.lua | 27 | ||||
| -rw-r--r-- | xmake/modules/detect/packages/find_mysql.lua | 13 | ||||
| -rw-r--r-- | xmake/modules/detect/packages/find_pcre.lua | 28 | ||||
| -rw-r--r-- | xmake/modules/detect/packages/find_pcre2.lua | 36 | ||||
| -rw-r--r-- | xmake/modules/lib/detect/conan.lua | 151 | ||||
| -rw-r--r-- | xmake/modules/lib/detect/find_package.lua | 96 | ||||
| -rw-r--r-- | xmake/modules/package/manager/find_package.lua | 129 | ||||
| -rw-r--r-- | xmake/modules/package/manager/vcpkg/find_package.lua (renamed from xmake/modules/lib/detect/vcpkg.lua) | 31 |
9 files changed, 246 insertions, 793 deletions
diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_package.lua b/xmake/core/sandbox/modules/import/lib/detect/find_package.lua deleted file mode 100644 index de082c4ee..000000000 --- a/xmake/core/sandbox/modules/import/lib/detect/find_package.lua +++ /dev/null @@ -1,528 +0,0 @@ ---!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 --- - --- define module -local sandbox_lib_detect_find_package = sandbox_lib_detect_find_package or {} - --- load modules -local os = require("base/os") -local path = require("base/path") -local utils = require("base/utils") -local table = require("base/table") -local option = require("base/option") -local global = require("base/global") -local config = require("project/config") -local target = require("project/target") -local project = require("project/project") -local raise = require("sandbox/modules/raise") -local import = require("sandbox/modules/import") -local cache = require("sandbox/modules/import/lib/detect/cache") -local semver = require("base/semver") -local pkg_config = import("lib.detect.pkg_config") - --- find package from the package directories -function sandbox_lib_detect_find_package._find_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 - - -- get interpreter - local interp = project.interpreter() - - -- register filter handler - interp:filter():register("find_package_" .. name, function (variable) - - -- init maps - local maps = - { - arch = opt.arch - , plat = opt.plat - , mode = opt.mode or config.get("mode") - } - - -- 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:load(packagefile, "option", true, true) - if not packageinfos then - raise(errors) - end - - -- clear filter handler - interp:filter():register("find_package_" .. name, nil) - - -- get package info - local packageinfo = packageinfos[name] - if not packageinfo then - return - end - - -- get linkdirs - local linkdirs = {} - for _, linkdir in ipairs(table.wrap(packageinfo.linkdirs)) do - table.insert(linkdirs, path.join(packagepath, linkdir)) - end - if #linkdirs == 0 then - return - end - - -- import find_library - local find_library = import("lib.detect.find_library") - - -- find library - local result = nil - for _, link in ipairs(table.wrap(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(table.wrap(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 from the prefix directories (maybe only include and no links) -function sandbox_lib_detect_find_package._find_from_prefixdirs(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(table.wrap(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(table.wrap(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 - - -- import find_library - local find_library = import("lib.detect.find_library") - - -- 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 modules (detect.packages.find_xxx) -function sandbox_lib_detect_find_package._find_from_modules(name, opt) - - -- "detect.packages.find_xxx" exists? - local find_package = import("detect.packages.find_" .. name, {try = true}) - if find_package then - return find_package(opt) - end -end - --- find package from the pkg-config/brew -function sandbox_lib_detect_find_package._find_from_pkg_config(name, opt) - return import("lib.detect.pkg_config").find(name, opt) -end - --- find package from vcpkg -function sandbox_lib_detect_find_package._find_from_vcpkg(name, opt) - return import("lib.detect.vcpkg").find(name, opt) -end - --- find package from conan -function sandbox_lib_detect_find_package._find_from_conan(name, opt) - return import("lib.detect.conan").find(name, opt) -end - --- find package from the system directories -function sandbox_lib_detect_find_package._find_from_systemdirs(name, opt) - - -- add default search includedirs on pc host - local includedirs = table.wrap(opt.includedirs) - if opt.plat == "linux" or opt.plat == "macosx" then - table.insert(includedirs, "/usr/local/include") - table.insert(includedirs, "/usr/include") - table.insert(includedirs, "/opt/local/include") - table.insert(includedirs, "/opt/include") - end - - -- add default search linkdirs on pc host - local linkdirs = table.wrap(opt.linkdirs) - if opt.plat == "linux" or opt.plat == "macosx" then - table.insert(linkdirs, "/usr/local/lib") - table.insert(linkdirs, "/usr/lib") - table.insert(linkdirs, "/opt/local/lib") - table.insert(linkdirs, "/opt/lib") - if opt.plat == "linux" and opt.arch == "x86_64" then - table.insert(linkdirs, "/usr/local/lib/x86_64-linux-gnu") - table.insert(linkdirs, "/usr/lib/x86_64-linux-gnu") - table.insert(linkdirs, "/usr/lib64") - table.insert(linkdirs, "/opt/lib64") - end - end - - -- attempt to get links from pkg-config - local pkginfo = nil - local version = nil - local links = table.wrap(opt.links) - if #links == 0 then - pkginfo = import("lib.detect.pkg_config").info(name) - if pkginfo then - links = table.wrap(pkginfo.links) - version = pkginfo.version - end - end - - -- uses name as links directly .e.g libname.a - if #links == 0 then - links = table.wrap(name) - end - - -- import find_path and find_library - local find_path = import("lib.detect.find_path") - local find_library = import("lib.detect.find_library") - - -- find library - local result = nil - for _, link in ipairs(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 - - -- find includes - for _, include in ipairs(table.wrap(opt.includes)) do - local includedir = find_path(include, includedirs) - if includedir then - result = result or {} - result.includedirs = table.join(result.includedirs or {}, includedir) - end - end - for _, include in ipairs({name .. "/" .. name .. ".h", name .. ".h"}) do - local includedir = find_path(include, includedirs) - if includedir then - result = result or {} - result.includedirs = table.join(result.includedirs or {}, includedir) - break - end - end - - -- not found? only add links - if not result and pkginfo and pkginfo.links then - result = {links = pkginfo.links} - end - - -- save version - if result and version then - result.version = version - end - - -- ok - return result -end - --- find package --- --- opt.system: --- nil: find local or system packages --- true: only find system package --- false: only find local packages --- -function sandbox_lib_detect_find_package._find(name, opt) - - -- init find scripts - local findscripts = {} - - -- we cannot find it if only find system packages - if opt.system ~= true then - -- find package from the prefix directories - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_prefixdirs) - end - - -- find package from the package directories - if opt.packagedirs then - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_packagedirs) - end - - -- find system package if be not disabled - if opt.system ~= false then - - -- find package from modules - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_modules) - - -- find package from vcpkg (support multi-platforms/architectures) - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_vcpkg) - - -- find package from conan - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_conan) - - -- find package from the current host platform - if opt.plat == os.host() and opt.arch == os.arch() then - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_pkg_config) - table.insert(findscripts, sandbox_lib_detect_find_package._find_from_systemdirs) - end - end - - -- find it - local result = nil - for _, find in ipairs(findscripts) do - result = find(name, opt) - if result then - break - end - end - - -- remove repeat - if result then - result.linkdirs = table.unique(result.linkdirs) - result.includedirs = table.unique(result.includedirs) - end - - -- check valid version - if result and result.version then - local version = semver.new(result.version) - if version then - result.version = version:rawstr() - else - result.version = nil - end - end - - -- ok? - return result -end - --- find package --- --- @param name the package name --- @param opt the package options. --- e.g. { verbose = false, force = false, plat = "iphoneos", arch = "arm64", mode = "debug", version = "1.0.1", --- linkdirs = {"/usr/lib"}, includedirs = "/usr/include", links = {"ssl"}, includes = {"ssl.h"} --- packagedirs = {"/tmp/packages"}, system = true, cachekey = "xxxx"} --- --- @return {links = {"ssl", "crypto", "z"}, linkdirs = {"/usr/local/lib"}, includedirs = {"/usr/local/include"}} --- --- @code --- --- local package = find_package("openssl") --- local package = find_package("openssl", {version = "1.0.*"}) --- local package = find_package("openssl", {plat = "iphoneos"}) --- local package = find_package("openssl", {linkdirs = {"/usr/lib", "/usr/local/lib"}, includedirs = "/usr/local/include", version = "1.0.1"}) --- local package = find_package("openssl", {linkdirs = {"/usr/lib", "/usr/local/lib", links = {"ssl", "crypto"}, includes = {"ssl.h"}}) --- --- @endcode --- -function sandbox_lib_detect_find_package.main(name, opt) - - -- init options - opt = opt or {} - opt.plat = opt.plat or config.get("plat") or os.host() - opt.arch = opt.arch or config.get("arch") or os.arch() - - -- init cache key - local key = "find_package_" .. opt.plat .. "_" .. opt.arch - if opt.version then - key = key .. "_" .. opt.version - end - if opt.cachekey then - key = key .. "_" .. opt.cachekey - end - if opt.mode then - key = key .. "_" .. opt.mode - end - - -- attempt to get result from cache first - local cacheinfo = cache.load(key) - local result = cacheinfo[name] - if result ~= nil and not opt.force then - return utils.ifelse(result, result, nil) - end - - -- get version from the name, e.g. find("zlib ~1.x") - local nameinfo = name:split("%s+") - local require_ver = opt.version - if #nameinfo > 1 then - name = nameinfo[1] - require_ver = require_ver or nameinfo[2] - end - - -- find package - result = sandbox_lib_detect_find_package._find(name, opt) - - -- match version? - if require_ver and result then - if not result.version or not semver.satisfies(result.version, require_ver) then - result = nil - end - end - - -- cache result - cacheinfo[name] = result and result or false - cache.save(key, cacheinfo) - - -- trace - if opt.verbose or option.get("verbose") then - if result then - utils.cprint("checking for the %s ... ${color.success}%s", name, result.version and result.version or "${text.success}") - else - utils.cprint("checking for the %s ... ${color.nothing}${text.nothing}", name) - end - end - - -- ok? - return result -end - --- return module -return sandbox_lib_detect_find_package diff --git a/xmake/modules/detect/packages/find_libxml2.lua b/xmake/modules/detect/packages/find_libxml2.lua index 307ac0899..2a71e3b99 100644 --- a/xmake/modules/detect/packages/find_libxml2.lua +++ b/xmake/modules/detect/packages/find_libxml2.lua @@ -23,7 +23,7 @@ -- -- imports -import("lib.detect.pkg_config") +import("package.manager.find_package") -- find libxml2 -- @@ -33,16 +33,25 @@ import("lib.detect.pkg_config") -- function main(opt) - -- find package from the current host platform - if opt.plat == os.host() and opt.arch == os.arch() then - local result = pkg_config.find("libxml2") - if result then - local includedirs = {} - for _, includedir in ipairs(result.includedirs) do + -- find package by the builtin script + local result = opt.find_package("libxml2", opt) + + -- find package from the homebrew package manager + if not result and opt.plat == os.host() and opt.arch == os.arch() then + result = find_package("brew::libxml2/libxml-2.0", opt) + end + + -- patch "include/libxml2" + if result then + local includedirs = {} + for _, includedir in ipairs(result.includedirs) do + if includedir:endswith("include") then table.insert(includedirs, path.join(includedir, "libxml2")) + else + table.insert(includedirs, includedir) end - result.includedirs = includedirs - return result end + result.includedirs = includedirs end + return result end diff --git a/xmake/modules/detect/packages/find_mysql.lua b/xmake/modules/detect/packages/find_mysql.lua index 430bf5149..eedd2fad4 100644 --- a/xmake/modules/detect/packages/find_mysql.lua +++ b/xmake/modules/detect/packages/find_mysql.lua @@ -23,7 +23,7 @@ -- -- imports -import("lib.detect.pkg_config") +import("package.manager.find_package") -- find mysql -- @@ -33,8 +33,13 @@ import("lib.detect.pkg_config") -- function main(opt) - -- find package from the current host platform - if opt.plat == os.host() and opt.arch == os.arch() then - return pkg_config.find("mysqlclient") + -- find package by the builtin script + local result = opt.find_package("mysql", opt) + + -- find package from the homebrew package manager + if not result and opt.plat == os.host() and opt.arch == os.arch() then + result = find_package("brew::mysqlclient", opt) end + return result end + diff --git a/xmake/modules/detect/packages/find_pcre.lua b/xmake/modules/detect/packages/find_pcre.lua index 149f29c90..f109673f4 100644 --- a/xmake/modules/detect/packages/find_pcre.lua +++ b/xmake/modules/detect/packages/find_pcre.lua @@ -23,8 +23,7 @@ -- -- imports -import("lib.detect.vcpkg") -import("lib.detect.pkg_config") +import("package.manager.find_package") -- find pcre -- @@ -34,28 +33,17 @@ import("lib.detect.pkg_config") -- function main(opt) - -- find package from vcpkg first - local result = vcpkg.find("pcre", opt) - if result then - local links = {} - for _, link in ipairs(result.links) do - links[link] = true - end - for _, width in ipairs({"", "16", "32"}) do - if links["pcre" .. width] then - result.links = {"pcre" .. width} - return result - end - end - end + -- find package by the builtin script + local result = opt.find_package("pcre", opt) - -- find package from the current host platform - if opt.plat == os.host() and opt.arch == os.arch() then + -- find package from the homebrew package manager + if not result and opt.plat == os.host() and opt.arch == os.arch() then for _, width in ipairs({"", "16", "32"}) do - local result = pkg_config.find("libpcre" .. width, {brewhint = "pcre"}) + result = find_package("brew::pcre/libpcre" .. width, opt) if result then - return result + break end end end + return result end diff --git a/xmake/modules/detect/packages/find_pcre2.lua b/xmake/modules/detect/packages/find_pcre2.lua index 8754382f3..c65022c9c 100644 --- a/xmake/modules/detect/packages/find_pcre2.lua +++ b/xmake/modules/detect/packages/find_pcre2.lua @@ -23,8 +23,7 @@ -- -- imports -import("lib.detect.vcpkg") -import("lib.detect.pkg_config") +import("package.manager.find_package") -- find pcre2 -- @@ -34,30 +33,31 @@ import("lib.detect.pkg_config") -- function main(opt) - -- find package from vcpkg first - local result = vcpkg.find("pcre2", opt) - if result then - local links = {} - for _, link in ipairs(result.links) do - links[link] = true - end + -- find package by the builtin script + local result = opt.find_package("pcre2", opt) + + -- find package from the homebrew package manager + if not result and opt.plat == os.host() and opt.arch == os.arch() then for _, width in ipairs({"8", "16", "32"}) do - if links["pcre2-" .. width] then - result.links = {"pcre2-" .. width} - result.defines = {"PCRE2_CODE_UNIT_WIDTH=" .. width} - return result + result = find_package("brew::pcre2/libpcre2-" .. width, opt) + if result then + break end end end - -- find package from the current host platform - if opt.plat == os.host() and opt.arch == os.arch() then + -- patch PCRE2_CODE_UNIT_WIDTH + if result and not result.defines then + local links = {} + for _, link in ipairs(result.links) do + links[link] = true + end for _, width in ipairs({"8", "16", "32"}) do - local result = pkg_config.find("libpcre2-" .. width, {brewhint = "pcre2"}) - if result then + if links["pcre2-" .. width] then result.defines = {"PCRE2_CODE_UNIT_WIDTH=" .. width} - return result + break end end end + return result end diff --git a/xmake/modules/lib/detect/conan.lua b/xmake/modules/lib/detect/conan.lua deleted file mode 100644 index 4660e0670..000000000 --- a/xmake/modules/lib/detect/conan.lua +++ /dev/null @@ -1,151 +0,0 @@ ---!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 conan.lua --- - --- imports -import("lib.detect.find_file") -import("lib.detect.find_library") -import("detect.sdks.find_conandir") -import("core.project.config") -import("core.project.target") - --- get package info --- --- @param name the package name --- @param opt the argument options, {version = true, arch = "", plat = "", mode = "", conandir = ""} --- --- @return {links = {"ssl", "crypto", "z"}, linkdirs = {""}, includedirs = {""}, version = ""} --- --- @code --- --- local pkginfo = conan.info("openssl") --- --- @endcode --- -function info(name, opt) - - -- init options - opt = opt or {} - - -- attempt to find the conan root directory - local conandir = find_conandir(opt.conandir) - if not conandir then - return - end - - -- init cache - _g._INFO = _g._INFO or {} - - -- get it from cache first - local key = name - local result = _g._INFO[key] - if result ~= nil then - return result and result or nil - end - - -- find the package conanmanifest file, .e.g ~/.conan/data/pcre2/10.31/bincrafters/stable/package/519f362e9832d00859a5da6d5f76da34ecf8e237/conanmanifest.txt - local manifestfile = find_file("conanmanifest.txt", path.join(conandir, "data", name, "*", "*", "*", "package", "*")) - - -- save includedirs, linkdirs and links - local info = manifestfile and io.readfile(manifestfile) or nil - if info then - local installdir = path.directory(manifestfile) - result = {includedirs = path.join(installdir, "include"), linkdirs = path.join(installdir, "lib")} - for _, line in ipairs(info:split('\n')) do - line = line:split(':')[1]:trim() - if line:startswith("lib") and (line:endswith(".lib") or line:endswith(".a")) then - result.links = result.links or {} - table.insert(result.links, target.linkname(path.filename(line))) - end - end - end - - -- save version - if result and manifestfile then - result.version = manifestfile:match(path.join(name, "(%d+%.?%d*%.?%d*.-)")) - if not result.version then - result.version = manifestfile:match(path.join(name, "(%d+%.?%d*%.-)")) - end - end - - -- save result to cache - _g._INFO[key] = result and result or false - - -- ok? - return result -end - --- find package --- --- @param name the package name --- @param opt the argument options, {version = "1.0.1", links = {...}, conandir = ""} --- --- @return {links = {"ssl", "crypto", "z"}, linkdirs = {""}, includedirs = {""}} --- --- @code --- --- local pkginfo = conan.find("openssl") --- --- @endcode --- -function find(name, opt) - - -- get package info - local pkginfo = info(name, opt) - if not pkginfo then - return - end - - -- match version? - opt = opt or {} - if opt.version and pkginfo.version ~= opt.version then - return - end - - -- get links - local links = pkginfo.links - if not links or #links == 0 then - links = opt.links - end - - -- find library - local result = nil - for _, link in ipairs(table.wrap(links)) do - local libinfo = find_library(link, pkginfo.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 - - -- found? - if result and result.links then - result.linkdirs = table.unique(result.linkdirs) - result.includedirs = table.join(result.includedirs or {}, pkginfo.includedirs) - end - - -- ok? - return result -end - diff --git a/xmake/modules/lib/detect/find_package.lua b/xmake/modules/lib/detect/find_package.lua new file mode 100644 index 000000000..6c069dd67 --- /dev/null +++ b/xmake/modules/lib/detect/find_package.lua @@ -0,0 +1,96 @@ +--!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.option") +import("core.project.config") +import("lib.detect.cache") +import("package.manager.find_package") + +-- find package using the package manager +-- +-- @param name the package name +-- e.g. zlib 1.12.x (try all), xmake::zlib 1.12.x, brew::zlib, brew::pcre/libpcre16, vcpkg::zlib, conan::OpenSSL/1.0.2n@conan/stable +-- @param opt the options +-- e.g. { verbose = false, force = false, plat = "iphoneos", arch = "arm64", mode = "debug", version = "1.0.x", +-- linkdirs = {"/usr/lib"}, includedirs = "/usr/include", links = {"ssl"}, includes = {"ssl.h"} +-- packagedirs = {"/tmp/packages"}, system = true, cachekey = "xxxx"} +-- +-- @return {links = {"ssl", "crypto", "z"}, linkdirs = {"/usr/local/lib"}, includedirs = {"/usr/local/include"}} +-- +-- @code +-- +-- local package = find_package("openssl") +-- local package = find_package("openssl", {version = "1.0.*"}) +-- local package = find_package("openssl", {plat = "iphoneos"}) +-- local package = find_package("openssl", {linkdirs = {"/usr/lib", "/usr/local/lib"}, includedirs = "/usr/local/include", version = "1.0.1"}) +-- local package = find_package("openssl", {linkdirs = {"/usr/lib", "/usr/local/lib", links = {"ssl", "crypto"}, includes = {"ssl.h"}}) +-- +-- @endcode +-- +function main(name, opt) + + -- get the copied options + opt = table.copy(opt) + opt.plat = opt.plat or config.get("plat") or os.host() + opt.arch = opt.arch or config.get("arch") or os.arch() + + -- init cache key + local key = "find_package_" .. opt.plat .. "_" .. opt.arch + if opt.version then + key = key .. "_" .. opt.version + end + if opt.cachekey then + key = key .. "_" .. opt.cachekey + end + if opt.mode then + key = key .. "_" .. opt.mode + end + + -- attempt to get result from cache first + local cacheinfo = cache.load(key) + local result = cacheinfo[name] + if result ~= nil and not opt.force then + return result and result or nil + end + + -- find package + result = find_package(name, opt) + + -- cache result + cacheinfo[name] = result and result or false + cache.save(key, cacheinfo) + + -- trace + if opt.verbose or option.get("verbose") then + if result then + cprint("checking for the %s ... ${color.success}%s", name, result.version and result.version or "${text.success}") + else + cprint("checking for the %s ... ${color.nothing}${text.nothing}", name) + end + end + + -- ok? + return result +end diff --git a/xmake/modules/package/manager/find_package.lua b/xmake/modules/package/manager/find_package.lua index 41c342095..0cd2463b8 100644 --- a/xmake/modules/package/manager/find_package.lua +++ b/xmake/modules/package/manager/find_package.lua @@ -26,51 +26,44 @@ import("core.base.semver") import("core.base.option") import("core.project.config") -import("lib.detect.cache") --- find package +-- find package with the builtin rule -- -- 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) +function _find_package_with_builtin_rule(package_name, opt) - -- get managers + -- we cannot find it from xmake repo and package directories if only find system packages local managers = {} - if manager_name then - table.insert(managers, manager_name) - else + if opt.system ~= true then + table.insert(managers, "xmake") + end - -- 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 system package if be not disabled - if opt.system ~= false then + -- find it from homebrew + if not is_host("windows") and (opt.mode == nil or opt.mode == "release") then + table.insert(managers, "brew") + end - -- find it from homebrew - if not is_host("windows") and (opt.mode == nil or opt.mode == "release") then - table.insert(managers, "brew") - end + -- find it from vcpkg (support multi-platforms/architectures) +-- table.insert(managers, "vcpkg") - -- find it from vcpkg - table.insert(managers, "vcpkg") + -- find it from conan (support multi-platforms/architectures) +-- table.insert(managers, "conan") - -- find it from conan - table.insert(managers, "conan") - - -- only support the current host platform and architecture - if opt.plat == os.host() and opt.arch == os.arch() and (opt.mode == nil or opt.mode == "release") then + -- only support the current host platform and architecture + if opt.plat == os.host() and opt.arch == os.arch() and (opt.mode == nil or opt.mode == "release") then - -- find it from pkg-config - table.insert(managers, "pkg_config") + -- find it from pkg-config + table.insert(managers, "pkg_config") - -- find it from system - table.insert(managers, "system") - end + -- find it from system + table.insert(managers, "system") end end @@ -84,6 +77,50 @@ function _find_package(manager_name, package_name, opt) end end + -- check result? + if result and not result.includedirs then + result = nil + end + + -- ok? + return result +end + +-- find package +function _find_package(manager_name, package_name, opt) + + -- find package from the given package manager + local result = nil + if manager_name then + + -- trace + dprint("finding %s from %s ..", package_name, manager_name) + + -- find it + result = import("package.manager." .. manager_name .. ".find_package", {anonymous = true})(package_name, opt) + else + + -- find package from the given custom "detect.packages.find_xxx" script + local builtin = false + local find_package = import("detect.packages.find_" .. package_name, {anonymous = true, try = true}) + if find_package then + + -- trace + dprint("finding %s from find_%s ..", package_name, package_name) + + -- find it + result = find_package(table.join(opt, { find_package = function (...) + builtin = true + return _find_package_with_builtin_rule(...) + end})) + end + + -- find package with the builtin rule + if not result and not builtin then + result = _find_package_with_builtin_rule(package_name, opt) + end + end + -- found? if result then @@ -113,7 +150,7 @@ end -- @param opt the options -- e.g. { verbose = false, force = false, plat = "iphoneos", arch = "arm64", mode = "debug", version = "1.0.x", -- linkdirs = {"/usr/lib"}, includedirs = "/usr/include", links = {"ssl"}, includes = {"ssl.h"} --- packagedirs = {"/tmp/packages"}, system = true, cachekey = "xxxx"} +-- packagedirs = {"/tmp/packages"}, system = true} -- -- @return {links = {"ssl", "crypto", "z"}, linkdirs = {"/usr/local/lib"}, includedirs = {"/usr/local/include"}} -- @@ -148,25 +185,6 @@ function main(name, opt) package_name, require_version = unpack(package_name:trim():split("%s+")) opt.version = require_version or opt.version - -- init cache key - local key = "find_package_" .. opt.plat .. "_" .. opt.arch - if opt.version then - key = key .. "_" .. opt.version - end - if opt.cachekey then - key = key .. "_" .. opt.cachekey - end - if opt.mode then - key = key .. "_" .. opt.mode - end - - -- attempt to get result from cache first - local cacheinfo = cache.load(key) - local result = cacheinfo[package_name] - if result ~= nil and not opt.force then - return result and result or nil - end - -- find package result = _find_package(manager_name, package_name, opt) @@ -177,19 +195,6 @@ function main(name, opt) end end - -- cache result - cacheinfo[package_name] = result and result or false - cache.save(key, cacheinfo) - - -- trace - if opt.verbose or option.get("verbose") then - if result then - cprint("checking for the %s ... ${color.success}%s", package_name, result.version and result.version or "${text.success}") - else - cprint("checking for the %s ... ${color.nothing}${text.nothing}", package_name) - end - end - -- ok? return result end diff --git a/xmake/modules/lib/detect/vcpkg.lua b/xmake/modules/package/manager/vcpkg/find_package.lua index 573830fef..9bb06d767 100644 --- a/xmake/modules/lib/detect/vcpkg.lua +++ b/xmake/modules/package/manager/vcpkg/find_package.lua @@ -19,7 +19,7 @@ -- Copyright (C) 2015 - 2019, TBOOX Open Source Group. -- -- @author ruki --- @file vcpkg.lua +-- @file find_package.lua -- -- imports @@ -173,3 +173,32 @@ function find(name, opt) return result end +-- find package from the brew package manager +-- +-- @param name the package name, e.g. zlib, pcre/libpcre16 +-- @param opt the options, .e.g {verbose = true, version = "1.12.x") +-- +function main(name, opt) + + -- find brew + local brew = find_tool("brew") + if not brew then + return + end + + -- parse name, .e.g pcre/libpcre16 + local nameinfo = name:split('/') + local pcname = nameinfo[2] or nameinfo[1] + + -- find the prefix directory of brew + local brew_pkg_root = try { function () return os.iorunv(brew.program, {"--prefix"}) end } or "/usr/local" + brew_pkg_root = path.join(brew_pkg_root:trim(), opt.plat == "macosx" and "Cellar" or "opt") + local pcfile = find_file(pcname .. ".pc", path.join(brew_pkg_root, nameinfo[1], "*/lib/pkgconfig")) + if not pcfile then + return + end + + -- do find + opt.configdirs = path.directory(pcfile) + return pkg_config.find(pcname, opt) +end |
