diff --git a/CHANGELOG.md b/CHANGELOG.md index bcd9ef59d7f..2ee820c92b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ ## master (unreleased) +### New features + +* [#68](https://github.com/tboox/xmake/issues/68): Add `$(programdir)` and `$(xmake)` builtin variables +* add `is_host` api to get current host operating system +* [#79](https://github.com/tboox/xmake/issues/79): Improve `xmake lua` to run interactive commands, read-eval-print (REPL) + +### Changes + +* Modify option menu color. +* [#71](https://github.com/tboox/xmake/issues/71): Improve to map optimization flags for cl.exe +* [#73](https://github.com/tboox/xmake/issues/73): Attempt to get executable path as xmake's program directory +* Improve the scope of `xmake.lua` in `add_subdirs` and use independent sub-scope to avoid dirty scope +* [#78](https://github.com/tboox/xmake/pull/78): Get terminal size in runtime and soft-wrap the help printing +* Avoid generate `.xmake` directory if be not in project + +### Bugs fixed + +* [#67](https://github.com/tboox/xmake/issues/67): Fix `sudo make install` permission problem +* [#70](https://github.com/tboox/xmake/issues/70): Fix check android compiler error +* Fix temporary file path conflict +* Fix `os.host` and `os.arch` interfaces +* Fix interpreter bug for loading root api +* [#77](https://github.com/tboox/xmake/pull/77): fix `cprint` no color reset eol + ## v2.1.3 ### New features @@ -19,7 +43,7 @@ * Improve check toolchains and implement delay checking * Add user tips when scanning and generating `xmake.lua` automatically -## Bugs fixed +### Bugs fixed * Fix error tips for checking xmake min version * [#60](https://github.com/tboox/xmake/issues/60): Fix self-build for macosx and windows @@ -246,6 +270,30 @@ ## master (开发中) +### 新特性 + +* [#68](https://github.com/tboox/xmake/issues/68): 增加`$(programdir)`和`$(xmake)`内建变量 +* 添加`is_host`接口去判断当前的主机环境 +* [#79](https://github.com/tboox/xmake/issues/79): 增强`xmake lua`,支持交互式解释执行 + +### 改进 + +* 修改菜单选项颜色 +* [#71](https://github.com/tboox/xmake/issues/71): 针对widows编译器改进优化选项映射 +* [#73](https://github.com/tboox/xmake/issues/73): 尝试获取可执行文件路径来作为xmake的脚本目录 +* 在`add_subdirs`中的子`xmake.lua`中,使用独立子作用域,避免作用域污染导致的干扰问题 +* [#78](https://github.com/tboox/xmake/pull/78): 美化非全屏终端窗口下的`xmake --help`输出 +* 避免产生不必要的`.xmake`目录,如果不在工程中的时候 + +### Bugs修复 + +* [#67](https://github.com/tboox/xmake/issues/67): 修复 `sudo make install` 命令权限问题 +* [#70](https://github.com/tboox/xmake/issues/70): 修复检测android编译器错误 +* 修复临时文件路径冲突问题 +* 修复`os.host`, `os.arch`等接口 +* 修复根域api加载干扰其他子作用域问题 +* [#77](https://github.com/tboox/xmake/pull/77): 修复`cprint`色彩打印中断问题 + ## v2.1.3 ### 新特性 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75b2ad34072..16d7cdc4906 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,4 +44,4 @@ try to follow these guidelines when you do so. * 请提交代码到`dev`分支,如果通过,我们会在特定时间合并到`master`分支上 * 为了规范化提交日志的格式,commit消息,不要用中文,请用英文描述 -[1]: https://github.com/waruqi/xmake/issues +[1]: https://github.com/tboox/xmake/issues diff --git a/Makefile b/Makefile index 0aad898bb27..f50d094c9d6 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ ARCH :=$(if $(findstring android,$(PLAT)),armv7,$(ARCH)) endif xmake_dir_install :=$(prefix)/share/xmake -xmake_core :=./core/bin/demo.pkg/bin/$(PLAT)/$(ARCH)/demo.b +xmake_core :=./core/src/demo/demo.b xmake_core_install :=$(xmake_dir_install)/xmake xmake_loader :=/tmp/xmake_loader xmake_loader_install:=$(prefix)/bin/xmake @@ -53,7 +53,6 @@ install: @echo plat: $(PLAT) @echo arch: $(ARCH) @# create the xmake install directory - @$(MAKE) -C core --no-print-directory i @if [ -d $(xmake_dir_install) ]; then rm -rf $(xmake_dir_install); fi @if [ ! -d $(xmake_dir_install) ]; then mkdir -p $(xmake_dir_install); fi @# install the xmake core file diff --git a/README.md b/README.md index f4ea6e72f01..2b9762bcb1a 100755 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ so that any developer can quickly pick it up and enjoy the productivity boost wh If you want to known more, please refer to: * [Documents](http://xmake.io/#/home) -* [Github](https://github.com/waruqi/xmake) +* [Github](https://github.com/tboox/xmake) * [HomePage](http://www.xmake.io) ## Simple description diff --git a/README_zh.md b/README_zh.md index 66b5fd1d306..10466a7bb69 100755 --- a/README_zh.md +++ b/README_zh.md @@ -18,7 +18,7 @@ xmake的目标是开发者更加关注于项目本身开发,简化项目的描 如果你想要了解更多,请参考: * [在线文档](http://xmake.io/#/zh/) -* [在线源码](https://github.com/waruqi/xmake) +* [在线源码](https://github.com/tboox/xmake) * [项目主页](http://www.xmake.io/cn) ## 简单的工程描述 diff --git a/appveyor.yml b/appveyor.yml index b070081700d..3ecf71db428 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,6 +11,10 @@ before_build: - cmd: xmake-installer.exe /S /D=C:\xmake - cmd: PATH=%PATH%;C:\xmake - cmd: xmake --version + - cmd: cd core + - cmd: xmake -v + - ps: cp -force build\xmake.exe C:\xmake\xmake.exe + - cmd: cd .. - ps: cp -r -force xmake\* C:\xmake - cmd: xmake --version - cmd: dir C:\xmake @@ -18,4 +22,4 @@ before_build: build_script: - cmd: cd core - cmd: if %platform%==Win64 xmake f -a x64 - - cmd: xmake -v + - cmd: xmake -r -v diff --git a/core/pkg/tbox.pkg/inc/linux/tbox.config.h b/core/pkg/tbox.pkg/inc/linux/tbox.config.h index 4c1a5ff84f9..ec8ed49aa0b 100644 --- a/core/pkg/tbox.pkg/inc/linux/tbox.config.h +++ b/core/pkg/tbox.pkg/inc/linux/tbox.config.h @@ -6,7 +6,7 @@ #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 6 #define TB_CONFIG_VERSION_ALTER 2 -#define TB_CONFIG_VERSION_BUILD 201703291752 +#define TB_CONFIG_VERSION_BUILD 201704211356 // defines #define TB_CONFIG_OS_LINUX 1 diff --git a/core/pkg/tbox.pkg/inc/macosx/tbox.config.h b/core/pkg/tbox.pkg/inc/macosx/tbox.config.h index 624f8cbfa1b..cef43e46bad 100644 --- a/core/pkg/tbox.pkg/inc/macosx/tbox.config.h +++ b/core/pkg/tbox.pkg/inc/macosx/tbox.config.h @@ -6,7 +6,7 @@ #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 6 #define TB_CONFIG_VERSION_ALTER 2 -#define TB_CONFIG_VERSION_BUILD 201703291743 +#define TB_CONFIG_VERSION_BUILD 201704210948 // defines #define TB_CONFIG_OS_MACOSX 1 diff --git a/core/pkg/tbox.pkg/inc/tbox/prefix/arm64/prefix.S b/core/pkg/tbox.pkg/inc/tbox/prefix/arm64/prefix.S index b2dd79425c2..bcd65c0ae8b 100644 --- a/core/pkg/tbox.pkg/inc/tbox/prefix/arm64/prefix.S +++ b/core/pkg/tbox.pkg/inc/tbox/prefix/arm64/prefix.S @@ -30,7 +30,7 @@ # define ELF # define EXTERN_ASM #else -# define ELF # +# define ELF // # define EXTERN_ASM _ #endif diff --git a/core/pkg/tbox.pkg/inc/windows/tbox.config.h b/core/pkg/tbox.pkg/inc/windows/tbox.config.h index d9f19f03c1d..98639e64e34 100644 --- a/core/pkg/tbox.pkg/inc/windows/tbox.config.h +++ b/core/pkg/tbox.pkg/inc/windows/tbox.config.h @@ -6,7 +6,7 @@ #define TB_CONFIG_VERSION_MAJOR 1 #define TB_CONFIG_VERSION_MINOR 6 #define TB_CONFIG_VERSION_ALTER 2 -#define TB_CONFIG_VERSION_BUILD 201703301429 +#define TB_CONFIG_VERSION_BUILD 201704211132 // defines #define TB_CONFIG_OS_WINDOWS 1 diff --git a/core/pkg/tbox.pkg/lib/release/linux/i386/libtbox.a b/core/pkg/tbox.pkg/lib/release/linux/i386/libtbox.a index 68ca0290f5a..256ee847e59 100644 Binary files a/core/pkg/tbox.pkg/lib/release/linux/i386/libtbox.a and b/core/pkg/tbox.pkg/lib/release/linux/i386/libtbox.a differ diff --git a/core/pkg/tbox.pkg/lib/release/linux/x86_64/libtbox.a b/core/pkg/tbox.pkg/lib/release/linux/x86_64/libtbox.a index 788eba22081..bd40a510030 100644 Binary files a/core/pkg/tbox.pkg/lib/release/linux/x86_64/libtbox.a and b/core/pkg/tbox.pkg/lib/release/linux/x86_64/libtbox.a differ diff --git a/core/pkg/tbox.pkg/lib/release/macosx/x86_64/libtbox.a b/core/pkg/tbox.pkg/lib/release/macosx/x86_64/libtbox.a index c35e270ef47..c6df4196ed0 100644 Binary files a/core/pkg/tbox.pkg/lib/release/macosx/x86_64/libtbox.a and b/core/pkg/tbox.pkg/lib/release/macosx/x86_64/libtbox.a differ diff --git a/core/pkg/tbox.pkg/lib/release/windows/x64/tbox.lib b/core/pkg/tbox.pkg/lib/release/windows/x64/tbox.lib index b48b20aed3b..e7973acd857 100644 Binary files a/core/pkg/tbox.pkg/lib/release/windows/x64/tbox.lib and b/core/pkg/tbox.pkg/lib/release/windows/x64/tbox.lib differ diff --git a/core/pkg/tbox.pkg/lib/release/windows/x86/tbox.lib b/core/pkg/tbox.pkg/lib/release/windows/x86/tbox.lib index 63318aa9f8d..5c8a3b20f89 100644 Binary files a/core/pkg/tbox.pkg/lib/release/windows/x86/tbox.lib and b/core/pkg/tbox.pkg/lib/release/windows/x86/tbox.lib differ diff --git a/core/pkg/tbox.pkg/xmake.lua b/core/pkg/tbox.pkg/xmake.lua index c6bc5ee18fc..b946b73b2b0 100644 --- a/core/pkg/tbox.pkg/xmake.lua +++ b/core/pkg/tbox.pkg/xmake.lua @@ -1,30 +1,30 @@ - --- the tbox package -option("tbox") - - -- show menu - set_showmenu(true) - - -- set category - set_category("package") - - -- set description - set_description("The tbox package") - - -- set language: c99, c++11 - set_languages("c99", "cxx11") - - -- add defines to config.h if checking ok - add_defines_h_if_ok("$(prefix)_PACKAGE_HAVE_TBOX") - - -- add links for checking - add_links("tbox") - - -- add link directories - add_linkdirs("lib/$(mode)/$(plat)/$(arch)") - - -- add c includes for checking - add_cincludes("tbox/tbox.h") - - -- add include directories - add_includedirs("inc/$(plat)", "inc") + +-- the tbox package +option("tbox") + + -- show menu + set_showmenu(true) + + -- set category + set_category("package") + + -- set description + set_description("The tbox package") + + -- set language: c99, c++11 + set_languages("c99", "cxx11") + + -- add defines to config.h if checking ok + add_defines_h_if_ok("$(prefix)_PACKAGE_HAVE_TBOX") + + -- add links for checking + add_links("tbox") + + -- add link directories + add_linkdirs("lib/$(mode)/$(plat)/$(arch)") + + -- add c includes for checking + add_cincludes("tbox/tbox.h") + + -- add include directories + add_includedirs("inc/$(plat)", "inc") diff --git a/core/src/demo/makefile b/core/src/demo/makefile index 7a9b7754cd2..b24bf4a958b 100644 --- a/core/src/demo/makefile +++ b/core/src/demo/makefile @@ -15,10 +15,15 @@ demo_PKGS-$(TBOX) += tbox demo_PKGS-$(BASE) += base # others -demo_LIBS += xmake$(DTYPE) luajit$(DTYPE) +demo_LIBS += xmake$(DTYPE) luajit$(DTYPE) demo_INC_DIRS += ../ ../luajit/src demo_LIB_DIRS += ../xmake ../luajit demo_CXFLAGS += -D__tb_prefix__=\"xmake\" + +# add readline +ifneq ($(PLAT),windows) +demo_LIBS += readline +endif # suffix include $(PRO_DIR)/suffix.mak diff --git a/core/src/demo/xmake.lua b/core/src/demo/xmake.lua index 6449ef8d2c0..174b2fd38b5 100644 --- a/core/src/demo/xmake.lua +++ b/core/src/demo/xmake.lua @@ -23,6 +23,11 @@ target("demo") add_links("xmake", "luajit") add_linkdirs("$(buildir)") + -- link readline + if not is_plat("windows") then + add_links("readline") + end + -- add packages add_packages("tbox", "base") diff --git a/core/src/xmake/hash/prefix.h b/core/src/xmake/hash/prefix.h new file mode 100644 index 00000000000..5df85a1d350 --- /dev/null +++ b/core/src/xmake/hash/prefix.h @@ -0,0 +1,36 @@ +/*!The Make-like 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 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file prefix.h + * + */ +#ifndef XM_HASH_PREFIX_H +#define XM_HASH_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + + +#endif + + diff --git a/core/src/xmake/hash/sha256.c b/core/src/xmake/hash/sha256.c new file mode 100644 index 00000000000..6a9b1f5dfc9 --- /dev/null +++ b/core/src/xmake/hash/sha256.c @@ -0,0 +1,110 @@ +/*!The Make-like 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 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file sha256.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "sha256" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_hash_sha256(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get the filename + tb_char_t const* filename = luaL_checkstring(lua, 1); + tb_check_return_val(filename, 0); + + // load data from file + tb_bool_t ok = tb_false; + tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO); + if (stream) + { + // open stream + if (tb_stream_open(stream)) + { + // init sha256 + tb_sha_t sha; + tb_sha_init(&sha, TB_SHA_MODE_SHA2_256); + + // read data and update sha256 + tb_byte_t data[TB_STREAM_BLOCK_MAXN]; + while (!tb_stream_beof(stream)) + { + // read data + tb_long_t real = tb_stream_read(stream, data, sizeof(data)); + + // ok? + if (real > 0) tb_sha_spak(&sha, data, real); + // no data? continue it + else if (!real) + { + // wait + real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream)); + tb_check_break(real > 0); + + // has read? + tb_assert_and_check_break(real & TB_STREAM_WAIT_READ); + } + // failed or end? + else break; + } + + // exit sha256 + tb_byte_t buffer[32]; + tb_sha_exit(&sha, buffer, sizeof(buffer)); + + // make sha256 string + tb_size_t i = 0; + tb_size_t n = sha.digest_len << 2; + tb_char_t s[256] = {0}; + for (i = 0; i < n; ++i) tb_snprintf(s + (i << 1), 3, "%02x", buffer[i]); + + // save result + lua_pushstring(lua, s); + + // ok + ok = tb_true; + } + + // exit stream + tb_stream_exit(stream); + } + + // failed? return nil + if (!ok) lua_pushnil(lua); + + // ok + return 1; +} diff --git a/core/src/xmake/os/uuid.c b/core/src/xmake/hash/uuid.c similarity index 97% rename from core/src/xmake/os/uuid.c rename to core/src/xmake/hash/uuid.c index 044bbe83d6a..9dc8e0eb76e 100644 --- a/core/src/xmake/os/uuid.c +++ b/core/src/xmake/hash/uuid.c @@ -37,7 +37,7 @@ /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ -tb_int_t xm_os_uuid(lua_State* lua) +tb_int_t xm_hash_uuid(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c index 84bb69649f7..6830735d2ce 100644 --- a/core/src/xmake/machine.c +++ b/core/src/xmake/machine.c @@ -33,8 +33,12 @@ * includes */ #include "xmake.h" -#ifdef TB_CONFIG_OS_WINDOWS +#if defined(TB_CONFIG_OS_WINDOWS) # include +#elif defined(TB_CONFIG_OS_MACOSX) +# include +#elif defined(TB_CONFIG_OS_LINUX) +# include #endif /* ////////////////////////////////////////////////////////////////////////////////////// @@ -56,13 +60,13 @@ typedef struct __xm_machine_impl_t // the os functions tb_int_t xm_os_argv(lua_State* lua); tb_int_t xm_os_find(lua_State* lua); -tb_int_t xm_os_uuid(lua_State* lua); tb_int_t xm_os_isdir(lua_State* lua); tb_int_t xm_os_rmdir(lua_State* lua); tb_int_t xm_os_mkdir(lua_State* lua); tb_int_t xm_os_cpdir(lua_State* lua); tb_int_t xm_os_chdir(lua_State* lua); tb_int_t xm_os_mtime(lua_State* lua); +tb_int_t xm_os_sleep(lua_State* lua); tb_int_t xm_os_mclock(lua_State* lua); tb_int_t xm_os_curdir(lua_State* lua); tb_int_t xm_os_tmpdir(lua_State* lua); @@ -75,6 +79,7 @@ tb_int_t xm_os_setenv(lua_State* lua); tb_int_t xm_os_getenv(lua_State* lua); tb_int_t xm_os_emptydir(lua_State* lua); tb_int_t xm_os_strerror(lua_State* lua); +tb_int_t xm_os_getwinsize(lua_State* lua); // the path functions tb_int_t xm_path_relative(lua_State* lua); @@ -82,6 +87,10 @@ tb_int_t xm_path_absolute(lua_State* lua); tb_int_t xm_path_translate(lua_State* lua); tb_int_t xm_path_is_absolute(lua_State* lua); +// the hash functions +tb_int_t xm_hash_uuid(lua_State* lua); +tb_int_t xm_hash_sha256(lua_State* lua); + // the string functions tb_int_t xm_string_strcmp(lua_State* lua); tb_int_t xm_string_endswith(lua_State* lua); @@ -94,6 +103,9 @@ tb_int_t xm_process_wait(lua_State* lua); tb_int_t xm_process_waitlist(lua_State* lua); tb_int_t xm_process_close(lua_State* lua); +// the sandbox functions +tb_int_t xm_sandbox_interactive(lua_State* lua); + /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ @@ -103,13 +115,13 @@ static luaL_Reg const g_os_functions[] = { { "argv", xm_os_argv } , { "find", xm_os_find } -, { "uuid", xm_os_uuid } , { "isdir", xm_os_isdir } , { "rmdir", xm_os_rmdir } , { "mkdir", xm_os_mkdir } , { "cpdir", xm_os_cpdir } , { "chdir", xm_os_chdir } , { "mtime", xm_os_mtime } +, { "sleep", xm_os_sleep } , { "mclock", xm_os_mclock } , { "curdir", xm_os_curdir } , { "tmpdir", xm_os_tmpdir } @@ -122,6 +134,7 @@ static luaL_Reg const g_os_functions[] = , { "getenv", xm_os_getenv } , { "emptydir", xm_os_emptydir } , { "strerror", xm_os_strerror } +, { "getwinsize", xm_os_getwinsize} , { tb_null, tb_null } }; @@ -135,6 +148,14 @@ static luaL_Reg const g_path_functions[] = , { tb_null, tb_null } }; +// the hash functions +static luaL_Reg const g_hash_functions[] = +{ + { "uuid", xm_hash_uuid } +, { "sha256", xm_hash_sha256 } +, { tb_null, tb_null } +}; + // the string functions static luaL_Reg const g_string_functions[] = { @@ -155,6 +176,13 @@ static luaL_Reg const g_process_functions[] = , { tb_null, tb_null } }; +// the sandbox functions +static luaL_Reg const g_sandbox_functions[] = +{ + { "interactive", xm_sandbox_interactive } +, { tb_null, tb_null } +}; + /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ @@ -199,8 +227,8 @@ static tb_bool_t xm_machine_main_get_program_directory(xm_machine_impl_t* impl, break; } -#ifdef TB_CONFIG_OS_WINDOWS - // get the program directory +#if defined(TB_CONFIG_OS_WINDOWS) + // get the executale file path as program directory tb_size_t size = (tb_size_t)GetModuleFileName(tb_null, path, (DWORD)maxn); tb_assert_and_check_break(size < maxn); @@ -219,6 +247,57 @@ static tb_bool_t xm_machine_main_get_program_directory(xm_machine_impl_t* impl, // ok ok = tb_true; +#elif defined(TB_CONFIG_OS_MACOSX) + /* + * _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter + * should initially be the size of the buffer. The function returns 0 if the path was successfully copied, + * and *bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *bufsize is set + * to the size required. + * + * Note that _NSGetExecutablePath will return "a path" to the executable not a "real path" to the executable. + * That is the path may be a symbolic link and not the real file. With deep directories the total bufsize + * needed could be more than MAXPATHLEN. + */ + tb_uint32_t size = (tb_uint32_t)maxn; + if (!_NSGetExecutablePath(path, &size)) + { + // get path size + size = tb_strlen(path); + + // get the directory + while (size-- > 0) + { + if (path[size] == '/') + { + path[size] = '\0'; + break; + } + } + + // ok + ok = tb_true; + } +#elif defined(TB_CONFIG_OS_LINUX) + // get the executale file path as program directory + ssize_t size = readlink("/proc/self/exe", path, (size_t)maxn); + if (size > 0 && size < maxn) + { + // end + path[size] = '\0'; + + // get the directory + while (size-- > 0) + { + if (path[size] == '/') + { + path[size] = '\0'; + break; + } + } + + // ok + ok = tb_true; + } #endif } while (0); @@ -301,12 +380,18 @@ xm_machine_ref_t xm_machine_init() // bind path functions luaL_register(impl->lua, "path", g_path_functions); + // bind hash functions + luaL_register(impl->lua, "hash", g_hash_functions); + // bind string functions luaL_register(impl->lua, "string", g_string_functions); // bind process functions luaL_register(impl->lua, "process", g_process_functions); + // bind sandbox functions + luaL_register(impl->lua, "sandbox", g_sandbox_functions); + // init host #if defined(TB_CONFIG_OS_WINDOWS) lua_pushstring(impl->lua, "windows"); diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile index 0d0399bb14f..f9eb925d72c 100644 --- a/core/src/xmake/makefile +++ b/core/src/xmake/makefile @@ -16,13 +16,13 @@ xmake_C_FILES += \ machine \ os/argv \ os/find \ - os/uuid \ os/isdir \ os/rmdir \ os/mkdir \ os/cpdir \ os/chdir \ os/mtime \ + os/sleep \ os/mclock \ os/curdir \ os/tmpdir \ @@ -35,10 +35,13 @@ xmake_C_FILES += \ os/getenv \ os/emptydir \ os/strerror \ + os/getwinsize \ path/relative \ path/absolute \ path/translate \ path/is_absolute \ + hash/uuid \ + hash/sha256 \ string/strcmp \ string/endswith \ string/startswith \ @@ -46,7 +49,8 @@ xmake_C_FILES += \ process/openv \ process/wait \ process/waitlist \ - process/close + process/close \ + sandbox/interactive # flags diff --git a/core/src/xmake/os/getwinsize.c b/core/src/xmake/os/getwinsize.c new file mode 100644 index 00000000000..3a8da7a1155 --- /dev/null +++ b/core/src/xmake/os/getwinsize.c @@ -0,0 +1,92 @@ +/*!The Make-like 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 - 2017, TBOOX Open Source Group. + * + * @author TitanSnow + * @file getwinsize.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "getwinsize" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" +#ifdef TB_CONFIG_OS_WINDOWS +# include +#else +# include +# include // for errno +# include // for STDOUT_FILENO +#endif + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// get console window size +tb_int_t xm_os_getwinsize(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // init default window size (we will not consider winsize limit if cannot get it) + tb_int_t w = TB_MAXS16, h = TB_MAXS16; + + // get winsize +#ifdef TB_CONFIG_OS_WINDOWS + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + { + w = (tb_int_t)csbi.dwSize.X; + h = (tb_int_t)csbi.dwSize.Y; + } +#else + struct winsize size; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == 0) + { + w = (tb_int_t)size.ws_col; + h = (tb_int_t)size.ws_row; + } +#endif + + /* local winsize = os.getwinsize() + * + * return + * { + * width = -1 or .. + * , height = -1 or .. + * } + */ + lua_newtable(lua); + lua_pushstring(lua, "width"); + lua_pushinteger(lua, w); + lua_settable(lua, -3); + lua_pushstring(lua, "height"); + lua_pushinteger(lua, h); + lua_settable(lua, -3); + + // ok + return 1; +} diff --git a/core/src/xmake/os/sleep.c b/core/src/xmake/os/sleep.c new file mode 100644 index 00000000000..4615c274f09 --- /dev/null +++ b/core/src/xmake/os/sleep.c @@ -0,0 +1,53 @@ +/*!The Make-like 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 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file sleep.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "sleep" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_os_sleep(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // get the interval (ms) + tb_long_t interval = (tb_long_t)luaL_checklong(lua, 1); + + // sleep it + if (interval >= 0) tb_msleep(interval); + + // ok + return 0; +} diff --git a/core/src/xmake/sandbox/interactive.c b/core/src/xmake/sandbox/interactive.c new file mode 100644 index 00000000000..c3c706abb18 --- /dev/null +++ b/core/src/xmake/sandbox/interactive.c @@ -0,0 +1,358 @@ +/*!The Make-like 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 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file interactive.c + * + */ + +/* Runs interactive commands, read-eval-print (REPL) + * + * Major portions taken verbatim or adapted from LuaJIT frontend and the Lua interpreter. + * Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h + * Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "sandbox.interactive" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +// interactive prompt +#define LUA_PROMPT "> " + +// continuation prompt +#define LUA_PROMPT2 ">> " + +/* ////////////////////////////////////////////////////////////////////////////////////// + * declaration + */ +#ifndef TB_CONFIG_OS_WINDOWS +extern char* readline (const char*); +extern void add_history(const char*); +#endif + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ + +// report results +static tb_void_t xm_sandbox_report(lua_State *lua) +{ + if (!lua_isnil(lua, -1)) + { + // get message + tb_char_t const* msg = lua_tostring(lua, -1); + if (!msg) msg = "(error object is not a string)"; + + // print it + tb_printl(msg); + tb_print_sync(); + + // pop this message + lua_pop(lua, 1); + } +} + +// the traceback function +static tb_int_t xm_sandbox_traceback(lua_State *lua) +{ + if (!lua_isstring(lua, 1)) + { + // non-string error object? try metamethod. + if (lua_isnoneornil(lua, 1) || !luaL_callmeta(lua, 1, "__tostring") || !lua_isstring(lua, -1)) + return 1; // return non-string error object. + + // replace object by result of __tostring metamethod. + lua_remove(lua, 1); + } + + // return backtrace + luaL_traceback(lua, lua, lua_tostring(lua, 1), 1); + return 1; +} + +// execute codes +static tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) +{ + /* get error function index + * + * stack: arg1(sandbox_scope) scriptfunc(top) -> ... + */ + tb_int_t errfunc = lua_gettop(lua) - narg; + + // push traceback function + lua_pushcfunction(lua, xm_sandbox_traceback); + + // put it under chunk and args + lua_insert(lua, errfunc); + + /* execute it + * + * stack: errfunc arg1 scriptfunc -> ... + * after: errfunc arg1 [results] -> ... + */ + tb_int_t status = lua_pcall(lua, narg, (clear? 0 : LUA_MULTRET), errfunc); + + // remove traceback function + lua_remove(lua, errfunc); + + // force a complete garbage collection in case of errors + if (status != 0) lua_gc(lua, LUA_GCCOLLECT, 0); + + // ok? + return status; +} + +// this line is incomplete? +static tb_int_t xm_sandbox_incomplete(lua_State *lua, tb_int_t status) +{ + // syntax error? + if (status == LUA_ERRSYNTAX) + { + size_t lmsg; + tb_char_t const* msg = lua_tolstring(lua, -1, &lmsg); + tb_char_t const* tp = msg + lmsg - (sizeof(LUA_QL("")) - 1); + if (tb_strstr(msg, LUA_QL("")) == tp) + { + lua_pop(lua, 1); + return 1; + } + } + return 0; +} +// read line +static tb_size_t xm_sandbox_readline(tb_char_t* data, tb_size_t maxn, tb_char_t const* prompt) +{ +#ifndef TB_CONFIG_OS_WINDOWS + // get line + tb_char_t const* line = readline(prompt); + if (line) + { + // add line to history + add_history(line); + + // copy line to data + tb_size_t size = tb_strlcpy(data, line, maxn); + + // free line + tb_free(line); + + // truncated? + if (size >= maxn) + return 0; + + // ok + return size; + } +#else + + // print prompt + tb_printf(prompt); + tb_print_sync(); + + // get input buffer + if (fgets(data, (tb_int_t)maxn, stdin)) + return tb_strlen(data); +#endif + + // no more input + return 0; +} + +// read and push input line +static tb_int_t xm_sandbox_pushline(lua_State *lua) +{ + // read line + tb_char_t data[1024]; + tb_size_t size = xm_sandbox_readline(data, sizeof(data), LUA_PROMPT2); + if (size) + { + // split line '\0' + if (data[size - 1] == '\n') + data[size - 1] = '\0'; + + // push line + lua_pushstring(lua, data); + + // ok + return 1; + } + + // no input + return 0; +} + +// load code line +static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) +{ + // clear stack + lua_settop(lua, top); + + // read first line + tb_int_t status; + tb_char_t data[1024]; + tb_size_t size = xm_sandbox_readline(data + 7, sizeof(data) - 7, LUA_PROMPT); + if (size) + { + // split line '\0' + if (data[size - 1] == '\n') + data[--size] = '\0'; + + // patch "return " + tb_memcpy(data, "return ", 7); + + // attempt to load "return ..." + status = luaL_loadbuffer(lua, data, size + 7, "=stdin"); + + // ok? + if (status != LUA_ERRSYNTAX) return status; + + // pop error msg + lua_pop(lua, 1); + + // push line to load it again + lua_pushstring(lua, data + 7); + } + else return -1; + + // load input line + while (1) + { + /* repeat until gets a complete line + * + * stack: arg1(sandbox_scope) scriptbuffer(top) -> ... + * after: arg1(sandbox_scope) scriptbuffer scriptfunc(top) -> ... + */ + status = luaL_loadbuffer(lua, lua_tostring(lua, -1), lua_strlen(lua, -1), "=stdin"); + + // complete? + if (!xm_sandbox_incomplete(lua, status)) break; + + // get more input + if (!xm_sandbox_pushline(lua)) + return -1; + + // cancel multi-line input? + if (!tb_strcmp(lua_tostring(lua, -1), "q")) + { + lua_pop(lua, 2); + lua_pushstring(lua, "return "); + continue ; + } + + /* add a new line + * + * stack: arg1 scriptbuffer scriptfunc scriptbuffer "\n"(top) -> ... + */ + lua_pushliteral(lua, "\n"); + + // between the two lines + lua_insert(lua, -2); + + /* join them + * + * stack: arg1 scriptbuffer scriptfunc scriptbuffer scriptbuffer "\n"(top) -> ... + * after: arg1 scriptbuffer scriptfunc scriptbuffer+"\n"(top) -> ... + */ + lua_concat(lua, 3); + } + + // remove redundant scriptbuffer + lua_remove(lua, -2); + return status; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +// sandbox.interactive() +tb_int_t xm_sandbox_interactive(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + /* get init stack top + * + * stack: arg1(sandbox_scope) + */ + tb_int_t top = lua_gettop(lua); + + // enter interactive + tb_int_t status; + while ((status = xm_sandbox_loadline(lua, top)) != -1) + { + // execute codes + if (status == 0) + { + /* bind sandbox + * + * stack: arg1(top) scriptfunc arg1(sandbox_scope) -> ... + */ + lua_pushvalue(lua, 1); + lua_setfenv(lua, -2); + + /* run script + * + * stack: arg1(top) scriptfunc -> ... + */ + status = xm_sandbox_docall(lua, 0, 0); + } + + // report errors + if (status) xm_sandbox_report(lua); + + // print any results + if (status == 0 && lua_gettop(lua) > top) + { + // get results count + tb_int_t count = lua_gettop(lua) - top; + + /* print errors + * + * stack: arg1(sandbox_scope) [results] -> ... + * after: arg1(sandbox_scope) print [results] -> ... + */ + lua_getglobal(lua, "print"); + lua_insert(lua, -(count + 1)); + if (lua_pcall(lua, count, 0, 0) != 0) + tb_printl(lua_pushfstring(lua, "error calling " LUA_QL("print") " (%s)", lua_tostring(lua, -1))); + } + } + + // clear stack + lua_settop(lua, top); + tb_printl(""); + tb_print_sync(); + + // end + return 0; +} diff --git a/core/src/xmake/sandbox/prefix.h b/core/src/xmake/sandbox/prefix.h new file mode 100644 index 00000000000..a953cc85e21 --- /dev/null +++ b/core/src/xmake/sandbox/prefix.h @@ -0,0 +1,36 @@ +/*!The Make-like 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 - 2017, TBOOX Open Source Group. + * + * @author ruki + * @file prefix.h + * + */ +#ifndef XM_SANDBOX_PREFIX_H +#define XM_SANDBOX_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + + +#endif + + diff --git a/docs/README.md b/docs/README.md index b26724e29c2..197a36c58a4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,12 +15,18 @@ so that any developer can quickly pick it up and enjoy the productivity boost wh ## Installation -##### Windows +#### Windows 1. Download xmake windows installer from [Releases](https://github.com/tboox/xmake/releases) 2. Run xmake-[version].exe -##### MacOS +Or install master version in powershell: + +```bash +$ Invoke-Expression (Invoke-Webrequest 'https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.ps1' -UseBasicParsing).Content +``` + +#### MacOS ```bash $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" @@ -32,7 +38,17 @@ Or 1. Download xmake `.pkg` install package from [Releases](https://github.com/tboox/xmake/releases) 2. Run it -##### Linux +Or install master version: + +```bash +# use homebrew +$ brew install xmake --HEAD + +# or download install directly +$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh) +``` + +#### Linux Using Linuxbrew: @@ -79,7 +95,17 @@ On Redhat/Centos: 1. Download xmake `.rpm` install package from [Releases](https://github.com/tboox/xmake/releases) 2. Run `yum install xmake-xxx.rpm --nogpgcheck` -##### Compilation +Or install master version: + +```bash +# use linuebrew +$ brew install xmake --HEAD + +# or download install directly +$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh) +``` + +#### Compilation ```bash $ git clone git@github.com:waruqi/xmake.git diff --git a/docs/cn/index.html b/docs/cn/index.html index 6ea91db864d..6fbff04b15f 100644 --- a/docs/cn/index.html +++ b/docs/cn/index.html @@ -49,7 +49,13 @@

一个基于Lua的轻量级自动构建工具

-

简单的工程描述

+

安装

+ +
$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
+
+
+ +

简单的工程描述

target("console")
     set_kind("binary")
@@ -57,25 +63,25 @@ 

简单的工程描述

-

构建工程

+

构建工程

$ xmake
 
-

运行目标

+

运行目标

$ xmake run console
 
-

调试程序

+

调试程序

$ xmake run -d console
 
-

支持特性

+

支持特性

  • Tasks
  • @@ -86,7 +92,7 @@

    支持特性

  • Templates
-

支持平台

+

支持平台

  • Windows (x86, x64)
  • @@ -98,7 +104,7 @@

    支持平台

  • Mingw (i386, x86_64)
-

支持语言

+

支持语言

  • C/C++
  • @@ -110,7 +116,7 @@

    支持语言

  • Dlang
-

内置插件

+

内置插件

  • 宏记录脚本和回放插件
  • @@ -120,11 +126,11 @@

    内置插件

  • iOS app2ipa插件
-

使用演示

+

使用演示

usage_demo

-

联系方式

+

联系方式

  • 邮箱:waruqi@gmail.com
  • diff --git a/docs/landing.html b/docs/landing.html index 400bc741fab..98eeaee5d82 100644 --- a/docs/landing.html +++ b/docs/landing.html @@ -49,7 +49,13 @@

    A make-like build utility based on Lua

    -

    Simple description

    +

    Installation

    + +
    $ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
    +
    +
    + +

    Simple description

    target("console")
         set_kind("binary")
    diff --git a/docs/landing/index.cn.md b/docs/landing/index.cn.md
    index 7899399d9c3..b53a46d31d7 100755
    --- a/docs/landing/index.cn.md
    +++ b/docs/landing/index.cn.md
    @@ -3,6 +3,12 @@ layout: default.cn
     title: {{ site.name }}
     ---
     
    +## 安装
    +
    +```bash
    +$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
    +```
    +
     ## 简单的工程描述
     
     ```lua
    diff --git a/docs/landing/index.md b/docs/landing/index.md
    index 3192712ca13..b2b49aa50f5 100755
    --- a/docs/landing/index.md
    +++ b/docs/landing/index.md
    @@ -3,6 +3,12 @@ layout: default
     title: {{ site.name }}
     ---
     
    +## Installation
    +
    +```bash
    +$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
    +```
    +
     ## Simple description
     
     ```lua
    diff --git a/docs/manual.md b/docs/manual.md
    index 803eb02839e..aed9bdfef1a 100644
    --- a/docs/manual.md
    +++ b/docs/manual.md
    @@ -28,18 +28,19 @@ It's according to the following rules:
     
     Conditions are generally used to handle some special compilation platforms. 
     
    -| 接口                      | 描述                                     | 支持版本 |
    -| ------------------------- | ---------------------------------------- | -------- |
    -| [is_os](#is_os)           | Is the current compilation system?       | >= 2.0.1 |
    -| [is_arch](#is_arch)       | Is the current compilation architecture? | >= 2.0.1 |
    -| [is_plat](#is_plat)       | Is the current compilation platform?     | >= 2.0.1 |
    -| [is_mode](#is_mode)       | Is the current compilation mode?         | >= 2.0.1 |
    -| [is_kind](#is_kind)       | Is the current target kind?              | >= 2.0.1 |
    -| [is_option](#is_option)   | Is the given options enabled?            | >= 2.0.1 |
    +| 接口                      | 描述                                      | 支持版本 |
    +| ------------------------- | ----------------------------------------  | -------- |
    +| [is_os](#is_os)           | Is the current compilation target system? | >= 2.0.1 |
    +| [is_arch](#is_arch)       | Is the current compilation architecture?  | >= 2.0.1 |
    +| [is_plat](#is_plat)       | Is the current compilation platform?      | >= 2.0.1 |
    +| [is_host](#is_host)       | Is the current compilation host system?   | >= 2.1.4 |
    +| [is_mode](#is_mode)       | Is the current compilation mode?          | >= 2.0.1 |
    +| [is_kind](#is_kind)       | Is the current target kind?               | >= 2.0.1 |
    +| [is_option](#is_option)   | Is the given options enabled?             | >= 2.0.1 |
     
     ##### is_os 
     
    -###### Is the current compilation system
    +###### Is the current compilation target system
     
     ```lua
     if is_os("ios") then
    @@ -110,6 +111,30 @@ Support platforms:
     * iphoneos
     * watchos
     
    +##### is_host
    +
    +###### Is the current compilation host system
    +
    +Some compilation platforms can be built on multiple different operating systems, for example: android ndk (on linux, macOS and windows).
    +
    +So, we can use this api to determine the current host operating system.
    +
    +```lua
    +if is_host("windows") then
    +    add_includes("C:\\includes")
    +else
    +    add_includes("/usr/includess")
    +end
    +```
    +
    +Support hosts:
    +
    +* windows
    +* linux
    +* macosx
    +
    +We can also get it from [$(host)](#var-host) or [os.host](#os-host).
    +
     ##### is_mode
     
     ###### Is the current compilation mode
    diff --git a/docs/zh/README.md b/docs/zh/README.md
    index 0ed8fb3169c..7fec9e79efc 100755
    --- a/docs/zh/README.md
    +++ b/docs/zh/README.md
    @@ -22,12 +22,18 @@ xmake的目标是开发者更加关注于项目本身开发,简化项目的描
     
     ## 安装
     
    -##### Windows
    +#### Windows
     
     1. 从 [Releases](https://github.com/tboox/xmake/releases) 上下载windows安装包
     2. 运行安装程序 xmake-[version].exe
     
    -##### MacOS
    +或者在powershell中安装master版本:
    +
    +```bash
    +$ Invoke-Expression (Invoke-Webrequest 'https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.ps1' -UseBasicParsing).Content
    +```
    +
    +#### MacOS
     
     ```bash
     $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    @@ -39,7 +45,17 @@ $ brew install xmake
     1. 从 [Releases](https://github.com/tboox/xmake/releases) 上下载pkg安装包
     2. 双击运行
     
    -##### Linux
    +或者安装master版本:
    +
    +```bash
    +# 使用homebrew安装master版本
    +$ brew install xmake --HEAD
    +
    +# 或者直接调用shell下载安装
    +$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
    +```
    +
    +#### Linux
     
     使用linuxbrew安装:
     
    @@ -86,7 +102,17 @@ $ sudo apt-get install xmake
     1. 从 [Releases](https://github.com/tboox/xmake/releases) 上下载rpm安装包
     2. 运行: `yum install xmake-xxx.rpm --nogpgcheck`
     
    -##### 编译安装
    +或者安装master版本:
    +
    +```bash
    +# 使用linuxbrew安装master版本
    +$ brew install xmake --HEAD
    +
    +# 或者直接调用shell下载安装
    +$ bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh)
    +```
    +
    +#### 编译安装
     
     ```bash
     $ git clone git@github.com:waruqi/xmake.git
    diff --git a/docs/zh/manual.md b/docs/zh/manual.md
    index d7a4d9b7d8b..63c6f7f0de7 100755
    --- a/docs/zh/manual.md
    +++ b/docs/zh/manual.md
    @@ -30,16 +30,17 @@ search: zh
     
     | 接口                      | 描述                          | 支持版本 |
     | ------------------------- | ----------------------------- | -------- |
    -| [is_os](#is_os)           | 判断当前构建的操作系统        | >= 2.0.1 |
    +| [is_os](#is_os)           | 判断当前构建目标的操作系统    | >= 2.0.1 |
     | [is_arch](#is_arch)       | 判断当前编译架构              | >= 2.0.1 |
     | [is_plat](#is_plat)       | 判断当前编译平台              | >= 2.0.1 |
    +| [is_host](#is_host)       | 判断当前主机环境操作系统      | >= 2.1.4 |
     | [is_mode](#is_mode)       | 判断当前编译模式              | >= 2.0.1 |
     | [is_kind](#is_kind)       | 判断当前编译类型              | >= 2.0.1 |
     | [is_option](#is_option)   | 判断选项是否启用              | >= 2.0.1 |
     
     ##### is_os 
     
    -###### 判断当前构建的操作系统
    +###### 判断当前构建目标的操作系统
     
     ```lua
     -- 如果当前操作系统是ios
    @@ -115,6 +116,31 @@ end
     
     当然你也可以自己扩展添加自己的平台。。。
     
    +##### is_host
    +
    +###### 判断当前主机环境的操作系统
    +
    +有些编译平台是可以在多个不同的操作系统进行构建的,例如:android的ndk就支持linux,macOS还有windows环境。
    +
    +这个时候就可以通过这个接口,区分当前是在哪个系统环境下进行的构建。
    +
    +```lua
    +-- 如果当前主机环境是windows
    +if is_host("windows") then
    +    add_includes("C:\\includes")
    +else
    +    add_includes("/usr/includess")
    +end
    +```
    +
    +目前支持的主机环境有:
    +
    +* windows
    +* linux
    +* macosx
    +
    +你也可以通过[$(host)](#var-host)内置变量或者[os.host](#os-host)接口,来进行获取
    +
     ##### is_mode
     
     ###### 判断当前编译模式
    diff --git a/scripts/get.ps1 b/scripts/get.ps1
    new file mode 100644
    index 00000000000..120605ce501
    --- /dev/null
    +++ b/scripts/get.ps1
    @@ -0,0 +1,109 @@
    +# xmake getter
    +# usage: (in powershell)
    +#  Invoke-Expression (Invoke-Webrequest  -UseBasicParsing).Content
    +
    +& {
    +
    +Function myExit($code){
    +    if($code -is [int] -and $code -ne 0){
    +        throw $Error[0]
    +    }else{
    +        break
    +    }
    +}
    +
    +Function writeErrorTip($msg){
    +    Write-Host $msg -BackgroundColor Red -ForegroundColor White
    +}
    +
    +Function writeLogoLine($msg){
    +    Write-Host $msg -BackgroundColor White -ForegroundColor DarkBlue
    +}
    +
    +writeLogoLine '                         _                      '
    +writeLogoLine '    __  ___ __  __  __ _| | ______              '
    +writeLogoLine '    \ \/ / |  \/  |/ _  | |/ / __ \             '
    +writeLogoLine '     >  <  | \__/ | /_| |   <  ___/             '
    +writeLogoLine '    /_/\_\_|_|  |_|\__ \|_|\_\____| getter      '
    +writeLogoLine '                                                '
    +writeLogoLine '                                                '
    +
    +if($PSVersionTable.PSVersion.Major -lt 5){
    +    writeErrorTip 'Sorry but PowerShell v5+ is required'
    +    throw 'PowerShell''s version too low'
    +}
    +$temppath=($env:TMP,$env:TEMP,'.' -ne $null)[0]
    +$outfile=$temppath+"\$pid-xmake-installer.exe"
    +try{
    +    Write-Output "$pid"|Out-File -FilePath "$outfile"
    +    Remove-Item "$outfile"
    +}catch{
    +    writeErrorTip 'Cannot write to temp path'
    +    writeErrorTip 'Please set environment var "TMP" to another path'
    +    myExit 1
    +}
    +if($ver -eq $null){ $ver='v2.1.3' }
    +Write-Host 'Start downloading... Hope amazon S3 is not broken again'
    +try{
    +    Invoke-Webrequest "https://github.com/tboox/xmake/releases/download/$ver/xmake-$ver.exe" -OutFile "$outfile"
    +}catch{
    +    writeErrorTip 'Download failed!'
    +    writeErrorTip 'Check your network or... the news of S3 break'
    +    myExit 1
    +}
    +Write-Host 'Start installation... Hope your antivirus doesn''t trouble'
    +$installdir=$HOME+'\xmake'
    +Write-Host "Install to $installdir"
    +try{
    +    Start-Process -FilePath "$outfile" -ArgumentList "/S /D=$installdir" -Wait
    +}catch{
    +    Remove-Item "$outfile"
    +    writeErrorTip 'Install failed!'
    +    writeErrorTip 'Close your antivirus then try again'
    +    myExit 1
    +}
    +Remove-Item "$outfile"
    +Write-Host 'Adding to PATH... almost done'
    +$env:Path+=";$installdir"
    +[Environment]::SetEnvironmentVariable("Path",[Environment]::GetEnvironmentVariable("Path",[System.EnvironmentVariableTarget]::User)+";$installdir",[System.EnvironmentVariableTarget]::User)    # this step is optional because installer writes path to regedit
    +try{
    +    xmake --version
    +}catch{
    +    writeErrorTip 'Everything is showing installation has finished'
    +    writeErrorTip 'But xmake could not run... Why?'
    +    myExit 1
    +}
    +if($branch -eq $null){ $branch='master' }
    +Write-Host "Pulling xmake from branch $branch"
    +$outfile=$temppath+"\$pid-xmake-repo.zip"
    +try{
    +    Invoke-Webrequest "https://github.com/tboox/xmake/archive/$branch.zip" -OutFile "$outfile"
    +}catch{
    +    writeErrorTip 'Pull Failed!'
    +    writeErrorTip 'xmake is now available but may not be newest'
    +    myExit
    +}
    +Write-Host 'Expanding archive...'
    +New-Item -Path "$temppath" -Name "$pid-xmake-repo" -ItemType "directory" -Force
    +$oldpwd=$pwd
    +$repodir=$temppath+"\$pid-xmake-repo"
    +try{
    +    Expand-Archive "$outfile" "$repodir" -Force
    +    Write-Host 'Self-building...'
    +    Set-Location ($repodir+"\xmake-$branch\core")
    +    xmake
    +    Write-Host 'Copying new files...'
    +    Copy-Item 'build\xmake.exe' "$installdir" -Force
    +    Set-Location '..\xmake'
    +    Copy-Item * "$installdir" -Recurse -Force
    +    xmake --version
    +}catch{
    +    writeErrorTip 'Update Failed!'
    +    writeErrorTip 'xmake is now available but may not be newest'
    +}finally{
    +    Set-Location "$oldpwd" -ErrorAction SilentlyContinue
    +    Remove-Item "$outfile" -ErrorAction SilentlyContinue
    +    Remove-Item "$repodir" -Recurse -Force -ErrorAction SilentlyContinue
    +}
    +
    +}
    diff --git a/scripts/get.sh b/scripts/get.sh
    new file mode 100755
    index 00000000000..52a990dc708
    --- /dev/null
    +++ b/scripts/get.sh
    @@ -0,0 +1,94 @@
    +#!/bin/bash
    +
    +# xmake getter
    +# usage: bash <(curl -s ) [branch]
    +
    +# print a LOGO!
    +echo '                         _                      '
    +echo '    __  ___ __  __  __ _| | ______              '
    +echo '    \ \/ / |  \/  |/ _  | |/ / __ \             '
    +echo '     >  <  | \__/ | /_| |   <  ___/             '
    +echo '    /_/\_\_|_|  |_|\__ \|_|\_\____| getter      '
    +echo '                                                '
    +
    +brew --version >/dev/null 2>&1 && brew install --HEAD xmake && xmake --version && exit
    +if [ 0 -ne $(id -u) ]
    +then
    +    sudoprefix=sudo
    +else
    +    sudoprefix=
    +fi
    +my_exit(){
    +    rv=$?
    +    if [ "x$1" != x ]
    +    then
    +        echo -ne '\x1b[41;37m'
    +        echo "$1"
    +        echo -ne '\x1b[0m'
    +    fi
    +    rm -rf /tmp/$$xmake_getter 2>/dev/null
    +    if [ "x$2" != x ]
    +    then
    +        if [ $rv -eq 0 ];then rv=$2;fi
    +    fi
    +    exit $rv
    +}
    +test_tools()
    +{
    +    {
    +        git --version &&
    +        make --version &&
    +        {
    +            cc --version ||
    +            gcc --version ||
    +            clang --version
    +        }
    +    } >/dev/null 2>&1
    +}
    +install_tools()
    +{
    +    { apt-get --version >/dev/null 2>&1 && $sudoprefix apt-get install -y git build-essential; } ||
    +    { yum --version >/dev/null 2>&1 && $sudoprefix yum install -y git && $sudoprefix yum groupinstall -y 'Development Tools'; } ||
    +    { zypper --version >/dev/null 2>&1 && $sudoprefix zypper --non-interactive install git && $sudoprefix zypper --non-interactive install -t pattern devel_C_C++; } ||
    +    { pacman -V >/dev/null 2>&1 && $sudoprefix pacman -S --noconfirm git base-devel; }
    +}
    +test_tools || { install_tools && test_tools; } || my_exit 'Dependencies Installation Fail' 1
    +branch=
    +if [ x != "x$1" ]
    +then
    +    branch="-b $1"
    +    echo "Branch: $1"
    +fi
    +if [ 'x-b __local__' != "x$branch" ]
    +then
    +    git clone --depth=1 $branch https://github.com/tboox/xmake.git /tmp/$$xmake_getter || my_exit 'Clone Fail'
    +else
    +    cp -r "$(git rev-parse --show-toplevel 2>/dev/null || hg root 2>/dev/null || echo $PWD)" /tmp/$$xmake_getter || my_exit 'Clone Fail'
    +fi
    +make -C /tmp/$$xmake_getter --no-print-directory build || my_exit 'Build Fail'
    +IFS=':'
    +patharr=($PATH)
    +prefix=
    +for st in ${patharr[@]}
    +do
    +    if [[ "$st" = "$HOME"* ]]
    +    then
    +        cwd=$(pwd)
    +        mkdir -p "$st"
    +        cd "$st"
    +        echo $$ > $$xmake_getter_test 2>/dev/null || continue
    +        rm $$xmake_getter_test 2>/dev/null || continue
    +        cd ..
    +        mkdir -p share 2>/dev/null || continue
    +        prefix=$(pwd)
    +        cd "$cwd"
    +        break
    +    fi
    +done
    +if [ "x$prefix" != x ]
    +then
    +    make -C /tmp/$$xmake_getter --no-print-directory install prefix="$prefix"|| my_exit 'Install Fail'
    +else
    +    $sudoprefix make -C /tmp/$$xmake_getter --no-print-directory install || my_exit 'Install Fail'
    +fi
    +xmake --version
    diff --git a/tests/modules/ping.lua b/tests/modules/ping.lua
    new file mode 100755
    index 00000000000..53ee0132ac6
    --- /dev/null
    +++ b/tests/modules/ping.lua
    @@ -0,0 +1,13 @@
    +-- imports
    +import("core.tool.ping")
    +
    +--
    +-- run tests:
    +--
    +-- $ xmake l ./tests/modules/ping.lua
    +--
    +function main()
    +
    +    -- send ping
    +    table.dump(ping.send("www.tboox.org", "www.xmake.io", "www.github.com", "www.google.com", "unknown.invalid"))
    +end
    diff --git a/tests/console_c++/src/main.cpp b/tests/projects/console_c++/src/main.cpp
    similarity index 100%
    rename from tests/console_c++/src/main.cpp
    rename to tests/projects/console_c++/src/main.cpp
    diff --git a/tests/console_c++/xmake.lua b/tests/projects/console_c++/xmake.lua
    similarity index 100%
    rename from tests/console_c++/xmake.lua
    rename to tests/projects/console_c++/xmake.lua
    diff --git a/tests/console_c/src/main.c b/tests/projects/console_c/src/main.c
    similarity index 100%
    rename from tests/console_c/src/main.c
    rename to tests/projects/console_c/src/main.c
    diff --git a/tests/console_c/xmake.lua b/tests/projects/console_c/xmake.lua
    old mode 100755
    new mode 100644
    similarity index 100%
    rename from tests/console_c/xmake.lua
    rename to tests/projects/console_c/xmake.lua
    diff --git a/tests/console_dlang/src/main.d b/tests/projects/console_dlang/src/main.d
    similarity index 100%
    rename from tests/console_dlang/src/main.d
    rename to tests/projects/console_dlang/src/main.d
    diff --git a/tests/console_dlang/xmake.lua b/tests/projects/console_dlang/xmake.lua
    similarity index 100%
    rename from tests/console_dlang/xmake.lua
    rename to tests/projects/console_dlang/xmake.lua
    diff --git a/tests/console_go/src/main.go b/tests/projects/console_go/src/main.go
    similarity index 100%
    rename from tests/console_go/src/main.go
    rename to tests/projects/console_go/src/main.go
    diff --git a/tests/console_go/xmake.lua b/tests/projects/console_go/xmake.lua
    similarity index 100%
    rename from tests/console_go/xmake.lua
    rename to tests/projects/console_go/xmake.lua
    diff --git a/tests/console_objc++/src/main.mm b/tests/projects/console_objc++/src/main.mm
    similarity index 100%
    rename from tests/console_objc++/src/main.mm
    rename to tests/projects/console_objc++/src/main.mm
    diff --git a/tests/console_objc++/xmake.lua b/tests/projects/console_objc++/xmake.lua
    similarity index 100%
    rename from tests/console_objc++/xmake.lua
    rename to tests/projects/console_objc++/xmake.lua
    diff --git a/tests/console_objc/src/main.m b/tests/projects/console_objc/src/main.m
    similarity index 100%
    rename from tests/console_objc/src/main.m
    rename to tests/projects/console_objc/src/main.m
    diff --git a/tests/console_objc/xmake.lua b/tests/projects/console_objc/xmake.lua
    similarity index 100%
    rename from tests/console_objc/xmake.lua
    rename to tests/projects/console_objc/xmake.lua
    diff --git a/tests/console_rust/src/main.rs b/tests/projects/console_rust/src/main.rs
    similarity index 100%
    rename from tests/console_rust/src/main.rs
    rename to tests/projects/console_rust/src/main.rs
    diff --git a/tests/console_rust/xmake.lua b/tests/projects/console_rust/xmake.lua
    similarity index 100%
    rename from tests/console_rust/xmake.lua
    rename to tests/projects/console_rust/xmake.lua
    diff --git a/tests/console_swift/src/main.swift b/tests/projects/console_swift/src/main.swift
    similarity index 100%
    rename from tests/console_swift/src/main.swift
    rename to tests/projects/console_swift/src/main.swift
    diff --git a/tests/console_swift/xmake.lua b/tests/projects/console_swift/xmake.lua
    similarity index 100%
    rename from tests/console_swift/xmake.lua
    rename to tests/projects/console_swift/xmake.lua
    diff --git a/tests/deps_console_c/src/main.c b/tests/projects/deps_console_c/src/main.c
    similarity index 100%
    rename from tests/deps_console_c/src/main.c
    rename to tests/projects/deps_console_c/src/main.c
    diff --git a/tests/deps_console_c/xmake.lua b/tests/projects/deps_console_c/xmake.lua
    old mode 100755
    new mode 100644
    similarity index 68%
    rename from tests/deps_console_c/xmake.lua
    rename to tests/projects/deps_console_c/xmake.lua
    index f56bd50731f..f96866d100e
    --- a/tests/deps_console_c/xmake.lua
    +++ b/tests/projects/deps_console_c/xmake.lua
    @@ -1,16 +1,17 @@
     -- define package
     package("mbedtls")
    -    set_url("git@github.com:ARMmbed/mbedtls.git")
    -    add_requires("git@github.com:glennrp/libpng.git@libpng >=1.6.28")
    -    on_build(function (package)
    -    end)
    -    on_install(function (package)
    -    end)
    +    set_urls("https://github.com/ARMmbed/mbedtls.git")
    +    add_requires("https://github.com/glennrp/libpng.git@libpng >=1.6.28")
    +package_end()
    +
    +-- group packages
    +package("zlib-mbedtls")
    +    add_requires("zlib >=1.2.11")
    +    add_requires("mbedtls master optional")
     package_end()
     
     -- requires
    -add_requires("zlib >=1.2.11")
    -add_requires("mbedtls master optional")
    +add_requires("zlib-mbedtls")
     add_requires("xmake-repo@tboox.tbox >=1.5.1 <1.6.1 optional")
     
     -- the debug mode
    diff --git a/tests/merge_object/src/interface.c b/tests/projects/merge_object/src/interface.c
    similarity index 100%
    rename from tests/merge_object/src/interface.c
    rename to tests/projects/merge_object/src/interface.c
    diff --git a/tests/merge_object/src/interface.h b/tests/projects/merge_object/src/interface.h
    similarity index 100%
    rename from tests/merge_object/src/interface.h
    rename to tests/projects/merge_object/src/interface.h
    diff --git a/tests/merge_object/src/test.c b/tests/projects/merge_object/src/test.c
    similarity index 100%
    rename from tests/merge_object/src/test.c
    rename to tests/projects/merge_object/src/test.c
    diff --git a/tests/merge_object/xmake.lua b/tests/projects/merge_object/xmake.lua
    similarity index 100%
    rename from tests/merge_object/xmake.lua
    rename to tests/projects/merge_object/xmake.lua
    diff --git a/tests/merge_static_library/src/add.c b/tests/projects/merge_static_library/src/add.c
    similarity index 100%
    rename from tests/merge_static_library/src/add.c
    rename to tests/projects/merge_static_library/src/add.c
    diff --git a/tests/merge_static_library/src/mul.c b/tests/projects/merge_static_library/src/mul.c
    similarity index 100%
    rename from tests/merge_static_library/src/mul.c
    rename to tests/projects/merge_static_library/src/mul.c
    diff --git a/tests/merge_static_library/src/sub.c b/tests/projects/merge_static_library/src/sub.c
    similarity index 100%
    rename from tests/merge_static_library/src/sub.c
    rename to tests/projects/merge_static_library/src/sub.c
    diff --git a/tests/merge_static_library/xmake.lua b/tests/projects/merge_static_library/xmake.lua
    similarity index 100%
    rename from tests/merge_static_library/xmake.lua
    rename to tests/projects/merge_static_library/xmake.lua
    diff --git a/tests/shared_library_c++/src/interface.cpp b/tests/projects/shared_library_c++/src/interface.cpp
    similarity index 100%
    rename from tests/shared_library_c++/src/interface.cpp
    rename to tests/projects/shared_library_c++/src/interface.cpp
    diff --git a/tests/shared_library_c++/src/interface.h b/tests/projects/shared_library_c++/src/interface.h
    similarity index 100%
    rename from tests/shared_library_c++/src/interface.h
    rename to tests/projects/shared_library_c++/src/interface.h
    diff --git a/tests/shared_library_c++/src/test.cpp b/tests/projects/shared_library_c++/src/test.cpp
    similarity index 100%
    rename from tests/shared_library_c++/src/test.cpp
    rename to tests/projects/shared_library_c++/src/test.cpp
    diff --git a/tests/shared_library_c++/xmake.lua b/tests/projects/shared_library_c++/xmake.lua
    similarity index 100%
    rename from tests/shared_library_c++/xmake.lua
    rename to tests/projects/shared_library_c++/xmake.lua
    diff --git a/tests/shared_library_c/src/interface.c b/tests/projects/shared_library_c/src/interface.c
    similarity index 100%
    rename from tests/shared_library_c/src/interface.c
    rename to tests/projects/shared_library_c/src/interface.c
    diff --git a/tests/shared_library_c/src/interface.cpp b/tests/projects/shared_library_c/src/interface.cpp
    similarity index 100%
    rename from tests/shared_library_c/src/interface.cpp
    rename to tests/projects/shared_library_c/src/interface.cpp
    diff --git a/tests/shared_library_c/src/interface.h b/tests/projects/shared_library_c/src/interface.h
    similarity index 100%
    rename from tests/shared_library_c/src/interface.h
    rename to tests/projects/shared_library_c/src/interface.h
    diff --git a/tests/shared_library_c/src/test.c b/tests/projects/shared_library_c/src/test.c
    similarity index 100%
    rename from tests/shared_library_c/src/test.c
    rename to tests/projects/shared_library_c/src/test.c
    diff --git a/tests/shared_library_c/src/test.cpp b/tests/projects/shared_library_c/src/test.cpp
    similarity index 100%
    rename from tests/shared_library_c/src/test.cpp
    rename to tests/projects/shared_library_c/src/test.cpp
    diff --git a/tests/shared_library_c/xmake.lua b/tests/projects/shared_library_c/xmake.lua
    similarity index 100%
    rename from tests/shared_library_c/xmake.lua
    rename to tests/projects/shared_library_c/xmake.lua
    diff --git a/tests/shared_library_dlang/src/interfaces.d b/tests/projects/shared_library_dlang/src/interfaces.d
    similarity index 100%
    rename from tests/shared_library_dlang/src/interfaces.d
    rename to tests/projects/shared_library_dlang/src/interfaces.d
    diff --git a/tests/shared_library_dlang/src/main.d b/tests/projects/shared_library_dlang/src/main.d
    similarity index 100%
    rename from tests/shared_library_dlang/src/main.d
    rename to tests/projects/shared_library_dlang/src/main.d
    diff --git a/tests/shared_library_dlang/xmake.lua b/tests/projects/shared_library_dlang/xmake.lua
    similarity index 100%
    rename from tests/shared_library_dlang/xmake.lua
    rename to tests/projects/shared_library_dlang/xmake.lua
    diff --git a/tests/shared_library_rust/src/interfaces.rs b/tests/projects/shared_library_rust/src/interfaces.rs
    similarity index 100%
    rename from tests/shared_library_rust/src/interfaces.rs
    rename to tests/projects/shared_library_rust/src/interfaces.rs
    diff --git a/tests/shared_library_rust/src/main.rs b/tests/projects/shared_library_rust/src/main.rs
    similarity index 100%
    rename from tests/shared_library_rust/src/main.rs
    rename to tests/projects/shared_library_rust/src/main.rs
    diff --git a/tests/shared_library_rust/xmake.lua b/tests/projects/shared_library_rust/xmake.lua
    similarity index 100%
    rename from tests/shared_library_rust/xmake.lua
    rename to tests/projects/shared_library_rust/xmake.lua
    diff --git a/tests/static_library_c++/src/interface.cpp b/tests/projects/static_library_c++/src/interface.cpp
    similarity index 100%
    rename from tests/static_library_c++/src/interface.cpp
    rename to tests/projects/static_library_c++/src/interface.cpp
    diff --git a/tests/static_library_c++/src/interface.h b/tests/projects/static_library_c++/src/interface.h
    similarity index 100%
    rename from tests/static_library_c++/src/interface.h
    rename to tests/projects/static_library_c++/src/interface.h
    diff --git a/tests/static_library_c++/src/test.cpp b/tests/projects/static_library_c++/src/test.cpp
    similarity index 100%
    rename from tests/static_library_c++/src/test.cpp
    rename to tests/projects/static_library_c++/src/test.cpp
    diff --git a/tests/static_library_c++/xmake.lua b/tests/projects/static_library_c++/xmake.lua
    similarity index 100%
    rename from tests/static_library_c++/xmake.lua
    rename to tests/projects/static_library_c++/xmake.lua
    diff --git a/tests/static_library_c/src/interface.c b/tests/projects/static_library_c/src/interface.c
    similarity index 100%
    rename from tests/static_library_c/src/interface.c
    rename to tests/projects/static_library_c/src/interface.c
    diff --git a/tests/static_library_c/src/interface.h b/tests/projects/static_library_c/src/interface.h
    similarity index 100%
    rename from tests/static_library_c/src/interface.h
    rename to tests/projects/static_library_c/src/interface.h
    diff --git a/tests/static_library_c/src/test.c b/tests/projects/static_library_c/src/test.c
    similarity index 100%
    rename from tests/static_library_c/src/test.c
    rename to tests/projects/static_library_c/src/test.c
    diff --git a/tests/static_library_c/xmake.lua b/tests/projects/static_library_c/xmake.lua
    similarity index 100%
    rename from tests/static_library_c/xmake.lua
    rename to tests/projects/static_library_c/xmake.lua
    diff --git a/tests/static_library_dlang/src/interfaces.d b/tests/projects/static_library_dlang/src/interfaces.d
    similarity index 100%
    rename from tests/static_library_dlang/src/interfaces.d
    rename to tests/projects/static_library_dlang/src/interfaces.d
    diff --git a/tests/static_library_dlang/src/main.d b/tests/projects/static_library_dlang/src/main.d
    similarity index 100%
    rename from tests/static_library_dlang/src/main.d
    rename to tests/projects/static_library_dlang/src/main.d
    diff --git a/tests/static_library_dlang/xmake.lua b/tests/projects/static_library_dlang/xmake.lua
    similarity index 100%
    rename from tests/static_library_dlang/xmake.lua
    rename to tests/projects/static_library_dlang/xmake.lua
    diff --git a/tests/static_library_go/src/main.go b/tests/projects/static_library_go/src/main.go
    similarity index 100%
    rename from tests/static_library_go/src/main.go
    rename to tests/projects/static_library_go/src/main.go
    diff --git a/tests/static_library_go/src/test.go b/tests/projects/static_library_go/src/test.go
    similarity index 100%
    rename from tests/static_library_go/src/test.go
    rename to tests/projects/static_library_go/src/test.go
    diff --git a/tests/static_library_go/src/test/add.go b/tests/projects/static_library_go/src/test/add.go
    similarity index 100%
    rename from tests/static_library_go/src/test/add.go
    rename to tests/projects/static_library_go/src/test/add.go
    diff --git a/tests/static_library_go/src/test/sub.go b/tests/projects/static_library_go/src/test/sub.go
    similarity index 100%
    rename from tests/static_library_go/src/test/sub.go
    rename to tests/projects/static_library_go/src/test/sub.go
    diff --git a/tests/static_library_go/xmake.lua b/tests/projects/static_library_go/xmake.lua
    similarity index 100%
    rename from tests/static_library_go/xmake.lua
    rename to tests/projects/static_library_go/xmake.lua
    diff --git a/tests/static_library_rust/src/interfaces.rs b/tests/projects/static_library_rust/src/interfaces.rs
    similarity index 100%
    rename from tests/static_library_rust/src/interfaces.rs
    rename to tests/projects/static_library_rust/src/interfaces.rs
    diff --git a/tests/static_library_rust/src/main.rs b/tests/projects/static_library_rust/src/main.rs
    similarity index 100%
    rename from tests/static_library_rust/src/main.rs
    rename to tests/projects/static_library_rust/src/main.rs
    diff --git a/tests/static_library_rust/xmake.lua b/tests/projects/static_library_rust/xmake.lua
    similarity index 100%
    rename from tests/static_library_rust/xmake.lua
    rename to tests/projects/static_library_rust/xmake.lua
    diff --git a/tests/tests b/tests/tests
    index 5caeb88f954..5888fbe3e10 100755
    --- a/tests/tests
    +++ b/tests/tests
    @@ -45,44 +45,44 @@ function build_for_iphoenos()
     }
     
     # build for c
    -build "./tests/console_c" 
    -build "./tests/static_library_c" 
    -build "./tests/shared_library_c" 
    +build "./tests/projects/console_c" 
    +build "./tests/projects/static_library_c" 
    +build "./tests/projects/shared_library_c" 
     
     # build for c++
    -build "./tests/console_c++"
    -build "./tests/static_library_c++" 
    -build "./tests/shared_library_c++" 
    +build "./tests/projects/console_c++"
    +build "./tests/projects/static_library_c++" 
    +build "./tests/projects/shared_library_c++" 
     
     # merge object 
    -build "./tests/merge_object"
    +build "./tests/projects/merge_object"
     
     # merge static library
    -build "./tests/merge_static_library"
    +build "./tests/projects/merge_static_library"
     
     # build for macosx
     if [ $host = "macosx" ]; then
     
         # build for objc/c++
    -    build "./tests/console_objc" 
    -    build "./tests/console_objc++" 
    -    build_for_iphoenos "./tests/console_objc" 
    -    build_for_iphoenos "./tests/console_objc++" 
    +    build "./tests/projects/console_objc" 
    +    build "./tests/projects/console_objc++" 
    +    build_for_iphoenos "./tests/projects/console_objc" 
    +    build_for_iphoenos "./tests/projects/console_objc++" 
     
         # build for swift
    -    build "./tests/console_swift" 
    -    build_for_iphoenos "./tests/console_swift" 
    +    build "./tests/projects/console_swift" 
    +    build_for_iphoenos "./tests/projects/console_swift" 
     
         # build for go
    -    build "./tests/console_go" 
    -    build "./tests/static_library_go" 
    +    build "./tests/projects/console_go" 
    +    build "./tests/projects/static_library_go" 
     
         # build for dlang
    -    build "./tests/console_dlang" 
    -    build "./tests/static_library_dlang" 
    +    build "./tests/projects/console_dlang" 
    +    build "./tests/projects/static_library_dlang" 
     
         # build for rust
    -    build "./tests/console_rust" 
    -    build "./tests/static_library_rust" 
    +    build "./tests/projects/console_rust" 
    +    build "./tests/projects/static_library_rust" 
     fi
     
    diff --git a/xmake/actions/build/builder.lua b/xmake/actions/build/builder.lua
    index beef67c41b5..a910e61071d 100644
    --- a/xmake/actions/build/builder.lua
    +++ b/xmake/actions/build/builder.lua
    @@ -31,8 +31,10 @@ import("core.platform.environment")
     function _on_build_target(target)
     
         -- the target kind
    -    local kind = target:get("kind") 
    -    assert(kind, "target(%s).kind not found!", target:name())
    +    local kind = target:targetkind()
    +    if not kind then
    +        return 
    +    end
     
         -- build target
         import("kinds." .. kind).build(target, _g)
    diff --git a/xmake/actions/build/kinds/binary.lua b/xmake/actions/build/kinds/binary.lua
    index b7dd5f5121c..00d7dbc774b 100644
    --- a/xmake/actions/build/kinds/binary.lua
    +++ b/xmake/actions/build/kinds/binary.lua
    @@ -54,11 +54,11 @@ function _build_from_objects(target, buildinfo)
         local verbose = option.get("verbose")
     
         -- trace percent into
    -    cprintf("${green}[%02d%%]:${clear} ", (buildinfo.targetindex + 1) * 100 / buildinfo.targetcount)
    +    local percent = (buildinfo.targetindex + 1) * 100 / buildinfo.targetcount
         if verbose then
    -        cprint("${dim magenta}linking.$(mode) %s", path.filename(targetfile))
    +        cprint("${green}[%02d%%]: ${dim magenta}linking.$(mode) %s", percent, path.filename(targetfile))
         else
    -        cprint("${magenta}linking.$(mode) %s", path.filename(targetfile))
    +        cprint("${green}[%02d%%]: ${magenta}linking.$(mode) %s", percent, path.filename(targetfile))
         end
     
         -- trace verbose info
    diff --git a/xmake/actions/build/kinds/object.lua b/xmake/actions/build/kinds/object.lua
    index b12fb1b2fd9..96a55df1db2 100644
    --- a/xmake/actions/build/kinds/object.lua
    +++ b/xmake/actions/build/kinds/object.lua
    @@ -36,11 +36,10 @@ function _build_from_object(target, sourcefile, objectfile, percent)
         local verbose = option.get("verbose")
     
         -- trace percent info
    -    cprintf("${green}[%02d%%]:${clear} ", percent)
         if verbose then
    -        cprint("${dim magenta}inserting.$(mode) %s", sourcefile)
    +        cprint("${green}[%02d%%]: ${dim magenta}inserting.$(mode) %s", percent, sourcefile)
         else
    -        cprint("${magenta}inserting.$(mode) %s", sourcefile)
    +        cprint("${green}[%02d%%]: ${magenta}inserting.$(mode) %s", percent, sourcefile)
         end
     
         -- trace verbose info
    @@ -59,11 +58,10 @@ function _build_from_static(target, sourcefile, objectfile, percent)
         local verbose = option.get("verbose")
     
         -- trace percent info
    -    cprintf("${green}[%02d%%]:${clear} ", percent)
         if verbose then
    -        cprint("${dim magenta}inserting.$(mode) %s", sourcefile)
    +        cprint("${green}[%02d%%]: ${dim magenta}inserting.$(mode) %s", percent, sourcefile)
         else
    -        cprint("${magenta}inserting.$(mode) %s", sourcefile)
    +        cprint("${green}[%02d%%]: ${magenta}inserting.$(mode) %s", percent, sourcefile)
         end
     
         -- trace verbose info
    @@ -146,11 +144,10 @@ function _build_object(target, buildinfo, index, sourcebatch)
         local verbose = option.get("verbose")
     
         -- trace percent info
    -    cprintf("${green}[%02d%%]:${clear} ", percent)
         if verbose then
    -        cprint("${dim}%scompiling.$(mode) %s", ifelse(tool.shellname("ccache"), "ccache ", ""), sourcefile)
    +        cprint("${green}[%02d%%]:${dim} %scompiling.$(mode) %s", percent, ifelse(tool.shellname("ccache"), "ccache ", ""), sourcefile)
         else
    -        print("%scompiling.$(mode) %s", ifelse(tool.shellname("ccache"), "ccache ", ""), sourcefile)
    +        cprint("${green}[%02d%%]:${clear} %scompiling.$(mode) %s", percent, ifelse(tool.shellname("ccache"), "ccache ", ""), sourcefile)
         end
     
         -- trace verbose info
    @@ -165,96 +162,17 @@ end
     -- build each objects from the given source batch
     function _build_each_objects(target, buildinfo, sourcekind, sourcebatch, jobs)
     
    -    -- make objects
    -    local index = 1
    -    local total = #sourcebatch.sourcefiles
    -    local tasks = {}
    -    local procs = {}
    -    repeat
    -
    -        -- wait processes
    -        local tasks_finished = {}
    -        local procs_count = #procs
    -        if procs_count > 0 then
    -
    -            -- wait them
    -            local procinfos = process.waitlist(procs, ifelse(procs_count < jobs, 0, -1))
    -            for _, procinfo in ipairs(procinfos) do
    -                
    -                -- the process info
    -                local proc      = procinfo[1]
    -                local procid    = procinfo[2]
    -                local status    = procinfo[3]
    -
    -                -- check
    -                assert(procs[procid] == proc)
    -
    -                -- resume this task
    -                local job_task = tasks[procid]
    -                local job_proc = coroutine.resume(job_task, 1, status)
    -
    -                -- the other process is pending for this task?
    -                if coroutine.status(job_task) ~= "dead" then
    -
    -                    -- check
    -                    assert(job_proc)
    -
    -                    -- update the pending process
    -                    procs[procid] = job_proc
    -
    -                -- this task has been finised?
    -                else
    -
    -                    -- mark this task as finised
    -                    tasks_finished[procid] = true
    -                end
    -            end
    -        end
    -
    -        -- update the pending tasks and procs
    -        local tasks_pending = {}
    -        local procs_pending = {}
    -        for taskid, job_task in ipairs(tasks) do
    -            if not tasks_finished[taskid] then
    -                table.insert(tasks_pending, job_task)
    -                table.insert(procs_pending, procs[taskid])
    -            end
    -        end
    -        tasks = tasks_pending
    -        procs = procs_pending
    -
    -        -- produce tasks
    -        local curdir = os.curdir()
    -        while #tasks < jobs and index <= total do
    -
    -            -- new task
    -            local job_task = coroutine.create(function (index)
    +    -- run build jobs for each source file 
    +    local curdir = os.curdir()
    +    process.runjobs(function (index)
     
    -                            -- force to set the current directory first because the other jobs maybe changed it
    -                            os.cd(curdir)
    +        -- force to set the current directory first because the other jobs maybe changed it
    +        os.cd(curdir)
     
    -                            -- build object
    -                            _build_object(target, buildinfo, index, sourcebatch)
    -
    -                        end)
    -
    -            -- resume it first
    -            local job_proc = coroutine.resume(job_task, index)
    -            if coroutine.status(job_task) ~= "dead" then
    -
    -                -- check
    -                assert(job_proc)
    -
    -                -- put task and proc to the pendings tasks
    -                table.insert(tasks, job_task)
    -                table.insert(procs, job_proc)
    -            end
    -
    -            -- next index
    -            index = index + 1
    -        end
    +        -- build object
    +        _build_object(target, buildinfo, index, sourcebatch)
     
    -    until #tasks == 0
    +    end, #sourcebatch.sourcefiles, jobs)
     
         -- update object index
         _g.sourceindex = _g.sourceindex + #sourcebatch.sourcefiles
    diff --git a/xmake/actions/build/kinds/shared.lua b/xmake/actions/build/kinds/shared.lua
    index ab2cd40b0c9..77c819febfd 100644
    --- a/xmake/actions/build/kinds/shared.lua
    +++ b/xmake/actions/build/kinds/shared.lua
    @@ -67,11 +67,11 @@ function _build_from_objects(target, buildinfo)
         local verbose = option.get("verbose")
     
         -- trace percent info
    -    cprintf("${green}[%02d%%]:${clear} ", (buildinfo.targetindex + 1) * 100 / buildinfo.targetcount)
    +    local percent = (buildinfo.targetindex + 1) * 100 / buildinfo.targetcount
         if verbose then
    -        cprint("${dim magenta}linking.$(mode) %s", path.filename(targetfile))
    +        cprint("${green}[%02d%%]: ${dim magenta}linking.$(mode) %s", percent, path.filename(targetfile))
         else
    -        cprint("${magenta}linking.$(mode) %s", path.filename(targetfile))
    +        cprint("${green}[%02d%%]: ${magenta}linking.$(mode) %s", percent, path.filename(targetfile))
         end
     
         -- trace verbose info
    diff --git a/xmake/actions/build/kinds/static.lua b/xmake/actions/build/kinds/static.lua
    index 6dcacbd3082..7d9dce09d3d 100644
    --- a/xmake/actions/build/kinds/static.lua
    +++ b/xmake/actions/build/kinds/static.lua
    @@ -67,11 +67,11 @@ function _build_from_objects(target, buildinfo)
         local verbose = option.get("verbose")
     
         -- trace percent info
    -    cprintf("${green}[%02d%%]:${clear} ", (buildinfo.targetindex + 1) * 100 / buildinfo.targetcount)
    +    local percent = (buildinfo.targetindex + 1) * 100 / buildinfo.targetcount
         if verbose then
    -        cprint("${dim magenta}archiving.$(mode) %s", path.filename(targetfile))
    +        cprint("${green}[%02d%%]: ${dim magenta}archiving.$(mode) %s", percent, path.filename(targetfile))
         else
    -        cprint("${magenta}archiving.$(mode) %s", path.filename(targetfile))
    +        cprint("${green}[%02d%%]: ${magenta}archiving.$(mode) %s", percent, path.filename(targetfile))
         end
     
         -- trace verbose info
    diff --git a/xmake/actions/clean/main.lua b/xmake/actions/clean/main.lua
    index eb5f85cab53..37e7d07886b 100644
    --- a/xmake/actions/clean/main.lua
    +++ b/xmake/actions/clean/main.lua
    @@ -51,6 +51,11 @@ end
     -- on clean target 
     function _on_clean_target(target)
     
    +    -- no target kind?
    +    if not target:targetkind() then
    +        return 
    +    end
    +
         -- remove the target file 
         _remove(target:targetfile()) 
     
    diff --git a/xmake/actions/deps/action/download.lua b/xmake/actions/deps/action/download.lua
    deleted file mode 100644
    index 4f2c0a42825..00000000000
    --- a/xmake/actions/deps/action/download.lua
    +++ /dev/null
    @@ -1,85 +0,0 @@
    ---!The Make-like download 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 - 2017, TBOOX Open Source Group.
    ---
    --- @author      ruki
    --- @file        download.lua
    ---
    -
    --- imports
    -import("core.base.option")
    -import("core.tool.git")
    -import("core.tool.downloader")
    -
    --- checkout codes from git
    -function _checkout(package, url)
    -
    -    -- TODO
    -    -- cache checkouted files
    -        
    -    -- from branches?
    -    if package:verfrom() == "branches" then
    -
    -        -- only shadow clone this branch 
    -        git.clone(url, {verbose = option.get("verbose"), depth = 1, branch = package:version(), outputdir = "source"})
    -
    -    -- from tags or versions?
    -    else
    -
    -        -- clone whole history and tags
    -        git.clone(url, {verbose = option.get("verbose"), outputdir = "source"})
    -
    -        -- attempt to checkout the given version
    -        git.checkout(package:version(), {verbose = option.get("verbose"), repodir = "source"})
    -    end
    -end
    -
    --- download codes from ftp/http/https
    -function _download(package, url)
    -
    -    -- TODO
    -    -- cache downloaded file
    -        
    -    -- get package file
    -    local packagefile = path.filename(url)
    -
    -    -- download package file
    -    downloader.download(url, packagefile, {verbose = option.get("verbose")})
    -
    -    -- extract package file
    -    -- TODO
    -end
    -
    --- download the given package
    -function main(package)
    -
    -    -- get url
    -    local url = package:filter():handle(package:get("url"))
    -
    -    -- trace
    -    print("downloading %s-%s: %s ..", package:name(), package:version(), url)
    -
    -    -- download package using git?
    -    if git.checkurl(url) then
    -        _checkout(package, url)
    -    else
    -        _download(package, url)
    -    end
    -end
    -
    diff --git a/xmake/actions/install/main.lua b/xmake/actions/install/main.lua
    index 3ca155789b1..e80ad5fcb0d 100644
    --- a/xmake/actions/install/main.lua
    +++ b/xmake/actions/install/main.lua
    @@ -58,7 +58,7 @@ function main()
                 function (errors)
     
                     -- show tips
    -                cprint("${bright red}error: ${default red}installation failed, may permission denied!")
    +                cprint("${bright red}error: ${clear}installation failed, may permission denied!")
     
                     -- continue to install with administrator permission?
                     if os.feature("sudo") then
    diff --git a/xmake/actions/package/main.lua b/xmake/actions/package/main.lua
    index 0e0566c92d7..25328a25c51 100644
    --- a/xmake/actions/package/main.lua
    +++ b/xmake/actions/package/main.lua
    @@ -117,6 +117,9 @@ function _package_target(target)
     
         -- get kind
         local kind = target:get("kind")
    +    if not kind then
    +        return 
    +    end
     
         -- get script 
         local scripts =
    diff --git a/xmake/actions/require/action/build.lua b/xmake/actions/require/action/build.lua
    new file mode 100644
    index 00000000000..9d19920f355
    --- /dev/null
    +++ b/xmake/actions/require/action/build.lua
    @@ -0,0 +1,222 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        build.lua
    +--
    +
    +-- imports
    +import("core.base.option")
    +import("core.tool.tool")
    +import("core.project.config")
    +import("core.sandbox.sandbox")
    +import(".environment")
    +
    +-- build for xmake file
    +function _build_for_xmakefile(package)
    +
    +    -- configure it first
    +    if config.plat() and config.arch() then
    +        os.vrun("$(xmake) f -p $(plat) -a $(arch) -c")
    +    else
    +        os.vrun("$(xmake) f -c")
    +    end
    +
    +    -- build it
    +    os.vrun("$(xmake) -r")
    +end
    +
    +-- build for makefile
    +function _build_for_makefile(package)
    +
    +    -- build it
    +    os.vrun("$(make)")
    +end
    +
    +-- build for configure
    +function _build_for_configure(package)
    +
    +    -- configure it first
    +    os.vrun("./configure")
    +
    +    -- build it
    +    _build_for_makefile(package)
    +end
    +
    +-- build for cmakelist
    +function _build_for_cmakelists(package)
    +
    +    -- make makefile first
    +    os.vrun("cmake .")
    +
    +    -- build it
    +    _build_for_makefile(package)
    +end
    +
    +-- on build the given package
    +function _on_build_package(package)
    +
    +    -- TODO *.vcproj, premake.lua, scons, autogen.sh, Makefile.am, ...
    +    -- init build scripts
    +    local buildscripts =
    +    {
    +        {"xmake.lua",       _build_for_xmakefile    }
    +    ,   {"CMakeLists.txt",  _build_for_cmakelists   }
    +    ,   {"configure",       _build_for_configure    }
    +    ,   {"[mM]akefile",     _build_for_makefile     }
    +    }
    +
    +    -- attempt to build it
    +    for _, buildscript in pairs(buildscripts) do
    +        local ok = try
    +        {
    +            function ()
    +
    +                -- attempt to build it if file exists
    +                local files = os.files(buildscript[1])
    +                if #files > 0 then
    +                    buildscript[2](package)
    +                    return true
    +                end
    +            end,
    +
    +            catch
    +            {
    +                function (errors)
    +
    +                    -- trace verbose info
    +                    if errors then
    +                        vprint(errors)
    +                    end
    +                end
    +            }
    +        }
    +
    +        -- ok?
    +        if ok then return end
    +    end
    +
    +    -- failed
    +    raise("attempt to build package %s failed!", package:name())
    +end
    +
    +-- run script
    +function _run_script(script, package)
    +
    +    -- register filter handler before building
    +    sandbox.filter_register(script, "package.build", function (var) 
    +        
    +        -- attempt to get shellname from tool 
    +        local shellname = tool.shellname(var)
    +        if shellname then
    +            result = shellname
    +        end
    +
    +        -- ok
    +        return shellname
    +    end)
    +
    +    -- run it
    +    script(package)
    +
    +    -- cancel filter handler before building
    +    sandbox.filter_register(script, "package.build", nil)
    +end
    +
    +-- build the given package
    +function main(package)
    +
    +    -- skip phony package without urls
    +    if #package:urls() == 0 then
    +        return
    +    end
    +
    +    -- trace
    +    cprintf("${yellow}  => ${clear}building %s-%s .. ", package:name(), package:version())
    +    if option.get("verbose") then
    +        print("")
    +    end
    +
    +    -- enter source codes directory
    +    local oldir = os.cd("source")
    +
    +    -- build it
    +    try
    +    {
    +        function ()
    +
    +            -- the package scripts
    +            local scripts =
    +            {
    +                package:get("build_before") 
    +            ,   package:get("build")  or _on_build_package
    +            ,   package:get("build_after") 
    +            }
    +
    +            -- run the package scripts
    +            local buildtask = function () 
    +
    +                -- enter environment
    +                environment.enter()
    +
    +                -- build it
    +                for i = 1, 3 do
    +                    local script = scripts[i]
    +                    if script ~= nil then
    +                        _run_script(script, package)
    +                    end
    +                end
    +
    +                -- leave environment
    +                environment.leave()
    +            end
    +
    +            -- download package file
    +            if option.get("verbose") then
    +                buildtask()
    +            else
    +                process.asyncrun(buildtask)
    +            end
    +
    +            -- trace
    +            cprint("${green}ok")
    +        end,
    +
    +        catch
    +        {
    +            function (errors)
    +
    +                -- verbose?
    +                if option.get("verbose") and errors then
    +                    cprint("${bright red}error: ${clear}%s", errors)
    +                end
    +
    +                -- trace
    +                cprint("${red}failed")
    +
    +                -- failed
    +                raise("build failed!")
    +            end
    +        }
    +    }
    +
    +    -- leave source codes directory
    +    os.cd(oldir)
    +end
    diff --git a/xmake/actions/require/action/download.lua b/xmake/actions/require/action/download.lua
    new file mode 100644
    index 00000000000..ac81f8c3642
    --- /dev/null
    +++ b/xmake/actions/require/action/download.lua
    @@ -0,0 +1,185 @@
    +--!The Make-like download 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        download.lua
    +--
    +
    +-- imports
    +import("core.base.option")
    +import("core.tool.git")
    +import("core.tool.unarchiver")
    +import("core.tool.downloader")
    +
    +-- checkout codes from git
    +function _checkout(package, url, sourcedir)
    +
    +    -- trace
    +    cprintf("${yellow}  => ${clear}cloning %s %s .. ", url, package:version())
    +    if option.get("verbose") then
    +        print("")
    +    end
    +
    +    -- attempt to remove source directory first
    +    os.tryrm(sourcedir)
    +
    +    -- create a clone task
    +    local task = function ()
    +
    +        -- from branches?
    +        if package:versionfrom() == "branches" then
    +
    +            -- only shadow clone this branch 
    +            git.clone(url, {depth = 1, branch = package:version(), outputdir = sourcedir})
    +
    +        -- from tags or versions?
    +        else
    +
    +            -- clone whole history and tags
    +            git.clone(url, {outputdir = sourcedir})
    +
    +            -- attempt to checkout the given version
    +            git.checkout(package:version(), {repodir = sourcedir})
    +        end
    +    end
    +
    +    -- download package file
    +    if option.get("verbose") then
    +        task()
    +    else
    +        process.asyncrun(task)
    +    end
    +
    +    -- trace
    +    cprint("${green}ok")
    +end
    +
    +-- download codes from ftp/http/https
    +function _download(package, url, sourcedir)
    +
    +    -- trace
    +    cprintf("${yellow}  => ${clear}downloading %s .. ", url)
    +    if option.get("verbose") then
    +        print("")
    +    end
    +
    +    -- get package file
    +    local packagefile = path.filename(url)
    +
    +    -- the package file have been downloaded?
    +    local sha256 = package:sha256()
    +    if option.get("force") or not os.isfile(packagefile) or (sha256 and sha256 ~= hash.sha256(packagefile)) then
    +
    +        -- attempt to remove package file first
    +        os.tryrm(packagefile)
    +
    +        -- create a download task
    +        local task = function ()
    +            downloader.download(url, packagefile)
    +        end
    +
    +        -- download package file
    +        if option.get("verbose") then
    +            task()
    +        else
    +            process.asyncrun(task)
    +        end
    +
    +        -- check hash
    +        if sha256 and sha256 ~= hash.sha256(packagefile) then
    +            raise("unmatched checksum!")
    +        end
    +    end
    +
    +    -- attempt to remove source directory first
    +    os.tryrm(sourcedir)
    +
    +    -- extract package file
    +    unarchiver.extract(packagefile, sourcedir)
    +    
    +    -- trace
    +    cprint("${green}ok")
    +end
    +
    +-- download the given package
    +function main(package)
    +
    +    -- download package from url or mirror
    +    local urls = package:urls()
    +    for idx, url in ipairs(urls) do
    +
    +        -- filter url
    +        url = package:filter():handle(url)
    +
    +        -- download url
    +        local ok = try
    +        {
    +            function ()
    +
    +                -- init source files directory
    +                local sourcedir = "source"
    +                local sourcedir_tmp = sourcedir .. ".tmp"
    +
    +                -- has been finished?
    +                if os.isdir(sourcedir) and not option.get("force") then
    +                    return true 
    +                end
    +
    +                -- download package 
    +                if git.checkurl(url) then
    +                    _checkout(package, url, sourcedir_tmp)
    +                else
    +                    _download(package, url, sourcedir_tmp)
    +                end
    +
    +                -- remove the previous source directory
    +                os.tryrm(sourcedir)
    +
    +                -- rename source directory
    +                os.mv(sourcedir_tmp, sourcedir)
    +
    +                -- ok
    +                return true
    +            end,
    +            catch 
    +            {
    +                function (errors)
    +
    +                    -- verbose?
    +                    if option.get("verbose") and errors then
    +                        cprint("${bright red}error: ${clear}%s", errors)
    +                    end
    +
    +                    -- trace
    +                    cprint("${red}failed")
    +
    +                    -- failed? break it
    +                    if idx == #urls then
    +                        raise("download failed!")
    +                    end
    +                end
    +            }
    +        }
    +
    +        -- ok? break it
    +        if ok then break end
    +    end
    +end
    +
    diff --git a/xmake/actions/deps/action/install.lua b/xmake/actions/require/action/install.lua
    similarity index 87%
    rename from xmake/actions/deps/action/install.lua
    rename to xmake/actions/require/action/install.lua
    index 31d8101f39d..a54cfcfea0f 100644
    --- a/xmake/actions/deps/action/install.lua
    +++ b/xmake/actions/require/action/install.lua
    @@ -24,22 +24,17 @@
     
     -- imports
     import("build")
    -import("clean")
     import("download")
     
     -- on install the given package
     function _on_install_package(package)
    -    print("install %s", package:name())
     end
     
     -- install the given package
    -function main(package, is_global)
    -
    -    -- TODO is_global for install
    -    --
    +function main(package, cachedir)
     
         -- get working directory of this package
    -    local workdir = path.join(os.tmpdir(), "packages", package:name())
    +    local workdir = path.join(cachedir, package:name() .. "-" .. (package:version() or "group"))
     
         -- ensure the working directory first
         os.mkdir(workdir)
    @@ -69,9 +64,6 @@ function main(package, is_global)
             end
         end
     
    -    -- clean package last
    -    clean.main(package)
    -
         -- leave working directory
         os.cd(oldir)
     end
    diff --git a/xmake/actions/require/environment.lua b/xmake/actions/require/environment.lua
    new file mode 100644
    index 00000000000..bec46309cbf
    --- /dev/null
    +++ b/xmake/actions/require/environment.lua
    @@ -0,0 +1,88 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        environment.lua
    +--
    +
    +-- imports
    +import("core.platform.environment")
    +
    +-- load linux environment
    +function _load_linux()
    +end
    +
    +-- load macosx environment
    +function _load_macosx()
    +end
    +
    +-- load windows environment
    +function _load_windows()
    +
    +    -- TODO: download and install git, tar, unzip toolchains 
    +    --
    +    -- @note curl has been placed in the xmake installation package
    +    --
    +end
    +
    +-- laod host environment
    +--
    +-- ensure that we can find some basic tools: git, tar/unzip, make/nmake/cmake, msbuild ...
    +--
    +-- If these tools not exist, we will install it first.
    +--
    +function load()
    +
    +    -- init loaders
    +    local loaders = 
    +    {
    +        linux   = _load_linux
    +    ,   macosx  = _load_macosx
    +    ,   windows = _load_windows
    +    }
    +
    +    -- load host environment
    +    local loader = loaders[os.host()]
    +    if loader then
    +        loader()
    +    end
    +end
    +
    +-- enter environment
    +function enter()
    +
    +    -- set search pathes of toolchains 
    +    environment.enter("toolchains")
    +
    +    -- TODO set toolchains for CC, LD, ..
    +
    +    -- TODO set flags of toolchains
    +end
    +
    +-- leave environment
    +function leave()
    +
    +    -- restore search pathes of toolchains
    +    environment.leave("toolchains")
    +
    +    -- TODO restore toolchains for CC, LD
    +    
    +    -- TODO set flags of toolchains
    +end
    diff --git a/xmake/actions/require/fasturl.lua b/xmake/actions/require/fasturl.lua
    new file mode 100644
    index 00000000000..2018a4d5dcc
    --- /dev/null
    +++ b/xmake/actions/require/fasturl.lua
    @@ -0,0 +1,91 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        fasturl.lua
    +--
    +
    +-- imports
    +import("core.tool.ping")
    +
    +-- parse host from url
    +function _parse_host(url)
    +
    +    -- init host cache
    +    _g._URLHOSTS = _g._URLHOSTS or {}
    +
    +    -- http[s]://xxx.com/.. or git@git.xxx.com:xxx/xxx.git
    +    local host = _g._URLHOSTS[url] or url:match("://(.-)/") or url:match("@(.-):")
    +
    +    -- save to cache
    +    _g._URLHOSTS[url] = host
    +
    +    -- ok
    +    return host
    +end
    +
    +-- add urls
    +function add(urls)
    +
    +    -- get current ping info
    +    local pinginfo = _g._PINGINFO or {}
    +
    +    -- add ping hosts
    +    _g._PINGHOSTS = _g._PINGHOSTS or {}
    +    for _, url in ipairs(urls) do
    +
    +        -- parse host
    +        local host = _parse_host(url)
    +
    +        -- this host has not been tested?
    +        if host and not pinginfo[host] then
    +            table.insert(_g._PINGHOSTS, host)
    +        end
    +    end
    +end
    +
    +-- sort urls
    +function sort(urls)
    +
    +    -- ping hosts
    +    local pinghosts = table.unique(_g._PINGHOSTS or {})
    +    if pinghosts and #pinghosts > 0 then
    +
    +        -- ping them and test speed
    +        local pinginfo = ping.send(unpack(pinghosts))
    +        
    +        -- merge to ping info
    +        _g._PINGINFO = table.join(_g._PINGINFO or {}, pinginfo) 
    +    end
    +
    +    -- sort urls by the ping info
    +    local pinginfo = _g._PINGINFO or {}
    +    table.sort(urls, function(a, b) 
    +        a = pinginfo[_parse_host(a) or ""] or 65536
    +        b = pinginfo[_parse_host(b) or ""] or 65536
    +        return a < b 
    +    end)
    +
    +    -- clear hosts
    +    _g._PINGHOSTS = {}
    +
    +    -- ok
    +    return urls
    +end
    diff --git a/xmake/actions/deps/main.lua b/xmake/actions/require/main.lua
    similarity index 86%
    rename from xmake/actions/deps/main.lua
    rename to xmake/actions/require/main.lua
    index 44a19f48e56..4f71ac067a2 100644
    --- a/xmake/actions/deps/main.lua
    +++ b/xmake/actions/require/main.lua
    @@ -24,6 +24,7 @@
     
     -- imports
     import("core.base.option")
    +import("core.project.task")
     import("core.project.config")
     import("core.project.project")
     import("core.platform.platform")
    @@ -55,29 +56,25 @@ import("repository")
     -- load project
     function _load_project()
     
    +    -- config it first
    +    task.run("config")
    +
         -- enter project directory
         os.cd(project.directory())
    -
    -    -- load config
    -    config.load()
    -
    -    -- load platform
    -    platform.load(config.plat())
    -
    -    -- load project
    -    project.load()
     end
     
     -- install and update all outdated package dependencies
    -function _install(is_global)
    +function _install(requires)
     
         -- install packages
    -    package.install_packages(is_global)
    +    package.install_packages(requires)
     end
     
    --- clear all installed packages cache
    -function _clear(is_global)
    -    -- TODO
    +-- clear all installed package caches
    +function _clear()
    +
    +    -- clear all caches
    +    package.clear_caches()
     end
     
     -- search for the given packages from repositories
    @@ -106,13 +103,8 @@ function main()
         -- load project first
         _load_project()
     
    -    -- install and update all outdated package dependencies
    -    if option.get("install") then
    -
    -        _install(option.get("global"))
    -
         -- clear all installed packages cache
    -    elseif option.get("clear") then
    +    if option.get("clear") then
     
             _clear(option.get("global"))
     
    @@ -133,7 +125,7 @@ function main()
     
         -- install and update all outdated package dependencies by default if no arguments
         else
    -        _install(option.get("global"))
    +        _install(option.get("requires"))
         end
     end
     
    diff --git a/xmake/actions/deps/package.lua b/xmake/actions/require/package.lua
    similarity index 83%
    rename from xmake/actions/deps/package.lua
    rename to xmake/actions/require/package.lua
    index 0f1503ac7e5..f363c837aae 100644
    --- a/xmake/actions/deps/package.lua
    +++ b/xmake/actions/require/package.lua
    @@ -25,10 +25,13 @@
     -- imports
     import("core.tool.git")
     import("core.base.semver")
    +import("core.project.global")
     import("core.project.project")
     import("core.package.package", {alias = "core_package"})
    -import("repository")
     import("action")
    +import("fasturl")
    +import("repository")
    +import("environment")
     
     --
     -- parse require string
    @@ -187,11 +190,8 @@ function _load_package(packagename, requireinfo)
         -- check
         assert(instance, "package(%s) not found!", packagename)
     
    -    -- select package version
    -    local version, source = _select_package_version(instance, requireinfo.version)
    -
    -    -- save version info to package
    -    instance:versioninfo_set({version = version, source = source, mode = mode})
    +    -- save require info to package
    +    instance:requireinfo_set(requireinfo)
     
         -- save this package instance to cache
         packages[packagename] = instance
    @@ -204,21 +204,17 @@ end
     -- select package version
     function _select_package_version(package, required_ver)
     
    -    -- get package url    
    -    local url = package:get("url")
    -    assert(url, "package(%s): url not found!", package:name())
    -
    -    -- is git url?
    -    local is_giturl = git.checkurl(url)
    -
         -- get versions
         local versions = package:get("versions") 
     
         -- attempt to get tags and branches from the git url
         local tags = nil
         local branches = nil
    -    if is_giturl then
    -        tags, branches = git.refs(url) 
    +    for _, url in ipairs(package:urls()) do
    +        if git.checkurl(url) then
    +            tags, branches = git.refs(url) 
    +            break
    +        end
         end
     
         -- check
    @@ -228,6 +224,16 @@ function _select_package_version(package, required_ver)
         return semver.select(required_ver, versions, tags, branches)
     end
     
    +-- the cache directory
    +function cache_directory()
    +    return path.join(global.directory(), "cache", "packages")
    +end
    +
    +-- clear caches
    +function clear_caches()
    +    os.tryrm(cache_directory())
    +end
    +
     -- load requires
     function load_requires(requires)
     
    @@ -263,21 +269,47 @@ function load_packages(requires)
             table.insert(packages, package)
         end
     
    +    -- add all urls to fasturl and prepare to sort them together
    +    for _, package in ipairs(packages) do
    +        fasturl.add(package:urls())
    +    end
    +
    +    -- sort and update urls
    +    for _, package in ipairs(packages) do
    +
    +        -- sort package urls
    +        package:urls_set(fasturl.sort(package:urls()))
    +
    +        -- exists urls? otherwise be phony package (only as package group)
    +        if #package:urls() > 0 then
    +
    +            -- select package version
    +            local version, source = _select_package_version(package, package:requireinfo().version)
    +
    +            -- save version info to package
    +            package:versioninfo_set({version = version, source = source})
    +        end
    +    end
    +
         -- ok
         return packages
     end
     
     -- install packages
    -function install_packages(is_global)
    +function install_packages(requires)
    +
    +    -- load environment first
    +    environment.load()
     
         -- TODO need optimization
         -- pull all repositories first
         repository.pull()
     
         -- install all required packages from repositories
    -    for _, package in ipairs(load_packages(project.requires())) do
    +    for _, package in ipairs(load_packages(requires or project.requires())) do
    +
             -- install package
    -        action.install.main(package, is_global)
    +        action.install.main(package, cache_directory())
         end
     end
     
    diff --git a/xmake/actions/deps/repository.lua b/xmake/actions/require/repository.lua
    similarity index 96%
    rename from xmake/actions/deps/repository.lua
    rename to xmake/actions/require/repository.lua
    index d7699364fb4..ccd197f3fe2 100644
    --- a/xmake/actions/deps/repository.lua
    +++ b/xmake/actions/require/repository.lua
    @@ -48,6 +48,9 @@ end
     -- pull repositories
     function pull(position)
     
    +    -- trace
    +    print("updating repository ..")
    +
         -- pull all repositories 
         for _, repo in ipairs(repositories()) do
     
    @@ -56,7 +59,7 @@ function pull(position)
             if os.isdir(repodir) then
     
                 -- trace
    -            vprint("pulling repository(%s): %s in %s ..", repo.name, repo.url, repodir)
    +            vprint("pulling repository(%s): %s to %s ..", repo.name, repo.url, repodir)
     
                 -- pull it
                 git.pull({verbose = option.get("verbose"), branch = "master", repodir = repodir})
    diff --git a/xmake/actions/deps/xmake.lua b/xmake/actions/require/xmake.lua
    similarity index 63%
    rename from xmake/actions/deps/xmake.lua
    rename to xmake/actions/require/xmake.lua
    index efb67636354..6c5b7cacd61 100644
    --- a/xmake/actions/deps/xmake.lua
    +++ b/xmake/actions/require/xmake.lua
    @@ -19,11 +19,11 @@
     -- Copyright (C) 2015 - 2017, TBOOX Open Source Group.
     --
     -- @author      ruki
    --- @file        deps.lua
    +-- @file        require.lua
     --
     
     -- define task
    -task("deps")
    +task("require")
     
         -- set category
         set_category("action")
    @@ -34,25 +34,28 @@ task("deps")
         -- set menu
         set_menu {
                     -- usage
    -                usage = "xmake deps [options] [packages]"
    +                usage = "xmake require [options] [packages]"
     
                     -- description
    -            ,   description = "Install package dependencies."
    +            ,   description = "Install and update required packages."
     
    -                -- xmake d
    -            ,   shortname = 'd'
    +                -- xmake q
    +            ,   shortname = 'q'
     
                     -- options
                 ,   options = 
                     {
    -                    {'i', "install",    "k",  nil,       "Install and update outdated package dependencies."                           }
    -                ,   {'c', "clear",      "k",  nil,       "Clear all installed package caches."                                         }
    -                ,   {'l', "list",       "k",  nil,       "List all package dependencies."                                              }
    -                ,   {                                                                                                                  }
    -                ,   {nil, "info",       "k",  nil,       "Show the given package info."                                                }
    -                ,   {'g', "global",     "k",  nil,       "Install or clear packages in the global package directory. (default: local)" }
    -                ,   {'s', "search",     "k",  nil,       "Search for the given packages from repositories."                            }
    -                ,   {                                                                                                                  }
    -                ,   {nil, "packages",   "vs", nil,       "The packages."                                                               }
    +                    {'c', "clear",      "k",  nil,       "Clear all installed package caches."                                                       }
    +                ,   {'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, "requires",   "vs", nil,       "The package requires.",
    +                                                         ".e.g",
    +                                                         "    $ xmake require zlib tboox.tbox",
    +                                                         "    $ xmake require \"zlib >=1.2.11\" \"tboox.tbox master\"",
    +                                                         "    $ xmake require \"git@github.com:tboox/tbox.git@tboox.tbox >=1.6.0 <1.6.1 || master\"" }
                     }
                 } 
    diff --git a/xmake/actions/run/main.lua b/xmake/actions/run/main.lua
    index 3082783fedf..b2b13ae9659 100644
    --- a/xmake/actions/run/main.lua
    +++ b/xmake/actions/run/main.lua
    @@ -51,6 +51,9 @@ function _run_target(target)
     
         -- get kind
         local kind = target:get("kind")
    +    if not kind then
    +        return 
    +    end
     
         -- get script 
         local scripts =
    diff --git a/xmake/actions/uninstall/main.lua b/xmake/actions/uninstall/main.lua
    index a7cfec3dbdb..fe37ec8c707 100644
    --- a/xmake/actions/uninstall/main.lua
    +++ b/xmake/actions/uninstall/main.lua
    @@ -58,7 +58,7 @@ function main()
                 function (errors)
     
                     -- show tips
    -                cprint("${bright red}error: ${default red}failed to uninstall, may permission denied!")
    +                cprint("${bright red}error: ${clear}failed to uninstall, may permission denied!")
     
                     -- continue to uninstall with administrator permission?
                     if os.feature("sudo") then
    diff --git a/xmake/core/base/coroutine.lua b/xmake/core/base/coroutine.lua
    new file mode 100644
    index 00000000000..db2d363726c
    --- /dev/null
    +++ b/xmake/core/base/coroutine.lua
    @@ -0,0 +1,64 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        coroutine.lua
    +--
    +
    +-- define module: coroutine
    +local coroutine = coroutine or {}
    +
    +-- load modules
    +local utils     = require("base/utils")
    +local option    = require("base/option")
    +local string    = require("base/string")
    +
    +-- save original interfaces
    +coroutine._resume  = coroutine._resume or coroutine.resume
    +
    +-- resume coroutine
    +function coroutine.resume(co, ...)
    +
    +    -- resume it
    +    local ok, results = coroutine._resume(co, ...)
    +    if not ok then
    +
    +        -- get errors
    +        local errors = results
    +        if option.get("backtrace") then
    +            errors = debug.traceback(co, results)
    +        elseif type(results) == "string" then
    +            -- remove the prefix info
    +            local _, pos = results:find(":%d+: ")
    +            if pos then
    +                errors = results:sub(pos + 1)
    +            end
    +        end
    +
    +        -- failed
    +        return false, errors
    +    end
    +
    +    -- ok
    +    return true, results
    +end
    +
    +-- return module: coroutine
    +return coroutine
    diff --git a/xmake/core/base/filter.lua b/xmake/core/base/filter.lua
    index 19f502ffd5a..bd998cfb4bd 100644
    --- a/xmake/core/base/filter.lua
    +++ b/xmake/core/base/filter.lua
    @@ -32,13 +32,13 @@ local utils     = require("base/utils")
     local string    = require("base/string")
     
     -- new filter instance
    -function filter.new(handler)
    +function filter.new()
     
         -- init an filter instance
         local self = table.inherit(filter)
     
    -    -- save handler
    -    self._HANDLER = handler
    +    -- init handler
    +    self._HANDLERS = {}
     
         -- ok
         return self
    @@ -73,6 +73,13 @@ function filter.shell(cmd)
         return outdata or ""
     end
     
    +-- register handler
    +function filter:register(name, handler)
    +
    +    -- set handler
    +    self._HANDLERS[name] = handler
    +end
    +
     -- filter the builtin variables: "hello $(variable)" for string
     --
     -- .e.g  
    @@ -84,48 +91,50 @@ function filter:handle(value)
         -- check
         assert(type(value) == "string")
     
    -    -- return it directly if no handler
    -    local handler = self._HANDLER
    -    if handler == nil then
    -        return value
    -    end
    +    -- filter value for all handlers
    +    local count = 0
    +    for name, handler in pairs(self._HANDLERS) do
     
    -    -- filter the builtin variables
    -    return (value:gsub("%$%((.-)%)", function (variable) 
    +        -- filter the builtin variables
    +        value, count = value:gsub("%$%((.-)%)", function (variable) 
     
    -        -- check
    -        assert(variable)
    +            -- check
    +            assert(variable)
     
    -        -- is shell?
    -        if variable:startswith("shell ") then
    -            return filter.shell(variable:sub(7, -1))
    -        end
    +            -- is shell?
    +            if variable:startswith("shell ") then
    +                return filter.shell(variable:sub(7, -1))
    +            end
     
    -        -- parse variable:mode
    -        local varmode   = variable:split(':')
    -        local mode      = varmode[2]
    -        variable        = varmode[1]
    -       
    -        -- handler it
    -        local result = handler(variable)
    -
    -        -- invalid builtin variable?
    -        if result == nil then
    -            os.raise("invalid variable: $(%s)", variable)
    -        end
    - 
    -        -- handle mode
    -        if mode then
    -            if mode == "upper" then
    -                result = result:upper()
    -            elseif mode == "lower" then
    -                result = result:lower()
    +            -- parse variable:mode
    +            local varmode   = variable:split(':')
    +            local mode      = varmode[2]
    +            variable        = varmode[1]
    +           
    +            -- handler it
    +            local result = handler(variable)
    +
    +            -- handle mode
    +            if mode then
    +                if mode == "upper" then
    +                    result = result:upper()
    +                elseif mode == "lower" then
    +                    result = result:lower()
    +                end
                 end
    +
    +            -- ok?
    +            return result
    +        end)
    +
    +        -- end?
    +        if count == 0 then
    +            break
             end
    +    end
     
    -        -- ok?
    -        return result
    -    end))
    +    -- return old value
    +    return value
     end
     
     -- return module: filter
    diff --git a/xmake/core/base/interpreter.lua b/xmake/core/base/interpreter.lua
    index a207a32f26e..979b0cf57d9 100644
    --- a/xmake/core/base/interpreter.lua
    +++ b/xmake/core/base/interpreter.lua
    @@ -83,6 +83,39 @@ function interpreter._traceback(errors)
         return results
     end
     
    +-- merge the current root values to the previous scope
    +function interpreter._merge_root_scope(root, root_prev, override)
    +
    +    -- merge it
    +    root_prev = root_prev or {}
    +    for scope_kind_and_name, _ in pairs(root or {}) do
    +        
    +        -- is scope_kind.scope_name?
    +        scope_kind_and_name = scope_kind_and_name:split('%.')
    +        if #scope_kind_and_name == 2 then
    +            local scope_kind = scope_kind_and_name[1] 
    +            local scope_name = scope_kind_and_name[2]
    +            local scope_values = root_prev[scope_kind .. "." .. scope_name] or {}
    +            local scope_root = root[scope_kind] or {}
    +            for name, values in pairs(scope_root) do
    +                if not name:startswith("__") then
    +                    if scope_root["__override_" .. name] then
    +                        if override or scope_values[name] == nil then
    +                            scope_values[name] = values
    +                        end
    +                    else
    +                        scope_values[name] = table.join(values, scope_values[name] or {})
    +                    end
    +                end
    +            end
    +            root_prev[scope_kind .. "." .. scope_name] = scope_values
    +        end
    +    end
    +
    +    -- ok?
    +    return root_prev
    +end
    +
     -- register scope end: scopename_end()
     function interpreter:_api_register_scope_end(...)
     
    @@ -96,7 +129,7 @@ function interpreter:_api_register_scope_end(...)
             assert(apiname)
     
             -- register scope api
    -        self:api_register(ni, apiname .. "_end", function (self, ...) 
    +        self:api_register(nil, apiname .. "_end", function (self, ...) 
            
                 -- check
                 assert(self and self._PRIVATE and apiname)
    @@ -180,8 +213,8 @@ function interpreter:_api_register_xxx_values(scope_kind, action, apifunc, ...)
             local scope = scopes._CURRENT or root
             assert(scope)
     
    -        -- enter subscope and set values? override it
    -        if scopes._CURRENT and apiname and action == "set" then
    +        -- set values? mark as "override"
    +        if apiname and action ~= "add" then
                 scope["__override_" .. apiname] = true
             end
     
    @@ -273,12 +306,18 @@ function interpreter:_api_builtin_add_subdirfiles(isdirs, ...)
                     -- bind public scope
                     setfenv(script, self._PUBLIC)
     
    +                -- save the previous root scope
    +                local root_prev = scopes._ROOT
    +
                     -- save the previous scope
                     local scope_prev = scopes._CURRENT
     
                     -- save the previous scope kind
                     local scope_kind_prev = scopes._CURRENT_KIND
     
    +                -- clear the current root scope 
    +                scopes._ROOT = nil
    +
                     -- clear the current scope, force to enter root scope
                     scopes._CURRENT = nil
     
    @@ -303,6 +342,11 @@ function interpreter:_api_builtin_add_subdirfiles(isdirs, ...)
                     -- restore the previous scope
                     scopes._CURRENT = scope_prev
     
    +                -- restore the previous root scope and merge current root scope
    +                -- it will override the previous values if the current values are override mode 
    +                -- so we priority use the values in subdirs scope
    +                scopes._ROOT = interpreter._merge_root_scope(scopes._ROOT, root_prev, true)
    +
                     -- get mtime of the file
                     self._PRIVATE._MTIMES[path.relative(file, self._PRIVATE._ROOTDIR)] = os.mtime(file)
                 else
    @@ -326,7 +370,7 @@ function interpreter:_api_within_scope(scope_kind, apiname)
         local scopes = priv._SCOPES
         assert(scopes)
     
    -    -- done
    +    -- get scope api
         if scope_kind and priv._APIS then
     
             -- get api function
    @@ -459,8 +503,9 @@ function interpreter:_make(scope_kind, remove_repeat, enable_filter)
                 return {}
             end
     
    -        -- the root scope
    -        local scope_root = scopes._ROOT[scope_kind]
    +        -- merge root scope first and do not override the root values if be override mode 
    +        -- so we priority use the values in subdirs scope
    +        scopes._ROOT = interpreter._merge_root_scope(scopes._ROOT, scopes._ROOT, false)
     
             -- merge results
             for scope_name, scope in pairs(scope_for_kind) do
    @@ -473,19 +518,12 @@ function interpreter:_make(scope_kind, remove_repeat, enable_filter)
                     end
                 end
     
    -            -- merge root values
    +            -- merge root values with the given scope name
    +            local scope_root = scopes._ROOT[scope_kind .. "." .. scope_name]
                 if scope_root then
                     for name, values in pairs(scope_root) do
    -
    -                    -- merge values?
                         if not scope["__override_" .. name] then
    -
    -                        -- merge or add it
    -                        if scope_values[name] ~= nil then
    -                            scope_values[name] = table.join(values, scope_values[name])
    -                        else
    -                            scope_values[name] = values
    -                        end
    +                        scope_values[name] = table.join(values, scope_values[name] or {})
                         end
                     end
                 end
    @@ -509,7 +547,8 @@ function interpreter.new()
         -- init an interpreter instance
         local instance = {  _PUBLIC = {}
                         ,   _PRIVATE = {    _SCOPES = {}
    -                                    ,   _MTIMES = {}}}
    +                                    ,   _MTIMES = {}
    +                                    ,   _FILTER = require("base/filter").new()}}
     
         -- inherit the interfaces of interpreter
         table.inherit2(instance, interpreter)
    @@ -518,11 +557,20 @@ function interpreter.new()
         setmetatable(instance._PUBLIC, {    __index = function (tbl, key)
     
                                                 -- get the scope kind
    -                                            local priv = instance._PRIVATE
    -                                            local scope_kind = priv._SCOPES._CURRENT_KIND or priv._ROOTSCOPE
    +                                            local priv          = instance._PRIVATE
    +                                            local current_kind  = priv._SCOPES._CURRENT_KIND
    +                                            local scope_kind    = current_kind or priv._ROOTSCOPE
     
                                                 -- get the api function from the given scope
    -                                            return instance:_api_within_scope(scope_kind, key)
    +                                            local apifunc = instance:_api_within_scope(scope_kind, key)
    +
    +                                            -- get the api function from the root scope
    +                                            if not apifunc and priv._ROOTAPIS then
    +                                                apifunc = priv._ROOTAPIS[key]
    +                                            end
    +
    +                                            -- ok?
    +                                            return apifunc
                                         end}) 
     
         -- register the builtin interfaces
    @@ -626,16 +674,6 @@ function interpreter:filter()
         return self._PRIVATE._FILTER
     end
     
    --- set filter
    -function interpreter:filter_set(filter)
    -
    -    -- check
    -    assert(self and self._PRIVATE)
    -
    -    -- set it
    -    self._PRIVATE._FILTER = filter
    -end
    -
     -- get root directory
     function interpreter:rootdir()
     
    @@ -686,11 +724,6 @@ end
     --
     -- result:
     --
    --- _PUBLIC 
    --- {
    ---      apiroot = function () end
    --- }
    ---
     -- _PRIVATE
     -- {
     --      _APIS
    @@ -700,6 +733,11 @@ end
     --              apiname = function () end
     --          }
     --      }
    +--      
    +--      _ROOTAPIS
    +--      {
    +--          apiroot = function () end
    +--      }         
     -- }
     --
     function interpreter:api_register(scope_kind, name, func)
    @@ -722,8 +760,13 @@ function interpreter:api_register(scope_kind, name, func)
             -- register api
             scope[name] = function (...) return func(self, ...) end
         else
    +
    +        -- get root apis
    +        self._PRIVATE._ROOTAPIS = self._PRIVATE._ROOTAPIS or {}
    +        local apis = self._PRIVATE._ROOTAPIS
    +
             -- register api to the root scope
    -        self._PUBLIC[name] = function (...) return func(self, ...) end
    +        apis[name] = function (...) return func(self, ...) end
         end
     end
     
    @@ -812,6 +855,7 @@ function interpreter:api_register_scope(...)
                 scope_name = scope_name["name"]
             end
     
    +
             -- enter the given scope
             if scope_name ~= nil then
     
    @@ -833,6 +877,12 @@ function interpreter:api_register_scope(...)
             -- update the current scope kind
             scopes._CURRENT_KIND = scope_kind
     
    +        -- init scope_kind.scope_name for the current root scope
    +        scopes._ROOT = scopes._ROOT or {}
    +        if scope_name ~= nil then
    +            scopes._ROOT[scope_kind .. "." .. scope_name] = {}
    +        end
    +
             -- translate scope info 
             if scope_info then
                 scope_info["name"] = nil
    diff --git a/xmake/core/base/option.lua b/xmake/core/base/option.lua
    index 718cc68b842..a2388c91e34 100644
    --- a/xmake/core/base/option.lua
    +++ b/xmake/core/base/option.lua
    @@ -131,6 +131,51 @@ function option._bindings(name)
         end
     end
     
    +-- get line length
    +function option._get_linelen(st)
    +    local poss = st:reverse():find("\n")
    +    if not poss then return (#st) end
    +    local start_pos, _ = poss
    +    return start_pos - 1
    +end
    +
    +-- get last space
    +function option._get_lastspace(st)
    +    local poss = st:reverse():find("[%s-]")
    +    if not poss then return (#st) end
    +    local start_pos, _ = poss
    +    return (#st) - start_pos + 1
    +end
    +
    +-- append spaces in width
    +function option._inwidth_append(dst, st, padding, width, remain_width)
    +    
    +    if padding >= width then
    +        return dst .. st
    +    end
    +
    +    local white_padding = string.rep(" ", padding)
    +    if remain_width == nil then 
    +        -- TODO because of colored string, it's wrong sometimes
    +        remain_width = width - option._get_linelen(dst) 
    +    end
    +
    +    if remain_width <= 0 then
    +        return option._inwidth_append(dst .. "\n" .. white_padding, st, padding, width, width - padding)
    +    end
    +    
    +    if (#st) <= remain_width then
    +        return dst .. st
    +    end
    +    
    +    local lastspace = option._get_lastspace(st:sub(1, remain_width))
    +    if lastspace + 1 > (#st) then
    +        return dst .. st
    +    else
    +        return option._inwidth_append(dst .. st:sub(1, lastspace) .. "\n" .. white_padding, st:sub(lastspace + 1):ltrim(), padding, width, width - padding)
    +    end
    +end
    +
     -- save context
     function option.save(taskname)
     
    @@ -953,6 +998,9 @@ function option.show_main()
                 -- the padding spaces
                 local padding = 42
     
    +            -- get width of console
    +            local console_width = os.getwinsize()["width"]
    +
                 -- print tasks
                 for taskname, taskinfo in pairs(categorytask) do
     
    @@ -977,7 +1025,7 @@ function option.show_main()
     
                     -- append the task description
                     if taskinfo.description then
    -                    taskline = taskline .. taskinfo.description
    +                    taskline = option._inwidth_append(taskline, taskinfo.description, padding + 1 - 18, console_width, console_width - padding - 1 + 18)
                     end
     
                     -- print task line
    @@ -1044,18 +1092,27 @@ function option.show_options(options)
             end
     
             -- append color
    -        option_info = "${blue}" .. option_info .. "${clear}"
    +        option_info = "${green}" .. option_info .. "${clear}"
    +
    +        -- get width of console
    +        local console_width = os.getwinsize()["width"]
     
             -- append the option description
             local description = opt[5]
             if description then
    -            option_info = option_info .. description
    +            option_info = option._inwidth_append(option_info, description, padding + 1, console_width, console_width - padding - 1)
             end
     
             -- append the default value
             local default = opt[4]
             if default then
    -            option_info = option_info .. " (default: ${bright}" .. tostring(default) .. "${clear})"
    +            option_info  = option._inwidth_append(option_info, " (default: ", padding + 1, console_width)
    +            local origin_width = option._get_linelen(option_info)
    +            option_info  = option_info .. "${bright}"
    +            option_info  = option._inwidth_append(option_info, tostring(default), padding + 1, console_width, console_width - origin_width)
    +            origin_width = option._ifelse(origin_width + (#(tostring(default))) > console_width, option._get_linelen(option_info), origin_width + (#(tostring(default))))
    +            option_info  = option_info .. "${clear}"
    +            option_info  = option._inwidth_append(option_info, ")", padding + 1, console_width, console_width - origin_width)
             end
     
             -- print option info
    @@ -1083,7 +1140,7 @@ function option.show_options(options)
                     end
     
                     -- print this description
    -                print(spaces .. description)
    +                print(option._inwidth_append(spaces, description, padding + 1, console_width))
     
                 -- the description is table?
                 elseif type(description) == "table" then
    @@ -1098,7 +1155,7 @@ function option.show_options(options)
                         end
     
                         -- print this description
    -                    print(spaces .. v)
    +                    print(option._inwidth_append(spaces, v, padding + 1, console_width))
                     end
                 end
             end
    diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua
    index 5fb51b19475..888da03579f 100644
    --- a/xmake/core/base/os.lua
    +++ b/xmake/core/base/os.lua
    @@ -416,7 +416,7 @@ end
     function os.tmpfile()
     
         -- make it
    -    return path.join(os.tmpdir(), "_" .. (os.uuid():gsub("-", "")))
    +    return path.join(os.tmpdir(), "_" .. (hash.uuid():gsub("-", "")))
     end
     
     -- run shell
    diff --git a/xmake/core/base/process.lua b/xmake/core/base/process.lua
    new file mode 100644
    index 00000000000..5f2db9818e5
    --- /dev/null
    +++ b/xmake/core/base/process.lua
    @@ -0,0 +1,189 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        process.lua
    +--
    +
    +-- define module: process
    +local process = process or {}
    +
    +-- load modules
    +local utils     = require("base/utils")
    +local string    = require("base/string")
    +local coroutine = require("base/coroutine")
    +
    +-- async run task and echo waiting info
    +function process.asyncrun(task, waitchars)
    +
    +    -- create a coroutine task
    +    task = coroutine.create(task)
    +
    +    -- trace
    +    local waitindex = 0
    +    local waitchars = waitchars or {'\\', '|', '/', '-'}
    +    utils.printf(waitchars[waitindex + 1])
    +
    +    -- start and wait this task
    +    local ok, errors = coroutine.resume(task)
    +    if not ok then
    +
    +        -- remove wait charactor
    +        utils.printf("\b")
    +
    +        -- failed
    +        return false, errors
    +    end
    +
    +    -- wait and poll task
    +    while coroutine.status(task) ~= "dead" do
    +
    +        -- trace
    +        waitindex = ((waitindex + 1) % #waitchars)
    +        utils.printf("\b" .. waitchars[waitindex + 1])
    +
    +        -- wait some time
    +        os.sleep(300)
    +        
    +        -- continue to poll this task
    +        local ok, errors = coroutine.resume(task, 0)
    +        if not ok then
    +
    +            -- remove wait charactor
    +            utils.printf("\b")
    +
    +            -- failed
    +            return false, errors
    +        end
    +    end
    +
    +    -- remove wait charactor
    +    utils.printf("\b")
    +
    +    -- ok
    +    return true
    +end
    +
    +-- run jobs with processes
    +function process.runjobs(jobfunc, total, comax, timeout)
    +
    +    -- init max coroutine count
    +    comax = comax or total
    +
    +    -- make objects
    +    local index = 1
    +    local tasks = {}
    +    local procs = {}
    +    repeat
    +
    +        -- wait processes
    +        local tasks_finished = {}
    +        local procs_count = #procs
    +        if procs_count > 0 then
    +
    +            -- wait them
    +            local count, procinfos = process.waitlist(procs, utils.ifelse(procs_count < comax and index <= total, 0, -1))
    +            if count < 0 then
    +                return false, string.format("wait processes(%d) failed(%d)", #procs, count)
    +            end
    +
    +            -- wait ok
    +            for _, procinfo in ipairs(procinfos) do
    +                
    +                -- the process info
    +                local proc      = procinfo[1]
    +                local procid    = procinfo[2]
    +                local status    = procinfo[3]
    +
    +                -- check
    +                assert(procs[procid] == proc)
    +
    +                -- resume this task
    +                local job_task = tasks[procid]
    +                local ok, job_proc_or_errors = coroutine.resume(job_task, 1, status)
    +                if not ok then
    +                    return false, job_proc_or_errors
    +                end
    +
    +                -- the other process is pending for this task?
    +                if coroutine.status(job_task) ~= "dead" then
    +
    +                    -- check
    +                    assert(job_proc_or_errors)
    +
    +                    -- update the pending process
    +                    procs[procid] = job_proc_or_errors
    +
    +                -- this task has been finised?
    +                else
    +
    +                    -- mark this task as finised
    +                    tasks_finished[procid] = true
    +                end
    +            end
    +        end
    +
    +        -- update the pending tasks and procs
    +        local tasks_pending = {}
    +        local procs_pending = {}
    +        for taskid, job_task in ipairs(tasks) do
    +            if not tasks_finished[taskid] then
    +                table.insert(tasks_pending, job_task)
    +                table.insert(procs_pending, procs[taskid])
    +            end
    +        end
    +        tasks = tasks_pending
    +        procs = procs_pending
    +
    +        -- produce tasks
    +        while #tasks < comax and index <= total do
    +
    +            -- new task
    +            local job_task = coroutine.create(jobfunc)
    +
    +            -- resume it first
    +            local ok, job_proc_or_errors = coroutine.resume(job_task, index)
    +            if not ok then
    +                return false, job_proc_or_errors
    +            end
    +
    +            -- add pending tasks
    +            if coroutine.status(job_task) ~= "dead" then
    +
    +                -- check
    +                assert(job_proc_or_errors)
    +
    +                -- put task and proc to the pendings tasks
    +                table.insert(tasks, job_task)
    +                table.insert(procs, job_proc_or_errors)
    +            end
    +
    +            -- next index
    +            index = index + 1
    +        end
    +
    +    until #tasks == 0
    +
    +    -- ok
    +    return true
    +end
    +
    +-- return module: process
    +return process
    diff --git a/xmake/core/base/table.lua b/xmake/core/base/table.lua
    index 3767fc1c48a..c498df13b28 100644
    --- a/xmake/core/base/table.lua
    +++ b/xmake/core/base/table.lua
    @@ -220,6 +220,9 @@ function table._dump(self, exclude, level)
         -- dump function 
         elseif type(self) == "function" then  
             io.write("")  
    +    -- dump thread 
    +    elseif type(self) == "thread" then  
    +        io.write("")  
         -- dump table
         elseif type(self) == "table" then  
     
    diff --git a/xmake/core/base/utils.lua b/xmake/core/base/utils.lua
    index 030c10d5c64..aa77feefc4e 100644
    --- a/xmake/core/base/utils.lua
    +++ b/xmake/core/base/utils.lua
    @@ -45,6 +45,7 @@ function utils._iowrite(...)
         -- print it if not quiet
         if not option.get("quiet") then
             io.write(...)
    +        io.flush()
         end
     end
     
    @@ -106,7 +107,7 @@ function utils.verror(format, ...)
         if option.get("verbose") and format ~= nil then
             
             -- trace
    -        utils.cprint("${bright red}error: ${default red}" .. string.tryformat(format, ...))
    +        utils.cprint("${bright red}error: ${clear}" .. string.tryformat(format, ...))
         end
     end
     
    @@ -115,7 +116,7 @@ function utils.error(format, ...)
     
         -- trace
         if format ~= nil then
    -        utils.cprint("${bright red}error: ${default red}" .. string.tryformat(format, ...))
    +        utils.cprint("${bright red}error: ${clear}" .. string.tryformat(format, ...))
         end
     end
     
    diff --git a/xmake/core/main.lua b/xmake/core/main.lua
    index 49ff1570f0b..d26660f3c45 100644
    --- a/xmake/core/main.lua
    +++ b/xmake/core/main.lua
    @@ -51,10 +51,28 @@ local menu =
     
     }
     
    --- done help
    -function main._help()
    +-- show logo
    +function main._show_logo()
    +
    +    -- define logo
    +    local logo = [[
    +                         _        
    +    __  ___ __  __  __ _| | ______ 
    +    \ \/ / |  \/  |/ _  | |/ / __ \
    +     >  <  | \__/ | /_| |   <  ___/
    +    /_/\_\_|_|  |_|\__ \|_|\_\____| 
    +
    +                         by ruki, ${underline}tboox.org${clear}
    +                                      ]]
    +
    +    -- show logo
    +    utils.cprint(logo)
    +end
    +
    +-- show help and version info
    +function main._show_help()
     
    -    -- done help
    +    -- show help
         if option.get("help") then
         
             -- print menu
    @@ -63,19 +81,22 @@ function main._help()
             -- ok
             return true
     
    -    -- done version
    +    -- show version
         elseif option.get("version") then
     
    -        -- print title
    +        -- show title
             if menu.title then
                 utils.cprint(menu.title)
             end
     
    -        -- print copyright
    +        -- show copyright
             if menu.copyright then
                 utils.cprint(menu.copyright)
             end
     
    +        -- show logo
    +        main._show_logo()
    +
             -- ok
             return true
         end
    @@ -180,13 +201,15 @@ function main.done()
             profiler:start()
         end
     
    -    -- run help?
    -    if main._help() then
    +    -- show help?
    +    if main._show_help() then
             return 0
         end
     
         -- save command lines to history
    -    history.save("cmdlines", option.cmdline())
    +    if os.isfile(xmake._PROJECT_FILE) then
    +        history.save("cmdlines", option.cmdline())
    +    end
     
         -- run task    
         ok, errors = task.run(option.taskname() or "build")
    diff --git a/xmake/core/package/package.lua b/xmake/core/package/package.lua
    index 5d060078adc..62f4a86e9d2 100644
    --- a/xmake/core/package/package.lua
    +++ b/xmake/core/package/package.lua
    @@ -91,16 +91,47 @@ end
     
     -- get the package name
     function _instance:name()
    -
    -    -- get it
         return self._NAME
     end
     
     -- get the package filter 
     function _instance:filter()
    +    return self._FILTER
    +end
    +
    +-- get urls
    +function _instance:urls()
    +    return self._URLS or table.wrap(self:get("urls"))
    +end
    +
    +-- get urls
    +function _instance:urls_set(urls)
    +    self._URLS = urls
    +end
    +
    +-- get sha256
    +function _instance:sha256()
    +
    +    -- get it from cache first
    +    if self._SHA256 then
    +        return self._SHA256
    +    end
    +
    +    -- find sha256
    +    local version  = self:version()
    +    local sha256s  = table.wrap(self:get("sha256s"))
    +    local versions = table.wrap(self:get("versions"))
    +    if version then
    +        for idx, ver in ipairs(versions) do
    +            if ver == version then
    +                self._SHA256 = sha256s[idx]
    +                break
    +            end
    +        end
    +    end
     
         -- get it
    -    return self._FILTER
    +    return self._SHA256
     end
     
     -- get the version  
    @@ -116,13 +147,11 @@ end
     function _instance:optional()
     
         -- optional?
    -    if self._VERSIONINFO then
    -        return self._VERSIONINFO.mode == "optional"
    -    end
    +    return self._REQUIREINFO.mode == "optional"
     end
     
     -- the verson from tags, branches or versions?
    -function _instance:verfrom()
    +function _instance:versionfrom()
     
         -- optional?
         if self._VERSIONINFO then
    @@ -132,11 +161,19 @@ end
     
     -- set the version info 
     function _instance:versioninfo_set(versioninfo)
    -
    -    -- set it
         self._VERSIONINFO = versioninfo
     end
     
    +-- get the require info 
    +function _instance:requireinfo()
    +    return self._REQUIREINFO 
    +end
    +
    +-- set the require info 
    +function _instance:requireinfo_set(requireinfo)
    +    self._REQUIREINFO = requireinfo
    +end
    +
     -- the interpreter
     function package._interpreter()
     
    @@ -167,8 +204,7 @@ function package.apis()
             values =
             {
                 -- package.set_xxx
    -            "package.set_url"
    -        ,   "package.set_mirror"
    +            "package.set_urls"
             ,   "package.set_sha256s"
             ,   "package.set_versions"
             ,   "package.set_homepage"
    @@ -181,19 +217,16 @@ function package.apis()
                 -- package.on_xxx
                 "package.on_build"
             ,   "package.on_install"
    -        ,   "package.on_clean"
             ,   "package.on_test"
     
                 -- package.before_xxx
             ,   "package.before_build"
             ,   "package.before_install"
    -        ,   "package.before_clean"
             ,   "package.before_test"
     
                 -- package.before_xxx
             ,   "package.after_build"
             ,   "package.after_install"
    -        ,   "package.after_clean"
             ,   "package.after_test"
             }
         }
    @@ -219,7 +252,7 @@ function package.load_from_url(packagename, packageurl)
         -- make package description
         local packagedata = string.format([[
         package("%s")
    -        set_url("%s")
    +        set_urls("%s")
         ]], packagename, packageurl)
     
         -- write a temporary package description to file
    diff --git a/xmake/core/project/config.lua b/xmake/core/project/config.lua
    index 2f3ce1a96a6..ae90fb74f06 100644
    --- a/xmake/core/project/config.lua
    +++ b/xmake/core/project/config.lua
    @@ -101,12 +101,9 @@ end
     -- get all options
     function config.options()
     
    -    -- check
    -    assert(config._CONFIGS)
    -         
         -- remove values with "auto" and private item
         local configs = {}
    -    for name, value in pairs(config._CONFIGS) do
    +    for name, value in pairs(config._CONFIGS or {}) do
             if not name:find("^_%u+") and (type(value) ~= "string" or value ~= "auto") then
                 configs[name] = value
             end
    diff --git a/xmake/core/project/project.lua b/xmake/core/project/project.lua
    index 4f171085ee9..65d814d6c72 100644
    --- a/xmake/core/project/project.lua
    +++ b/xmake/core/project/project.lua
    @@ -119,6 +119,21 @@ function project._api_is_kind(interp, ...)
         end
     end
     
    +-- the current host is belong to the given hosts?
    +function project._api_is_host(interp, ...)
    +
    +    -- get the current host
    +    local host = xmake._HOST
    +    if not host then return false end
    +
    +    -- exists this host? and escape '-'
    +    for _, h in ipairs(table.join(...)) do
    +        if h and type(h) == "string" and host:find(h:gsub("%-", "%%-")) then
    +            return true
    +        end
    +    end
    +end
    +
     -- enable options?
     function project._api_is_option(interp, ...)
     
    @@ -256,6 +271,7 @@ function project._interpreter()
                 -- is_xxx
                 {"is_os",                   project._api_is_os          }
             ,   {"is_kind",                 project._api_is_kind        }
    +        ,   {"is_host",                 project._api_is_host        }
             ,   {"is_mode",                 project._api_is_mode        }
             ,   {"is_plat",                 project._api_is_plat        }
             ,   {"is_arch",                 project._api_is_arch        }
    @@ -279,7 +295,7 @@ function project._interpreter()
         deprecated_project.api_register(interp)
     
         -- set filter
    -    interp:filter_set(filter.new(function (variable)
    +    interp:filter():register("project", function (variable)
     
             -- check
             assert(variable)
    @@ -305,6 +321,8 @@ function project._interpreter()
                 ,   globaldir   = global.directory()
                 ,   configdir   = config.directory()
                 ,   projectdir  = project.directory()
    +            ,   programdir  = xmake._PROGRAM_DIR
    +            ,   xmake       = path.join(xmake._PROGRAM_DIR, "xmake")
                 }
     
                 -- map it
    @@ -323,7 +341,7 @@ function project._interpreter()
     
             -- ok?
             return result
    -    end))
    +    end)
     
         -- save interpreter
         project._INTERPRETER = interp
    diff --git a/xmake/core/project/task.lua b/xmake/core/project/task.lua
    index a82351ac205..cb0960cbdce 100644
    --- a/xmake/core/project/task.lua
    +++ b/xmake/core/project/task.lua
    @@ -168,7 +168,7 @@ function task._interpreter()
         interp:api_define(task.apis())
     
         -- set filter
    -    interp:filter_set(filter.new(function (variable)
    +    interp:filter():register("task", function (variable)
     
             -- check
             assert(variable)
    @@ -187,6 +187,8 @@ function task._interpreter()
                 ,   globaldir   = global.directory()
                 ,   configdir   = config.directory()
                 ,   projectdir  = xmake._PROJECT_DIR
    +            ,   programdir  = xmake._PROGRAM_DIR
    +            ,   xmake       = path.join(xmake._PROGRAM_DIR, "xmake")
                 }
     
                 -- map it
    @@ -195,7 +197,7 @@ function task._interpreter()
     
             -- ok?
             return result
    -    end))
    +    end)
     
         -- save interpreter
         task._INTERPRETER = interp
    diff --git a/xmake/core/project/template.lua b/xmake/core/project/template.lua
    index 91ce420bc9c..ad88d2cef9b 100644
    --- a/xmake/core/project/template.lua
    +++ b/xmake/core/project/template.lua
    @@ -192,7 +192,7 @@ function template.create(language, templateid, targetname)
         local projectdir = path.absolute(option.get("project") or path.join(os.curdir(), targetname))
     
         -- set filter
    -    interp:filter_set(filter.new(function (variable)
    +    interp:filter():register("template", function (variable)
     
             -- init maps
             local maps = 
    @@ -209,8 +209,7 @@ function template.create(language, templateid, targetname)
     
             -- ok?
             return variable
    -
    -    end))
    +    end)
     
         -- load all templates for the given language
         local templates = template.templates(language)
    diff --git a/xmake/core/sandbox/modules/coroutine.lua b/xmake/core/sandbox/modules/coroutine.lua
    index c1d74a9fdf0..2ed3cdb785d 100644
    --- a/xmake/core/sandbox/modules/coroutine.lua
    +++ b/xmake/core/sandbox/modules/coroutine.lua
    @@ -27,6 +27,7 @@ local sandbox_coroutine = sandbox_coroutine or {}
     
     -- load modules
     local option    = require("base/option")
    +local coroutine = require("base/coroutine")
     local raise     = require("sandbox/modules/raise")
     
     -- inherit some builtin interfaces
    @@ -40,27 +41,13 @@ sandbox_coroutine.running   = coroutine.running
     function sandbox_coroutine.resume(co, ...)
     
         -- resume it
    -    local ok, results = coroutine.resume(co, ...)
    +    local ok, results_or_errors = coroutine.resume(co, ...)
         if not ok then
    -
    -        -- get errors
    -        local errors = results
    -        if option.get("backtrace") then
    -            errors = debug.traceback(co, results)
    -        elseif type(results) == "string" then
    -            -- remove the prefix info
    -            local _, pos = results:find(":%d+: ")
    -            if pos then
    -                errors = results:sub(pos + 1)
    -            end
    -        end
    -
    -        -- raise it
    -        raise(errors)
    +        raise(results_or_errors)
         end
     
         -- ok
    -    return results
    +    return results_or_errors
     end
     
     -- load module
    diff --git a/xmake/core/sandbox/modules/hash.lua b/xmake/core/sandbox/modules/hash.lua
    new file mode 100644
    index 00000000000..7143aa51156
    --- /dev/null
    +++ b/xmake/core/sandbox/modules/hash.lua
    @@ -0,0 +1,59 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        hash.lua
    +--
    +
    +-- load modules
    +local raise = require("sandbox/modules/raise")
    +
    +-- define module
    +local sandbox_hash = sandbox_hash or {}
    +
    +-- make a new uuid
    +function sandbox_hash.uuid(name)
    +
    +    -- make it
    +    local uuid = hash.uuid(name)
    +    if not uuid then
    +        raise("cannot make uuid %s", name)
    +    end
    +
    +    -- ok?
    +    return uuid
    +end
    +
    +-- make sha256 from the given file
    +function sandbox_hash.sha256(file)
    +
    +    -- make it
    +    local sha256 = hash.sha256(file)
    +    if not sha256 then
    +        raise("cannot make sha256 for %s", file)
    +    end
    +
    +    -- ok?
    +    return sha256
    +end
    +
    +-- return module
    +return sandbox_hash
    +
    diff --git a/xmake/core/sandbox/modules/import.lua b/xmake/core/sandbox/modules/import.lua
    index 234e7692580..c0cc942b89c 100644
    --- a/xmake/core/sandbox/modules/import.lua
    +++ b/xmake/core/sandbox/modules/import.lua
    @@ -50,6 +50,32 @@ function sandbox_import._modulename(name)
         return name
     end
     
    +-- get module path from name
    +function sandbox_import._modulepath(name)
    +
    +    -- translate module path
    +    --
    +    -- "package.module" => "package/module"
    +    -- "..package.module" => "../../package/module"
    +    --
    +    local startdots = true
    +    local modulepath = name:gsub(".", function(c)
    +        if c == '.' then
    +            if startdots then
    +                return ".." .. path.seperator()
    +            else
    +                return path.seperator()
    +            end
    +        else
    +            startdots = false
    +            return c
    +        end
    +    end)
    +
    +    -- return module path
    +    return modulepath
    +end
    +
     -- load module from file
     function sandbox_import._loadfile(filepath, instance)
     
    @@ -97,8 +123,8 @@ function sandbox_import._find(dir, name)
         -- check
         assert(dir and name)
     
    -    -- replace "package.module" => "package/module"
    -    name = (name:gsub("%.", "/"))
    +    -- get module path
    +    name = sandbox_import._modulepath(name)
         assert(name)
     
         -- load the single module?
    @@ -127,8 +153,8 @@ function sandbox_import._load(dir, name, instance)
         -- check
         assert(dir and name)
     
    -    -- replace "package.module" => "package/module"
    -    name = (name:gsub("%.", "/"))
    +    -- get module path
    +    name = sandbox_import._modulepath(name)
         assert(name)
     
         -- load the single module?
    diff --git a/xmake/core/sandbox/modules/import/core/package/repository.lua b/xmake/core/sandbox/modules/import/core/package/repository.lua
    index e54fe48b0b7..68b97f651f8 100644
    --- a/xmake/core/sandbox/modules/import/core/package/repository.lua
    +++ b/xmake/core/sandbox/modules/import/core/package/repository.lua
    @@ -75,9 +75,14 @@ end
     -- get all repositories from global or local directory
     function sandbox_core_package_repository.repositories(is_global)
     
    -    -- load repositories from repository cache 
    +    -- add default global xmake repository
         local repositories = {}
    -    for name, url in ipairs(table.wrap(repository.repositories(is_global))) do
    +    if is_global then
    +        table.insert(repositories, {name = "xmake-repo", url = "https://github.com/tboox/xmake-repo.git", global = true})
    +    end
    +
    +    -- load repositories from repository cache 
    +    for name, url in pairs(table.wrap(repository.repositories(is_global))) do
             table.insert(repositories, {name = name, url = url, global = is_global})
         end
     
    @@ -93,11 +98,6 @@ function sandbox_core_package_repository.repositories(is_global)
             end
         end
     
    -    -- add default global xmake repository
    -    if is_global then
    -        table.insert(repositories, {name = "xmake-repo", url = "git@github.com:tboox/xmake-repo.git", global = true})
    -    end
    -
         -- get the repositories
         return repositories
     end
    diff --git a/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua b/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua
    new file mode 100644
    index 00000000000..803213fbc27
    --- /dev/null
    +++ b/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua
    @@ -0,0 +1,74 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        sandbox.lua
    +--
    +
    +-- define module
    +local sandbox_core_sandbox = sandbox_core_sandbox or {}
    +
    +-- load modules
    +local sandbox   = require("sandbox/sandbox")
    +local raise     = require("sandbox/modules/raise")
    +
    +-- enter interactive mode
    +function sandbox_core_sandbox.interactive()
    +
    +    -- get the current sandbox instance
    +    local instance = sandbox.instance()
    +    if not instance then
    +        raise("cannot get sandbox instance!")
    +    end
    +
    +    -- fork a new sandbox 
    +    instance, errors = instance:fork()
    +    if not instance then
    +        raise(errors)
    +    end
    +
    +    -- bind sandbox environment
    +--    setfenv(0, instance._PUBLIC)
    +
    +    -- enter interactive mode with this new sandbox
    +    sandbox.interactive(instance._PUBLIC) 
    +end
    +
    +-- register filter handler
    +function sandbox_core_sandbox.filter_register(script, name, handler)
    +
    +    -- get the sandbox instance
    +    local instance = sandbox.instance(script)
    +    if not instance then
    +        raise("sandbox instance not found when register %s!", name)
    +    end
    +
    +    -- get filter
    +    local filter = instance:filter()
    +    if not filter then
    +        raise("filter not found when register %s!", name)
    +    end
    +
    +    -- register handler
    +    filter:register(name, handler)
    +end
    +
    +-- return module
    +return sandbox_core_sandbox
    diff --git a/xmake/core/sandbox/modules/import/core/tool/archiver.lua b/xmake/core/sandbox/modules/import/core/tool/archiver.lua
    new file mode 100644
    index 00000000000..f851a928c3a
    --- /dev/null
    +++ b/xmake/core/sandbox/modules/import/core/tool/archiver.lua
    @@ -0,0 +1,50 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        archiver.lua
    +--
    +
    +-- define module
    +local sandbox_core_tool_archiver = sandbox_core_tool_archiver or {}
    +
    +-- load modules
    +local platform      = require("platform/platform")
    +local archiver      = require("tool/archiver")
    +local raise         = require("sandbox/modules/raise")
    +
    +-- archive file or directory
    +function sandbox_core_tool_archiver.archive(filedir, outputfile)
    + 
    +    -- get the archiver instance
    +    local instance, errors = archiver.load_from_file(outputfile)
    +    if not instance then
    +        raise(errors)
    +    end
    +
    +    -- archive it
    +    local ok, errors = instance:archive(filedir, outputfile)
    +    if not ok then
    +        raise(errors)
    +    end
    +end
    +
    +-- return module
    +return sandbox_core_tool_archiver
    diff --git a/xmake/core/sandbox/modules/import/core/tool/downloader.lua b/xmake/core/sandbox/modules/import/core/tool/downloader.lua
    index ba46f8ffb5c..130c340bd04 100644
    --- a/xmake/core/sandbox/modules/import/core/tool/downloader.lua
    +++ b/xmake/core/sandbox/modules/import/core/tool/downloader.lua
    @@ -35,9 +35,8 @@ local raise         = require("sandbox/modules/raise")
     -- .e.g
     -- 
     -- downloader.download(url, outputfile)
    --- downloader.download(url, outputfile, {verbose = true})
     --
    -function sandbox_core_tool_downloader.download(url, outputfile, args)
    +function sandbox_core_tool_downloader.download(url, outputfile)
      
         -- get the downloader instance
         local instance, errors = downloader.load()
    @@ -46,7 +45,7 @@ function sandbox_core_tool_downloader.download(url, outputfile, args)
         end
     
         -- download it
    -    local ok, errors = instance:download(url, outputfile, args)
    +    local ok, errors = instance:download(url, outputfile)
         if not ok then
             raise(errors)
         end
    diff --git a/xmake/core/sandbox/modules/import/core/tool/git.lua b/xmake/core/sandbox/modules/import/core/tool/git.lua
    index dd23c8c73f8..02a275d61d6 100644
    --- a/xmake/core/sandbox/modules/import/core/tool/git.lua
    +++ b/xmake/core/sandbox/modules/import/core/tool/git.lua
    @@ -35,7 +35,7 @@ local raise     = require("sandbox/modules/raise")
     -- .e.g
     -- 
     -- git.clone("git@github.com:tboox/xmake.git")
    --- git.clone("git@github.com:tboox/xmake.git", {verbose = true, depth = 1, branch = "master", outputdir = "/tmp/xmake"})
    +-- git.clone("git@github.com:tboox/xmake.git", {depth = 1, branch = "master", outputdir = "/tmp/xmake"})
     --
     function sandbox_core_tool_git.clone(url, args)
      
    @@ -57,7 +57,7 @@ end
     -- .e.g
     -- 
     -- git.pull()
    --- git.pull({verbose = true, remote = "origin", tags = true, branch = "master", repodir = "/tmp/xmake"})
    +-- git.pull({remote = "origin", tags = true, branch = "master", repodir = "/tmp/xmake"})
     --
     function sandbox_core_tool_git.pull(args)
     
    @@ -78,8 +78,8 @@ end
     --
     -- .e.g
     --
    --- git.checkout("master", {verbose = true, repodir = "/tmp/xmake"})
    --- git.checkout("v1.0.1", {verbose = true, repodir = "/tmp/xmake"})
    +-- git.checkout("master", {repodir = "/tmp/xmake"})
    +-- git.checkout("v1.0.1", {repodir = "/tmp/xmake"})
     --
     function sandbox_core_tool_git.checkout(commit, args)
     
    diff --git a/xmake/core/sandbox/modules/import/core/tool/ping.lua b/xmake/core/sandbox/modules/import/core/tool/ping.lua
    new file mode 100644
    index 00000000000..a01b1d48389
    --- /dev/null
    +++ b/xmake/core/sandbox/modules/import/core/tool/ping.lua
    @@ -0,0 +1,58 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        ping.lua
    +--
    +
    +-- define module
    +local sandbox_core_tool_ping = sandbox_core_tool_ping or {}
    +
    +-- load modules
    +local platform      = require("platform/platform")
    +local ping          = require("tool/ping")
    +local raise         = require("sandbox/modules/raise")
    +
    +-- send ping to hosts
    +--
    +-- .e.g
    +-- 
    +-- local results = ping.send("www.tboox.org", "www.xmake.io")
    +--
    +function sandbox_core_tool_ping.send(...)
    + 
    +    -- get the ping instance
    +    local instance, errors = ping.load()
    +    if not instance then
    +        raise(errors)
    +    end
    +
    +    -- send ping to hosts
    +    local results, errors = instance:send(...)
    +    if not results then
    +        raise(errors)
    +    end
    +
    +    -- ok
    +    return results
    +end
    +
    +-- return module
    +return sandbox_core_tool_ping
    diff --git a/xmake/core/sandbox/modules/import/core/tool/unarchiver.lua b/xmake/core/sandbox/modules/import/core/tool/unarchiver.lua
    new file mode 100644
    index 00000000000..4cdf8715f5e
    --- /dev/null
    +++ b/xmake/core/sandbox/modules/import/core/tool/unarchiver.lua
    @@ -0,0 +1,50 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        unarchiver.lua
    +--
    +
    +-- define module
    +local sandbox_core_tool_unarchiver = sandbox_core_tool_unarchiver or {}
    +
    +-- load modules
    +local platform      = require("platform/platform")
    +local unarchiver    = require("tool/unarchiver")
    +local raise         = require("sandbox/modules/raise")
    +
    +-- extract archived file
    +function sandbox_core_tool_unarchiver.extract(archivefile, outputdir)
    + 
    +    -- get the unarchiver instance
    +    local instance, errors = unarchiver.load_from_file(archivefile)
    +    if not instance then
    +        raise(errors)
    +    end
    +
    +    -- extract it
    +    local ok, errors = instance:extract(archivefile, outputdir)
    +    if not ok then
    +        raise(errors)
    +    end
    +end
    +
    +-- return module
    +return sandbox_core_tool_unarchiver
    diff --git a/xmake/core/sandbox/modules/interpreter/os.lua b/xmake/core/sandbox/modules/interpreter/os.lua
    index eebaed102ed..534832379fc 100644
    --- a/xmake/core/sandbox/modules/interpreter/os.lua
    +++ b/xmake/core/sandbox/modules/interpreter/os.lua
    @@ -35,23 +35,35 @@ sandbox_os.time     = os.time
     sandbox_os.mtime    = os.mtime
     sandbox_os.mclock   = os.mclock
     sandbox_os.getenv   = os.getenv
    -sandbox_os.dirs     = os.dirs
    -sandbox_os.host     = os.host
    -sandbox_os.arch     = os.arch
    +sandbox_os.isdir    = os.isdir
     sandbox_os.isfile   = os.isfile
     sandbox_os.exists   = os.exists
     sandbox_os.curdir   = os.curdir
     sandbox_os.tmpdir   = os.tmpdir
    -sandbox_os.uuid     = os.uuid
     
     -- match files
     function sandbox_os.files(pattern, ...)
    -    return os.match(string.format(pattern, ...))
    +    return os.files(string.format(pattern, ...))
     end
     
     -- match directories
     function sandbox_os.dirs(pattern, ...)
    -    return os.match(string.format(pattern, ...), true)
    +    return os.dirs(string.format(pattern, ...))
    +end
    +
    +-- match file and directories
    +function sandbox_os.filedirs(pattern, ...)
    +    return os.filedirs(string.format(pattern, ...))
    +end
    +
    +-- get the system host
    +function sandbox_os.host()
    +    return xmake._HOST
    +end
    +
    +-- get the system architecture
    +function sandbox_os.arch()
    +    return xmake._ARCH
     end
     
     -- return module
    diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua
    index b0c7741b985..f6788f45b5a 100644
    --- a/xmake/core/sandbox/modules/os.lua
    +++ b/xmake/core/sandbox/modules/os.lua
    @@ -40,6 +40,7 @@ sandbox_os.time     = os.time
     sandbox_os.argv     = os.argv
     sandbox_os.argw     = os.argw
     sandbox_os.mtime    = os.mtime
    +sandbox_os.sleep    = os.sleep
     sandbox_os.mclock   = os.mclock
     sandbox_os.emptydir = os.emptydir
     
    @@ -220,7 +221,7 @@ function sandbox_os.scriptdir()
         return rootdir
     end
     
    --- run shell
    +-- quietly run shell
     function sandbox_os.run(cmd, ...)
     
         -- make command
    @@ -233,7 +234,7 @@ function sandbox_os.run(cmd, ...)
         end
     end
     
    --- run shell with arguments list
    +-- quietly run shell with arguments list
     function sandbox_os.runv(shellname, argv)
     
         -- make shellname
    @@ -246,6 +247,30 @@ function sandbox_os.runv(shellname, argv)
         end
     end
     
    +-- quietly run shell and echo verbose info if [-v|--verbose] option is enabled
    +function sandbox_os.vrun(cmd, ...)
    +
    +    -- echo command
    +    if option.get("verbose") then
    +        print(vformat(cmd, ...))
    +    end
    +
    +    -- run it
    +    utils.ifelse(option.get("verbose"), sandbox_os.exec, sandbox_os.run)(cmd, ...)  
    +end
    +
    +-- quietly run shell with arguments list and echo verbose info if [-v|--verbose] option is enabled
    +function sandbox_os.vrunv(shellname, argv)
    +
    +    -- echo command
    +    if option.get("verbose") then
    +        print(vformat(shellname), table.concat(argv, " "))
    +    end
    +
    +    -- run it
    +    utils.ifelse(option.get("verbose"), sandbox_os.execv, sandbox_os.runv)(shellname, argv)  
    +end
    +
     -- run shell and return output and error data
     function sandbox_os.iorun(cmd, ...)
     
    @@ -397,22 +422,16 @@ end
     
     -- get the system host
     function sandbox_os.host()
    -
    -    -- get it
         return xmake._HOST
     end
     
     -- get the system architecture
     function sandbox_os.arch()
    -
    -    -- get it
         return xmake._ARCH
     end
     
     -- get the system null device
     function sandbox_os.nuldev()
    -
    -    -- get it
         return xmake._NULDEV
     end
     
    @@ -436,17 +455,6 @@ function sandbox_os.setenv(name, values)
         os.setenv(name, values)
     end
     
    --- make a new uuid
    -function sandbox_os.uuid(name)
    -
    -    -- make it
    -    local uuid = os.uuid(name)
    -    assert(uuid)
    -
    -    -- ok?
    -    return uuid
    -end
    -
     -- get the feature of os
     function sandbox_os.feature(name)
     
    diff --git a/xmake/core/sandbox/modules/process.lua b/xmake/core/sandbox/modules/process.lua
    index 619a3dfc653..1f47e5d1797 100644
    --- a/xmake/core/sandbox/modules/process.lua
    +++ b/xmake/core/sandbox/modules/process.lua
    @@ -23,6 +23,7 @@
     --
     
     -- load modules
    +local process   = require("base/process")
     local sandbox   = require("sandbox/sandbox")
     local raise     = require("sandbox/modules/raise")
     local vformat   = require("sandbox/modules/vformat")
    @@ -127,6 +128,26 @@ function sandbox_process.waitlist(processes, timeout)
         return infos
     end
     
    +-- async run task and echo waiting info
    +function sandbox_process.asyncrun(task, waitchars)
    +
    +    -- async run it
    +    local ok, errors = process.asyncrun(task, waitchars)
    +    if not ok then
    +        raise(errors)
    +    end
    +end
    +
    +-- run jobs with processes
    +function sandbox_process.runjobs(jobfunc, total, comax)
    +
    +    -- run them
    +    local ok, errors = process.runjobs(jobfunc, total, comax)
    +    if not ok then
    +        raise(errors)
    +    end
    +end
    +
     -- return module
     return sandbox_process
     
    diff --git a/xmake/core/sandbox/modules/utils.lua b/xmake/core/sandbox/modules/utils.lua
    index 94f21721076..3f0aed80caa 100644
    --- a/xmake/core/sandbox/modules/utils.lua
    +++ b/xmake/core/sandbox/modules/utils.lua
    @@ -42,6 +42,23 @@ for k, v in pairs(utils) do
         end
     end
     
    +-- print each arguments
    +function sandbox_utils._print(...)
    +
    +    -- format each arguments
    +    local args = {}
    +    for _, arg in ipairs({...}) do
    +        if type(arg) == "string" then
    +            table.insert(args, vformat(arg))
    +        else
    +            table.insert(args, arg)
    +        end
    +    end
    +
    +    -- print multi-variables with raw lua action
    +    utils._print(unpack(args))
    +end
    +
     -- print format string with newline
     -- print builtin-variables with $(var)
     -- print multi-variables with raw lua action
    @@ -56,20 +73,20 @@ function sandbox_utils.print(format, ...)
             {
                 function ()
                     -- attempt to print format string first
    -                utils._iowrite(vformat(format, unpack(args)) .. "\n")
    +                utils._print(vformat(format, unpack(args)))
                 end,
                 catch 
                 {
                     function ()
                         -- print multi-variables with raw lua action
    -                    utils._print(format, unpack(args))
    +                    sandbox_utils._print(format, unpack(args))
                     end
                 }
             }
     
         else
             -- print multi-variables with raw lua action
    -        utils._print(format, ...)
    +        sandbox_utils._print(format, ...)
         end
     end
     
    @@ -84,7 +101,7 @@ end
     function sandbox_utils.cprint(format, ...)
     
         -- done
    -    utils._iowrite(colors(vformat(format, ...) .. "\n"))
    +    utils._print(colors(vformat(format, ...)))
     end
     
     -- print format string, the builtin variables and colors without newline
    @@ -124,7 +141,6 @@ function sandbox_utils.assert(value, format, ...)
         return value
     end
     
    -
     -- return module
     return sandbox_utils
     
    diff --git a/xmake/core/sandbox/sandbox.lua b/xmake/core/sandbox/sandbox.lua
    index fe5648cbd27..c84f6fbf82a 100644
    --- a/xmake/core/sandbox/sandbox.lua
    +++ b/xmake/core/sandbox/sandbox.lua
    @@ -165,7 +165,7 @@ function sandbox.new(script, filter, rootdir)
         assert(self and self._PUBLIC and self._PRIVATE)
     
         -- save filter
    -    self._PRIVATE._FILTER = filter
    +    self._PRIVATE._FILTER = filter or require("base/filter"):new()
     
         -- save root directory
         self._PRIVATE._ROOTDIR = rootdir
    @@ -195,11 +195,6 @@ end
     -- fork a new sandbox from the given sandbox
     function sandbox:fork(script, rootdir)
     
    -    -- no script?
    -    if script == nil then
    -        return nil, "no script!"
    -    end
    -
         -- invalid script?
         if script ~= nil and type(script) ~= "function" then
             return nil, "invalid script!"
    @@ -212,16 +207,16 @@ function sandbox:fork(script, rootdir)
         assert(instance and instance._PUBLIC and instance._PRIVATE)
     
         -- inherit the filter
    -    instance._PRIVATE._FILTER = self:filter()
    +    instance._PRIVATE._FILTER = self:filter() or require("base/filter"):new()
     
         -- inherit the root directory
         instance._PRIVATE._ROOTDIR = rootdir or self:rootdir()
     
         -- bind public scope
    -    setfenv(script, instance._PUBLIC)
    -
    -    -- save script
    -    instance._PRIVATE._SCRIPT = script
    +    if script then
    +        setfenv(script, instance._PUBLIC)
    +        instance._PRIVATE._SCRIPT = script
    +    end
     
         -- ok?
         return instance
    @@ -293,7 +288,7 @@ function sandbox:rootdir()
     end
     
     -- get current instance in the sandbox modules
    -function sandbox.instance()
    +function sandbox.instance(script)
     
         -- find self instance for the current sandbox
         local instance = nil
    @@ -301,7 +296,7 @@ function sandbox.instance()
         while level < 16 do
     
             -- get scope
    -        local scope = getfenv(level)
    +        local scope = getfenv(utils.ifelse(script, script, level))
             if scope then
     
                 -- enable to read _SANDBOX
    diff --git a/xmake/core/tool/archiver.lua b/xmake/core/tool/archiver.lua
    new file mode 100644
    index 00000000000..6a6e6a2208f
    --- /dev/null
    +++ b/xmake/core/tool/archiver.lua
    @@ -0,0 +1,105 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        archiver.lua
    +--
    +
    +-- define module
    +local archiver = archiver or {}
    +
    +-- load modules
    +local io        = require("base/io")
    +local path      = require("base/path")
    +local utils     = require("base/utils")
    +local table     = require("base/table")
    +local string    = require("base/string")
    +local sandbox   = require("sandbox/sandbox")
    +local platform  = require("platform/platform")
    +local tool      = require("tool/tool")
    +local archiver  = require("tool/archiver")
    +
    +-- get the current tool
    +function archiver:_tool()
    +
    +    -- get it
    +    return self._TOOL
    +end
    +
    +-- load the archiver for the archive file kind
    +function archiver.load(kind)
    +
    +    -- get it directly from cache dirst
    +    if archiver._INSTANCE then
    +        return archiver._INSTANCE
    +    end
    +
    +    -- new instance
    +    local instance = table.inherit(archiver)
    +
    +    -- init tool kinds
    +    local toolkinds =
    +    {
    +        gzip        = {"tar", "gzip"}
    +    ,   zip         = {"tar", "zip"}
    +    ,   bzip2       = {"tar"}
    +    ,   ["7zip"]    = {"7z"}
    +    ,   rar         = {}
    +    ,   tar         = {"tar"}
    +    ,   xz          = {"tar"}
    +    ,   lzma        = {"tar"}
    +    }
    +
    +    -- attempt to load the archiver tool 
    +    local result = nil
    +    for _, toolkind in ipairs(toolkinds[kind] or {}) do
    +        result = tool.load(toolkind)
    +        if result then 
    +            break
    +        end
    +    end
    +    if not result then
    +        return nil, string.format("cannot load archiver for %s file!", kind)
    +    end
    +        
    +    -- save tool
    +    instance._TOOL = result
    +
    +    -- save this instance
    +    archiver._INSTANCE = instance
    +
    +    -- ok
    +    return instance
    +end
    +
    +-- load the archiver for the archive file kind
    +function archiver.load_from_file(file)
    +    return archiver.load(unarchiver.kind_of_file(file))
    +end
    +
    +-- archive the given file or directory
    +function archiver:archive(filedir, outputfile)
    +
    +    -- archive it
    +    return sandbox.load(self:_tool().archive, path.translate(filedir), path.translate(outputfile))
    +end
    +
    +-- return module
    +return archiver
    diff --git a/xmake/core/tool/downloader.lua b/xmake/core/tool/downloader.lua
    index 5044414eab7..9e8bacd145b 100644
    --- a/xmake/core/tool/downloader.lua
    +++ b/xmake/core/tool/downloader.lua
    @@ -65,24 +65,16 @@ function downloader.load()
         return instance
     end
     
    --- get properties of the tool
    -function downloader:get(name)
    -
    -    -- get it
    -    return self:_tool().get(name)
    -end
    -
     -- download url
     --
     -- .e.g
     --
     -- downloader.load():download(url, outputfile)
    --- downloader.load():download(url, outputfile, {verbose = true})
     --
    -function downloader:download(url, outputfile, args)
    +function downloader:download(url, outputfile)
     
         -- download it
    -    return sandbox.load(self:_tool().download, url, outputfile, args)
    +    return sandbox.load(self:_tool().download, url, path.translate(outputfile))
     end
     
     -- return module
    diff --git a/xmake/core/tool/git.lua b/xmake/core/tool/git.lua
    index 845427cbf34..6b57c09d2e3 100644
    --- a/xmake/core/tool/git.lua
    +++ b/xmake/core/tool/git.lua
    @@ -73,19 +73,12 @@ function git.load()
         return instance
     end
     
    --- get properties of the tool
    -function git:get(name)
    -
    -    -- get it
    -    return self:_tool().get(name)
    -end
    -
     -- clone url
     --
     -- .e.g
     -- 
     -- git.load():clone("git@github.com:tboox/xmake.git")
    --- git.load():clone("git@github.com:tboox/xmake.git", {verbose = true, depth = 1, branch = "master", outputdir = "/tmp/xmake"})
    +-- git.load():clone("git@github.com:tboox/xmake.git", {depth = 1, branch = "master", outputdir = "/tmp/xmake"})
     --
     function git:clone(url, args)
     
    @@ -98,7 +91,7 @@ end
     -- .e.g
     -- 
     -- git.load():pull()
    --- git.load():pull({verbose = true, remote = "origin", tags = true, branch = "master", repodir = "/tmp/xmake"})
    +-- git.load():pull({remote = "origin", tags = true, branch = "master", repodir = "/tmp/xmake"})
     --
     function git:pull(args)
     
    @@ -160,8 +153,8 @@ end
     --
     -- .e.g
     --
    --- git.load():checkout("master", {verbose = true, repodir = "/tmp/xmake"})
    --- git.load():checkout("v1.0.1", {verbose = true, repodir = "/tmp/xmake"})
    +-- git.load():checkout("master", {repodir = "/tmp/xmake"})
    +-- git.load():checkout("v1.0.1", {repodir = "/tmp/xmake"})
     --
     function git:checkout(commit, args)
     
    diff --git a/xmake/core/tool/ping.lua b/xmake/core/tool/ping.lua
    new file mode 100644
    index 00000000000..2e5e129d77e
    --- /dev/null
    +++ b/xmake/core/tool/ping.lua
    @@ -0,0 +1,104 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        ping.lua
    +--
    +
    +-- define module
    +local ping = ping or {}
    +
    +-- load modules
    +local io        = require("base/io")
    +local path      = require("base/path")
    +local utils     = require("base/utils")
    +local table     = require("base/table")
    +local string    = require("base/string")
    +local process   = require("base/process")
    +local sandbox   = require("sandbox/sandbox")
    +local platform  = require("platform/platform")
    +local tool      = require("tool/tool")
    +
    +-- get the current tool
    +function ping:_tool()
    +
    +    -- get it
    +    return self._TOOL
    +end
    +
    +-- load the ping for the archive file kind
    +function ping.load(kind)
    +
    +    -- get it directly from cache dirst
    +    if ping._INSTANCE then
    +        return ping._INSTANCE
    +    end
    +
    +    -- new instance
    +    local instance = table.inherit(ping)
    +
    +    -- load the ping tool 
    +    local result, errors = tool.load("ping")
    +    if not result then 
    +        return nil, errors
    +    end 
    +
    +    -- save tool
    +    instance._TOOL = result
    +
    +    -- save this instance
    +    ping._INSTANCE = instance
    +
    +    -- ok
    +    return instance
    +end
    +
    +-- send ping to hosts
    +--
    +-- .e.g
    +-- 
    +-- local results = ping.load():send("www.tboox.org", "www.xmake.io")
    +--
    +function ping:send(...)
    +
    +    -- run tasks
    +    local hosts = {...}
    +    local results = {}
    +    local ok, errors = process.runjobs(function (index)
    +        local host = hosts[index]
    +        if host then
    +            local ok, time_or_errors = sandbox.load(self:_tool().send, host)
    +            if ok then
    +                results[host] = time_or_errors
    +            end
    +        end
    +    end, #hosts)
    +
    +    -- failed?
    +    if not ok then
    +        return nil, errors
    +    end
    +
    +    -- ok
    +    return results
    +end
    +
    +-- return module
    +return ping
    diff --git a/xmake/core/tool/unarchiver.lua b/xmake/core/tool/unarchiver.lua
    new file mode 100644
    index 00000000000..57751b7fe08
    --- /dev/null
    +++ b/xmake/core/tool/unarchiver.lua
    @@ -0,0 +1,127 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        unarchiver.lua
    +--
    +
    +-- define module
    +local unarchiver = unarchiver or {}
    +
    +-- load modules
    +local io        = require("base/io")
    +local path      = require("base/path")
    +local utils     = require("base/utils")
    +local table     = require("base/table")
    +local string    = require("base/string")
    +local sandbox   = require("sandbox/sandbox")
    +local platform  = require("platform/platform")
    +local tool      = require("tool/tool")
    +
    +-- get the current tool
    +function unarchiver:_tool()
    +
    +    -- get it
    +    return self._TOOL
    +end
    +
    +-- load the unarchiver for the archive file kind
    +function unarchiver.load(kind)
    +
    +    -- get it directly from cache dirst
    +    if unarchiver._INSTANCE then
    +        return unarchiver._INSTANCE
    +    end
    +
    +    -- new instance
    +    local instance = table.inherit(unarchiver)
    +
    +    -- init tool kinds
    +    local toolkinds =
    +    {
    +        gzip        = {"tar", "gzip"}
    +    ,   zip         = {"tar", "unzip"}
    +    ,   bzip2       = {"tar"}
    +    ,   ["7zip"]    = {"7z"}
    +    ,   rar         = {}
    +    ,   tar         = {"tar"}
    +    ,   xz          = {"tar"}
    +    ,   lzma        = {"tar"}
    +    }
    +
    +    -- attempt to load the unarchiver tool 
    +    local result = nil
    +    for _, toolkind in ipairs(toolkinds[kind] or {}) do
    +        result = tool.load(toolkind)
    +        if result then 
    +            break
    +        end
    +    end
    +    if not result then
    +        return nil, string.format("cannot load unarchiver for %s file!", kind)
    +    end
    +        
    +    -- save tool
    +    instance._TOOL = result
    +
    +    -- save this instance
    +    unarchiver._INSTANCE = instance
    +
    +    -- ok
    +    return instance
    +end
    +
    +-- load the unarchiver for the archive file kind
    +function unarchiver.load_from_file(file)
    +    return unarchiver.load(unarchiver.kind_of_file(file))
    +end
    +
    +-- get archive kind of file
    +function unarchiver.kind_of_file(file)
    +
    +    -- get extension
    +    local extension = path.extension(file)
    +
    +    -- init kinds
    +    local kinds = 
    +    {
    +        [".gz"]   = "gzip"
    +    ,   [".zip"]  = "zip"
    +    ,   [".bz2"]  = "bzip2"
    +    ,   [".7z"]   = "7zip"
    +    ,   [".rar"]  = "rar"
    +    ,   [".tar"]  = "tar"
    +    ,   [".xz"]   = "xz"
    +    ,   [".lzma"] = "lzma"
    +    }
    +
    +    -- get it
    +    return kinds[extension]
    +end
    +
    +-- extract the archived file
    +function unarchiver:extract(archivefile, outputdir)
    +
    +    -- extract it
    +    return sandbox.load(self:_tool().extract, path.translate(archivefile), path.translate(outputdir))
    +end
    +
    +-- return module
    +return unarchiver
    diff --git a/xmake/platforms/android/check.lua b/xmake/platforms/android/check.lua
    index 5300e35f8ff..e2972bb198a 100644
    --- a/xmake/platforms/android/check.lua
    +++ b/xmake/platforms/android/check.lua
    @@ -167,11 +167,21 @@ function _toolchains(config)
         checker.toolchain_insert(toolchains, "rc-sh",    "",      "rustc",       "the rust shared library linker") 
         checker.toolchain_insert(toolchains, "rc-ld",    "",      "rustc",       "the rust linker") 
     
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",         "",   "tar",         "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",        "",   "gzip",        "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",          "",   "7z",          "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",         "",   "zip",         "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",       "",   "unzip",       "the zip file unarchiver") 
    +
         -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",   "make",        "the make utility") 
    +    checker.toolchain_insert(toolchains, "make",        "",   "nmake",       "the make utility") 
         checker.toolchain_insert(toolchains, "ccache",      "",   "ccache",      "the compiler cache") 
         checker.toolchain_insert(toolchains, "git",         "",   "git",         "the version control utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",   "curl",        "the url download utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",   "wget",        "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",   "ping",        "the ping utility") 
     
         -- save toolchains
         _g.TOOLCHAINS = toolchains
    diff --git a/xmake/platforms/android/load.lua b/xmake/platforms/android/load.lua
    index e80ff5c89cc..a9b00b554c8 100644
    --- a/xmake/platforms/android/load.lua
    +++ b/xmake/platforms/android/load.lua
    @@ -51,8 +51,8 @@ function main()
             _g.cxxflags     = {}
         end
     
    -    -- init cxflags and ldflags for the target kind: binary 
    -    _g.binary           = { cxflags = {"-fPIE", "-pie"}, ldflags = {"-fPIE", "-pie"} }
    +    -- init cxflags for the target kind: binary 
    +    _g.binary           = { cxflags = {"-fPIE", "-pie"} }
     
         -- add flags for the sdk directory of ndk
         local ndk = config.get("ndk")
    @@ -75,6 +75,10 @@ function main()
                 insert(_g.shflags, format("--sysroot=%s/arch-arm", ndk_sdkdir))
             end
     
    +        -- add "-fPIE -pie" to ldflags
    +        insert(_g.ldflags, "-fPIE")
    +        insert(_g.ldflags, "-pie")
    +
             -- only for c++ stl
             local toolchains_ver = config.get("toolchains_ver")
             if toolchains_ver then
    diff --git a/xmake/platforms/checker.lua b/xmake/platforms/checker.lua
    index 63b629b8fde..c22c74b4b84 100644
    --- a/xmake/platforms/checker.lua
    +++ b/xmake/platforms/checker.lua
    @@ -192,9 +192,9 @@ function check_xcode(config)
             else
                 -- failed
                 cprint("checking for the Xcode application directory ... ${red}no")
    -            cprint("${bright red}please run:")
    -            cprint("${red}    - xmake config --xcode_dir=xxx")
    -            cprint("${red}or  - xmake global --xcode_dir=xxx")
    +            cprint("${bright}please run:")
    +            cprint("    - xmake config --xcode_dir=xxx")
    +            cprint("or  - xmake global --xcode_dir=xxx")
                 raise()
             end
         end
    @@ -240,9 +240,9 @@ function check_xcode_sdkver(config)
             else
                 -- failed
                 cprint("checking for the Xcode SDK version for %s ... ${red}no", plat)
    -            cprint("${bright red}please run:")
    -            cprint("${red}    - xmake config --xcode_sdkver=xxx")
    -            cprint("${red}or  - xmake global --xcode_sdkver=xxx")
    +            cprint("${bright}please run:")
    +            cprint("    - xmake config --xcode_sdkver=xxx")
    +            cprint("or  - xmake global --xcode_sdkver=xxx")
                 raise()
             end
         end
    diff --git a/xmake/platforms/installer.lua b/xmake/platforms/installer.lua
    index 0cc388edb64..12aa9132cb9 100644
    --- a/xmake/platforms/installer.lua
    +++ b/xmake/platforms/installer.lua
    @@ -29,6 +29,11 @@ import("core.platform.platform")
     -- install binary
     function install_binary_on_unix(target)
     
    +    -- check kind
    +    if not target:targetkind() then
    +        return 
    +    end
    +
         -- the install directory
         local installdir = option.get("installdir") or platform.get("installdir")
         assert(installdir, "unknown install directory!")
    @@ -46,6 +51,11 @@ end
     -- install library
     function install_library_on_unix(target)
     
    +    -- check kind
    +    if not target:targetkind() then
    +        return 
    +    end
    +
         -- the install directory
         local installdir = option.get("installdir") or platform.get("installdir")
         assert(installdir, "unknown install directory!")
    @@ -88,6 +98,11 @@ end
     -- uninstall binary
     function uninstall_binary_on_unix(target)
     
    +    -- check kind
    +    if not target:targetkind() then
    +        return 
    +    end
    +
         -- the install directory
         local installdir = option.get("installdir") or platform.get("installdir")
         assert(installdir, "unknown install directory!")
    @@ -102,6 +117,11 @@ end
     -- uninstall library
     function uninstall_library_on_unix(target)
     
    +    -- check kind
    +    if not target:targetkind() then
    +        return 
    +    end
    +
         -- the install directory
         local installdir = option.get("installdir") or platform.get("installdir")
         assert(installdir, "unknown install directory!")
    diff --git a/xmake/platforms/iphoneos/check.lua b/xmake/platforms/iphoneos/check.lua
    index dd8f0d11dc7..ca8b91db54e 100644
    --- a/xmake/platforms/iphoneos/check.lua
    +++ b/xmake/platforms/iphoneos/check.lua
    @@ -30,7 +30,7 @@ import("platforms.checker", {rootdir = os.programdir()})
     function _check_as(shellname)
     
         -- make an empty tmp.S
    -    local tmpfile = path.join(os.tmpdir(), "xmake.checker.as.S")
    +    local tmpfile = os.tmpfile() .. ".S"
         io.writefile(tmpfile, "")
     
         -- check it
    @@ -86,12 +86,21 @@ function _toolchains(config)
             checker.toolchain_insert(toolchains, "as",      path.join(os.toolsdir(), "utils/gas-preprocessor.pl " .. cross), "clang", "the assember", _check_as)
         end
     
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",         "",   "tar",            "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",        "",   "gzip",           "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",          "",   "7z",             "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",         "",   "zip",            "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",       "",   "unzip",          "the zip file unarchiver") 
    +
         -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",     "make",         "the make utility") 
         checker.toolchain_insert(toolchains, "debugger",    cross,  "lldb",         "the debugger") 
         checker.toolchain_insert(toolchains, "ccache",      "",     "ccache",       "the compiler cache") 
         checker.toolchain_insert(toolchains, "git",         "",     "git",          "the git version control utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",     "curl",         "the url download utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",     "wget",         "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",     "ping",         "the ping utility") 
     
         -- save toolchains
         _g.TOOLCHAINS = toolchains
    diff --git a/xmake/platforms/linux/check.lua b/xmake/platforms/linux/check.lua
    index 0d376959c27..3cec2fcde37 100644
    --- a/xmake/platforms/linux/check.lua
    +++ b/xmake/platforms/linux/check.lua
    @@ -131,13 +131,22 @@ function _toolchains(config)
         checker.toolchain_insert(toolchains, "rc-sh",    "",      "rustc",       "the rust shared library linker") 
         checker.toolchain_insert(toolchains, "rc-ld",    "",      "rustc",       "the rust linker") 
     
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",      "",      "tar",          "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",     "",      "gzip",         "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",       "",      "7z",           "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",      "",      "zip",          "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",    "",      "unzip",        "the zip file unarchiver") 
    +
         -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",      "make",        "the make utility") 
         checker.toolchain_insert(toolchains, "debugger",    cross,   "gdb",         "the debugger") 
         checker.toolchain_insert(toolchains, "debugger",    cross,   "lldb",        "the debugger") 
         checker.toolchain_insert(toolchains, "ccache",      "",      "ccache",      "the compiler cache") 
         checker.toolchain_insert(toolchains, "git",         "",      "git",         "the git version control utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",      "curl",        "the url download utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",      "wget",        "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",      "ping",        "the ping utility") 
     
         -- save toolchains
         _g.TOOLCHAINS = toolchains
    diff --git a/xmake/platforms/macosx/check.lua b/xmake/platforms/macosx/check.lua
    index 63c88d79c39..7ebb9352f7c 100644
    --- a/xmake/platforms/macosx/check.lua
    +++ b/xmake/platforms/macosx/check.lua
    @@ -89,12 +89,21 @@ function _toolchains(config)
         checker.toolchain_insert(toolchains, "rc-sh",       "",                     "rustc",        "the rust shared library linker") 
         checker.toolchain_insert(toolchains, "rc-ld",       "",                     "rustc",        "the rust linker") 
     
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",         "",                     "tar",          "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",        "",                     "gzip",         "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",          "",                     "7z",           "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",         "",                     "zip",          "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",       "",                     "unzip",        "the zip file unarchiver") 
    +
         -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",                     "make",         "the make utility") 
         checker.toolchain_insert(toolchains, "debugger",    "xcrun -sdk macosx ",   "lldb",         "the debugger") 
         checker.toolchain_insert(toolchains, "ccache",      "",                     "ccache",       "the compiler cache") 
         checker.toolchain_insert(toolchains, "git",         "",                     "git",          "the git version control utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",                     "curl",         "the url download utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",                     "wget",         "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",                     "ping",         "the ping utility") 
     
         -- save toolchains
         _g.TOOLCHAINS = toolchains
    diff --git a/xmake/platforms/mingw/check.lua b/xmake/platforms/mingw/check.lua
    index ddb6dff1d04..81cea784e9f 100644
    --- a/xmake/platforms/mingw/check.lua
    +++ b/xmake/platforms/mingw/check.lua
    @@ -68,11 +68,21 @@ function _toolchains(config)
         checker.toolchain_insert(toolchains, "sh",      cross, "g++",       "the shared library linker") 
         checker.toolchain_insert(toolchains, "sh",      cross, "gcc",       "the shared library linker") 
     
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",         "",    "tar",       "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",        "",    "gzip",      "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",          "",    "7z",        "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",         "",    "zip",       "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",       "",    "unzip",     "the zip file unarchiver") 
    +
         -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",    "make",      "the make utility") 
    +    checker.toolchain_insert(toolchains, "make",        "",    "nmake",     "the make utility") 
         checker.toolchain_insert(toolchains, "ccache",      "",    "ccache",    "the compiler cache") 
         checker.toolchain_insert(toolchains, "git",         "",    "git",       "the git version control utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",    "curl",      "the url download utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",    "wget",      "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",    "ping",      "the ping utility") 
     
         -- save toolchains
         _g.TOOLCHAINS = toolchains
    diff --git a/xmake/platforms/watchos/check.lua b/xmake/platforms/watchos/check.lua
    index 2beb0b09f81..8cc27921365 100644
    --- a/xmake/platforms/watchos/check.lua
    +++ b/xmake/platforms/watchos/check.lua
    @@ -30,7 +30,7 @@ import("platforms.checker", {rootdir = os.programdir()})
     function _check_as(shellname)
     
         -- make an empty tmp.S
    -    local tmpfile = path.join(os.tmpdir(), "xmake.checker.as.S")
    +    local tmpfile = os.tmpfile() .. ".S"
         io.writefile(tmpfile, "")
     
         -- check it
    @@ -86,12 +86,21 @@ function _toolchains(config)
             checker.toolchain_insert(toolchains, "as",      path.join(os.toolsdir(), "utils/gas-preprocessor.pl " .. cross), "clang", "the assember", _check_as)
         end
     
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",         "",     "tar",          "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",        "",     "gzip",         "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",          "",     "7z",           "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",         "",     "zip",          "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",       "",     "unzip",        "the zip file unarchiver") 
    +
         -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",     "make",         "the make utility") 
         checker.toolchain_insert(toolchains, "debugger",    cross,  "lldb",         "the debugger") 
         checker.toolchain_insert(toolchains, "ccache",      "",     "ccache",       "the compiler cache") 
         checker.toolchain_insert(toolchains, "git",         "",     "git",          "the git version control utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",     "curl",         "the url download utility") 
         checker.toolchain_insert(toolchains, "downloader",  "",     "wget",         "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",     "ping",         "the ping utility") 
     
         -- save toolchains
         _g.TOOLCHAINS = toolchains
    diff --git a/xmake/platforms/windows/check.lua b/xmake/platforms/windows/check.lua
    index c7ec16584c5..396740dc8ce 100644
    --- a/xmake/platforms/windows/check.lua
    +++ b/xmake/platforms/windows/check.lua
    @@ -90,8 +90,8 @@ function _apply_vsenv(config, vs)
         end
     
         -- make the genvcvars.bat 
    -    local genvcvars_bat = path.join(os.tmpdir(), "xmake.genvcvars.bat")
    -    local genvcvars_dat = path.join(os.tmpdir(), "xmake.genvcvars.dat")
    +    local genvcvars_bat = os.tmpfile() .. "_genvcvars.bat"
    +    local genvcvars_dat = os.tmpfile() .. "_genvcvars.dat"
         local file = io.open(genvcvars_bat, "w")
         file:print("@echo off")
         file:print("call \"%s\" %s > nul", vcvarsall, config.get("arch"))
    @@ -305,12 +305,28 @@ function _toolchains(config)
         checker.toolchain_insert(toolchains, "rc-ld",    "",    "rustc",            "the rust linker") 
     
         -- insert asm tools to toolchains
    -    if config.get("arch"):find("64") then
    +    local arch = config.get("arch")
    +    if arch and arch:find("64") then
             checker.toolchain_insert(toolchains, "as",   "",    "ml64.exe",         "the assember") 
         else
             checker.toolchain_insert(toolchains, "as",   "",    "ml.exe",           "the assember") 
         end
     
    +    -- TODO
    +    -- insert archiver and unarchiver tools to toolchains
    +    checker.toolchain_insert(toolchains, "tar",         "",   "tar",            "the common file [un]archiverr") 
    +    checker.toolchain_insert(toolchains, "gzip",        "",   "gzip",           "the gzip file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "7z",          "",   "7z",             "the 7z file [un]archiver") 
    +    checker.toolchain_insert(toolchains, "zip",         "",   "zip",            "the zip file archiver") 
    +    checker.toolchain_insert(toolchains, "unzip",       "",   "unzip",          "the zip file unarchiver") 
    +
    +    -- insert other tools to toolchains
    +    checker.toolchain_insert(toolchains, "make",        "",   "nmake",          "the make utility") 
    +    checker.toolchain_insert(toolchains, "git",         "",   "git",            "the version control utility") 
    +    checker.toolchain_insert(toolchains, "downloader",  "",   "curl",           "the url download utility") 
    +    checker.toolchain_insert(toolchains, "downloader",  "",   "wget",           "the url download utility") 
    +    checker.toolchain_insert(toolchains, "ping",        "",   "ping",           "the ping utility") 
    +
         -- save toolchains
         _g.TOOLCHAINS = toolchains
     
    @@ -328,18 +344,20 @@ function main(kind, toolkind)
             local config = import("core.project." .. kind)
     
             -- apply vs envirnoment (maybe config.arch has been updated)
    -        if not _apply_vsenv(config, config.get("vs")) then
    -            return 
    -        end
    +        local vsenv = _apply_vsenv(config, config.get("vs"))
     
             -- enter environment
    -        environment.enter("toolchains")
    +        if vsenv then
    +            environment.enter("toolchains")
    +        end
     
             -- check it
             checker.toolchain_check(config, toolkind, _toolchains)
     
             -- leave environment
    -        environment.leave("toolchains")
    +        if vsenv then
    +            environment.leave("toolchains")
    +        end
     
             -- end
             return 
    diff --git a/xmake/plugins/lua/xmake.lua b/xmake/plugins/lua/xmake.lua
    index 917d66119c8..1c6b2bf270b 100644
    --- a/xmake/plugins/lua/xmake.lua
    +++ b/xmake/plugins/lua/xmake.lua
    @@ -33,6 +33,7 @@ task("lua")
                
             -- imports
             import("core.base.option")
    +        import("core.sandbox.sandbox")
     
             -- list all scripts?
             if option.get("list") then
    @@ -46,15 +47,17 @@ task("lua")
     
             -- get script name
             local name = option.get("script")
    -        if not name then
    -            raise("no script!")
    -        end
    +        if name then
     
    -        -- import script
    -        if os.isfile(name) then
    -            import(path.basename(name), {rootdir = path.directory(name)}).main(unpack(option.get("arguments") or {}))
    +            -- import and run script
    +            if os.isfile(name) then
    +                import(path.basename(name), {rootdir = path.directory(name)}).main(unpack(option.get("arguments") or {}))
    +            else
    +                import("scripts." .. name).main(unpack(option.get("arguments") or {}))
    +            end
             else
    -            import("scripts." .. name).main(unpack(option.get("arguments") or {}))
    +            -- enter interactive mode
    +            sandbox.interactive()
             end
         end)
     
    diff --git a/xmake/plugins/project/vstudio/impl/vs200x_solution.lua b/xmake/plugins/project/vstudio/impl/vs200x_solution.lua
    index 85de807cc6b..4be10b026da 100644
    --- a/xmake/plugins/project/vstudio/impl/vs200x_solution.lua
    +++ b/xmake/plugins/project/vstudio/impl/vs200x_solution.lua
    @@ -42,12 +42,12 @@ function _make_projects(slnfile, vsinfo)
         for targetname, target in pairs(project.targets()) do
     
             -- enter project
    -        slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, os.uuid(targetname))
    +        slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid(targetname))
     
             -- add dependences
             for _, dep in ipairs(target:get("deps")) do
                 slnfile:enter("ProjectSection(ProjectDependencies) = postProject")
    -            slnfile:print("{%s} = {%s}", os.uuid(dep), os.uuid(dep))
    +            slnfile:print("{%s} = {%s}", hash.uuid(dep), hash.uuid(dep))
                 slnfile:leave("EndProjectSection")
             end
     
    @@ -70,8 +70,8 @@ function _make_global(slnfile, vsinfo)
         -- add project configuration platforms
         slnfile:enter("GlobalSection(ProjectConfigurationPlatforms) = postSolution")
         for targetname, _ in pairs(project.targets()) do
    -        slnfile:print("{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32", os.uuid(targetname))
    -        slnfile:print("{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32", os.uuid(targetname))
    +        slnfile:print("{%s}.$(mode)|Win32.ActiveCfg = $(mode)|Win32", hash.uuid(targetname))
    +        slnfile:print("{%s}.$(mode)|Win32.Build.0 = $(mode)|Win32", hash.uuid(targetname))
         end
         slnfile:leave("EndGlobalSection")
     
    diff --git a/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua b/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua
    index 094b7a1666f..19e70851492 100644
    --- a/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua
    +++ b/xmake/plugins/project/vstudio/impl/vs200x_vcproj.lua
    @@ -133,7 +133,7 @@ function _make_header(vcprojfile, vsinfo, target)
             vcprojfile:print("ProjectType=\"Visual C++\"")
             vcprojfile:print("Version=\"%s0\"", assert(versions["vs" .. vsinfo.vstudio_version]))
             vcprojfile:print("Name=\"%s\"", targetname)
    -        vcprojfile:print("ProjectGUID=\"{%s}\"", os.uuid(targetname))
    +        vcprojfile:print("ProjectGUID=\"{%s}\"", hash.uuid(targetname))
             vcprojfile:print("RootNamespace=\"%s\"", targetname)
             vcprojfile:print("TargetFrameworkVersion=\"196613\"")
             vcprojfile:print(">")
    diff --git a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua
    index a3182d9fdbb..f95ac72c930 100644
    --- a/xmake/plugins/project/vstudio/impl/vs201x_solution.lua
    +++ b/xmake/plugins/project/vstudio/impl/vs201x_solution.lua
    @@ -42,12 +42,12 @@ function _make_projects(slnfile, vsinfo)
         for targetname, target in pairs(project.targets()) do
     
             -- enter project
    -        slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, os.uuid(targetname))
    +        slnfile:enter("Project(\"{%s}\") = \"%s\", \"%s\\%s.vcxproj\", \"{%s}\"", vctool, targetname, targetname, targetname, hash.uuid(targetname))
     
             -- add dependences
             for _, dep in ipairs(target:get("deps")) do
                 slnfile:enter("ProjectSection(ProjectDependencies) = postProject")
    -            slnfile:print("{%s} = {%s}", os.uuid(dep), os.uuid(dep))
    +            slnfile:print("{%s} = {%s}", hash.uuid(dep), hash.uuid(dep))
                 slnfile:leave("EndProjectSection")
             end
     
    @@ -76,8 +76,8 @@ function _make_global(slnfile, vsinfo)
         for targetname, _ in pairs(project.targets()) do
             for _, mode in ipairs(vsinfo.modes) do
                 for _, arch in ipairs({"x86", "x64"}) do
    -                slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", os.uuid(targetname), mode, arch, mode, arch)
    -                slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", os.uuid(targetname), mode, arch, mode, arch)
    +                slnfile:print("{%s}.%s|%s.ActiveCfg = %s|%s", hash.uuid(targetname), mode, arch, mode, arch)
    +                slnfile:print("{%s}.%s|%s.Build.0 = %s|%s", hash.uuid(targetname), mode, arch, mode, arch)
                 end
             end
         end
    diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
    index 320c4813c11..6bea83d7adf 100644
    --- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
    +++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj.lua
    @@ -161,7 +161,7 @@ function _make_configurations(vcxprojfile, vsinfo, target, vcxprojdir)
     
         -- make Globals
         vcxprojfile:enter("")
    -        vcxprojfile:print("{%s}", os.uuid(targetname))
    +        vcxprojfile:print("{%s}", hash.uuid(targetname))
             vcxprojfile:print("%s", targetname)
             if vsinfo.vstudio_version >= "2015" then
                 vcxprojfile:print("%s", sdk_versions["vs" .. vsinfo.vstudio_version])
    diff --git a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
    index c101373032d..c402c2f5118 100644
    --- a/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
    +++ b/xmake/plugins/project/vstudio/impl/vs201x_vcxproj_filters.lua
    @@ -75,7 +75,7 @@ function _make_filters(filtersfile, vsinfo, target, vcxprojdir)
                 while filter and filter ~= '.' do
                     if not exists[filter] then
                         filtersfile:enter("", filter)
    -                    filtersfile:print("{%s}", os.uuid(filter))
    +                    filtersfile:print("{%s}", hash.uuid(filter))
                         filtersfile:leave("")
                         exists[filter] = true
                     end
    diff --git a/xmake/plugins/repo/main.lua b/xmake/plugins/repo/main.lua
    index 50ecd0dd0c7..73f57941209 100644
    --- a/xmake/plugins/repo/main.lua
    +++ b/xmake/plugins/repo/main.lua
    @@ -84,18 +84,25 @@ end
     -- list all repositories
     function _list(is_global)
     
    -    -- trace
    -    print("%s repositories:", ifelse(is_global, "global", "local"))
    -
    -    -- list all
    +    -- list all repositories
         local count = 0
    -    for _, repo in pairs(repository.repositories(is_global)) do
    +    for _, position in ipairs({"local", "global"}) do
     
             -- trace
    -        print("    %s %s", repo.name, repo.url)
    +        print("%s repositories:", position)
    +
    +        -- list all
    +        for _, repo in pairs(repository.repositories(position == "global")) do
     
    -        -- update count
    -        count = count + 1
    +            -- trace
    +            print("    %s %s", repo.name, repo.url)
    +
    +            -- update count
    +            count = count + 1
    +        end
    +
    +        -- trace
    +        print("")
         end
     
         -- trace
    diff --git a/xmake/actions/deps/action/build.lua b/xmake/tools/7z.lua
    similarity index 64%
    rename from xmake/actions/deps/action/build.lua
    rename to xmake/tools/7z.lua
    index a016c2910e4..b20533a4419 100644
    --- a/xmake/actions/deps/action/build.lua
    +++ b/xmake/tools/7z.lua
    @@ -19,31 +19,19 @@
     -- Copyright (C) 2015 - 2017, TBOOX Open Source Group.
     --
     -- @author      ruki
    --- @file        build.lua
    +-- @file        7z.lua
     --
     
    --- on build the given package
    -function _on_build_package(package)
    -    print("build %s", package:name())
    -end
    +-- init it
    +function init(shellname)
     
    --- build the given package
    -function main(package)
    +    -- save name
    +    _g.shellname = shellname or "7z"
    +end
     
    -    -- the package scripts
    -    local scripts =
    -    {
    -        package:get("build_before") 
    -    ,   package:get("build")  or _on_build_package
    -    ,   package:get("build_after") 
    -    }
    +-- check the given flags 
    +function check(flags)
     
    -    -- run the package scripts
    -    for i = 1, 3 do
    -        local script = scripts[i]
    -        if script ~= nil then
    -            script(package)
    -        end
    -    end
    +    -- check it
    +    os.run("%s --help", _g.shellname)
     end
    -
    diff --git a/xmake/tools/ar.lua b/xmake/tools/ar.lua
    index 281055c404b..e870aa86619 100644
    --- a/xmake/tools/ar.lua
    +++ b/xmake/tools/ar.lua
    @@ -116,9 +116,9 @@ end
     function check(flags)
     
         -- make an stub source file
    -    local libraryfile   = path.join(os.tmpdir(), "xmake.ar.a")
    -    local objectfile    = path.join(os.tmpdir(), "xmake.ar.o")
    -    local sourcefile    = path.join(os.tmpdir(), "xmake.ar.c")
    +    local libraryfile   = os.tmpfile() .. ".a"
    +    local objectfile    = os.tmpfile() .. ".o"
    +    local sourcefile    = os.tmpfile() .. ".c"
         io.writefile(sourcefile, "int test(void)\n{return 0;}")
     
         -- make flags
    diff --git a/xmake/tools/cl.lua b/xmake/tools/cl.lua
    index 68881995ea8..7781d619ddb 100644
    --- a/xmake/tools/cl.lua
    +++ b/xmake/tools/cl.lua
    @@ -42,8 +42,10 @@ function init(shellname, kind)
         {
             -- optimize
             ["-O0"]                     = "-Od"
    -    ,   ["-O3"]                     = "-Ot"
    -    ,   ["-Ofast"]                  = "-Ox"
    +    ,   ["-O1"]                     = ""
    +    ,   ["-Os"]                     = "-O1"
    +    ,   ["-O3"]                     = "-Ox"
    +    ,   ["-Ofast"]                  = "-Ox -fp:fast"
         ,   ["-fomit-frame-pointer"]    = "-Oy"
     
             -- symbols
    @@ -154,11 +156,11 @@ function nf_optimize(level)
         local maps = 
         {   
             none        = "-Od"
    -    ,   fast        = "-O1"
    -    ,   faster      = "-O2"
    -    ,   fastest     = "-Ot"
    -    ,   smallest    = "-Os"
    -    ,   aggressive  = "-Ox"
    +    ,   fast        = ""
    +    ,   faster      = "-Ox"
    +    ,   fastest     = "-Ox -fp:fast"
    +    ,   smallest    = "-O1"
    +    ,   aggressive  = "-Ox -fp:fast"
         }
     
         -- make it
    diff --git a/xmake/tools/curl.lua b/xmake/tools/curl.lua
    index 3122830d412..108ca158257 100644
    --- a/xmake/tools/curl.lua
    +++ b/xmake/tools/curl.lua
    @@ -22,6 +22,9 @@
     -- @file        curl.lua
     --
     
    +-- imports
    +import("core.base.option")
    +
     -- init it
     function init(shellname)
     
    @@ -29,13 +32,6 @@ function init(shellname)
         _g.shellname = shellname or "curl"
     end
     
    --- get the property
    -function get(name)
    -
    -    -- get it
    -    return _g[name]
    -end
    -
     -- download url
     function download(url, outputfile, args)
     
    @@ -43,7 +39,17 @@ function download(url, outputfile, args)
         assert(outputfile)
     
         -- init argv
    -    local argv = {"-fsSL", url}
    +    local argv = {}
    +
    +    -- set basic arguments
    +    if option.get("verbose") then
    +        table.insert(argv, "-SL")
    +    else
    +        table.insert(argv, "-fsSL")
    +    end
    +
    +    -- set url
    +    table.insert(argv, url)
     
         -- ensure output directory
         local outputdir = path.directory(outputfile)
    @@ -55,14 +61,8 @@ function download(url, outputfile, args)
         table.insert(argv, "-o")
         table.insert(argv, outputfile)
     
    -    -- verbose?
    -    local runner = os.runv
    -    if args.verbose then
    -        runner = os.execv
    -    end
    -
         -- clone it
    -    runner(_g.shellname, argv)
    +    os.vrunv(_g.shellname, argv)
     end
     
     -- check the given flags 
    diff --git a/xmake/tools/dmd.lua b/xmake/tools/dmd.lua
    index 928d98fb303..bd6b67379d0 100644
    --- a/xmake/tools/dmd.lua
    +++ b/xmake/tools/dmd.lua
    @@ -168,7 +168,7 @@ function nf_rpathdir(dir)
             _g._RPATH = try
             {
                 function ()
    -                check(flag)
    +                check(flag, true)
                     return true
                 end
             }
    @@ -215,19 +215,25 @@ function compile(sourcefiles, objectfile, incdepfile, flags)
     end
     
     -- check the given flags 
    -function check(flags)
    +function check(flags, trylink)
     
         -- make an stub source file
         local binaryfile = os.tmpfile() .. ".b"
    +    local objectfile = os.tmpfile() .. ".o"
         local sourcefile = os.tmpfile() .. ".d"
     
         -- make stub code
         io.writefile(sourcefile, "void main() {\n}")
     
         -- check it, need check compflags and linkflags
    -    os.run("%s %s -of%s %s", _g.shellname, ifelse(flags, flags, ""), binaryfile, sourcefile)
    +    if trylink then
    +        os.run("%s %s -of%s %s", _g.shellname, ifelse(flags, flags, ""), binaryfile, sourcefile)
    +    else
    +        os.run("%s -c %s -of%s %s", _g.shellname, ifelse(flags, flags, ""), binaryfile, sourcefile)
    +    end
     
         -- remove files
    -    os.rm(binaryfile)
    -    os.rm(sourcefile)
    +    os.tryrm(binaryfile)
    +    os.tryrm(objectfile)
    +    os.tryrm(sourcefile)
     end
    diff --git a/xmake/tools/gcc.lua b/xmake/tools/gcc.lua
    index 1ca2bffee36..fbe91dfb1e7 100644
    --- a/xmake/tools/gcc.lua
    +++ b/xmake/tools/gcc.lua
    @@ -250,7 +250,7 @@ function nf_rpathdir(dir)
             _g._RPATH = try
             {
                 function ()
    -                check(flag)
    +                check(flag, true)
                     return true
                 end
             }
    @@ -394,20 +394,26 @@ function compile(sourcefiles, objectfile, incdepfile, flags)
     end
     
     -- check the given flags 
    -function check(flags)
    +function check(flags, trylink)
     
         -- make an stub source file
         local binaryfile = os.tmpfile() .. ".b"
    +    local objectfile = os.tmpfile() .. ".o"
         local sourcefile = os.tmpfile() .. ".c" .. ifelse(_g.kind == "cxx", "pp", "")
     
         -- make stub code
         io.writefile(sourcefile, "int main(int argc, char** argv)\n{return 0;}")
     
         -- check it, need check compflags and linkflags
    -    os.run("%s %s -o %s %s", _g.shellname, ifelse(flags, flags, ""), binaryfile, sourcefile)
    +    if trylink then
    +        os.run("%s %s -o %s %s", _g.shellname, ifelse(flags, flags, ""), binaryfile, sourcefile)
    +    else
    +        os.run("%s -c %s -o %s %s", _g.shellname, ifelse(flags, flags, ""), binaryfile, sourcefile)
    +    end
     
         -- remove files
    -    os.rm(binaryfile)
    -    os.rm(sourcefile)
    +    os.tryrm(binaryfile)
    +    os.tryrm(objectfile)
    +    os.tryrm(sourcefile)
     end
     
    diff --git a/xmake/tools/git.lua b/xmake/tools/git.lua
    index 4d8637dcab2..f740104dde9 100644
    --- a/xmake/tools/git.lua
    +++ b/xmake/tools/git.lua
    @@ -22,6 +22,9 @@
     -- @file        git.lua
     --
     
    +-- imports
    +import("core.base.option")
    +
     -- init it
     function init(shellname)
     
    @@ -29,13 +32,6 @@ function init(shellname)
         _g.shellname = shellname or "git"
     end
     
    --- get the property
    -function get(name)
    -
    -    -- get it
    -    return _g[name]
    -end
    -
     -- clone url
     function clone(url, args)
     
    @@ -56,12 +52,12 @@ function clone(url, args)
     
         -- set outputdir
         if args.outputdir then
    -        table.insert(argv, args.outputdir)
    +        table.insert(argv, path.translate(args.outputdir))
         end
     
         -- verbose?
         local runner = os.runv
    -    if args.verbose then
    +    if option.get("verbose") then
             runner = os.execv
         end
     
    @@ -92,14 +88,8 @@ function pull(args)
             oldir = os.cd(args.repodir)
         end
     
    -    -- verbose?
    -    local runner = os.runv
    -    if args.verbose then
    -        runner = os.execv
    -    end
    -
         -- clone it
    -    runner(_g.shellname, argv)
    +    os.vrunv(_g.shellname, argv)
     
         -- leave repository directory
         if oldir then
    @@ -155,14 +145,8 @@ function checkout(commit, args)
             oldir = os.cd(args.repodir)
         end
     
    -    -- verbose?
    -    local runner = os.runv
    -    if args.verbose then
    -        runner = os.execv
    -    end
    -
         -- clone it
    -    runner(_g.shellname, argv)
    +    os.vrunv(_g.shellname, argv)
     
         -- leave repository directory
         if oldir then
    diff --git a/xmake/actions/deps/action/clean.lua b/xmake/tools/gzip.lua
    similarity index 64%
    rename from xmake/actions/deps/action/clean.lua
    rename to xmake/tools/gzip.lua
    index c44eb6278b6..785d7f1c133 100644
    --- a/xmake/actions/deps/action/clean.lua
    +++ b/xmake/tools/gzip.lua
    @@ -19,31 +19,19 @@
     -- Copyright (C) 2015 - 2017, TBOOX Open Source Group.
     --
     -- @author      ruki
    --- @file        clean.lua
    +-- @file        gzip.lua
     --
     
    --- on clean the given package
    -function _on_clean_package(package)
    -    print("clean %s", package:name())
    -end
    +-- init it
    +function init(shellname)
     
    --- clean the given package
    -function main(package)
    +    -- save name
    +    _g.shellname = shellname or "gzip"
    +end
     
    -    -- the package scripts
    -    local scripts =
    -    {
    -        package:get("clean_before") 
    -    ,   package:get("clean")  or _on_clean_package
    -    ,   package:get("clean_after") 
    -    }
    +-- check the given flags 
    +function check(flags)
     
    -    -- run the package scripts
    -    for i = 1, 3 do
    -        local script = scripts[i]
    -        if script ~= nil then
    -            script(package)
    -        end
    -    end
    +    -- check it
    +    os.run("%s --help", _g.shellname)
     end
    -
    diff --git a/xmake/tools/make.lua b/xmake/tools/make.lua
    new file mode 100644
    index 00000000000..e4564c3cfd4
    --- /dev/null
    +++ b/xmake/tools/make.lua
    @@ -0,0 +1,37 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        make.lua
    +--
    +
    +-- init it
    +function init(shellname)
    +
    +    -- save name
    +    _g.shellname = shellname or "make"
    +end
    +
    +-- check the given flags 
    +function check(flags)
    +
    +    -- check it
    +    os.run("%s --version", _g.shellname)
    +end
    diff --git a/xmake/tools/ping.lua b/xmake/tools/ping.lua
    new file mode 100644
    index 00000000000..184acc38232
    --- /dev/null
    +++ b/xmake/tools/ping.lua
    @@ -0,0 +1,62 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        ping.lua
    +--
    +
    +-- init it
    +function init(shellname)
    +
    +    -- save name
    +    _g.shellname = shellname or "ping"
    +end
    +
    +-- send ping to host
    +function send(host)
    +
    +    -- ping it
    +    local data = nil
    +    if os.host() == "windows" then
    +        data = os.iorun("%s -n 1 %s", _g.shellname, host)
    +    else
    +        data = os.iorun("%s -c 1 %s", _g.shellname, host)
    +    end
    +
    +    -- find time
    +    local time = data:match("time=(.-)ms", 1, true)
    +    if time then
    +        return tonumber(time:trim())
    +    end
    +
    +    -- failed
    +    return -1
    +end
    +
    +-- check the given flags 
    +function check(flags)
    +
    +    -- check it
    +    if os.host() == "windows" then
    +        os.run("%s -n 1 127.0.0.1", _g.shellname)
    +    else
    +        os.run("%s -c 1 127.0.0.1", _g.shellname)
    +    end
    +end
    diff --git a/xmake/tools/tar.lua b/xmake/tools/tar.lua
    new file mode 100644
    index 00000000000..6285466d3f0
    --- /dev/null
    +++ b/xmake/tools/tar.lua
    @@ -0,0 +1,63 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        tar.lua
    +--
    +
    +-- imports
    +import("core.base.option")
    +
    +-- init it
    +function init(shellname)
    +
    +    -- save name
    +    _g.shellname = shellname or "tar"
    +end
    +
    +-- extract the archived file
    +function extract(archivefile, outputdir)
    +
    +    -- check 
    +    assert(archivefile)
    +
    +    -- init argv
    +    local argv = {ifelse(option.get("verbose"), "-xvf", "-xf"), archivefile}
    +
    +    -- ensure output directory
    +    if not os.isdir(outputdir) then
    +        os.mkdir(outputdir)
    +    end
    +
    +    -- set outputdir
    +    table.insert(argv, "-C")
    +    table.insert(argv, outputdir)
    +    table.insert(argv, "--strip-components=1")
    +
    +    -- clone it
    +    os.vrunv(_g.shellname, argv)
    +end
    +
    +-- check the given flags 
    +function check(flags)
    +
    +    -- check it
    +    os.run("%s --help", _g.shellname)
    +end
    diff --git a/xmake/tools/unzip.lua b/xmake/tools/unzip.lua
    new file mode 100644
    index 00000000000..78409621788
    --- /dev/null
    +++ b/xmake/tools/unzip.lua
    @@ -0,0 +1,62 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        unzip.lua
    +--
    +
    +-- imports
    +import("core.base.option")
    +
    +-- init it
    +function init(shellname)
    +
    +    -- save name
    +    _g.shellname = shellname or "unzip"
    +end
    +
    +-- extract the archived file
    +function extract(archivefile, outputdir)
    +
    +    -- check 
    +    assert(archivefile)
    +
    +    -- init argv
    +    local argv = {ifelse(option.get("verbose"), "-j", "-jq"), archivefile}
    +
    +    -- ensure output directory
    +    if not os.isdir(outputdir) then
    +        os.mkdir(outputdir)
    +    end
    +
    +    -- set outputdir
    +    table.insert(argv, "-d")
    +    table.insert(argv, outputdir)
    +
    +    -- clone it
    +    os.vrunv(_g.shellname, argv)
    +end
    +
    +-- check the given flags 
    +function check(flags)
    +
    +    -- check it
    +    os.run("%s --help", _g.shellname)
    +end
    diff --git a/xmake/tools/wget.lua b/xmake/tools/wget.lua
    index 349e45bed8f..bf1c40647bd 100644
    --- a/xmake/tools/wget.lua
    +++ b/xmake/tools/wget.lua
    @@ -22,6 +22,9 @@
     -- @file        wget.lua
     --
     
    +-- imports
    +import("core.base.option")
    +
     -- init it
     function init(shellname)
     
    @@ -29,13 +32,6 @@ function init(shellname)
         _g.shellname = shellname or "wget"
     end
     
    --- get the property
    -function get(name)
    -
    -    -- get it
    -    return _g[name]
    -end
    -
     -- download url
     function download(url, outputfile, args)
     
    @@ -55,14 +51,8 @@ function download(url, outputfile, args)
         table.insert(argv, "-O")
         table.insert(argv, outputfile)
     
    -    -- verbose?
    -    local runner = os.runv
    -    if args.verbose then
    -        runner = os.execv
    -    end
    -
         -- clone it
    -    runner(_g.shellname, argv)
    +    os.vrunv(_g.shellname, argv)
     end
     
     -- check the given flags 
    diff --git a/xmake/tools/zip.lua b/xmake/tools/zip.lua
    new file mode 100644
    index 00000000000..3be29379a3e
    --- /dev/null
    +++ b/xmake/tools/zip.lua
    @@ -0,0 +1,37 @@
    +--!The Make-like 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 - 2017, TBOOX Open Source Group.
    +--
    +-- @author      ruki
    +-- @file        zip.lua
    +--
    +
    +-- init it
    +function init(shellname)
    +
    +    -- save name
    +    _g.shellname = shellname or "zip"
    +end
    +
    +-- check the given flags 
    +function check(flags)
    +
    +    -- check it
    +    os.run("%s --help", _g.shellname)
    +end