diff options
| author | ruki <[email protected]> | 2019-03-20 14:54:49 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2019-03-20 14:54:49 +0800 |
| commit | 85deccc73a0278e01fa8580b68b38f16e0598bf7 (patch) | |
| tree | a9a446a5be5ca662525df921e50ce66029bc3359 /xmake/actions/require | |
| parent | 57506c7b8ba8941ebac3676a241f8444e0079a56 (diff) | |
| parent | 8bb6ddf5c40f15fe6570f73dc5c4e5295ce95180 (diff) | |
Merge branch 'repo' into dev
Diffstat (limited to 'xmake/actions/require')
| -rw-r--r-- | xmake/actions/require/clean.lua | 87 | ||||
| -rw-r--r-- | xmake/actions/require/clear.lua | 40 | ||||
| -rw-r--r-- | xmake/actions/require/impl/action/download.lua | 12 | ||||
| -rw-r--r-- | xmake/actions/require/impl/action/install.lua | 121 | ||||
| -rw-r--r-- | xmake/actions/require/impl/action/prefix/install.lua | 352 | ||||
| -rw-r--r-- | xmake/actions/require/impl/action/prefix/uninstall.lua | 53 | ||||
| -rw-r--r-- | xmake/actions/require/impl/environment.lua | 105 | ||||
| -rw-r--r-- | xmake/actions/require/impl/package.lua | 112 | ||||
| -rw-r--r-- | xmake/actions/require/info.lua | 113 | ||||
| -rw-r--r-- | xmake/actions/require/install.lua | 39 | ||||
| -rw-r--r-- | xmake/actions/require/list.lua | 14 | ||||
| -rw-r--r-- | xmake/actions/require/main.lua | 14 | ||||
| -rw-r--r-- | xmake/actions/require/unlink.lua | 77 | ||||
| -rw-r--r-- | xmake/actions/require/xmake.lua | 3 |
14 files changed, 494 insertions, 648 deletions
diff --git a/xmake/actions/require/clean.lua b/xmake/actions/require/clean.lua new file mode 100644 index 000000000..cb69d85a4 --- /dev/null +++ b/xmake/actions/require/clean.lua @@ -0,0 +1,87 @@ +--!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 clean.lua +-- + +-- imports +import("core.base.option") +import("core.project.cache") +import("core.package.package") + +-- clean all installed package caches +function main() + + -- trace + print("clear all package caches ..") + + -- clear cache directory + os.rm(package.cachedir()) + + -- clear require cache + local require_cache = cache("local.require") + require_cache:clear() + require_cache:flush() + + -- trace + print("clear all unused packages ..") + + -- clear all unused packages + local installdir = package.installdir() + for _, references_file in ipairs(os.files(path.join(installdir, "*", "*", "*", "*", "references.txt"))) do + local references = io.load(references_file) + if references then + local found = false + for projectdir, refdate in pairs(references) do + if os.isdir(projectdir) then + found = true + break + end + end + if not found then + + -- get package directory + local packagedir = path.directory(references_file) + print("remove %s ..", packagedir) + + -- get confirm + local confirm = option.get("yes") + if confirm == nil then + + -- show tips + cprint("${bright color.warning}note: ${clear}no projects are using this package, remove it (pass -y to skip confirm)?") + cprint("please input: y (y/n)") + + -- get answer + io.flush() + local answer = io.read() + if answer == 'y' or answer == '' then + confirm = true + end + end + if confirm then + os.rm(packagedir) + end + end + end + end +end + diff --git a/xmake/actions/require/clear.lua b/xmake/actions/require/clear.lua deleted file mode 100644 index ffe73ed26..000000000 --- a/xmake/actions/require/clear.lua +++ /dev/null @@ -1,40 +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 clear.lua --- - --- imports -import("core.project.cache") -import("core.package.package") - --- clear all installed package caches -function main() - - -- clear cache directory - os.rm(package.cachedir()) - - -- clear require cache - local require_cache = cache("local.require") - require_cache:clear() - require_cache:flush() -end - diff --git a/xmake/actions/require/impl/action/download.lua b/xmake/actions/require/impl/action/download.lua index a01d9aef2..9eba21afd 100644 --- a/xmake/actions/require/impl/action/download.lua +++ b/xmake/actions/require/impl/action/download.lua @@ -91,13 +91,13 @@ function _download(package, url, sourcedir, url_alias, url_excludes) -- get package file local packagefile = path.filename(url) - -- get sha256 - local sha256 = package:sha256(url_alias) - assert(sha256, "cannot get sha256 of %s in package(%s)", url, package:name()) + -- get sourcehash + local sourcehash = package:sourcehash(url_alias) + assert(sourcehash, "cannot get source hash of %s in package(%s)", url, package:name()) -- the package file have been downloaded? local cached = true - if option.get("force") or not os.isfile(packagefile) or sha256 ~= hash.sha256(packagefile) then + if option.get("force") or not os.isfile(packagefile) or sourcehash ~= hash.sha256(packagefile) then -- no cached cached = false @@ -109,7 +109,7 @@ function _download(package, url, sourcedir, url_alias, url_excludes) http.download(url, packagefile) -- check hash - if sha256 and sha256 ~= hash.sha256(packagefile) then + if sourcehash and sourcehash ~= hash.sha256(packagefile) then raise("unmatched checksum!") end end @@ -146,7 +146,7 @@ function _urls(package) for _, url in ipairs(package:urls()) do if git.checkurl(url) then table.insert(urls[1], url) - elseif package:sha256(package:url_alias(url)) then + elseif package:sourcehash(package:url_alias(url)) then table.insert(urls[2], url) end end diff --git a/xmake/actions/require/impl/action/install.lua b/xmake/actions/require/impl/action/install.lua index 181bded44..6bb9d85ca 100644 --- a/xmake/actions/require/impl/action/install.lua +++ b/xmake/actions/require/impl/action/install.lua @@ -27,7 +27,62 @@ import("core.base.option") import("core.project.target") import("test") import(".utils.filter") -import("prefix") + +-- patch pkgconfig if not exists +function _patch_pkgconfig(package) + + -- get lib/pkgconfig/*.pc file + local pcfile = path.join(package:installdir(), "lib", "pkgconfig", package:name() .. ".pc") + if os.isfile(pcfile) then + return + end + + -- trace + vprint("patching %s ..", pcfile) + + -- fetch package + local fetchinfo = package:fetchdeps() + if not fetchinfo then + return + end + + -- get libs + local libs = "" + for _, linkdir in ipairs(fetchinfo.linkdirs) do + libs = libs .. "-L" .. linkdir + end + libs = libs .. " -L${libdir}" + for _, link in ipairs(fetchinfo.links) do + libs = libs .. " -l" .. link + end + for _, link in ipairs(fetchinfo.syslinks) do + libs = libs .. " -l" .. link + end + + -- cflags + local cflags = "" + for _, includedir in ipairs(fetchinfo.includedirs) do + cflags = cflags .. "-I" .. includedir + end + cflags = cflags .. " -I${includedir}" + + -- patch a *.pc file + local file = io.open(pcfile, 'w') + if file then + file:print("prefix=%s", package:installdir()) + file:print("exec_prefix=${prefix}") + file:print("libdir=${exec_prefix}/lib") + file:print("includedir=${prefix}/include") + file:print("") + file:print("Name: %s", package:name()) + file:print("Description: %s", package:description()) + file:print("Version: %s", package:version_str()) + file:print("Libs: %s", libs) + file:print("Libs.private: ") + file:print("Cflags: %s", cflags) + file:close() + end +end -- install the given package function main(package) @@ -80,6 +135,7 @@ function main(package) local installtask = function () -- install the third-party package directly, e.g. brew::pcre2/libpcre2-8, conan::OpenSSL/1.0.2n@conan/stable + local installed_now = false if package:is3rd() then local script = package:script("install") if script ~= nil then @@ -87,16 +143,17 @@ function main(package) end else - -- uninstall it from the prefix directory first - prefix.uninstall(package) - -- build and install package to the install directory - local installedfile = path.join(package:installdir(), "installed.txt") - if not os.isfile(installedfile) then + if option.get("force") or not package:manifest_load() then -- clean install directory first os.tryrm(package:installdir()) + -- enter the environments of all package dependencies + for _, dep in ipairs(package:orderdeps()) do + dep:envs_enter() + end + -- do install for i = 1, 3 do local script = scripts[i] @@ -105,16 +162,39 @@ function main(package) end end - -- mark as installed - io.writefile(installedfile, "") + -- leave the environments of all package dependencies + for _, dep in irpairs(package:orderdeps()) do + dep:envs_leave() + end + + -- save the package info to the manifest file + package:manifest_save() + installed_now = true end + end + + -- enter the package environments + package:envs_enter() + + -- fetch package and force to flush the cache + local fetchinfo = package:fetch({force = true}) + if option.get("verbose") or option.get("diagnosis") then + print(fetchinfo) + end + assert(fetchinfo, "fetch %s failed!", tipname) + + -- this package is installed now + if installed_now then - -- install to the prefix directory - prefix.install(package) + -- patch pkg-config files for package + _patch_pkgconfig(package) -- test it test(package) end + + -- leave the package environments + package:envs_leave() end -- install package @@ -124,13 +204,6 @@ function main(package) process.asyncrun(installtask) end - -- fetch package and force to flush the cache - local fetchinfo = package:fetch({force = true}) - if option.get("verbose") or option.get("diagnosis") then - print(fetchinfo) - end - assert(fetchinfo, "fetch %s failed!", tipname) - -- trace cprint("${color.success}${text.success}") end, @@ -147,6 +220,20 @@ function main(package) -- trace cprint("${color.failure}${text.failure}") + -- leave the package environments + package:envs_leave() + + -- copy the invalid package directory to cache + local installdir = package:installdir() + if os.isdir(installdir) then + local installdir_failed = path.join(package:cachedir(), "installdir.failed") + os.tryrm(installdir_failed) + if not os.isdir(installdir_failed) then + os.cp(installdir, installdir_failed) + end + end + os.tryrm(installdir) + -- failed if not package:requireinfo().optional then raise("install failed!") diff --git a/xmake/actions/require/impl/action/prefix/install.lua b/xmake/actions/require/impl/action/prefix/install.lua deleted file mode 100644 index 041c3c983..000000000 --- a/xmake/actions/require/impl/action/prefix/install.lua +++ /dev/null @@ -1,352 +0,0 @@ ---!The Make-like install 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 install.lua --- - --- imports -import("core.base.global") -import("core.project.config") -import("core.project.target") -import("uninstall") - --- copy files to the prefix directory -function _copy(mode, pattern) - - -- do install - local prefixdir = _g.prefixdir - local installdir = _g.installdir - local relative_pathes = _g.relative_pathes - for _, sourcepath in ipairs(os.match(path.join(installdir, pattern), mode)) do - - -- get relative path - local relative_path = path.relative(sourcepath, installdir) - - -- trace - vprint("copying %s ..", relative_path) - - -- copy file to the prefix directory - os.vcp(sourcepath, path.absolute(relative_path, prefixdir)) - - -- save this relative path - table.insert(relative_pathes, relative_path) - end -end - --- copy directories to the prefix directory -function _copy_dirs(pattern) - _copy('d', pattern) -end - --- copy files to the prefix directory -function _copy_files(pattern) - _copy('f', pattern) -end - --- copy files and directories to the prefix directory -function _copy_filedirs(pattern) - _copy('a', pattern) -end - --- find the prefix info file of the previous package -function _find_prefixfile(originpath) - local parentdir = path.directory(originpath) - while parentdir and os.isdir(parentdir) and parentdir ~= "/" do - local relative_path = path.relative(parentdir, path.join(global.directory(), "installed")) - local prefixfile_local = path.join(config.directory(), "prefix", "info", relative_path, "info.txt") - if os.isfile(prefixfile_local) then - return prefixfile_local - end - local prefixfile_global = path.join(global.directory(), "prefix", "info", relative_path, "info.txt") - if os.isfile(prefixfile_global) then - return prefixfile_global - end - parentdir = path.directory(parentdir) - end -end - --- do link -function _do_link(sourcepath, relativepath) - - -- link conflicts? - local destpath = path.absolute(relativepath, _g.prefixdir) - if os.islink(destpath) then - - -- get the original path of destpath - local originpath = os.readlink(destpath) - - -- fix conflicts - if os.isdir(sourcepath) and os.isdir(originpath) then - - -- trace - vprint("unlinking %s ..", relativepath) - - - -- find the prefix info file of the previous package - local prefixfile = _find_prefixfile(originpath) - - -- get the prefix info - local prefixinfo = nil - if prefixfile and os.isfile(prefixfile) then - prefixinfo = io.load(prefixfile) - end - - -- remove the previous link - os.rm(destpath) - if prefixinfo then - for idx, installfile in ipairs(prefixinfo.installed) do - if installfile == relativepath then - table.remove(prefixinfo.installed, idx) - break - end - end - end - - -- expand and relink the previous directories - for _, filedir in ipairs(os.filedirs(path.join(originpath, "*"))) do - - -- get file or directory name - local filename = path.filename(filedir) - - -- trace - vprint("relinking %s ..", path.join(relativepath, filename)) - - -- do link - os.vln(filedir, path.join(destpath, filename)) - - -- save this relative path - table.insert(prefixinfo.installed, path.join(relativepath, filename)) - end - - -- update the previous prefix info file - if prefixinfo then - io.save(prefixfile, prefixinfo) - end - - -- link the child pathes - for _, filedir in ipairs(os.filedirs(path.join(sourcepath, "*"))) do - _do_link(filedir, path.join(relativepath, path.filename(filedir))) - end - - -- fix broken link path - elseif os.isdir(sourcepath) and not os.exists(originpath) then - - -- remove the broken link path - os.rm(destpath) - - -- trace - vprint("linking %s ..", relativepath) - - -- do link - os.vln(sourcepath, destpath) - - -- save this relative path - table.insert(_g.relative_pathes, relativepath) - else - -- link conflicts - os.raise("cannot link %s => %s", sourcepath, destpath) - end - elseif os.isdir(destpath) then - - -- link the child pathes - for _, filedir in ipairs(os.filedirs(path.join(sourcepath, "*"))) do - _do_link(filedir, path.join(relativepath, path.filename(filedir))) - end - else - - -- trace - vprint("linking %s ..", relativepath) - - -- do link - os.vln(sourcepath, destpath) - - -- save this relative path - table.insert(_g.relative_pathes, relativepath) - end -end - --- link files to the prefix directory -function _link(mode, pattern) - local installdir = _g.installdir - for _, sourcepath in ipairs(os.match(path.join(installdir, pattern), mode)) do - _do_link(sourcepath, path.relative(sourcepath, installdir)) - end -end - --- link directories to the prefix directory -function _link_dirs(pattern) - _link('d', pattern) -end - --- link files to the prefix directory -function _link_files(pattern) - _link('f', pattern) -end - --- link files and directories to the prefix directory -function _link_filedirs(pattern) - _link('a', pattern) -end - --- patch pkgconfig if not exists -function _patch_pkgconfig(package) - - -- get lib/pkgconfig/*.pc file - local pcfile = path.join(package:installdir("lib", "pkgconfig"), package:name() .. ".pc") - if os.isfile(pcfile) then - return - end - - -- trace - vprint("patching %s ..", pcfile) - - -- get libs - local libs = "" - for _, linkdir in ipairs(package:getvar("linkdirs")) do - libs = libs .. "-L" .. linkdir - end - libs = libs .. " -L${libdir}" - local links = package:getvar("links") - if links then - for _, link in ipairs(links) do - libs = libs .. " -l" .. link - end - else - local found = false - for _, libfile in ipairs(os.files(path.join(package:installdir("lib"), "*.a"))) do - local link = target.linkname(path.filename(libfile)) - if link then - libs = libs .. " -l" .. link - found = true - end - end - if not found then - for _, libfile in ipairs(os.files(path.join(package:installdir("lib"), "*.so"))) do - local link = target.linkname(path.filename(libfile)) - if link then - libs = libs .. " -l" .. link - end - end - end - end - for _, link in ipairs(package:getvar("syslinks")) do - libs = libs .. " -l" .. link - end - - -- cflags - local cflags = "" - for _, includedir in ipairs(package:getvar("includedirs")) do - cflags = cflags .. "-I" .. includedir - end - cflags = cflags .. " -I${includedir}" - - -- patch a *.pc file - local file = io.open(pcfile, 'w') - if file then - file:print("prefix=%s", package:prefixdir()) - file:print("exec_prefix=${prefix}") - file:print("libdir=${exec_prefix}/lib") - file:print("includedir=${prefix}/include") - file:print("") - file:print("Name: %s", package:name()) - file:print("Description: %s", package:description()) - file:print("Version: %s", package:version_str()) - file:print("Libs: %s", libs) - file:print("Libs.private: ") - file:print("Cflags: %s", cflags) - file:close() - end -end - --- install package with link -function _install_with_link(package) - _link_files("bin/*") - _link_files("sbin/*") - _link_filedirs("include/*") - _link_filedirs("lib/*") - _link_filedirs("share/*|info") - _link_filedirs("share/info/*|dir") -end - --- install package without link (windows) -function _install_without_link(package) - if package:kind() == "binary" then - _copy_filedirs("**") - else - _copy_filedirs("lib/**") - _copy_filedirs("include/**") - end -end - --- install package -function _install(package) - - -- patch pkgconfig if not exists - if not is_plat("windows") then - _patch_pkgconfig(package) - end - - -- install package to the prefix directory - if is_host("windows") then - _install_without_link(package) - else - _install_with_link(package) - end -end - --- install package to the prefix directory -function main(package) - - -- init some pathes - _g.prefixdir = package:prefixdir() - _g.installdir = package:installdir() - _g.relative_pathes = {} - - -- trace - vprint("installing %s to %s ..", _g.installdir, _g.prefixdir) - - -- install to the prefix directory - local relative_pathes = {} - try - { - function () - _install(package) - end, - finally - { - function (ok, errors) - -- save the prefix info to file - local prefixinfo = package:prefixinfo() - prefixinfo.installed = _g.relative_pathes - io.save(package:prefixfile(), prefixinfo) - - -- register this package - package:register() - - -- continue to raise errors - if not ok then - raise(errors) - end - end - } - } -end - diff --git a/xmake/actions/require/impl/action/prefix/uninstall.lua b/xmake/actions/require/impl/action/prefix/uninstall.lua deleted file mode 100644 index 3e48695ed..000000000 --- a/xmake/actions/require/impl/action/prefix/uninstall.lua +++ /dev/null @@ -1,53 +0,0 @@ ---!The Make-like install 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 uninstall.lua --- - --- uninstall package from the prefix directory -function main(package) - - -- remove the previous installed files - local prefixdir = package:prefixdir() - for _, relativefile in ipairs(package:prefixinfo().installed) do - - -- trace - vprint("removing %s ..", relativefile) - - -- remove file - local prefixfile = path.absolute(relativefile, prefixdir) - os.tryrm(prefixfile) - - -- remove it if the parent directory is empty - local parentdir = path.directory(prefixfile) - while parentdir and os.isdir(parentdir) and os.emptydir(parentdir) do - os.tryrm(parentdir) - parentdir = path.directory(parentdir) - end - end - - -- unregister this package - package:unregister() - - -- remove the prefix file - os.tryrm(package:prefixfile()) -end - diff --git a/xmake/actions/require/impl/environment.lua b/xmake/actions/require/impl/environment.lua index e4cf1ff10..8fffddd7f 100644 --- a/xmake/actions/require/impl/environment.lua +++ b/xmake/actions/require/impl/environment.lua @@ -29,9 +29,69 @@ import("core.package.package", {alias = "core_package"}) import("lib.detect.find_tool") import("package") +-- enter the package environments +function _enter_package(package_name, envs, installdir) + + -- save the old environments + _g._OLDENVS = _g._OLDENVS or {} + local oldenvs = _g._OLDENVS[package_name] + if not oldenvs then + oldenvs = {} + _g._OLDENVS[package_name] = oldenvs + end + + -- add the new environments + oldenvs.PATH = os.getenv("PATH") + for name, values in pairs(envs) do + oldenvs[name] = oldenvs[name] or os.getenv(name) + if name == "PATH" then + for _, value in ipairs(values) do + if path.is_absolute(value) then + os.addenv(name, value) + else + os.addenv(name, path.join(installdir, value)) + end + end + else + os.addenv(name, unpack(table.wrap(values))) + end + end +end + +-- leave the package environments +function _leave_package(package_name) + _g._OLDENVS = _g._OLDENVS or {} + local oldenvs = _g._OLDENVS[package_name] + if oldenvs then + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end + _g._OLDENVS[package_name] = nil + end +end + +-- enter environment of the given binary packages, git, 7z, .. +function _enter_packages(...) + for _, name in ipairs({...}) do + for _, manifest_file in ipairs(os.files(path.join(core_package.installdir(), name:sub(1, 1), name, "*", "*", "manifest.txt"))) do + local manifest = io.load(manifest_file) + if manifest and manifest.plat == os.host() and manifest.arch == os.arch() then + _enter_package(name, manifest.envs, path.directory(manifest_file)) + end + end + end +end + +-- leave environment of the given binary packages, git, 7z, .. +function _leave_packages(...) + for _, name in ipairs({...}) do + _leave_package(name) + end +end + -- enter environment -- --- ensure that we can find some basic tools: git, make/nmake/cmake, msbuild ... +-- ensure that we can find some basic tools: git, unzip, ... -- -- If these tools not exist, we will install it first. -- @@ -45,45 +105,38 @@ function enter() raise("unzip not found! we need install it first") end + -- enter the environments of git and 7z + _enter_packages("git", "7z") + -- git not found? install it first + local packages = {} if not find_tool("git") then - package.install_packages("git") + table.join2(packages, package.install_packages("git")) end -- missing the necessary unarchivers for *.gz, *.7z? install them first, e.g. gzip, 7z, tar .. if not ((find_tool("gzip") and find_tool("tar")) or find_tool("7z")) then - package.install_packages("7z") + table.join2(packages, package.install_packages("7z")) end - -- get prefix directories - local plat = get_config("plat") - local arch = get_config("arch") - _g.prefixdirs = _g.prefixdirs or - { - core_package.prefixdir(false, "release", plat, arch), - core_package.prefixdir(true, "release", plat, arch), - } - - -- add search directories of pkgconfig, aclocal, cmake - _g._ACLOCAL_PATH = os.getenv("ACLOCAL_PATH") - _g._PKG_CONFIG_PATH = os.getenv("PKG_CONFIG_PATH") - _g._CMAKE_PREFIX_PATH = os.getenv("CMAKE_PREFIX_PATH") - for _, prefixdir in ipairs(_g.prefixdirs) do - if not is_plat("windows") then - os.addenv("ACLOCAL_PATH", path.join(prefixdir, "share", "aclocal")) - os.addenv("PKG_CONFIG_PATH", path.join(prefixdir, "lib", "pkgconfig")) - end - os.addenv("CMAKE_PREFIX_PATH", prefixdir) + -- enter the environments of installed packages + for _, instance in ipairs(packages) do + instance:envs_enter() end + _g._PACKAGES = packages end -- leave environment function leave() - -- restore search directories of pkgconfig, aclocal, cmake - os.setenv("ACLOCAL_PATH", _g._ACLOCAL_PATH) - os.setenv("PKG_CONFIG_PATH", _g._PKG_CONFIG_PATH) - os.setenv("CMAKE_PREFIX_PATH", _g._CMAKE_PREFIX_PATH) + -- leave the environments of installed packages + for _, instance in irpairs(_g._PACKAGES) do + instance:envs_leave() + end + _g._PACKAGES = nil + + -- leave the environments of git and 7z + _leave_packages("7z", "git") -- restore search pathes of toolchains environment.leave("toolchains") diff --git a/xmake/actions/require/impl/package.lua b/xmake/actions/require/impl/package.lua index 159497b60..f55b6a98a 100644 --- a/xmake/actions/require/impl/package.lua +++ b/xmake/actions/require/impl/package.lua @@ -114,6 +114,13 @@ function _parse_require(require_str, requires_extra, parentinfo) require_extra = requires_extra[require_str] or {} end + -- get required building configurations + local require_build_configs = require_extra.configs or require_extra.config + if require_extra.debug then + require_build_configs = require_build_configs or {} + require_build_configs.debug = true + end + -- init required item local required = {} parentinfo = parentinfo or {} @@ -124,11 +131,10 @@ function _parse_require(require_str, requires_extra, parentinfo) reponame = reponame, version = version, alias = require_extra.alias, -- set package alias name - debug = require_extra.debug, -- uses the debug package, default: false group = require_extra.group, -- only uses the first package in same group system = require_extra.system, -- default: true, we can set it to disable system package manually option = require_extra.option, -- set and attach option - config = require_extra.config, -- the build configuration of package + configs = require_build_configs, -- the required building configurations default = require_extra.default, -- default: true, we can set it to disable package manually optional = parentinfo.optional or require_extra.optional -- default: false, inherit parentinfo.optional } @@ -240,6 +246,16 @@ function _sort_packagedeps(package) return orderdeps end +-- add some builtin configs to package +function _add_package_configs(package) + package:add("configs", "debug", {builtin = true, description = "Enable debug symbols.", default = false, type = "boolean"}) + package:add("configs", "cflags", {builtin = true, description = "Set the C compiler flags."}) + package:add("configs", "cxflags", {builtin = true, description = "Set the C/C++ compiler flags."}) + package:add("configs", "cxxflags", {builtin = true, description = "Set the C++ compiler flags."}) + package:add("configs", "asflags", {builtin = true, description = "Set the assembler flags."}) + package:add("configs", "vs_runtime", {builtin = true, description = "Set vs compiler runtime.", default = "MT", values = {"MT", "MD"}}) +end + -- load all required packages function _load_packages(requires, opt) @@ -270,6 +286,9 @@ function _load_packages(requires, opt) package._ORDERDEPS = table.unique(_sort_packagedeps(package)) end + -- add some builtin configs to package + _add_package_configs(package) + -- save this package package table.insert(packages, package) end @@ -292,6 +311,50 @@ function _sort_packages_urls(packages) package:urls_set(fasturl.sort(package:urls())) end end + +-- check the configurations of packages +-- +-- package("pcre2") +-- add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values = {"8", "16", "32"}}) +-- add_configs("bitwidth", {type = "number", values = {8, 16, 32}}) +-- add_configs("bitwidth", {restrict = function(value) if tonumber(value) < 100 then return true end}) +-- +function _check_packages_configs(packages) + for _, package in ipairs(packages) do + local configs_defined = {} + for _, name in ipairs(package:get("configs")) do + configs_defined[name] = package:extraconf("configs", name) or {} + end + for name, value in pairs(package:configs()) do + local conf = configs_defined[name] + if conf then + local config_type = conf.type or "string" + if type(value) ~= config_type then + raise("package(%s %s): invalid type(%s) for config(%s), need type(%s)!", package:name(), package:version_str(), type(value), name, config_type) + end + if conf.values then + local found = false + for _, config_value in ipairs(conf.values) do + if tostring(value) == tostring(config_value) then + found = true + break + end + end + if not found then + raise("package(%s %s): invalid value(%s) for config(%s), please run `xmake require --info %s` to get all valid values!", package:name(), package:version_str(), value, name, package:name()) + end + end + if conf.restrict then + if not conf.restrict(value) then + raise("package(%s %s): invalid value(%s) for config(%s)!", package:name(), package:version_str(), value, name) + end + end + else + raise("package(%s %s): invalid config(%s), please run `xmake require --info %s` to get all configurations!", package:name(), package:version_str(), name, package:name()) + end + end + end +end -- select packages version function _select_packages_version(packages) @@ -344,7 +407,7 @@ function _get_confirm(packages) -- get packages for each repositories local packages_repo = {} for _, package in ipairs(packages) do - local reponame = package:repo() and package:repo():name() or package:fromkind() + local reponame = package:repo() and package:repo():name() or (package:isSys() and "system" or "") if package:is3rd() then reponame = package:name():lower():split("::")[1] end @@ -355,7 +418,9 @@ function _get_confirm(packages) -- show tips cprint("${bright color.warning}note: ${clear}try installing these packages (pass -y to skip confirm)?") for reponame, packages in pairs(packages_repo) do - print("in %s:", reponame) + if reponame ~= "" then + print("in %s:", reponame) + end for _, package in ipairs(packages) do print(" -> %s %s %s", package:name(), package:version_str() or "", package:debug() and "(debug)" or "") end @@ -409,6 +474,9 @@ function load_packages(requires, opt) -- select packages version _select_packages_version(packages) + -- check the configurations of packages + _check_packages_configs(packages) + -- remove repeat packages with same the package name and version local unique = {} local results = {} @@ -551,48 +619,14 @@ function uninstall_packages(requires, opt) -- remove all packages local packages = {} for _, instance in ipairs(load_packages(requires, opt)) do - if os.isfile(instance:prefixfile()) then - - -- uninstall package from the prefix directory - action.prefix.uninstall(instance) - - -- remove ok + if os.isfile(instance:manifest_file()) then table.insert(packages, instance) end - - -- remove the installed files os.tryrm(instance:installdir()) end return packages end --- only unlink packages from the prefix directory -function unlink_packages(requires, opt) - - -- init options - opt = opt or {} - - -- do not remove dependent packages - opt.nodeps = true - - -- clear the detect cache - detectcache.clear() - - -- unlink all packages - local packages = {} - for _, instance in ipairs(load_packages(requires, opt)) do - if os.isfile(instance:prefixfile()) then - - -- uninstall package from the prefix directory - action.prefix.uninstall(instance) - - -- remove ok - table.insert(packages, instance) - end - end - return packages -end - -- search packages function search_packages(names) diff --git a/xmake/actions/require/info.lua b/xmake/actions/require/info.lua index d0060e0f7..d35f503cf 100644 --- a/xmake/actions/require/info.lua +++ b/xmake/actions/require/info.lua @@ -31,14 +31,20 @@ import("impl.package") import("impl.repository") import("impl.environment") --- from local/global/system/remote? +-- from xmake/system/remote? function _from(instance) - local fetchinfo, fetchfrom = instance:fetch() + local fetchinfo = instance:fetch() if fetchinfo then - return ", ${green}" .. fetchfrom .. "${clear}" + if instance:is3rd() then + return ", ${green}3rd${clear}" + elseif instance:isSys() then + return ", ${green}system${clear}" + else + return "" + end elseif #instance:urls() > 0 then return instance:supported() and format(", ${yellow}remote${clear}(in %s)", instance:repo():name()) or format(", ${yellow}remote${clear}(${red}unsupported${clear} in %s)", instance:repo():name()) - elseif instance:from("system") then + elseif instance:isSys() then return ", ${red}missing${clear}" else return "" @@ -116,13 +122,19 @@ function main(package_names) cprint(" -> ${magenta}urls${clear}:") for _, url in ipairs(urls) do print(" -> %s", filter.handle(url, instance)) - local sha256 = instance:sha256(instance:url_alias(url)) - if sha256 then - cprint(" -> ${yellow}%s${clear}", sha256) + local sourcehash = instance:sourcehash(instance:url_alias(url)) + if sourcehash then + cprint(" -> ${yellow}%s${clear}", sourcehash) end end end + -- show repository + local repo = instance:repo() + if repo then + cprint(" -> ${magenta}repo${clear}: %s %s %s", repo:name(), repo:url(), repo:branch() or "") + end + -- show deps local deps = instance:orderdeps() if deps and #deps > 0 then @@ -136,12 +148,6 @@ function main(package_names) -- show cache directory cprint(" -> ${magenta}cachedir${clear}: %s", instance:cachedir()) - -- show prefix directory - cprint(" -> ${magenta}prefixdir${clear}: %s", instance:prefixdir()) - - -- show prefix file - cprint(" -> ${magenta}prefixfile${clear}: %s", instance:prefixfile()) - -- show install directory cprint(" -> ${magenta}installdir${clear}: %s", instance:installdir()) @@ -154,6 +160,87 @@ function main(package_names) end end + -- show supported platforms + local platforms = {} + local on_install = instance:get("install") + if type(on_install) == "table" then + for plat, _ in pairs(on_install) do + table.insert(platforms, plat) + end + else + table.insert(platforms, "all") + end + cprint(" -> ${magenta}platforms${clear}: %s", table.concat(platforms, ", ")) + + -- show requires + cprint(" -> ${magenta}requires${clear}:") + cprint(" -> ${cyan}plat${clear}: %s", instance:plat()) + cprint(" -> ${cyan}arch${clear}: %s", instance:arch()) + local configs_required = instance:configs() + if configs_required then + cprint(" -> ${cyan}configs${clear}:") + for name, value in pairs(configs_required) do + cprint(" -> %s: %s", name, value) + end + end + + -- show user configs + local configs_defined = instance:get("configs") + if configs_defined then + cprint(" -> ${magenta}configs${clear}:") + for _, conf in ipairs(configs_defined) do + local configs_extra = instance:extraconf("configs", conf) + if configs_extra and not configs_extra.builtin then + cprintf(" -> ${cyan}%s${clear}: ", conf) + if configs_extra.description then + printf(configs_extra.description) + end + if configs_extra.default ~= nil then + printf(" (default: %s)", configs_extra.default) + elseif configs_extra.type ~= nil and configs_extra.type ~= "string" then + printf(" (type: %s)", configs_extra.type) + end + print("") + if configs_extra.values then + cprint(" -> values: %s", string.serialize(configs_extra.values, true)) + end + end + end + end + + -- show builtin configs + local configs_defined = instance:get("configs") + if configs_defined then + cprint(" -> ${magenta}configs (builtin)${clear}:") + for _, conf in ipairs(configs_defined) do + local configs_extra = instance:extraconf("configs", conf) + if configs_extra and configs_extra.builtin then + cprintf(" -> ${cyan}%s${clear}: ", conf) + if configs_extra.description then + printf(configs_extra.description) + end + if configs_extra.default ~= nil then + printf(" (default: %s)", configs_extra.default) + elseif configs_extra.type ~= nil and configs_extra.type ~= "string" then + printf(" (type: %s)", configs_extra.type) + end + print("") + if configs_extra.values then + cprint(" -> values: %s", string.serialize(configs_extra.values, true)) + end + end + end + end + + -- show references + local references = instance:references() + if references then + cprint(" -> ${magenta}references${clear}:") + for projectdir, refdate in pairs(references) do + cprint(" -> %s: %s%s", refdate, projectdir, os.isdir(projectdir) and "" or " ${red}(not found)${clear}") + end + end + -- end print("") end diff --git a/xmake/actions/require/install.lua b/xmake/actions/require/install.lua index 80df043ba..65c624d99 100644 --- a/xmake/actions/require/install.lua +++ b/xmake/actions/require/install.lua @@ -38,11 +38,11 @@ function _register_required_package(instance, requireinfo) if _g.optional_missing[instance:name()] then requireinfo:enable(false) else - -- add this package info + -- clear require info first requireinfo:clear() - requireinfo:add(instance:fetch()) - -- add all dependent packages info + -- add include and links info + requireinfo:add(instance:fetch()) local orderdeps = instance:orderdeps() if orderdeps then local total = #orderdeps @@ -54,6 +54,29 @@ function _register_required_package(instance, requireinfo) end end + -- add environments + local envs = {} + local hasenvs = false + local installdir = instance:installdir() + for name, values in pairs(instance:envs()) do + if name == "PATH" then + for _, value in ipairs(values) do + envs[name] = envs[name] or {} + if path.is_absolute(value) then + table.insert(envs[name], value) + else + table.insert(envs[name], path.join(installdir, value)) + end + end + else + envs[name] = values + end + hasenvs = true + end + if hasenvs then + requireinfo:add({envs = envs}) + end + -- save this package version requireinfo:version_set(instance:version_str()) @@ -75,11 +98,9 @@ function _register_required_packages(packages) if not group or not registered_in_group[group] then -- do not register binary package - if instance:kind() ~= "binary" then - local requireinfo = project.require(instance:alias() or instance:name()) - if requireinfo then - _register_required_package(instance, requireinfo) - end + local requireinfo = project.require(instance:alias() or instance:name()) + if requireinfo then + _register_required_package(instance, requireinfo) end -- mark as registered in group @@ -97,7 +118,7 @@ function _check_missing_packages(packages) local packages_missing = {} local optional_missing = {} for _, instance in ipairs(packages) do - if not instance:exists() and (#instance:urls() > 0 or instance:from("system")) then + if not instance:exists() and (#instance:urls() > 0 or instance:isSys()) then if instance:optional() then optional_missing[instance:name()] = instance else diff --git a/xmake/actions/require/list.lua b/xmake/actions/require/list.lua index 71d50c18f..5fd282b26 100644 --- a/xmake/actions/require/list.lua +++ b/xmake/actions/require/list.lua @@ -29,14 +29,20 @@ import("impl.package") import("impl.repository") import("impl.environment") --- from local/global/system/remote? +-- from xmake/system/remote? function _from(instance) - local fetchinfo, fetchfrom = instance:fetch() + local fetchinfo = instance:fetch() if fetchinfo then - return ", ${green}" .. fetchfrom .. "${clear}" + if instance:is3rd() then + return ", ${green}3rd${clear}" + elseif instance:isSys() then + return ", ${green}system${clear}" + else + return "" + end elseif #instance:urls() > 0 then return instance:supported() and format(", ${yellow}remote${clear}(in %s)", instance:repo():name()) or format(", ${yellow}remote${clear}(${red}unsupported${clear} in %s)", instance:repo():name()) - elseif instance:from("system") then + elseif instance:isSys() then return ", ${red}missing${clear}" else return "" diff --git a/xmake/actions/require/main.lua b/xmake/actions/require/main.lua index 5e5ccd830..6311434cc 100644 --- a/xmake/actions/require/main.lua +++ b/xmake/actions/require/main.lua @@ -30,11 +30,10 @@ import("core.project.project") import("core.platform.platform") import("list") import("info") -import("clear") +import("clean") import("search") import("install") import("uninstall") -import("unlink") -- -- the default repositories: @@ -74,10 +73,10 @@ function main() -- load project first _load_project() - -- clear all installed packages cache - if option.get("clear") then + -- clean all installed packages cache + if option.get("clean") then - clear(option.get("global")) + clean(option.get("global")) -- search for the given packages from repositories elseif option.get("search") then @@ -89,11 +88,6 @@ function main() uninstall(option.get("requires")) - -- unlink the installed packages - elseif option.get("unlink") then - - unlink(option.get("requires")) - -- show the given package info elseif option.get("info") then diff --git a/xmake/actions/require/unlink.lua b/xmake/actions/require/unlink.lua deleted file mode 100644 index de1cd5f99..000000000 --- a/xmake/actions/require/unlink.lua +++ /dev/null @@ -1,77 +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 unlink.lua --- - --- imports -import("core.base.task") -import("core.base.option") -import("core.project.project") -import("impl.package") -import("impl.repository") -import("impl.environment") - --- unlink the given packages -function main(package_names) - - -- no package names? - if not package_names then - return - end - - -- enter environment - environment.enter() - - -- pull all repositories first if not exists - if not repository.pulled() then - task.run("repo", {update = true}) - end - - -- get project requires - local project_requires, requires_extra = project.requires_str() - if not project_requires then - raise("requires(%s) not found in project!", table.concat(requires, " ")) - end - - -- find required package in project - local requires = {} - for _, name in ipairs(package_names) do - for _, require_str in ipairs(project_requires) do - if require_str:split(' ')[1]:lower():find(name:lower()) then - table.insert(requires, require_str) - end - end - end - if #requires == 0 then - raise("%s not found in project!", table.concat(package_names, " ")) - end - - -- unlink packages - local packages = package.unlink_packages(requires, {requires_extra = requires_extra}) - for _, instance in ipairs(packages) do - print("unlink: %s%s ok!", instance:name(), instance:version_str() and ("-" .. instance:version_str()) or "") - end - - -- leave environment - environment.leave() -end - diff --git a/xmake/actions/require/xmake.lua b/xmake/actions/require/xmake.lua index 35d6e0853..06147576a 100644 --- a/xmake/actions/require/xmake.lua +++ b/xmake/actions/require/xmake.lua @@ -45,13 +45,12 @@ task("require") -- options , options = { - {'c', "clear", "k", nil, "Clear all installed package caches." } + {'c', "clean", "k", nil, "Clear all package caches and uninstall all not-referenced packages." } , {'f', "force", "k", nil, "Force to reinstall all package dependencies." } , {'l', "list", "k", nil, "List all package dependencies." } , { } , {nil, "info", "k", nil, "Show the given package info." } , {'s', "search", "k", nil, "Search for the given packages from repositories." } - , {nil, "unlink", "k", nil, "Only unlink the installed packages." } , {nil, "uninstall", "k", nil, "Uninstall the installed packages." } , {nil, "extra", "kv", nil, "Set the extra info of packages." } , { } |
