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 | |
| parent | 57506c7b8ba8941ebac3676a241f8444e0079a56 (diff) | |
| parent | 8bb6ddf5c40f15fe6570f73dc5c4e5295ce95180 (diff) | |
Merge branch 'repo' into dev
54 files changed, 1377 insertions, 1054 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 54ebe5014..4b1715292 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,10 +13,10 @@ install: build_script: - ps: Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-Webrequest "https://raw.githubusercontent.com/xmake-io/xmake/dev/scripts/get.ps1" -UseBasicParsing).Content)) -ArgumentList "dev" - - cmd: xmake lua versioninfo + - cmd: xmake --version - cmd: xmake -P core - cmd: set XMAKE_PROGRAM_DIR=%cd%\xmake - - cmd: core\build\xmake lua versioninfo + - cmd: core\build\xmake --version - ps: Copy-Item -Force core\build\xmake.exe $HOME\xmake - cmd: xmake lua -D tests\test.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index d587c7526..7b2f4bf81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * [#179](https://github.com/xmake-io/xmake/issues/179): Generate CMakelist.txt file for `xmake project` plugin * [#361](https://github.com/xmake-io/xmake/issues/361): Support vs2019 preview * [#368](https://github.com/xmake-io/xmake/issues/368): Support `private, public, interface` to improve dependency inheritance like cmake +* [#284](https://github.com/xmake-io/xmake/issues/284): Add passing user configs description for `package()` ### Changes @@ -572,6 +573,7 @@ * [#179](https://github.com/xmake-io/xmake/issues/179): 扩展`xmake project`插件,新增CMakelist.txt生成支持 * [#361](https://github.com/xmake-io/xmake/issues/361): 增加对vs2019 preview的支持 * [#368](https://github.com/xmake-io/xmake/issues/368): 支持`private, public, interface`属性设置去继承target配置 +* [#284](https://github.com/xmake-io/xmake/issues/284): 通过`add_configs()`添加和传递用户自定义配置到`package()` ### 改进 diff --git a/xmake/actions/build/build.lua b/xmake/actions/build/build.lua index 33bb920dc..03045ec8c 100644 --- a/xmake/actions/build/build.lua +++ b/xmake/actions/build/build.lua @@ -71,6 +71,13 @@ end -- build the given target function _build_target(target) + -- enter the environments of the target packages + local oldenvs = {} + for name, values in pairs(target:pkgenvs()) do + oldenvs[name] = os.getenv(name) + os.addenv(name, unpack(values)) + end + -- the target scripts local scripts = { @@ -138,6 +145,11 @@ function _build_target(target) end end + -- leave the environments of the target packages + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end + -- update target index _g.targetindex = _g.targetindex + 1 end diff --git a/xmake/actions/clean/main.lua b/xmake/actions/clean/main.lua index b5c90cd75..7717baf1d 100644 --- a/xmake/actions/clean/main.lua +++ b/xmake/actions/clean/main.lua @@ -114,6 +114,13 @@ end -- clean the given target files function _clean_target(target) + -- enter the environments of the target packages + local oldenvs = {} + for name, values in pairs(target:pkgenvs()) do + oldenvs[name] = os.getenv(name) + os.addenv(name, unpack(values)) + end + -- the target scripts local scripts = { @@ -159,6 +166,11 @@ function _clean_target(target) script(target, {origin = (i == 3 and _do_clean_target or nil)}) end end + + -- leave the environments of the target packages + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end end -- clean the given target and all dependent targets diff --git a/xmake/actions/install/install.lua b/xmake/actions/install/install.lua index fc8db342c..db035b3fb 100644 --- a/xmake/actions/install/install.lua +++ b/xmake/actions/install/install.lua @@ -157,6 +157,13 @@ function _install_target(target) -- enter project directory local oldir = os.cd(project.directory()) + -- enter the environments of the target packages + local oldenvs = {} + for name, values in pairs(target:pkgenvs()) do + oldenvs[name] = os.getenv(name) + os.addenv(name, unpack(values)) + end + -- the target scripts local scripts = { @@ -203,6 +210,11 @@ function _install_target(target) end end + -- leave the environments of the target packages + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end + -- leave project directory os.cd(oldir) end diff --git a/xmake/actions/package/main.lua b/xmake/actions/package/main.lua index f4cd40405..38a7df462 100644 --- a/xmake/actions/package/main.lua +++ b/xmake/actions/package/main.lua @@ -168,6 +168,13 @@ function _package(target) -- enter project directory local oldir = os.cd(project.directory()) + -- enter the environments of the target packages + local oldenvs = {} + for name, values in pairs(target:pkgenvs()) do + oldenvs[name] = os.getenv(name) + os.addenv(name, unpack(values)) + end + -- the target scripts local scripts = { @@ -200,6 +207,11 @@ function _package(target) end end + -- leave the environments of the target packages + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end + -- leave project directory os.cd(oldir) end 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/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." } , { } diff --git a/xmake/actions/run/main.lua b/xmake/actions/run/main.lua index 21783a125..156170871 100644 --- a/xmake/actions/run/main.lua +++ b/xmake/actions/run/main.lua @@ -103,6 +103,13 @@ end -- run the given target function _run(target) + -- enter the environments of the target packages + local oldenvs = {} + for name, values in pairs(target:pkgenvs()) do + oldenvs[name] = os.getenv(name) + os.addenv(name, unpack(values)) + end + -- the target scripts local scripts = { @@ -148,6 +155,11 @@ function _run(target) script(target, {origin = (i == 3 and _do_run_target or nil)}) end end + + -- leave the environments of the target packages + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end end -- run the all dependent targets diff --git a/xmake/actions/uninstall/uninstall.lua b/xmake/actions/uninstall/uninstall.lua index f79727947..0d1c07d51 100644 --- a/xmake/actions/uninstall/uninstall.lua +++ b/xmake/actions/uninstall/uninstall.lua @@ -134,6 +134,13 @@ function _uninstall_target(target) -- enter project directory local oldir = os.cd(project.directory()) + -- enter the environments of the target packages + local oldenvs = {} + for name, values in pairs(target:pkgenvs()) do + oldenvs[name] = os.getenv(name) + os.addenv(name, unpack(values)) + end + -- the target scripts local scripts = { @@ -180,6 +187,11 @@ function _uninstall_target(target) end end + -- leave the environments of the target packages + for name, values in pairs(oldenvs) do + os.setenv(name, values) + end + -- leave project directory os.cd(oldir) end diff --git a/xmake/core/base/scopeinfo.lua b/xmake/core/base/scopeinfo.lua index 351572dfa..1fe04a6eb 100644 --- a/xmake/core/base/scopeinfo.lua +++ b/xmake/core/base/scopeinfo.lua @@ -451,7 +451,7 @@ function _instance:apival_set(name, ...) for k, v in pairs(dict) do self:apival_set(k, unpack(table.wrap(v))) end - else + elseif name ~= nil then os.raise("unknown type(%s) for %s:set(%s, ...)", type(name), self:kind(), name) end end @@ -487,7 +487,7 @@ function _instance:apival_add(name, ...) for k, v in pairs(dict) do self:apival_add(k, unpack(table.wrap(v))) end - else + elseif name ~= nil then os.raise("unknown type(%s) for %s:add(%s, ...)", type(name), self:kind(), name) end end @@ -506,7 +506,7 @@ function _instance:apival_del(name, ...) else os.raise("unknown api(%s) for %s:del(%s, ...)", name, self:kind(), name) end - else + elseif name ~= nil then -- TODO os.raise("cannot support to remove a dictionary!") end diff --git a/xmake/core/base/string.lua b/xmake/core/base/string.lua index c3f3958d5..cf6f7b124 100644 --- a/xmake/core/base/string.lua +++ b/xmake/core/base/string.lua @@ -43,7 +43,9 @@ function string._makestr(object, deflate, serialize, level) if deflate then s = s .. "{" else - s = s .. "\n" + if level > 0 then + s = s .. "\n" + end for l = 1, level do s = s .. " " end @@ -69,7 +71,7 @@ function string._makestr(object, deflate, serialize, level) -- make key = value if type(k) == "string" then - if serialize then + if serialize and not k:match("^%a[%w_]+$") then k = string.format("[%q]", k) end if deflate then diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua index 87c075439..eeae38819 100644 --- a/xmake/core/package/package.lua +++ b/xmake/core/package/package.lua @@ -38,6 +38,7 @@ local interpreter = require("base/interpreter") local sandbox = require("sandbox/sandbox") local config = require("project/config") local platform = require("platform/platform") +local language = require("language/language") local sandbox = require("sandbox/sandbox") local sandbox_os = require("sandbox/modules/os") local sandbox_module = require("sandbox/modules/import/core/sandbox/module") @@ -50,6 +51,11 @@ function _instance.new(name, info) return instance end +-- get the package name +function _instance:name() + return self._NAME +end + -- get the package configure function _instance:get(name) @@ -60,9 +66,19 @@ function _instance:get(name) end end --- get the package name -function _instance:name() - return self._NAME +-- set the value to the package info +function _instance:set(name, ...) + self._INFO:apival_set(name, ...) +end + +-- add the value to the package info +function _instance:add(name, ...) + self._INFO:apival_add(name, ...) +end + +-- get the extra configuration +function _instance:extraconf(name, item, key) + return self._INFO:extraconf(name, item, key) end -- get the package description @@ -167,47 +183,30 @@ function _instance:orderdeps() return self._ORDERDEPS end --- get sha256 of the url_alias@version_str -function _instance:sha256(url_alias) +-- get hash of the source package for the url_alias@version_str +function _instance:sourcehash(url_alias) - -- get sha256 + -- get sourcehash local versions = self:get("versions") local version_str = self:version_str() if versions and version_str then - local sha256 = nil + local sourcehash = nil if url_alias then - sha256 = versions[url_alias .. ":" ..version_str] + sourcehash = versions[url_alias .. ":" ..version_str] end - if not sha256 then - sha256 = versions[version_str] + if not sourcehash then + sourcehash = versions[version_str] end -- ok? - return sha256 + return sourcehash end end -- get revision(commit, tag, branch) of the url_alias@version_str, only for git url function _instance:revision(url_alias) - return self:sha256(url_alias) -end - --- this package is from system/local/global? --- --- @param kind the from kind --- --- system: from the system directories (.e.g /usr/local) --- local: from the local project package directories (.e.g projectdir/.xmake/packages) --- global: from the global package directories (.e.g ~/.xmake/packages) --- -function _instance:from(kind) - return self._FROMKIND == kind -end - --- get from kind -function _instance:fromkind() - return self._FROMKIND + return self:sourcehash(url_alias) end -- get the package kind, binary or nil(static, shared) @@ -223,94 +222,164 @@ end -- get the installed directory of this package function _instance:installdir(...) - - -- make the given install directory local name = self:name():lower():gsub("::", "_") - local dir = path.join(package.installdir(table.concat({self:mode(), self:configs_hash()}, '_'), self:plat(), self:arch()), name:sub(1, 1):lower(), name, self:version_str(), ...) - - -- ensure the install directory + local dir = path.join(package.installdir(), name:sub(1, 1):lower(), name, self:version_str(), self:buildhash(), ...) if not os.isdir(dir) then os.mkdir(dir) end return dir end --- get the prefix directory -function _instance:prefixdir(...) - - -- make the given prefix directory - local dir = path.join(package.prefixdir(self:from("global"), table.concat({self:mode(), self:configs_hash()}, '_'), self:plat(), self:arch()), ...) - - -- ensure the prefix directory - if not os.isdir(dir) then - os.mkdir(dir) +-- get the references info of this package +function _instance:references() + local references_file = path.join(self:installdir(), "references.txt") + if os.isfile(references_file) then + local references, errors = io.load(references_file) + if not references then + os.raise(errors) + end + return references end - return dir end --- get the prefix info -function _instance:prefixinfo() - if self._PREFIXINFO == nil then - local prefixfile = self:prefixfile() - self._PREFIXINFO = os.isfile(prefixfile) and io.load(prefixfile) or {} - end - return self._PREFIXINFO +-- get the manifest file of this package +function _instance:manifest_file() + return path.join(self:installdir(), "manifest.txt") end --- get the prefix info file -function _instance:prefixfile() - local name = self:name():lower():gsub("::", "_") - return path.join(package.prefixinfodir(self:from("global"), table.concat({self:mode(), self:configs_hash()}, '_'), self:plat(), self:arch()), name:sub(1, 1):lower(), name, self:version_str(), "info.txt") +-- load the manifest file of this package +function _instance:manifest_load() + local manifest_file = self:manifest_file() + if os.isfile(manifest_file) then + + -- load manifest + local manifest, errors = io.load(manifest_file) + if not manifest then + os.raise(errors) + end + return manifest + end end --- get prefix variables -function _instance:getvar(name) - return self:prefixinfo()[name] +-- save the manifest file of this package +function _instance:manifest_save() + + -- make manifest + local manifest = {} + manifest.name = self:name() + manifest.description = self:description() + manifest.version = self:version_str() + manifest.kind = self:kind() + manifest.plat = self:plat() + manifest.arch = self:arch() + manifest.mode = self:mode() + manifest.configs = self:configs() + manifest.envs = self:envs() + + -- save variables + local vars = {} + local apis = language.apis() + for _, apiname in ipairs(table.join(apis.values, apis.pathes)) do + if apiname:startswith("package.add_") or apiname:startswith("package.set_") then + local name = apiname:sub(13) + local value = self:get(name) + if value ~= nil then + vars[name] = value + end + end + end + manifest.vars = vars + + -- save repository + local repo = self:repo() + if repo then + manifest.repo = {} + manifest.repo.name = repo:name() + manifest.repo.url = repo:url() + manifest.repo.branch = repo:branch() + end + + -- save manifest + local ok, errors = io.save(self:manifest_file(), manifest) + if not ok then + os.raise(errors) + end end --- set prefix variables +-- TODO: set the given variable, deprecated function _instance:setvar(name, ...) - self:prefixinfo()[name] = {...} + self:set(name, ...) end --- add prefix variables +-- TODO add the given variable, deprecated function _instance:addvar(name, ...) - self:prefixinfo()[name] = table.join(self:prefixinfo()[name] or {}, ...) + self:add(name, ...) end --- get environment variables -function _instance:getenv(name) - return self:prefixinfo().envars and self:prefixinfo().envars[name] or nil +-- get the exported environments +function _instance:envs() + local envs = self._ENVS + if not envs then + envs = {} + if self:kind() == "binary" then + envs.PATH = {"bin"} + end + self._ENVS = envs + end + return envs end --- set environment variables -function _instance:setenv(name, ...) - self:prefixinfo().envars = self:prefixinfo().envars or {} - self:prefixinfo().envars[name] = {...} -end +-- enter the package environments +function _instance:envs_enter() --- add values to environment variable -function _instance:addenv(name, ...) - self:prefixinfo().envars = self:prefixinfo().envars or {} - self:prefixinfo().envars[name] = table.join(self:prefixinfo().envars[name] or {}, ...) -end + -- save the old environments + local oldenvs = self._OLDENVS + if not oldenvs then + oldenvs = {} + self._OLDENVS = oldenvs + end --- register package info in the root prefix info -function _instance:register() + -- add the new environments + local installdir = self:installdir() + for name, values in pairs(self: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 - -- register the environment variables - for name, values in pairs(table.wrap(self:prefixinfo().envars)) do - package.addenv(self:from("global"), table.concat({self:mode(), self:configs_hash()}, '_'), self:plat(), self:arch(), name, values) +-- leave the package environments +function _instance:envs_leave() + if self._OLDENVS then + for name, values in pairs(self._OLDENVS) do + os.setenv(name, values) + end + self._OLDENVS = nil end end --- unregister package info from the root prefix info -function _instance:unregister() +-- get the given environment variable +function _instance:getenv(name) + return self:envs()[name] +end + +-- set the given environment variable +function _instance:setenv(name, ...) + self:envs()[name] = {...} +end - -- unregister the environment variables - for name, values in pairs(table.wrap(self:prefixinfo().envars)) do - package.delenv(self:from("global"), table.concat({self:mode(), self:configs_hash()}, '_'), self:plat(), self:arch(), name, values) - end +-- add the given environment variable +function _instance:addenv(name, ...) + self:envs()[name] = table.join(self:envs()[name] or {}, ...) end -- get user private data @@ -406,44 +475,52 @@ end -- set the require info function _instance:requireinfo_set(requireinfo) - - -- save require info self._REQUIREINFO = requireinfo +end - -- get version - local version = requireinfo and requireinfo.version or nil - local limitversion = version and version ~= "master" and version ~= "lastest" - if requireinfo and not self:is3rd() then - - -- switch to local package if exists package configuration or debug package or limit version - if requireinfo.config or requireinfo.debug or limitversion then - self._FROMKIND = "local" - end - - -- disable the system package if limit version - if limitversion then - requireinfo.system = false - end +-- get the given configuration value of package +function _instance:config(name) + local configs = self:configs() + if configs then + return configs[name] end end --- get the all configuration values of package +-- get the configurations of package function _instance:configs() - local requireinfo = self:requireinfo() - if requireinfo then - return requireinfo.config + local configs = self._CONFIGS + if configs == nil then + local configs_defined = self:get("configs") + if configs_defined then + configs = {} + local requireinfo = self:requireinfo() + local configs_required = requireinfo and requireinfo.configs or {} + for _, name in ipairs(table.wrap(configs_defined)) do + local value = configs_required[name] + if value == nil then + value = self:extraconf("configs", name, "default") + end + configs[name] = value + end + else + configs = false + end + self._CONFIGS = configs end + return configs and configs or nil end --- get the hash of configs -function _instance:configs_hash() - if self._CONFIGS_HASH == nil then +-- get the build hash +function _instance:buildhash() + if self._BUILDHASH == nil then + local str = self:plat() .. self:arch() local configs = self:configs() if configs then - self._CONFIGS_HASH = hash.uuid(string.serialize(configs, true)):split('-')[1]:lower() + str = str .. string.serialize(configs, true) end + self._BUILDHASH = hash.uuid(str):gsub('-', ''):lower() end - return self._CONFIGS_HASH + return self._BUILDHASH end -- get the group name @@ -454,14 +531,6 @@ function _instance:group() end end --- get the given configuration value of package -function _instance:config(name) - local configs = self:configs() - if configs then - return configs[name] - end -end - -- is optional package? function _instance:optional() local requireinfo = self:requireinfo() @@ -470,12 +539,7 @@ end -- is debug package? function _instance:debug() - -- @note always release for the binary package - if self:kind() == "binary" then - return false - end - local requireinfo = self:requireinfo() - return requireinfo and requireinfo.debug or false + return self:config("debug") end -- is the supported package? @@ -488,7 +552,12 @@ end -- we need install and find package by third-party package manager directly -- function _instance:is3rd() - return self:name():find("::", 1, true) + return self._is3rd +end + +-- is the system package? +function _instance:isSys() + return self._isSys end -- get xxx_script @@ -545,11 +614,11 @@ function _instance:script(name, generic) return result end --- fetch package info from the local packages +-- fetch the local package info -- -- @param opt the fetch option, .e.g {force = true, system = false} -- --- @return {packageinfo}, fetchfrom (.e.g local/global/system) +-- @return {packageinfo}, fetchfrom (.e.g xmake/system) -- function _instance:fetch(opt) @@ -557,10 +626,9 @@ function _instance:fetch(opt) opt = opt or {} -- attempt to get it from cache - local fetchfrom = self._FETCHFROM local fetchinfo = self._FETCHINFO if not opt.force and fetchinfo then - return fetchinfo, fetchfrom + return fetchinfo end -- fetch the require version @@ -569,39 +637,52 @@ function _instance:fetch(opt) require_ver = nil end + -- nil: find xmake or system packages + -- true: only find system package + -- false: only find xmake packages + local system = opt.system or self:requireinfo().system + -- fetch binary tool? fetchinfo = nil - fetchfrom = nil + local isSys = nil if self:kind() == "binary" then -- import find_tool self._find_tool = self._find_tool or sandbox_module.import("lib.detect.find_tool", {anonymous = true}) - -- fetch it from the system directories, TODO find the given version - fetchinfo = self._find_tool(self:name(), {force = opt.force}) - if fetchinfo then - fetchfrom = "system" -- ignore self:requireinfo().system + -- only fetch it from the xmake repository first + if not fetchinfo and system ~= true and not self:is3rd() then + fetchinfo = self._find_tool(self:name(), {version = self:version_str(), + cachekey = "fetch_package_xmake", + buildhash = self:buildhash(), + force = opt.force}) + if fetchinfo then + isSys = self._isSys + end + end + + -- fetch it from the system directories + if not fetchinfo and system ~= false then + fetchinfo = self._find_tool(self:name(), {cachekey = "fetch_package_system", + force = opt.force}) + if fetchinfo then + isSys = true + end end else -- import find_package self._find_package = self._find_package or sandbox_module.import("lib.detect.find_package", {anonymous = true}) - -- nil: find local or system packages - -- true: only find system package - -- false: only find local packages - local system = opt.system or self:requireinfo().system - -- only fetch it from the xmake repository first if not fetchinfo and system ~= true and not self:is3rd() then - fetchinfo = self._find_package("xmake::" .. self:name(), {prefixdirs = self:prefixdir(), - mode = self:mode(), - islocal = self:from("local"), - version = require_ver, + fetchinfo = self._find_package("xmake::" .. self:name(), {version = self:version_str(), cachekey = "fetch_package_xmake", - configs_hash = self:configs_hash(), - force = opt.force or self:from("local")}) - if fetchinfo then fetchfrom = self._FROMKIND end + buildhash = self:buildhash(), + force = opt.force}) + if fetchinfo then + isSys = self._isSys + end end -- fetch it from the system directories @@ -611,21 +692,76 @@ function _instance:fetch(opt) mode = self:mode(), cachekey = "fetch_package_system", system = true}) - if fetchinfo then fetchfrom = "system" end + if fetchinfo then + isSys = true + end end end -- save to cache self._FETCHINFO = fetchinfo - self._FETCHFROM = fetchfrom + + -- mark as system package? + if isSys ~= nil then + self._isSys = isSys + end -- ok - return fetchinfo, fetchfrom + return fetchinfo end --- exists this package in local +-- exists this package? function _instance:exists() - return self._FETCHINFO + return self._FETCHINFO ~= nil +end + +-- fetch all local info with dependencies +function _instance:fetchdeps() + local fetchinfo = self:fetch() + if not fetchinfo then + return + end + local orderdeps = self:orderdeps() + if orderdeps then + local total = #orderdeps + for idx, _ in ipairs(orderdeps) do + local dep = orderdeps[total + 1 - idx] + local depinfo = dep:fetch() + if depinfo then + for name, values in pairs(depinfo) do + fetchinfo[name] = table.wrap(fetchinfo[name]) + table.join2(fetchinfo[name], values) + end + end + end + end + return fetchinfo +end + +-- has the given c funcs? +-- +-- @param funcs the funcs +-- @param opt the argument options, .e.g { includes = ""} +-- +-- @return true or false +-- +function _instance:has_cfuncs(funcs, opt) + opt = opt or {} + opt.configs = self:fetchdeps() + return sandbox_module.import("lib.detect.has_cfuncs", {anonymous = true})(funcs, opt) +end + +-- has the given c++ funcs? +-- +-- @param funcs the funcs +-- @param opt the argument options, .e.g { includes = ""} +-- +-- @return true or false +-- +function _instance:has_cxxfuncs(funcs, opt) + opt = opt or {} + opt.configs = self:fetchdeps() + return sandbox_module.import("lib.detect.has_cxxfuncs", {anonymous = true})(funcs, opt) end -- the current mode is belong to the given modes? @@ -662,6 +798,9 @@ function package._interpreter() -- define apis interp:api_define(package.apis()) + + -- define apis for language + interp:api_define(language.apis()) -- save interpreter package._INTERPRETER = interp @@ -686,6 +825,7 @@ function package.apis() , "package.add_deps" , "package.add_urls" , "package.add_imports" + , "package.add_configs" } , script = { @@ -724,77 +864,8 @@ function package.cachedir() end -- the install directory -function package.installdir(mode, plat, arch) - return path.join(global.directory(), "installed", plat or os.host(), arch or os.arch(), mode or "release") -end - --- get the prefix directory -function package.prefixdir(is_global, mode, plat, arch) - return path.join(is_global and global.directory() or config.directory(), "prefix", plat or os.host(), arch or os.arch(), mode or "release") -end - --- get the prefix info directory -function package.prefixinfodir(is_global, mode, plat, arch) - return path.join(is_global and global.directory() or config.directory(), "prefix", "info", plat or os.host(), arch or os.arch(), mode or "release") -end - --- get the prefix info -function package.prefixinfo(is_global, mode, plat, arch) - local prefixfile = package.prefixfile(is_global, mode, plat, arch) - return os.isfile(prefixfile) and io.load(prefixfile) or {} -end - --- get the prefix info file -function package.prefixfile(is_global, mode, plat, arch) - return path.join(package.prefixinfodir(is_global, mode, plat, arch), "info.txt") -end - --- get environment variables -function package.getenv(is_global, mode, plat, arch, name) - local prefixinfo = package.prefixinfo(is_global, mode, plat, arch) - return prefixinfo.envars and prefixinfo.envars[name] or nil -end - --- add values to environment variable -function package.addenv(is_global, mode, plat, arch, name, values) - - -- add to the root prefix info - local prefixinfo = package.prefixinfo(is_global, mode, plat, arch) - prefixinfo.envars = prefixinfo.envars or {} - prefixinfo.envars[name] = table.join(prefixinfo.envars[name] or {}, values) - io.save(package.prefixfile(is_global, mode, plat, arch), prefixinfo) - - -- add to the current environment - if values then - -- PATH? add the prefix root directory - if name:lower() == "path" then - local prefixdir = package.prefixdir(is_global, mode, plat, arch) - for _, value in ipairs(values) do - os.addenv(name, path.join(prefixdir, value)) - end - else - os.addenv(name, unpack(values)) - end - end -end - --- remove values to environment variable -function package.delenv(is_global, mode, plat, arch, name, values) - local prefixinfo = package.prefixinfo(is_global, mode, plat, arch) - local prefixvalues = prefixinfo.envars and prefixinfo.envars[name] or nil - if prefixvalues then - local exists = {} - for _, value in ipairs(values) do - exists[value:trim()] = true - end - for i = #prefixvalues, 1, -1 do - value = prefixvalues[i]:trim() - if exists[value] then - table.remove(prefixvalues, i) - end - end - io.save(package.prefixfile(is_global, mode, plat, arch), prefixinfo) - end +function package.installdir() + return path.join(global.directory(), "packages") end -- load the package from the system directories @@ -808,6 +879,7 @@ function package.load_from_system(packagename) -- get package info local packageinfo = {} + local is3rd = false if packagename:find("::", 1, true) then -- get interpreter @@ -830,6 +902,11 @@ function package.load_from_system(packagename) -- save the install script packageinfo.install = instance:script() + + -- is third-party package? + if not packagename:startswith("xmake::") then + is3rd = true + end end -- new an instance @@ -838,8 +915,9 @@ function package.load_from_system(packagename) return nil, errors end - -- mark as system package - instance._FROMKIND = "system" + -- mark as system or 3rd package + instance._isSys = true + instance._is3rd = is3rd -- save instance to the cache package._PACKAGES[packagename] = instance @@ -874,9 +952,6 @@ function package.load_from_project(packagename, project) return nil, errors end - -- mark as local package - instance._FROMKIND = "local" - -- save instance to the cache package._PACKAGES[packagename] = instance @@ -942,9 +1017,6 @@ function package.load_from_repository(packagename, repo, packagedir, packagefile -- save repository instance._REPO = repo - -- mark as global/project package? - instance._FROMKIND = repo:is_global() and "global" or "local" - -- save instance to the cache package._PACKAGES[packagename] = instance diff --git a/xmake/core/package/repository.lua b/xmake/core/package/repository.lua index 7c28b1b9a..9f10153a0 100644 --- a/xmake/core/package/repository.lua +++ b/xmake/core/package/repository.lua @@ -244,7 +244,8 @@ function repository.add(name, url, branch, is_global) repository._cache(is_global):set("repositories", repositories) -- flush it - return repository._cache(is_global):flush() + repository._cache(is_global):flush() + return true end -- remove repository from gobal or local directory @@ -263,7 +264,8 @@ function repository.remove(name, is_global) repository._cache(is_global):set("repositories", repositories) -- flush it - return repository._cache(is_global):flush() + repository._cache(is_global):flush() + return true end -- clear all repositories @@ -273,7 +275,8 @@ function repository.clear(is_global) repository._cache(is_global):set("repositories", {}) -- flush it - return repository._cache(is_global):flush() + repository._cache(is_global):flush() + return true end diff --git a/xmake/core/platform/environment.lua b/xmake/core/platform/environment.lua index b20d55fd7..5da87d2d1 100644 --- a/xmake/core/platform/environment.lua +++ b/xmake/core/platform/environment.lua @@ -39,20 +39,6 @@ function environment._enter_toolchains() -- save the toolchains environment environment._PATH = os.getenv("PATH") - -- add global search binary pathes - local globaldir = package.prefixdir(true, "release", os.host(), os.arch()) - for _, dir in ipairs(table.wrap(package.getenv(true, "release", os.host(), os.arch(), "PATH"))) do - os.addenv("PATH", path.join(globaldir, dir)) - end - os.addenv("PATH", path.join(globaldir, "bin")) - - -- add local search binary pathes - local localdir = package.prefixdir(false, "release", os.host(), os.arch()) - for _, dir in ipairs(table.wrap(package.getenv(false, "release", os.host(), os.arch(), "PATH"))) do - os.addenv("PATH", path.join(localdir, dir)) - end - os.addenv("PATH", path.join(localdir, "bin")) - -- add $programdir/winenv/bin to $path if os.host() == "windows" then os.addenv("PATH", path.join(os.programdir(), "winenv", "bin")) @@ -72,22 +58,6 @@ function environment._enter_run() -- save the running environment environment._PATH = os.getenv("PATH") environment._LD_LIBRARY_PATH = os.getenv("LD_LIBRARY_PATH") - - -- add global search library pathes of pathes - local globaldir = package.prefixdir(true, "release", os.host(), os.arch()) - if os.host() == "windows" then - os.addenv("PATH", path.join(globaldir, "lib")) - else - os.addenv("LD_LIBRARY_PATH", path.join(globaldir, "lib")) - end - - -- add local search library pathes of pathes - local localdir = package.prefixdir(false, "release", os.host(), os.arch()) - if os.host() == "windows" then - os.addenv("PATH", path.join(localdir, "lib")) - else - os.addenv("LD_LIBRARY_PATH", path.join(localdir, "lib")) - end end -- leave the running environment diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua index 1e0403fc3..e20884f54 100644 --- a/xmake/core/project/project.lua +++ b/xmake/core/project/project.lua @@ -195,7 +195,8 @@ function project.interpreter() { -- set_xxx "set_project" - , "set_modes" + , "set_modes" -- TODO deprecated + , "set_description" -- add_xxx , "add_requires" , "add_repositories" @@ -305,7 +306,7 @@ function project.get(name) end -- load the project file -function project._load(force) +function project._load(force, disable_filter) -- has already been loaded? if project._INFO and not force then @@ -328,13 +329,13 @@ function project._load(force) end -- load the root info of the project - local rootinfo, errors = project._load_scope("root", true, true) + local rootinfo, errors = project._load_scope("root", true, not disable_filter) if not rootinfo then return false, errors end -- load the root info of the target - local rootinfo_target, errors = project._load_scope("root.target", true, true) + local rootinfo_target, errors = project._load_scope("root.target", true, not disable_filter) if not rootinfo_target then return false, errors end @@ -411,8 +412,8 @@ function project._load_tasks() return {}, nil end - -- load the project file first - local ok, errors = project._load(true) + -- load the project file first and disable filter + local ok, errors = project._load(true, true) if not ok then return nil, errors end @@ -570,7 +571,7 @@ function project._load_options(disable_filter) end -- reload the project file to ensure `if is_plat() then add_packagedirs() end` works - local ok, errors = project._load(true) + local ok, errors = project._load(true, disable_filter) if not ok then return nil, errors end @@ -783,7 +784,6 @@ end -- get requires info function project.requires() - if not project._REQUIRES then local requires, errors = project._load_requires() if not requires then @@ -796,7 +796,6 @@ end -- get string requires function project.requires_str() - if not project._REQUIRES_STR then -- reload the project file to handle `has_config()` diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index 1bf85014d..a47291b5c 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -572,6 +572,28 @@ function _instance:orderpkgs() return self._ORDERPKGS_ENABLED end +-- get the environments of packages +function _instance:pkgenvs() + local pkgenvs = self._PKGENVS + if not pkgenvs then + pkgenvs = {} + self._PKGENVS = pkgenvs + for _, pkgname in ipairs(table.wrap(self:get("packages"))) do + local pkg = self:pkg(pkgname) + if pkg then + local envs = pkg:get("envs") + if envs then + for name, values in pairs(envs) do + pkgenvs[name] = pkgenvs[name] or {} + table.join2(pkgenvs[name], values) + end + end + end + end + end + return pkgenvs +end + -- get the config info of the given package function _instance:pkgconfig(pkgname) local extra_packages = self:get("__extra_packages") diff --git a/xmake/actions/require/clear.lua b/xmake/core/sandbox/modules/has_package.lua index ffe73ed26..7873a5d26 100644 --- a/xmake/actions/require/clear.lua +++ b/xmake/core/sandbox/modules/has_package.lua @@ -19,22 +19,19 @@ -- Copyright (C) 2015 - 2019, TBOOX Open Source Group. -- -- @author ruki --- @file clear.lua +-- @file has_package.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() +-- return module +return function (...) + require("sandbox/modules/import/core/sandbox/module").import("core.project.project") + local requires = project.requires() + if requires then + for _, name in ipairs(table.join(...)) do + local pkg = requires[name] + if pkg and pkg:enabled() then + return true + end + end + end end - diff --git a/xmake/core/sandbox/modules/import/core/package/package.lua b/xmake/core/sandbox/modules/import/core/package/package.lua index 54a1ce1de..563032482 100644 --- a/xmake/core/sandbox/modules/import/core/package/package.lua +++ b/xmake/core/sandbox/modules/import/core/package/package.lua @@ -36,18 +36,8 @@ function sandbox_core_package_package.cachedir() end -- the install directory -function sandbox_core_package_package.installdir(mode, plat, arch) - return package.installdir(mode, plat, arch) -end - --- get the prefix directory -function sandbox_core_package_package.prefixdir(is_global, mode, plat, arch) - return package.prefixdir(is_global, mode, plat, arch) -end - --- get the prefix info directory -function sandbox_core_package_package.prefixinfodir(is_global, mode, plat, arch) - return package.prefixinfodir(is_global, mode, plat, arch) +function sandbox_core_package_package.installdir() + return package.installdir() end -- load the package from the project file diff --git a/xmake/core/sandbox/modules/import/lib/detect/find_program.lua b/xmake/core/sandbox/modules/import/lib/detect/find_program.lua index 18c9be5e3..1cb1c1a81 100644 --- a/xmake/core/sandbox/modules/import/lib/detect/find_program.lua +++ b/xmake/core/sandbox/modules/import/lib/detect/find_program.lua @@ -117,16 +117,49 @@ function sandbox_lib_detect_find_program._find_from_pathes(name, pathes, opt) end end +-- find program from the xmake packages +function sandbox_lib_detect_find_program._find_from_packages(name, opt) + + -- get the manifest file of package, .e.g ~/.xmake/packages/g/git/1.1.12/ed41d5327fad3fc06fe376b4a94f62ef/manifest.txt + local manifest_file = path.join(package.installdir(), name:sub(1, 1), name, opt.version, opt.buildhash, "manifest.txt") + if not os.isfile(manifest_file) then + return + end + + -- get install directory of this package + local installdir = path.directory(manifest_file) + + -- init pathes + local pathes = {} + local manifest = io.load(manifest_file) + if manifest and manifest.envs then + local pathenvs = manifest.envs.PATH + if pathenvs then + for _, pathenv in ipairs(pathenvs) do + table.insert(pathes, path.join(installdir, pathenv)) + end + end + end + + -- find it + return sandbox_lib_detect_find_program._find_from_pathes(name, pathes, opt) +end + -- find program function sandbox_lib_detect_find_program._find(name, pathes, opt) - -- attempt to check it from the given directories + -- attempt to find it from the given directories local program_path = sandbox_lib_detect_find_program._find_from_pathes(name, pathes, opt) if program_path then return program_path end - -- attempt to check it from regists + -- attempt to find it from the xmake packages + if opt.version and opt.buildhash then + return sandbox_lib_detect_find_program._find_from_packages(name, opt) + end + + -- attempt to find it from regists if os.host() == "windows" then local program_name = name:lower() if not program_name:endswith(".exe") then @@ -143,7 +176,7 @@ function sandbox_lib_detect_find_program._find(name, pathes, opt) end end else - -- attempt to check it use `which program` command + -- attempt to find it use `which program` command local ok, program_path = os.iorunv("which", {name}) if ok and program_path then -- check it @@ -156,7 +189,7 @@ function sandbox_lib_detect_find_program._find(name, pathes, opt) end end - -- attempt to check it from the some default system directories + -- attempt to find it from the some default system directories local syspathes = {} if os.host() ~= "windows" then table.insert(syspathes, "/usr/local/bin") @@ -169,7 +202,7 @@ function sandbox_lib_detect_find_program._find(name, pathes, opt) end end - -- attempt to check it directly in current environment + -- attempt to find it directly in current environment -- -- @note must be detected at the end, because full path is more accurate -- diff --git a/xmake/core/sandbox/modules/irpairs.lua b/xmake/core/sandbox/modules/irpairs.lua new file mode 100644 index 000000000..e498ae363 --- /dev/null +++ b/xmake/core/sandbox/modules/irpairs.lua @@ -0,0 +1,72 @@ +--!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 irpairs.lua +-- + +-- load modules +local table = require("base/table") + +-- irpairs +-- +-- .e.g +-- +-- @code +-- +-- for idx, val in irpairs({"a", "b", "c", "d", "e", "f"}) do +-- print("%d %s", idx, val) +-- end +-- +-- for idx, val in irpairs({"a", "b", "c", "d", "e", "f"}, function (v) return v:upper() end) do +-- print("%d %s", idx, val) +-- end +-- +-- for idx, val in irpairs({"a", "b", "c", "d", "e", "f"}, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do +-- print("%d %s", idx, val) +-- end +-- +-- @endcode +function sandbox_irpairs(t, filter, ...) + + -- has filter? + local has_filter = type(filter) == "function" + + -- init iterator + local args = {...} + local iter = function (t, i) + if i > 1 then + i = i - 1 + local v = t[i] + if has_filter then + v = filter(v, unpack(args)) + end + return i, v + end + end + + -- return iterator and initialized state + t = table.wrap(t) + return iter, t, #t + 1 +end + +-- load module +return sandbox_irpairs + diff --git a/xmake/core/tool/builder.lua b/xmake/core/tool/builder.lua index a08f7226f..0eee93313 100644 --- a/xmake/core/tool/builder.lua +++ b/xmake/core/tool/builder.lua @@ -366,6 +366,8 @@ function builder:_add_flags_from_argument(flags, target, args) if target then local key = target:type() self:_add_flags_from_language(flags, target, {[key] = function (name) return args[name] end}) + else + self:_add_flags_from_language(flags, nil, {target = function (name) return args[name] end}) end end diff --git a/xmake/core/tool/compiler.lua b/xmake/core/tool/compiler.lua index 781e95e7d..01b9bf659 100644 --- a/xmake/core/tool/compiler.lua +++ b/xmake/core/tool/compiler.lua @@ -47,12 +47,10 @@ end -- add flags from the platform function compiler:_add_flags_from_platform(flags, targetkind) - -- add flags - local toolname = self:name() - for _, flagkind in ipairs(self:_flagkinds()) do - - -- add flags for platform with the given target kind, e.g. binary.gcc.cxflags or binary.cxflags - if targetkind then + -- add flags for platform with the given target kind, e.g. binary.gcc.cxflags or binary.cxflags + if targetkind then + local toolname = self:name() + for _, flagkind in ipairs(self:_flagkinds()) do local toolflags = platform.get(targetkind .. '.' .. toolname .. '.' .. flagkind) table.join2(flags, toolflags or platform.get(targetkind .. '.' .. flagkind)) end @@ -266,7 +264,7 @@ end -- -- @param opt the argument options (contain all the compiler attributes of target), -- .e.g --- {target = ..., targetkind = "static", config = {defines = "", cxflags = "", includedirs = ""}} +-- {target = ..., targetkind = "static", configs = {defines = "", cxflags = "", includedirs = ""}} -- -- @return flags string, flags list -- @@ -300,14 +298,13 @@ function compiler:compflags(opt) end -- add flags for the argument - if opt.config then - self:_add_flags_from_argument(flags, target, opt.config) + local configs = opt.configs or opt.config + if configs then + self:_add_flags_from_argument(flags, target, configs) end -- add flags from the platform - if target then - self:_add_flags_from_platform(flags, targetkind) - end + self:_add_flags_from_platform(flags, targetkind) -- add flags from the compiler self:_add_flags_from_compiler(flags, targetkind) diff --git a/xmake/core/tool/linker.lua b/xmake/core/tool/linker.lua index f7482888c..d582d62bb 100644 --- a/xmake/core/tool/linker.lua +++ b/xmake/core/tool/linker.lua @@ -43,13 +43,11 @@ local compiler = require("tool/compiler") -- add flags from the platform function linker:_add_flags_from_platform(flags, targetkind) - -- add flags - local toolkind = self:kind() - local toolname = self:name() - for _, flagkind in ipairs(self:_flagkinds()) do - - -- attempt to add special lanugage flags first for target kind, .e.g gc-ldflags, dc-arflags - if targetkind then + -- attempt to add special lanugage flags first for target kind, .e.g binary.gc-ldflags, static.dc-arflags + if targetkind then + local toolkind = self:kind() + local toolname = self:name() + for _, flagkind in ipairs(self:_flagkinds()) do local toolflags = platform.get(targetkind .. '.' .. toolname .. '.' .. toolkind .. 'flags') or platform.get(targetkind .. '.' .. toolname .. '.' .. flagkind) table.join2(flags, toolflags or platform.get(targetkind .. '.' .. toolkind .. 'flags') or platform.get(targetkind .. '.' .. flagkind)) end @@ -247,7 +245,7 @@ end -- get the link flags -- -- @param opt the argument options (contain all the linker attributes of target), --- .e.g {target = ..., targetkind = "static", config = {ldflags = "", links = "", linkdirs = "", ...}} +-- .e.g {target = ..., targetkind = "static", configs = {ldflags = "", links = "", linkdirs = "", ...}} -- function linker:linkflags(opt) @@ -271,14 +269,13 @@ function linker:linkflags(opt) self:_add_flags_from_target(flags, target) -- add flags for the argument - if opt.config then - self:_add_flags_from_argument(flags, target, opt.config) + local configs = opt.configs or opt.config + if configs then + self:_add_flags_from_argument(flags, target, configs) end -- add flags from the platform - if target then - self:_add_flags_from_platform(flags, targetkind) - end + self:_add_flags_from_platform(flags, targetkind) -- add flags from the compiler if target then diff --git a/xmake/languages/asm/api.lua b/xmake/languages/asm/api.lua index ddc850383..ac3378fa5 100644 --- a/xmake/languages/asm/api.lua +++ b/xmake/languages/asm/api.lua @@ -48,6 +48,16 @@ function apis() , "option.add_defines" , "option.add_undefines" , "option.add_rpathdirs" + -- package.add_xxx + , "package.add_links" + , "package.add_syslinks" + , "package.add_asflags" + , "package.add_ldflags" + , "package.add_arflags" + , "package.add_shflags" + , "package.add_defines" + , "package.add_undefines" + , "package.add_rpathdirs" } _g.pathes = { @@ -60,6 +70,9 @@ function apis() -- option.add_xxx , "option.add_linkdirs" , "option.add_includedirs" + -- package.add_xxx + , "package.add_linkdirs" + , "package.add_includedirs" } -- ok diff --git a/xmake/languages/c++/api.lua b/xmake/languages/c++/api.lua index 3b4506abd..9cba73bf1 100644 --- a/xmake/languages/c++/api.lua +++ b/xmake/languages/c++/api.lua @@ -48,7 +48,7 @@ function _funcinfo(func) return name:trim(), code end --- add c function +-- TODO add c function, deprecated function _api_add_cfunc(interp, module, alias, links, includes, func) -- parse the function info @@ -93,7 +93,7 @@ function _api_add_cfunc(interp, module, alias, links, includes, func) interp:api_call("add_options", name) end --- add c functions +-- TODO add c functions, deprecated function _api_add_cfuncs(interp, module, links, includes, ...) -- done @@ -102,7 +102,7 @@ function _api_add_cfuncs(interp, module, links, includes, ...) end end --- add c++ function +-- TODO add c++ function, deprecated function _api_add_cxxfunc(interp, module, alias, links, includes, func) -- parse the function info @@ -147,7 +147,7 @@ function _api_add_cxxfunc(interp, module, alias, links, includes, func) interp:api_call("add_options", name) end --- add c++ functions +-- TODO add c++ functions, deprecated function _api_add_cxxfuncs(interp, module, links, includes, ...) -- done @@ -205,6 +205,19 @@ function apis() , "option.add_undefines_h_if_ok"-- TODO deprecated , "option.add_frameworks" , "option.add_rpathdirs" + -- package.add_xxx + , "package.add_links" + , "package.add_syslinks" + , "package.add_cflags" + , "package.add_cxflags" + , "package.add_cxxflags" + , "package.add_ldflags" + , "package.add_arflags" + , "package.add_shflags" + , "package.add_defines" + , "package.add_undefines" + , "package.add_frameworks" + , "package.add_rpathdirs" } _g.pathes = { @@ -215,8 +228,8 @@ function apis() , "target.set_pcheader" , "target.set_pcxxheader" -- target.add_xxx - , "target.add_headers" -- TODO deprecated - , "target.add_headerdirs" + , "target.add_headers" -- TODO deprecated + , "target.add_headerdirs" -- TODO deprecated , "target.add_headerfiles" , "target.add_linkdirs" , "target.add_includedirs" @@ -225,6 +238,10 @@ function apis() , "option.add_linkdirs" , "option.add_includedirs" , "option.add_frameworkdirs" + -- package.add_xxx + , "package.add_linkdirs" + , "package.add_includedirs" + , "package.add_frameworkdirs" } _g.dictionary = { diff --git a/xmake/languages/dlang/api.lua b/xmake/languages/dlang/api.lua index 09d55c654..63ba3ec2d 100644 --- a/xmake/languages/dlang/api.lua +++ b/xmake/languages/dlang/api.lua @@ -44,6 +44,14 @@ function apis() , "option.add_arflags" , "option.add_shflags" , "option.add_rpathdirs" + -- package.add_xxx + , "package.add_links" + , "package.add_syslinks" + , "package.add_dcflags" + , "package.add_ldflags" + , "package.add_arflags" + , "package.add_shflags" + , "package.add_rpathdirs" } _g.pathes = { @@ -53,6 +61,9 @@ function apis() -- option.add_xxx , "option.add_linkdirs" , "option.add_includedirs" + -- package.add_xxx + , "package.add_linkdirs" + , "package.add_includedirs" } -- ok diff --git a/xmake/modules/detect/tools/find_cmake.lua b/xmake/modules/detect/tools/find_cmake.lua index e9a20232d..021133052 100644 --- a/xmake/modules/detect/tools/find_cmake.lua +++ b/xmake/modules/detect/tools/find_cmake.lua @@ -52,7 +52,7 @@ function main(opt) -- find program version local version = nil - if opt and opt.version then + if program and opt and opt.version then version = find_programver(program, opt) end diff --git a/xmake/modules/lib/detect/check_cxsnippets.lua b/xmake/modules/lib/detect/check_cxsnippets.lua index e44043b99..48a56fe1b 100644 --- a/xmake/modules/lib/detect/check_cxsnippets.lua +++ b/xmake/modules/lib/detect/check_cxsnippets.lua @@ -120,7 +120,7 @@ end -- .e.g -- { verbose = false, target = [target|option], sourcekind = "[cc|cxx]" -- , types = {"wchar_t", "char*"}, includes = "stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"} --- , config = {defines = "xx", cxflags = ""}} +-- , configs = {defines = "xx", cxflags = ""}} -- -- funcs: -- sigsetjmp @@ -144,11 +144,23 @@ function main(snippets, opt) -- init snippets snippets = snippets or {} + -- get configs + local configs = opt.configs or opt.config + -- get links - local links = table.wrap(opt.links) + local links = {} + if configs and configs.links then + table.join2(links, configs.links) + end if opt.target then table.join2(links, opt.target:get("links")) end + if configs and configs.syslinks then + table.join2(links, configs.syslinks) + end + if opt.target then + table.join2(links, opt.target:get("syslinks")) + end -- get types local types = table.wrap(opt.types) @@ -199,7 +211,7 @@ function main(snippets, opt) -- trace if opt.verbose or option.get("verbose") or option.get("diagnosis") then - local kind = ifelse(sourcekind == "cc", "c", "c++") + local kind = opt.sourcekind == "cc" and "c" or "c++" if #includes > 0 then cprint("${dim}> checking for the %s includes(%s)", kind, table.concat(includes, ", ")) end diff --git a/xmake/modules/lib/detect/find_package.lua b/xmake/modules/lib/detect/find_package.lua index dc9286c54..63745c48d 100644 --- a/xmake/modules/lib/detect/find_package.lua +++ b/xmake/modules/lib/detect/find_package.lua @@ -87,7 +87,6 @@ function main(name, opt) 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}") - dprint(result) else cprint("checking for the %s ... ${color.nothing}${text.nothing}", name) end diff --git a/xmake/modules/lib/detect/has_cfuncs.lua b/xmake/modules/lib/detect/has_cfuncs.lua index 6cf8f4cd3..73ab54eca 100644 --- a/xmake/modules/lib/detect/has_cfuncs.lua +++ b/xmake/modules/lib/detect/has_cfuncs.lua @@ -30,7 +30,7 @@ import("lib.detect.check_cxsnippets") -- @param funcs the funcs -- @param opt the argument options -- .e.g --- { verbose = false, target = [target|option], includes = "", config = {linkdirs = .., links = .., defines = .., ..}} +-- { verbose = false, target = [target|option], includes = "", configs = {linkdirs = .., links = .., defines = .., ..}} -- -- funcs: -- sigsetjmp @@ -55,5 +55,6 @@ function main(funcs, opt) opt.funcs = funcs -- has funcs? - return check_cxsnippets("", opt) + local name = opt.name or "has_cfuncs" + return check_cxsnippets({[name] = ""}, opt) end diff --git a/xmake/modules/lib/detect/has_cincludes.lua b/xmake/modules/lib/detect/has_cincludes.lua index a70c17f56..195a482e1 100644 --- a/xmake/modules/lib/detect/has_cincludes.lua +++ b/xmake/modules/lib/detect/has_cincludes.lua @@ -30,7 +30,7 @@ import("lib.detect.check_cxsnippets") -- @param includes the includes -- @param opt the argument options -- .e.g --- { verbose = false, target = [target|option], config = {defines = "..", .. }} +-- { verbose = false, target = [target|option], configs = {defines = "..", .. }} -- -- @return true or false -- @@ -49,5 +49,6 @@ function main(includes, opt) opt.includes = includes -- has includes? - return check_cxsnippets("", opt) + local name = opt.name or "has_cincludes" + return check_cxsnippets({[name] = ""}, opt) end diff --git a/xmake/modules/lib/detect/has_ctypes.lua b/xmake/modules/lib/detect/has_ctypes.lua index 2341b983d..2ac05a30e 100644 --- a/xmake/modules/lib/detect/has_ctypes.lua +++ b/xmake/modules/lib/detect/has_ctypes.lua @@ -30,7 +30,7 @@ import("lib.detect.check_cxsnippets") -- @param types the types -- @param opt the argument options -- .e.g --- { verbose = false, target = [target|option], includes = .., config = {defines = .., ..}} +-- { verbose = false, target = [target|option], includes = .., configs = {defines = .., ..}} -- -- @return true or false -- @@ -49,5 +49,6 @@ function main(types, opt) opt.types = types -- has types? - return check_cxsnippets("", opt) + local name = opt.name or "has_ctypes" + return check_cxsnippets({[name] = ""}, opt) end diff --git a/xmake/modules/lib/detect/has_cxxfuncs.lua b/xmake/modules/lib/detect/has_cxxfuncs.lua index 0ee26c897..e30a21416 100644 --- a/xmake/modules/lib/detect/has_cxxfuncs.lua +++ b/xmake/modules/lib/detect/has_cxxfuncs.lua @@ -30,7 +30,7 @@ import("lib.detect.check_cxsnippets") -- @param funcs the funcs -- @param opt the argument options -- .e.g --- { verbose = false, target = [target|option], includes = "", config = {linkdirs = .., links = .., defines = .., ..}} +-- { verbose = false, target = [target|option], includes = "", configs = {linkdirs = .., links = .., defines = .., ..}} -- -- funcs: -- sigsetjmp @@ -55,5 +55,6 @@ function main(funcs, opt) opt.funcs = funcs -- has funcs? - return check_cxsnippets("", opt) + local name = opt.name or "has_cxxfuncs" + return check_cxsnippets({[name] = ""}, opt) end diff --git a/xmake/modules/lib/detect/has_cxxincludes.lua b/xmake/modules/lib/detect/has_cxxincludes.lua index 57c08ddb6..6c4846134 100644 --- a/xmake/modules/lib/detect/has_cxxincludes.lua +++ b/xmake/modules/lib/detect/has_cxxincludes.lua @@ -30,7 +30,7 @@ import("lib.detect.check_cxsnippets") -- @param includes the includes -- @param opt the argument options -- .e.g --- { verbose = false, target = [target|option], config = {defines = "..", .. }} +-- { verbose = false, target = [target|option], configs = {defines = "..", .. }} -- -- @return true or false -- @@ -49,5 +49,6 @@ function main(includes, opt) opt.includes = includes -- has includes? - return check_cxsnippets("", opt) + local name = opt.name or "has_cxxincludes" + return check_cxsnippets({[name] = ""}, opt) end diff --git a/xmake/modules/lib/detect/has_cxxtypes.lua b/xmake/modules/lib/detect/has_cxxtypes.lua index 1011a4b5f..f52cee697 100644 --- a/xmake/modules/lib/detect/has_cxxtypes.lua +++ b/xmake/modules/lib/detect/has_cxxtypes.lua @@ -30,7 +30,7 @@ import("lib.detect.check_cxsnippets") -- @param types the types -- @param opt the argument options -- .e.g --- { verbose = false, target = [target|option], includes = .., config = {defines = .., ..}} +-- { verbose = false, target = [target|option], includes = .., configs = {defines = .., ..}} -- -- @return true or false -- @@ -49,5 +49,6 @@ function main(types, opt) opt.types = types -- has types? - return check_cxsnippets("", opt) + local name = opt.name or "has_cxxtypes" + return check_cxsnippets({[name] = ""}, opt) end diff --git a/xmake/modules/package/manager/find_package.lua b/xmake/modules/package/manager/find_package.lua index 7fec292e5..49ec98208 100644 --- a/xmake/modules/package/manager/find_package.lua +++ b/xmake/modules/package/manager/find_package.lua @@ -127,16 +127,6 @@ function _find_package(manager_name, package_name, opt) -- remove repeat result.linkdirs = table.unique(result.linkdirs) result.includedirs = table.unique(result.includedirs) - - -- check valid version - if result.version then - local version = try { function () return semver.new(result.version) end } - if version then - result.version = version:rawstr() - else - result.version = nil - end - end end -- ok? @@ -191,7 +181,7 @@ function main(name, opt) -- match version? if opt.version and result then - if not result.version or not semver.satisfies(result.version, opt.version) then + if not (result.version and (result.version == opt.version or semver.satisfies(result.version, opt.version))) then result = nil end end diff --git a/xmake/modules/package/manager/xmake/find_package.lua b/xmake/modules/package/manager/xmake/find_package.lua index cb00d5756..0c6461480 100644 --- a/xmake/modules/package/manager/xmake/find_package.lua +++ b/xmake/modules/package/manager/xmake/find_package.lua @@ -27,6 +27,7 @@ import("core.base.global") import("core.project.config") import("core.project.option") import("core.project.target") +import("core.package.package") import("core.language.language") import("lib.detect.find_file") import("lib.detect.find_library") @@ -34,86 +35,76 @@ import("lib.detect.find_library") -- find package from the repository (maybe only include and no links) function _find_package_from_repo(name, opt) - -- get build mode, e.g. debug_f7821231 - local mode = table.concat({opt.mode or "release", opt.configs_hash}, '_') - - -- 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, mode)) - end - - -- find the prefix info file of package, .e.g prefix/info/z/zlib/1.2.11/info.txt + -- find the manifest file of package, .e.g ~/.xmake/packages/z/zlib/1.1.12/ed41d5327fad3fc06fe376b4a94f62ef/manifest.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, mode, packagepath)) - local prefixfile = find_file("info.txt", packagedirs) - if not prefixfile then + table.insert(packagedirs, path.join(package.installdir(), name:sub(1, 1), name, opt.version or "*", opt.buildhash)) + local manifest_file = find_file("manifest.txt", packagedirs) + if not manifest_file then return end - -- load prefix info - local prefixinfo = io.load(prefixfile) - if not prefixinfo then + -- load manifest info + local manifest = io.load(manifest_file) + if not manifest 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/")) + -- get manifest variables + local vars = manifest.vars or {} + + -- get install directory of this package + local installdir = path.directory(manifest_file) -- 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)) + for _, includedir in ipairs(vars.includedirs) do + table.insert(includedirs, path.join(installdir, includedir)) end if #includedirs == 0 then - table.insert(includedirs, path.join(prefixdir, "include")) + table.insert(includedirs, path.join(installdir, "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)) + for _, linkdir in ipairs(vars.linkdirs) do + table.insert(linkdirs, path.join(installdir, linkdir)) end - if prefixinfo.links then - table.join2(links, prefixinfo.links) + if vars.links then + table.join2(links, vars.links) end - if prefixinfo.installed and (not prefixinfo.linkdirs or not prefixinfo.links) then + if not vars.linkdirs or not vars.links then local found = false - for _, line in ipairs(prefixinfo.installed) do - line = line:trim() - if line:endswith(".lib") or line:endswith(".a") then + for _, file in ipairs(os.files(path.join(installdir, "lib", "*"))) do + if file:endswith(".lib") or file:endswith(".a") then found = true - if not prefixinfo.linkdirs then - table.insert(linkdirs, path.join(prefixdir, path.directory(line))) + if not vars.linkdirs then + table.insert(linkdirs, path.directory(file)) end - if not prefixinfo.links then - table.insert(links, target.linkname(path.filename(line))) + if not vars.links then + table.insert(links, target.linkname(path.filename(file))) 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))) + for _, file in ipairs(os.files(path.join(installdir, "lib", "*"))) do + if file:endswith(".so") or file:endswith(".dylib") then + if not vars.linkdirs then + table.insert(linkdirs, path.directory(file)) end - if not prefixinfo.links then - table.insert(links, target.linkname(path.filename(line))) + if not vars.links then + table.insert(links, target.linkname(path.filename(file))) end end end end end - -- add root include and link directories + -- add root link directories if #linkdirs == 0 then - table.insert(linkdirs, path.join(prefixdir, "lib")) + table.insert(linkdirs, path.join(installdir, "lib")) end -- uses name as links directly .e.g libname.a @@ -135,16 +126,25 @@ function _find_package_from_repo(name, opt) 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 + for name, values in pairs(vars) do + if name ~= "links" and name ~= "linkdirs" and name ~= "includedirs" then result[name] = values end end - -- get version - result.version = path.filename(path.directory(prefixfile)) + -- update the project references file + if result then + local projectdir = os.projectdir() + if projectdir and os.isdir(projectdir) then + local references_file = path.join(installdir, "references.txt") + local references = os.isfile(references_file) and io.load(references_file) or {} + references[projectdir] = os.date("%y%m%d") + io.save(references_file, references) + end + end - -- ok + -- get version + result.version = manifest.version or path.filename(path.directory(path.directory(manifest_file))) return result end @@ -247,7 +247,7 @@ 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", configs_hash = "xxxxxx") +-- @param opt the options, .e.g {verbose = true, version = "1.12.x", buildhash = "xxxxxx") -- function main(name, opt) diff --git a/xmake/modules/package/tools/autoconf.lua b/xmake/modules/package/tools/autoconf.lua index 29e147636..32186a080 100644 --- a/xmake/modules/package/tools/autoconf.lua +++ b/xmake/modules/package/tools/autoconf.lua @@ -22,6 +22,68 @@ -- @file autoconf.lua -- +-- get configs +function _get_configs(package, configs) + local configs = configs or {} + table.insert(configs, "--prefix=" .. package:installdir()) + return configs +end + +-- enter environments +function _enter_envs(package) + + -- get old environments + local envs = {} + envs.CFLAGS = os.getenv("CFLAGS") + envs.CXXFLAGS = os.getenv("CXXFLAGS") + envs.ASFLAGS = os.getenv("ASFLAGS") + envs.ACLOCAL_PATH = os.getenv("ACLOCAL_PATH") + envs.PKG_CONFIG_PATH = os.getenv("PKG_CONFIG_PATH") + + -- set new environments + local cflags = package:config("cflags") + local cxflags = package:config("cxflags") + local cxxflags = package:config("cxxflags") + local asflags = package:config("asflags") + if package:plat() == "windows" then + local vs_runtime = package:config("vs_runtime") + if vs_runtime then + cxflags = (cxflags or "") .. " /" .. vs_runtime .. (package:debug() and "d" or "") + end + end + if cflags then + os.addenv("CFLAGS", cflags) + end + if cxflags then + os.addenv("CFLAGS", cxflags) + os.addenv("CXXFLAGS", cxflags) + end + if cxxflags then + os.addenv("CXXFLAGS", cxxflags) + end + if asflags then + os.addenv("ASFLAGS", asflags) + end + for _, dep in ipairs(package:orderdeps()) do + local pkgconfig = path.join(dep:installdir(), "lib", "pkgconfig") + if os.isdir(pkgconfig) then + os.addenv("PKG_CONFIG_PATH", pkgconfig) + end + local aclocal = path.join(dep:installdir(), "share", "aclocal") + if os.isdir(aclocal) then + os.addenv("ACLOCAL_PATH", aclocal) + end + end + return envs +end + +-- leave environments +function _leave_envs(package, envs) + for k, v in pairs(envs) do + os.setenv(k, v) + end +end + -- install package function install(package, configs) @@ -34,12 +96,9 @@ function install(package, configs) end end - -- inherit require and option configs + -- pass configurations local argv = {} - if not configs or not configs.prefix then - table.insert(argv, "--prefix=" .. package:installdir()) - end - for name, value in pairs(configs) do + for name, value in pairs(_get_configs(package, configs)) do value = tostring(value):trim() if type(name) == "number" then if value ~= "" then @@ -50,15 +109,8 @@ function install(package, configs) end end - -- inherit flags from configs - local flags_prev = {} - for _, name in ipairs({"cflags", "cxxflags", "ldflags"}) do - local flags = package:config(name) or (configs and configs[name] or nil) - if flags then - flags_prev[name] = os.getenv(name:upper()) - os.addenv(name:upper(), flags) - end - end + -- enter environments + local envs = _enter_envs(package) -- do configure os.vrunv("./configure", argv) @@ -67,9 +119,7 @@ function install(package, configs) os.vrun("make -j4") os.vrun("make install") - -- restore flags - for name, flags in pairs(flags_prev) do - os.setenv(name:upper(), flags) - end + -- leave environments + _leave_envs(package, envs) end diff --git a/xmake/modules/package/tools/cmake.lua b/xmake/modules/package/tools/cmake.lua index cbcf99014..f7afc56c5 100644 --- a/xmake/modules/package/tools/cmake.lua +++ b/xmake/modules/package/tools/cmake.lua @@ -26,6 +26,59 @@ import("core.base.option") import("lib.detect.find_file") +-- get configs +function _get_configs(package, configs) + local configs = configs or {} + if package:plat() == "windows" then + local vs_runtime = package:config("vs_runtime") + if vs_runtime then + table.insert(configs, '-DCMAKE_CXX_FLAGS_DEBUG="/' .. vs_runtime .. 'd"') + table.insert(configs, '-DCMAKE_CXX_FLAGS_RELEASE="/' .. vs_runtime .. '"') + table.insert(configs, '-DCMAKE_C_FLAGS_DEBUG="/' .. vs_runtime .. 'd"') + table.insert(configs, '-DCMAKE_C_FLAGS_RELEASE="/' .. vs_runtime .. '"') + end + end + local cflags = package:config("cflags") + if cflags then + table.insert(configs, '-DCMAKE_C_FLAGS="' .. cflags .. '"') + end + local cxflags = package:config("cxflags") + if cxflags then + table.insert(configs, '-DCMAKE_C_FLAGS="' .. cxflags .. '"') + table.insert(configs, '-DCMAKE_CXX_FLAGS="' .. cxflags .. '"') + end + local cxxflags = package:config("cxxflags") + if cxxflags then + table.insert(configs, '-DCMAKE_CXX_FLAGS="' .. cxxflags .. '"') + end + local asflags = package:config("asflags") + if asflags then + table.insert(configs, '-DCMAKE_ASM_FLAGS="' .. asflags .. '"') + end + return configs +end + +-- enter environments +function _enter_envs(package) + + -- get old environments + local envs = {} + envs.CMAKE_PREFIX_PATH = os.getenv("CMAKE_PREFIX_PATH") + + -- set new environments + for _, dep in ipairs(package:orderdeps()) do + os.addenv("CMAKE_PREFIX_PATH", dep:installdir()) + end + return envs +end + +-- leave environments +function _leave_envs(package, envs) + for k, v in pairs(envs) do + os.setenv(k, v) + end +end + -- install package function install(package, configs) @@ -39,7 +92,9 @@ function install(package, configs) table.insert(argv, "-A") table.insert(argv, "x64") end - for name, value in pairs(configs) do + + -- pass configurations + for name, value in pairs(_get_configs(package, configs)) do value = tostring(value):trim() if type(name) == "number" then if value ~= "" then @@ -51,6 +106,9 @@ function install(package, configs) end table.insert(argv, '..') + -- enter environments + local envs = _enter_envs(package) + -- generate build file os.vrunv("cmake", argv) @@ -74,6 +132,9 @@ function install(package, configs) os.cp("install/lib", package:installdir()) os.cp("install/include", package:installdir()) end + + -- leave environments + _leave_envs(package, envs) os.cd(oldir) end diff --git a/xmake/modules/package/tools/xmake.lua b/xmake/modules/package/tools/xmake.lua index 042b0c468..cc0fe0d45 100644 --- a/xmake/modules/package/tools/xmake.lua +++ b/xmake/modules/package/tools/xmake.lua @@ -25,11 +25,40 @@ -- imports import("core.base.option") +-- get configs +function _get_configs(package, configs) + local configs = configs or {} + local cflags = package:config("cflags") + local cxflags = package:config("cxflags") + local cxxflags = package:config("cxxflags") + local asflags = package:config("asflags") + if package:plat() == "windows" then + local vs_runtime = package:config("vs_runtime") + if vs_runtime then + cxflags = (cxflags or "") .. " /" .. vs_runtime .. (package:debug() and "d" or "") + end + end + table.insert(configs, "--mode=" .. (package:debug() and "debug" or "release")) + if cflags then + table.insert(configs, '--cflags="' .. cflags .. '"') + end + if cxflags then + table.insert(configs, '--cxflags="' .. cxflags .. '"') + end + if cxxflags then + table.insert(configs, '--cxxflags="' .. cxxflags .. '"') + end + if asflags then + table.insert(configs, '--asflags="' .. asflags .. '"') + end + return configs +end + -- install package function install(package, configs) -- inherit builtin configs - local argv = {"f", "-y"} + local argv = {"f", "-y"} local names = {"plat", "arch", "ndk", "ndk_sdkver", "vs", "sdk", "bin", "cross", "ld", "sh", "ar", "cc", "cxx", "mm", "mxx"} for _, name in ipairs(names) do local value = get_config(name) @@ -37,11 +66,17 @@ function install(package, configs) table.insert(argv, "--" .. name .. "=" .. tostring(value)) end end - table.insert(argv, "--mode=" .. (package:debug() and "debug" or "release")) - -- inherit require and option configs - for name, value in pairs(table.join(package:configs() or {}, configs or {})) do - table.insert(argv, "--" .. name .. "=" .. tostring(value)) + -- pass configurations + for name, value in pairs(_get_configs(package, configs)) do + value = tostring(value):trim() + if type(name) == "number" then + if value ~= "" then + table.insert(argv, value) + end + else + table.insert(argv, "--" .. name .. "=" .. value) + end end if option.get("verbose") then table.insert(argv, "-v") diff --git a/xmake/repository/packages/c/cmake/xmake.lua b/xmake/repository/packages/c/cmake/xmake.lua index e0994cf52..fd1b22be2 100644 --- a/xmake/repository/packages/c/cmake/xmake.lua +++ b/xmake/repository/packages/c/cmake/xmake.lua @@ -6,16 +6,28 @@ package("cmake") if is_host("macosx") then add_urls("https://cmake.org/files/v3.11/cmake-3.11.4-Darwin-x86_64.tar.gz") + add_urls("https://github.com/Kitware/CMake/releases/download/v3.11.4/cmake-3.11.4-Darwin-x86_64.tar.gz") + add_urls("https://gitlab.com/xmake-mirror/cmake-releases/raw/master/cmake-3.11.4-Darwin-x86_64.tar.gz") + add_urls("https://dev.tencent.com/u/waruqi/p/cmake-releases/git/raw/master/cmake-3.11.4-Darwin-x86_64.tar.gz") add_versions("3.11.4", "2b5eb705f036b1906a5e0bce996e9cd56d43d73bdee8318ece3e5ce31657b812") elseif is_host("linux") and is_arch("x86_64") then add_urls("https://cmake.org/files/v3.11/cmake-3.11.4-Linux-x86_64.tar.gz") + add_urls("https://github.com/Kitware/CMake/releases/download/v3.11.4/cmake-3.11.4-Linux-x86_64.tar.gz") + add_urls("https://gitlab.com/xmake-mirror/cmake-releases/raw/master/cmake-3.11.4-Linux-x86_64.tar.gz") + add_urls("https://dev.tencent.com/u/waruqi/p/cmake-releases/git/raw/master/cmake-3.11.4-Linux-x86_64.tar.gz") add_versions("3.11.4", "6dab016a6b82082b8bcd0f4d1e53418d6372015dd983d29367b9153f1a376435") elseif is_host("windows") then if os.arch() == "x64" then add_urls("https://cmake.org/files/v3.11/cmake-3.11.4-win64-x64.zip", {excludes = "*/doc/*"}) + add_urls("https://github.com/Kitware/CMake/releases/download/v3.11.4/cmake-3.11.4-win64-x64.zip", {excludes = "*/doc/*"}) + add_urls("https://gitlab.com/xmake-mirror/cmake-releases/raw/master/cmake-3.11.4-win64-x64.zip", {excludes = "*/doc/*"}) + add_urls("https://dev.tencent.com/u/waruqi/p/cmake-releases/git/raw/master/cmake-3.11.4-win64-x64.zip", {excludes = "*/doc/*"}) add_versions("3.11.4", "d3102abd0ded446c898252b58857871ee170312d8e7fd5cbff01fbcb1068a6e5") else add_urls("https://cmake.org/files/v3.11/cmake-3.11.4-win32-x86.zip", {excludes = "*/doc/*"}) + add_urls("https://github.com/Kitware/CMake/releases/download/v3.11.4/cmake-3.11.4-win32-x86.zip", {excludes = "*/doc/*"}) + add_urls("https://gitlab.com/xmake-mirror/cmake-releases/raw/master/cmake-3.11.4-win32-x86.zip", {excludes = "*/doc/*"}) + add_urls("https://dev.tencent.com/u/waruqi/p/cmake-releases/git/raw/master/cmake-3.11.4-win32-x86.zip", {excludes = "*/doc/*"}) add_versions("3.11.4", "b068001ff879f86e704977c50a8c5917e4b4406c66242366dba2674abe316579") end end diff --git a/xmake/repository/packages/g/git/xmake.lua b/xmake/repository/packages/g/git/xmake.lua index 74f000b65..f14d0c71b 100644 --- a/xmake/repository/packages/g/git/xmake.lua +++ b/xmake/repository/packages/g/git/xmake.lua @@ -27,6 +27,7 @@ package("git") end on_load("windows", function (package) + package:addenv("PATH", path.join("share", "MinGit", "mingw32", "bin")) package:addenv("PATH", path.join("share", "MinGit", "cmd")) end) |
