ソースを参照

add builtin-modules

ruki 6 ヶ月 前
コミット
0968ebc6ae

+ 5 - 4
docs/api/index.md

@@ -16,7 +16,8 @@ outline: deep
 
 ## Scripts API
 
-- [Target Instance](/api/scripts/target_instance)
-- [Option Instance](/api/scripts/option_instance)
-- [Package Instance](/api/scripts/package_instance)
-- [Native Modules](/api/scripts/native_modules)
+- [Target Instance](/api/scripts/target-instance)
+- [Option Instance](/api/scripts/option-instance)
+- [Package Instance](/api/scripts/package-instance)
+- [Builtin Modules](/api/scripts/builtin-modules/import)
+- [Native Modules](/api/scripts/native-modules)

+ 178 - 0
docs/api/scripts/builtin-modules/import.md

@@ -0,0 +1,178 @@
+# import
+
+Used in script code such as custom scripts, plug-in scripts, task scripts, platform extensions, template extensions, etc., that is, in code blocks like the following, you can use these module interfaces:
+
+```lua
+on_run(function (target)
+    print("hello xmake!")
+end)
+```
+
+::: tip NOTE
+In order to ensure that the description scope of the outer layer is as simple and secure as possible, it is generally not recommended to use the interface and module operation api in this domain. Therefore, most module interfaces can only be used in the script domain to implement complex functions. </br>
+:::
+
+Of course, a small number of read-only built-in interfaces can still be used in the description scope, as shown in the following table:
+
+An example of using an interface call in a description scope is as follows, generally only for conditional control:
+
+```lua
+-- Scan all subdirectories under the current xmake.lua directory, defining a task task with the name of each directory
+for _, taskname in ipairs(os.dirs("*"), path.basename) do
+    task(taskname)
+        on_run(function ()
+        end)
+end
+```
+
+The script scope and description scope mentioned above mainly refer to:
+
+```lua
+-- description scope
+target("test")
+
+    -- description scope
+    set_kind("static")
+    add_files("src/*.c")
+
+    on_run(function (target)
+        -- Script domain
+    end)
+
+-- description scope
+```
+
+## Importing extension blocks
+
+Import is mainly used to import xmake's extension class library and some custom class library modules, generally used to:
+
+* Custom script ([on_build](/api/description/project-target#on-build), [on_run](/api/description/project-target#on-run) ..)
+* Plugin development
+* Template development
+* Platform extension
+* Custom task task
+
+The import mechanism is as follows:
+
+1. Import from the current script directory first
+2. Import from the extended class library
+
+Imported grammar rules:
+
+Class library path rules based on `.`, for example:
+
+Import core core extension module
+
+```lua
+import("core.base.option")
+import("core.base.task")
+
+function main()
+
+    -- Get parameter options
+    print(option.get("version"))
+
+    -- Run tasks and plugins
+    task.run("hello")
+end
+```
+
+Import the custom module in the current directory:
+
+Directory Structure:
+
+```
+Plugin
+  - xmake.lua
+  - main.lua
+  - modules
+    - hello1.lua
+    - hello2.lua
+```
+
+Import modules in main.lua
+
+```lua
+import("modules.hello1")
+import("modules.hello2")
+```
+
+After importing, you can directly use all the public interfaces inside. The private interface is marked with the `_` prefix, indicating that it will not be exported and will not be called externally. .
+
+In addition to the current directory, we can also import libraries in other specified directories, for example:
+
+```lua
+import("hello3", {rootdir = "/home/xxx/modules"})
+```
+
+To prevent naming conflicts, you can also specify an alias after import:
+
+```lua
+import("core.platform.platform", {alias = "p"})
+
+function main()
+
+    -- So we can use p to call the plats interface of the platform module to get a list of all the platforms supported by xmake.
+    utils.dump(p.plats())
+end
+```
+
+Import can not only import the class library, but also import and import as inheritance, realize the inheritance relationship between modules.
+
+```lua
+import("xxx.xxx", {inherit = true})
+```
+
+This is not a reference to the module, but all the public interfaces of the module imported, so that it will be merged with the interface of the current module to achieve inheritance between modules.
+
+Version 2.1.5 adds two new properties: `import("xxx.xxx", {try = true, anonymous = true}).
+
+If the try is true, the imported module does not exist, only return nil, and will not interrupt xmake after throwing an exception.
+If anonymous is true, the imported module will not introduce the current scope, only the imported object reference will be returned in the import interface.
+
+## Custom extension module
+
+Through import, we can import not only many built-in extension modules of xmake, but also user-defined extension modules.
+
+Just put your own module in the project directory and import it according to the import method described above.
+
+So, what if you want to define a module? xmake has a set of convention rules for module writing specifications, and does not follow Lua's native require import mechanism, and there is no need to use return in the module to return it globally.
+
+If we have a module file foo.lua, its content is as follows:
+
+```lua
+function _foo(a, b)
+    return a + b
+end
+
+function add(a, b)
+    _foo(a, b)
+end
+
+function main(a, b)
+    add(a, b)
+end
+```
+
+Among them main is the entry function, optional, if set, the module foo can be called directly, for example:
+
+```lua
+import("foo")
+foo(1, 2)
+```
+
+Or directly like this:
+
+```lua
+import("foo")(1, 2)
+```
+
+
+Others without underscore are public module interface functions, such as add.
+
+```lua
+import("foo")
+foo.add(1, 2)
+```
+
+The underscore prefixed `_foo` is a private function that is used internally by the module and is not exported, so users cannot call it outside.

+ 612 - 0
docs/api/scripts/builtin-modules/os.md

@@ -0,0 +1,612 @@
+# os
+
+The system operation module belongs to the built-in module. It can be called directly by the script scope without using [import](/api/scripts/builtin-modules/import) to import.
+
+This module is also a native module of lua, and xmake has been extended to provide more practical interfaces.
+
+::: tip NOTE
+Only some readonly interfaces (for example: `os.getenv`, `os.arch`) in the os module can be used in the description scope. Other interfaces can only be used in the script domain, for example: `os.cp`, `os .rm`etc.
+:::
+
+## os.cp
+
+- Copy files or directories
+
+The behavior is similar to the `cp` command in the shell, supporting path wildcard matching (using lua pattern matching), support for multi-file copying, and built-in variable support.
+
+e.g:
+
+```lua
+os.cp("$(scriptdir)/*.h", "$(buildir)/inc")
+os.cp("$(projectdir)/src/test/**.h", "$(buildir)/inc")
+```
+
+The above code will copy all the header files in the current `xmake.lua` directory, the header files in the project source test directory to the `$(buildir)` output directory.
+
+Among them `$(scriptdir)`, `$(projectdir)` These variables are built-in variables of xmake. For details, see the related documentation of [built-in variables](#built-in variables).
+
+The matching patterns in `*.h` and `**.h` are similar to those in [add_files](/api/description/project-target#add-files), the former is a single-level directory matching, and the latter is a recursive multi-level directory matching.
+
+This interface also supports `recursive replication' of directories, for example:
+
+```lua
+-- Recursively copy the current directory to a temporary directory
+os.cp("$(curdir)/test/", "$(tmpdir)/test")
+```
+
+The copy at the top will expand and copy all files to the specified directory, and lose the source directory hierarchy. If you want to copy according to the directory structure that maintains it, you can set the rootdir parameter:
+
+```lua
+os.cp ("src/**.h", "/tmp/", {rootdir="src"})
+```
+
+The above script can press the root directory of `src` to copy all sub-files under src in the same directory structure.
+
+::: tip NOTE
+Try to use the `os.cp` interface instead of `os.run("cp ..")`, which will ensure platform consistency and cross-platform build description.
+:::
+
+Under 2.5.7, the parameter `{symlink = true}` is added to keep the symbolic link when copying files.
+
+```lua
+os.cp("/xxx/foo", "/xxx/bar", {symlink = true})
+```
+
+## os.mv
+
+- Move to rename a file or directory
+
+Similar to the use of [os.cp](#os-cp), it also supports multi-file move operations and pattern matching, for example:
+
+```lua
+-- Move multiple files to a temporary directory
+os.mv("$(buildir)/test1", "$(tmpdir)")
+
+-- File movement does not support bulk operations, which is file renaming
+os.mv("$(buildir)/libtest.a", "$(buildir)/libdemo.a")
+```
+
+## os.rm
+
+- Delete files or directory trees
+
+Support for recursive deletion of directories, bulk delete operations, and pattern matching and built-in variables, such as:
+
+```lua
+os.rm("$(buildir)/inc/**.h")
+os.rm("$(buildir)/lib/")
+```
+
+## os.trycp
+
+- Try copying files or directories
+
+Similar to [os.cp](#os-cp), the only difference is that this interface operation will not throw an exception interrupt xmake, but the return value indicates whether the execution is successful.
+
+```lua
+if os.trycp("file", "dest/file") then
+end
+```
+
+## os.trymv
+
+- Try moving a file or directory
+
+Similar to [os.mv](#os-mv), the only difference is that this interface operation will not throw an exception interrupt xmake, but the return value indicates whether the execution is successful.
+
+```lua
+if os.trymv("file", "dest/file") then
+end
+```
+
+## os.tryrm
+
+- Try deleting files or directories
+
+Similar to [os.rm](#os-rm), the only difference is that this interface operation will not throw an exception interrupt xmake, but the return value indicates whether the execution is successful.
+
+```lua
+if os.tryrm("file") then
+end
+```
+
+## os.cd
+
+- Enter the specified directory
+
+This operation is used for directory switching and also supports built-in variables, but does not support pattern matching and multi-directory processing, for example:
+
+```lua
+-- Enter the temporary directory
+os.cd("$(tmpdir)")
+```
+
+If you want to leave the previous directory, there are several ways:
+
+```lua
+-- Enter the parent directory
+os.cd("..")
+
+-- Enter the previous directory, equivalent to: cd -
+os.cd("-")
+
+-- Save the previous directory before entering the directory, then use it to cut back directly after the level
+local oldir = os.cd("./src")
+...
+os.cd(oldir)
+```
+
+## os.rmdir
+
+- delete only the directory
+
+If it is not a directory, it cannot be deleted.
+
+## os.mkdir
+
+- Create a directory
+
+Support for batch creation and built-in variables, such as:
+
+```lua
+os.mkdir("$(tmpdir)/test", "$(buildir)/inc")
+```
+
+## os.isdir
+
+- Determine if it is a directory
+
+Return false if the directory does not exist
+
+```lua
+if os.isdir("src") then
+    -- ...
+end
+```
+
+## os.isfile
+
+- Determine if it is a file
+
+Return false if the file does not exist
+
+```lua
+if os.isfile("$(buildir)/libxxx.a") then
+    -- ...
+end
+```
+
+## os.exists
+
+- Determine if a file or directory exists
+
+Return false if the file or directory does not exist
+
+```lua
+-- Judging the existence of the directory
+if os.exists("$(buildir)") then
+    -- ...
+end
+
+-- Judging the existence of the file
+if os.exists("$(buildir)/libxxx.a") then
+    -- ...
+end
+```
+
+## os.dirs
+
+- Traverse to get all the directories under the specified directory
+
+Supports pattern matching in [add_files](#targetadd_files), supports recursive and non-recursive mode traversal, and returns a table array. If not, returns an empty array, for example:
+
+```lua
+-- Recursive traversal to get all subdirectories
+for _, dir in ipairs(os.dirs("$(buildir)/inc/**")) do
+    print(dir)
+end
+```
+
+## os.files
+
+- Traverse to get all the files in the specified directory
+
+Supports pattern matching in [add_files](#targetadd_files), supports recursive and non-recursive mode traversal, and returns a table array. If not, returns an empty array, for example:
+
+```lua
+-- Non-recursive traversal to get all child files
+for _, filepath in ipairs(os.files("$(buildir)/inc/*.h")) do
+    print(filepath)
+end
+```
+
+## os.filedirs
+
+- Traverse to get all files and directories under the specified directory
+
+Supports pattern matching in [add_files](#targetadd_files), supports recursive and non-recursive mode traversal, and returns a table array. If not, returns an empty array, for example:
+
+```lua
+-- Recursive traversal to get all child files and directories
+for _, filedir in ipairs(os.filedirs("$(buildir)/**")) do
+    print(filedir)
+end
+```
+
+## os.exit
+
+- Exit the program
+
+## os.isexec
+
+- Test if a file is executable
+
+```lua
+if os.isexec("path/to/file.exe") then
+    os.run("path/to/file.exe")
+end
+```
+
+## os.run
+
+- Quietly running native shell commands
+
+Used to execute third-party shell commands, but will not echo the output, only after the error, highlight the error message.
+
+This interface supports parameter formatting and built-in variables such as:
+
+```lua
+-- Formatted parameters passed in
+os.run("echo hello %s!", "xmake")
+
+-- List build directory files
+os.run("ls -l $(buildir)")
+```
+
+::: tip WARN
+Using this interface to execute shell commands can easily reduce the cross-platform build. For `os.run("cp ..")`, try to use `os.cp` instead.
+If you must use this interface to run the shell program, please use the [config.plat](#config-plat) interface to determine the platform support.
+:::
+
+For more advanced process operations and control, see the [process](#process) module interface.
+
+## os.runv
+
+- Quietly running native shell commands with parameter list
+
+Similar to [os.run](#os-run), just the way to pass parameters is passed through the parameter list, not the string command, for example:
+
+```lua
+os.runv("echo", {"hello", "xmake!"})
+```
+
+## os.exec
+
+- Echo running native shell commands
+
+Similar to the [os.run](#os-run) interface, the only difference is that when this interface executes the shell program, it has the output output, which is used in general debugging.
+
+## os.execv
+
+- Echo running native shell commands with parameter list
+
+Similar to [os.exec](#os-exec), just the way to pass parameters is passed through the parameter list, not the string command, for example:
+
+```lua
+os.execv("echo", {"hello", "xmake!"})
+```
+
+In addition, this interface also supports an optional parameter for passing settings: redirect output, perform environment variable settings, for example:
+
+```lua
+os.execv("echo", {"hello", "xmake!"}, {stdout = outfile, stderr = errfile, envs = {PATH = "xxx;xx", CFLAGS = "xx"}}
+```
+
+Among them, the stdout and stderr parameters are used to pass redirected output and error output. You can directly pass in the file path or the file object opened by io.open.
+
+After v2.5.1, we also support setting the stdin parameter to support redirecting input files.
+
+::: tip NOTE
+stdout/stderr/stdin can simultaneously support three types of values: file path, file object, and pipe object.
+:::
+
+In addition, if you want to temporarily set and rewrite some environment variables during this execution, you can pass the envs parameter. The environment variable settings inside will replace the existing settings, but will not affect the outer execution environment, only the current command.
+
+We can also get all the current environment variables through the `os.getenvs()` interface, and then pass in the envs parameter after rewriting some parts.
+
+## os.iorun
+
+- Quietly running native shell commands and getting output
+
+Similar to the [os.run](#os-run) interface, the only difference is that after executing the shell program, this interface will get the execution result of the shell program, which is equivalent to redirecting the output.
+
+You can get the contents of `stdout`, `stderr` at the same time, for example:
+
+```lua
+local outdata, errdata = os.iorun("echo hello xmake!")
+```
+
+## os.iorunv
+
+- Run the native shell command quietly and get the output with a list of parameters
+
+Similar to [os.iorun](#os-iorun), just the way to pass arguments is passed through the argument list, not the string command, for example:
+
+```lua
+local outdata, errdata = os.iorunv("echo", {"hello", "xmake!"})
+local outdata, errdata = os.iorunv("echo", {"hello", "xmake!"}, {envs = {PATH="..."}})
+```
+
+## os.tmpdir
+
+- Get temporary directory
+
+Consistent with the result of [$(tmpdir)](#var-tmpdir), it is just a direct return to return a variable that can be maintained with subsequent strings.
+
+```lua
+print(path.join(os.tmpdir(), "file.txt"))
+```
+
+Equivalent to:
+
+```lua
+print("$(tmpdir)/file.txt")
+```
+
+## os.tmpfile
+
+- Get temporary file path
+
+Used to get a temporary file path, just a path, the file needs to be created by itself.
+
+## os.curdir
+
+- Get the current directory path
+
+Consistent with the result of [$(curdir)](#var-curdir), it is just a direct return to return a variable that can be maintained with subsequent strings.
+
+Usage reference: [os.tmpdir](#os-tmpdir).
+
+## os.filesize
+
+- Get file size
+
+```lua
+print(os.filesize("/tmp/a"))
+```
+
+## os.scriptdir
+
+- Get the path of the current description script
+
+Consistent with the result of [$(scriptdir)](#var-scriptdir), it is just a direct return to return a variable that can be maintained with subsequent strings.
+
+Usage reference: [os.tmpdir](#os-tmpdir).
+
+## os.programdir
+
+- Get the xmake installation main program script directory
+
+Consistent with the result of [$(programdir)](#var-programdir), it is just a direct get returned to a variable, which can be maintained with subsequent strings.
+
+## os.programfile
+
+- Get the path of the xmake executable
+
+## os.projectdir
+
+- Get the project home directory
+
+Consistent with the result of [$(projectdir)](#var-projectdir), it is just a direct return to return a variable that can be maintained with subsequent strings.
+
+## os.arch
+
+- Get current system architecture
+
+That is the default architecture of the current host system, for example, I execute xmake on `linux x86_64` to build, then the return value is: `x86_64`
+
+## os.host
+
+- Get the operating system of the current host
+
+Consistent with the result of [$(host)](#var-host), for example, if I execute xmake on `linux x86_64` to build, the return value is: `linux`
+
+## os.subhost
+
+- Get Subsystem host, e.g. msys, cygwin on windows
+
+## os.subarch
+
+- Get Subsystem host architecture
+
+## os.is_host
+
+- Test if a given host is the current
+
+## os.is_arch
+
+- Test if a given arch is the current
+
+## os.is_subhost
+
+- Test if a given sub host is the current
+
+## os.is_subarch
+
+- Test if a given sub arch is the current
+
+## os.ln
+
+- Create a symlink to a file or directory
+
+```lua
+-- creates a symlink file "xxx.txt.ln" which is pointing to "xxx.txt"
+os.ln("xxx.txt", "xxx.txt.ln")
+```
+
+## os.readlink
+
+- Read the content of a symlink
+
+## os.raise
+
+- Raise an exception and abort the current script
+
+```lua
+-- Raise exception with message "an error occurred"
+os.raise("an error occurred")
+```
+
+::: tip NOTE
+Recommanded to use builtin function `raise` instead of `os.raise`
+:::
+
+## os.raiselevel
+
+- Similar to [os.raise](#os-raise) but you can specify the level of the error
+
+```lua
+-- Raise exception with message "an error occurred"
+os.raiselevel(3,"an error occurred")
+```
+
+## os.features
+
+- Get features
+
+## os.getenvs
+
+- Get all current environment variables
+
+```lua
+local envs = os.getenvs()
+--- home directory (on linux)
+print(envs["HOME"])
+```
+
+## os.setenvs
+
+- Set environment variables. Replace the current envs by a new one and return old envs
+
+## os.addenvs
+
+- Add environment variables to current envs, return the all old envs
+
+```lua
+os.setenvs({EXAMPLE = "a/path"}) -- add a custom variable to see addenvs impact on it
+
+local oldenvs = os.addenvs({EXAMPLE = "some/path/"})
+print(os.getenvs()["EXAMPLE"]) --got some/path/;a/path
+print(oldenvs["EXAMPLE"]) -- got a/path
+```
+
+## os.joinenvs
+
+- Join environment variables. Similar to [os.addenvs](#os-addenvs) but with two envs variable
+
+```lua
+local envs = {CUSTOM = "a/path"}
+local envs2 = {CUSTOM = "some/path/"}
+print(os.joinenvs(envs, envs2))
+```
+
+The result is: `{ CUSTOM = "a/path;some/path/" }`
+
+## os.getenv
+
+- Get system environment variables
+
+```lua
+print(os.getenv("PATH"))
+```
+
+## os.setenv
+
+- Set system environment variables
+
+```lua
+os.setenv("HOME", "/tmp/")
+```
+
+## os.addenv
+
+- Add values to one environment variable
+
+```lua
+-- Add 'bin' to PATH
+os.addenv("PATH", "bin")
+```
+
+## os.setenvp
+
+- Setting environment variables with a given separator
+
+## os.addenvp
+
+- Add values to one environment variable with a given separator
+
+## os.workingdir
+
+- Get the working directory
+
+## os.isroot
+
+- Test if xmake is running as root
+
+## os.fscase
+
+- Test if the os has a case sensitive filesystem
+
+## os.term
+
+- Get current terminal (windows-terminal, vscode, ... )
+
+```lua
+print(os.term())
+-- got vscode
+```
+
+## os.shell
+
+- Get current shell  (pwsh, cmd, ...)
+
+```lua
+print(os.shell())
+-- got pwsh
+```
+
+## os.cpuinfo
+
+- Get cpu information
+
+```lua
+print(os.cpuinfo())
+-- got {
+--   ncpu = 8,
+--   usagerate = 0.0,
+--   model_name = "Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz",
+--   march = "Kaby Lake",
+--   vendor = "GenuineIntel",
+--   model = 158,
+--   family = 6
+-- }
+print(os.cpuinfo("march")) -- got "Kaby Lake"
+```
+
+## os.meminfo
+
+- Get memory information
+
+```lua
+print(os.meminfo())
+-- got {
+--   usagerate = 0.53490080822924,
+--   totalsize = 16332,
+--   availsize = 7596,
+--   pagesize = 4096
+-- }
+```
+
+## os.default_njob
+
+- Get default paralled jobs

+ 0 - 0
docs/api/scripts/native_modules.md → docs/api/scripts/native-modules.md


+ 0 - 0
docs/api/scripts/option_instance.md → docs/api/scripts/option-instance.md


+ 0 - 0
docs/api/scripts/package_instance.md → docs/api/scripts/package-instance.md


+ 0 - 0
docs/api/scripts/target_instance.md → docs/api/scripts/target-instance.md


+ 12 - 4
docs/config.ts

@@ -102,10 +102,18 @@ function descriptionApiGuide(): DefaultTheme.SidebarItem[] {
 
 function scriptsApiGuide(): DefaultTheme.SidebarItem[] {
   return [
-    { text: 'Target Instance', link: '/target_instance' },
-    { text: 'Option Instance', link: '/option_instance' },
-    { text: 'Package Instance', link: '/package_instance' },
-    { text: 'Native Modules', link: '/native_modules' }
+    { text: 'Target Instance', link: '/target-instance' },
+    { text: 'Option Instance', link: '/option-instance' },
+    { text: 'Package Instance', link: '/package-instance' },
+    {
+      text: 'Builtin Modules',
+      collapsed: false,
+      items: [
+        { text: 'import', link: '/builtin-modules/import' },
+        { text: 'os', link: '/builtin-modules/os' },
+      ]
+    },
+    { text: 'Native Modules', link: '/native-modules' }
   ]
 }
 

+ 5 - 4
docs/zh/api/index.md

@@ -15,7 +15,8 @@ outline: deep
 
 ## 脚本域 API {#scripts-api}
 
-- [目标实例](/zh/api/scripts/target_instance)
-- [选项实例](/zh/api/scripts/option_instance)
-- [包实例](/zh/api/scripts/package_instance)
-- [原生模块](/zh/api/scripts/native_modules)
+- [目标实例](/zh/api/scripts/target-instance)
+- [选项实例](/zh/api/scripts/option-instance)
+- [包实例](/zh/api/scripts/package-instance)
+- [内建模块](/zh/api/scripts/builtin-modules/import)
+- [原生模块](/zh/api/scripts/native-modules)

+ 176 - 0
docs/zh/api/scripts/builtin-modules/import.md

@@ -0,0 +1,176 @@
+# import
+
+在自定义脚本、插件脚本、任务脚本、平台扩展、模板扩展等脚本代码中使用,也就是在类似下面的代码块中,可以使用这些模块接口:
+
+```lua
+on_run(function (target)
+    print("hello xmake!")
+end)
+```
+
+::: tip 注意
+为了保证外层的描述域尽可能简洁、安全,一般不建议在这个域使用接口和模块操作api,因此大部分模块接口只能脚本域使用,来实现复杂功能
+:::
+
+当然少部分只读的内置接口还是可以在描述域使用的,具体见下表:
+
+在描述域使用接口调用的实例如下,一般仅用于条件控制:
+
+```lua
+-- 扫描当前xmake.lua目录下的所有子目录,以每个目录的名字定义一个task任务
+for _, taskname in ipairs(os.dirs("*"), path.basename) do
+    task(taskname)
+        on_run(function ()
+        end)
+end
+```
+
+上面所说的脚本域、描述域主要是指:
+
+```lua
+-- 描述域
+target("test")
+
+    -- 描述域
+    set_kind("static")
+    add_files("src/*.c")
+
+    on_run(function (target)
+        -- 脚本域
+    end)
+
+-- 描述域
+```
+
+## 导入扩展摸块
+
+import 的主要用于导入xmake的扩展类库以及一些自定义的类库模块,一般用于:
+
+* 自定义脚本 ([on_build](/zh/api/description/project-target#on-build), [on_run](/zh/api/description/project-target#on-run) ..)
+* 插件开发
+* 模板开发
+* 平台扩展
+* 自定义任务task
+
+导入机制如下:
+
+1. 优先从当前脚本目录下导入
+2. 再从扩展类库中导入
+
+导入的语法规则:
+
+基于`.`的类库路径规则,例如:
+
+```lua
+import("core.base.option")
+import("core.base.task")
+
+function main()
+
+    -- 获取参数选项
+    print(option.get("version"))
+
+    -- 运行任务和插件
+    task.run("hello")
+end
+```
+
+导入当前目录下的自定义模块:
+
+目录结构:
+
+```
+plugin
+  - xmake.lua
+  - main.lua
+  - modules
+    - hello1.lua
+    - hello2.lua
+```
+
+在main.lua中导入modules
+
+```lua
+import("modules.hello1")
+import("modules.hello2")
+```
+
+导入后就可以直接使用里面的所有公有接口,私有接口用`_`前缀标示,表明不会被导出,不会被外部调用到。。
+
+除了当前目录,我们还可以导入其他指定目录里面的类库,例如:
+
+```lua
+import("hello3", {rootdir = "/home/xxx/modules"})
+```
+
+为了防止命名冲突,导入后还可以指定的别名:
+
+```lua
+import("core.platform.platform", {alias = "p"})
+
+function main()
+
+    -- 这样我们就可以使用p来调用platform模块的plats接口,获取所有xmake支持的平台列表了
+    utils.dump(p.plats())
+end
+```
+
+import不仅可以导入类库,还支持导入的同时作为继承导入,实现模块间的继承关系
+
+```lua
+import("xxx.xxx", {inherit = true})
+```
+
+这样导入的不是这个模块的引用,而是导入的这个模块的所有公有接口本身,这样就会跟当前模块的接口进行合并,实现模块间的继承。
+
+2.1.5版本新增两个新属性:`import("xxx.xxx", {try = true, anonymous = true})`
+
+try为true,则导入的模块不存在的话,仅仅返回nil,并不会抛异常后中断xmake.
+anonymous为true,则导入的模块不会引入当前作用域,仅仅在import接口返回导入的对象引用。
+
+## 自定义扩展模块
+
+通过 import 我们除了可以导入 xmake 内置的很多扩展模块,还可以导入用户自己定义的扩展模块。
+
+只需要将自己的模块放到工程目录下,按照上文介绍的导入方式进行导入即可。
+
+那么,如果去定义模块呢?xmake 对模块的编写规范是有一套约定规则的,并没有沿用 lua 原生的 require 导入机制,并不需要在模块中使用 return 来全局返回它。
+
+假如我们有一个模块文件 foo.lua,它的内容如下:
+
+```lua
+function _foo(a, b)
+    return a + b
+end
+
+function add(a, b)
+    _foo(a, b)
+end
+
+function main(a, b)
+    add(a, b)
+end
+```
+
+其中 main 为入口函数,可选,如果设置,模块 foo 可以直接被调用,例如:
+
+```lua
+import("foo")
+foo(1, 2)
+```
+
+或者直接这样:
+
+```lua
+import("foo")(1, 2)
+```
+
+
+其他不带下划线的为 public 模块接口函数,例如 add。
+
+```lua
+import("foo")
+foo.add(1, 2)
+```
+
+而里面带下划线前缀的 `_foo` 是私有函数,模块内部使用,不对外导出,所以在外面用户是不能够调用它的。

+ 590 - 0
docs/zh/api/scripts/builtin-modules/os.md

@@ -0,0 +1,590 @@
+# os
+
+系统操作模块,属于内置模块,无需使用[import](/zh/api/scripts/builtin-modules/import)导入,可直接脚本域调用其接口。
+
+此模块也是lua的原生模块,xmake在其基础上进行了扩展,提供更多实用的接口。
+
+::: tip 注意
+os 模块里面只有部分readonly接口(例如:`os.getenv`, `os.arch`)是可以在描述域中使用,其他接口只能在脚本域中使用,例如:`os.cp`, `os.rm`等
+:::
+
+## os.cp
+
+- 复制文件或目录
+
+行为和shell中的`cp`命令类似,支持路径通配符匹配(使用的是lua模式匹配),支持多文件复制,以及内置变量支持。
+
+例如:
+
+```lua
+os.cp("$(scriptdir)/*.h", "$(buildir)/inc")
+os.cp("$(projectdir)/src/test/**.h", "$(buildir)/inc")
+```
+
+上面的代码将:当前`xmake.lua`目录下的所有头文件、工程源码test目录下的头文件全部复制到`$(buildir)`输出目录中。
+
+其中`$(scriptdir)`, `$(projectdir)` 这些变量是xmake的内置变量,具体详情见:[内置变量](#内置变量)的相关文档。
+
+而`*.h`和`**.h`中的匹配模式,跟[add_files](/zh/api/description/project-target#add-files)中的类似,前者是单级目录匹配,后者是递归多级目录匹配。
+
+此接口同时支持目录的`递归复制`,例如:
+
+```lua
+-- 递归复制当前目录到临时目录
+os.cp("$(curdir)/test/", "$(tmpdir)/test")
+```
+
+上面的复制,会把所有文件全部展开复制到指定目录,丢失源目录层级,如果要按保持原有的目录结构复制,可以设置rootdir参数:
+
+```lua
+os.cp("src/**.h", "/tmp/", {rootdir = "src"})
+```
+
+上面的脚本可以按`src`根目录,将src下的所有子文件保持目录结构复制过去。
+
+::: tip 注意
+尽量使用`os.cp`接口,而不是`os.run("cp ..")`,这样更能保证平台一致性,实现跨平台构建描述。
+:::
+
+2.5.7 下,新增 `{symlink = true}` 参数,在复制文件时候保留符号链接。
+
+```lua
+os.cp("/xxx/foo", "/xxx/bar", {symlink = true})
+```
+
+## os.mv
+
+- 移动重命名文件或目录
+
+跟[os.cp](#os-cp)的使用类似,同样支持多文件移动操作和模式匹配,例如:
+
+```lua
+-- 移动文件到临时目录
+os.mv("$(buildir)/test1", "$(tmpdir)")
+
+-- 文件移动不支持批量操作,也就是文件重命名
+os.mv("$(buildir)/libtest.a", "$(buildir)/libdemo.a")
+```
+
+## os.rm
+
+- 删除文件或目录树
+
+支持递归删除目录,批量删除操作,以及模式匹配和内置变量,例如:
+
+```lua
+os.rm("$(buildir)/inc/**.h")
+os.rm("$(buildir)/lib/")
+```
+
+## os.trycp
+
+- 尝试复制文件或目录
+
+跟[os.cp](#os-cp)类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。
+
+```lua
+if os.trycp("file", "dest/file") then
+end
+```
+
+## os.trymv
+
+- 尝试移动文件或目录
+
+跟[os.mv](#os-mv)类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。
+
+```lua
+if os.trymv("file", "dest/file") then
+end
+```
+
+## os.tryrm
+
+- 尝试删除文件或目录
+
+跟[os.rm](#os-rm)类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。
+
+```lua
+if os.tryrm("file") then
+end
+```
+
+## os.cd
+
+- 进入指定目录
+
+这个操作用于目录切换,同样也支持内置变量,但是不支持模式匹配和多目录处理,例如:
+
+```lua
+-- 进入临时目录
+os.cd("$(tmpdir)")
+```
+
+如果要离开进入之前的目录,有多种方式:
+
+```lua
+-- 进入上级目录
+os.cd("..")
+
+-- 进入先前的目录,相当于:cd -
+os.cd("-")
+
+-- 进入目录前保存之前的目录,用于之后跨级直接切回
+local oldir = os.cd("./src")
+...
+os.cd(oldir)
+```
+
+## os.rmdir
+
+- 仅删除目录
+
+如果不是目录就无法删除。
+
+## os.mkdir
+
+- 创建目录
+
+支持批量创建和内置变量,例如:
+
+```lua
+os.mkdir("$(tmpdir)/test", "$(buildir)/inc")
+```
+
+## os.isdir
+
+- 判断是否为目录
+
+如果目录不存在,则返回false
+
+```lua
+if os.isdir("src") then
+    -- ...
+end
+```
+
+## os.isfile
+
+- 判断是否为文件
+
+如果文件不存在,则返回false
+
+```lua
+if os.isfile("$(buildir)/libxxx.a") then
+    -- ...
+end
+```
+
+## os.exists
+
+- 判断文件或目录是否存在
+
+如果文件或目录不存在,则返回false
+
+```lua
+-- 判断目录存在
+if os.exists("$(buildir)") then
+    -- ...
+end
+
+-- 判断文件存在
+if os.exists("$(buildir)/libxxx.a") then
+    -- ...
+end
+```
+
+## os.dirs
+
+- 遍历获取指定目录下的所有目录
+
+支持[add_files](#targetadd_files)中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:
+
+```lua
+-- 递归遍历获取所有子目录
+for _, dir in ipairs(os.dirs("$(buildir)/inc/**")) do
+    print(dir)
+end
+```
+
+## os.files
+
+- 遍历获取指定目录下的所有文件
+
+支持[add_files](#targetadd_files)中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:
+
+```lua
+-- 非递归遍历获取所有子文件
+for _, filepath in ipairs(os.files("$(buildir)/inc/*.h")) do
+    print(filepath)
+end
+```
+
+## os.filedirs
+
+- 遍历获取指定目录下的所有文件和目录
+
+支持[add_files](#targetadd_files)中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:
+
+```lua
+-- 递归遍历获取所有子文件和目录
+for _, filedir in ipairs(os.filedirs("$(buildir)/**")) do
+    print(filedir)
+end
+```
+
+## os.run
+
+- 安静运行原生shell命令
+
+用于执行第三方的shell命令,但不会回显输出,仅仅在出错后,高亮输出错误信息。
+
+此接口支持参数格式化、内置变量,例如:
+
+```lua
+-- 格式化参数传入
+os.run("echo hello %s!", "xmake")
+
+-- 列举构建目录文件
+os.run("ls -l $(buildir)")
+```
+
+::: tip 注意
+使用此接口执行shell命令,容易使构建跨平台性降低,对于`os.run("cp ..")`这种尽量使用`os.cp`代替
+如果必须使用此接口运行shell程序,请自行使用[config.plat](#config-plat)接口判断平台支持。
+:::
+
+## os.runv
+
+- 安静运行原生shell命令,带参数列表
+
+跟[os.run](#os-run)类似,只是传递参数的方式是通过参数列表传递,而不是字符串命令,例如:
+
+```lua
+os.runv("echo", {"hello", "xmake!"})
+```
+
+另外,此接口也支持envs参数设置:
+
+```lua
+os.runv("echo", {"hello", "xmake!"}, {envs = {PATH = "xxx;xx", CFLAGS = "xx"}})
+```
+
+## os.exec
+
+- 回显运行原生shell命令
+
+与[os.run](#os-run)接口类似,唯一的不同是,此接口执行shell程序时,是带回显输出的,一般调试的时候用的比较多
+
+## os.execv
+
+- 回显运行原生shell命令,带参数列表
+
+跟[os.exec](#os-exec)类似,只是传递参数的方式是通过参数列表传递,而不是字符串命令,例如:
+
+```lua
+os.execv("echo", {"hello", "xmake!"})
+```
+
+另外,此接口还支持一个可选的参数,用于传递设置:重定向输出,执行环境变量设置,例如:
+
+```lua
+os.execv("echo", {"hello", "xmake!"}, {stdout = outfile, stderr = errfile, envs = {PATH = "xxx;xx", CFLAGS = "xx"}}
+```
+
+其中,stdout和stderr参数用于传递重定向输出和错误输出,可以直接传入文件路径,也可以传入io.open打开的文件对象。
+
+v2.5.1 之后的版本,我们还支持设置 stdin 参数,来支持重定向输入文件。
+
+::: tip 注意
+stdout/stderr/stdin 可以同时支持:文件路径、文件对象、管道对象等三种类型值。
+:::
+
+另外,如果想在这次执行中临时设置和改写一些环境变量,可以传递envs参数,里面的环境变量设置会替换已有的设置,但是不影响外层的执行环境,只影响当前命令。
+
+我们也可以通过`os.getenvs()`接口获取当前所有的环境变量,然后改写部分后传入envs参数。
+
+## os.iorun
+
+- 安静运行原生shell命令并获取输出内容
+
+与[os.run](#os-run)接口类似,唯一的不同是,此接口执行shell程序后,会获取shell程序的执行结果,相当于重定向输出。
+
+可同时获取`stdout`, `stderr`中的内容,例如:
+
+```lua
+local outdata, errdata = os.iorun("echo hello xmake!")
+```
+
+## os.iorunv
+
+- 安静运行原生shell命令并获取输出内容,带参数列表
+
+跟[os.iorun](#os-iorun)类似,只是传递参数的方式是通过参数列表传递,而不是字符串命令,例如:
+
+```lua
+local outdata, errdata = os.iorunv("echo", {"hello", "xmake!"})
+```
+
+另外,此接口也支持envs参数设置:
+
+```lua
+local outdata, errdata = os.iorunv("echo", {"hello", "xmake!"}, {envs = {PATH = "xxx;xx", CFLAGS = "xx"}}
+```
+
+## os.getenv
+
+- 获取系统环境变量
+
+```lua
+print(os.getenv("PATH"))
+```
+
+## os.setenv
+
+- 设置系统环境变量
+
+```lua
+os.setenv("HOME", "/tmp/")
+```
+
+## os.tmpdir
+
+- 获取临时目录
+
+跟[$(tmpdir)](#var-tmpdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
+
+```lua
+print(path.join(os.tmpdir(), "file.txt"))
+```
+
+等价于:
+
+```lua
+print("$(tmpdir)/file.txt")
+```
+
+## os.tmpfile
+
+- 获取临时文件路径
+
+用于获取生成一个临时文件路径,仅仅是个路径,文件需要自己创建。
+
+## os.curdir
+
+- 获取当前目录路径
+
+跟[$(curdir)](#var-curdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
+
+用法参考:[os.tmpdir](#os-tmpdir)。
+
+## os.filesize
+
+- 获取文件大小
+
+```lua
+print(os.filesize("/tmp/a"))
+```
+
+## os.scriptdir
+
+- 获取当前描述脚本的路径
+
+跟[$(scriptdir)](#var-scriptdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
+
+用法参考:[os.tmpdir](#os-tmpdir)。
+
+## os.programdir
+
+- 获取xmake安装主程序脚本目录
+
+跟[$(programdir)](#var-programdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
+
+## os.programfile
+
+- 获取xmake可执行文件路径
+
+## os.projectdir
+
+- 获取工程主目录
+
+跟[$(projectdir)](#var-projectdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。
+
+## os.arch
+
+- 获取当前系统架构
+
+也就是当前主机系统的默认架构,例如我在`linux x86_64`上执行xmake进行构建,那么返回值是:`x86_64`
+
+## os.host
+
+- 获取当前主机的操作系统
+
+跟[$(host)](#var-host)结果一致,例如我在`linux x86_64`上执行xmake进行构建,那么返回值是:`linux`
+
+## os.subhost
+
+- 获取当前子系统,如:在Windows上的msys、cygwin
+
+## os.subarch
+
+- 获取子系统架构
+
+## os.is_host
+
+- 判断给定系统是否为当前系统
+
+## os.is_arch
+
+- 判断给定架构是否为当前架构
+
+## os.is_subhost
+
+- 判断给定子系统是否为当前子系统
+
+## os.is_subarch
+
+- 判断给定子系统架构是否为当前子系统架构
+
+## os.ln
+
+- 为一个文件或目录创建符号链接
+
+```lua
+-- 创建一个指向 "tmp.txt" 文件的符号链接 "tmp.txt.ln"
+os.ln("xxx.txt", "xxx.txt.ln")
+```
+
+## os.readlink
+
+- 读取符号链接内容
+
+## os.raise
+
+- 抛出一个异常并且中止当前脚本运行
+
+```lua
+-- 抛出一个带 "an error occurred" 信息的异常
+os.raise("an error occurred")
+```
+
+::: tip 注意
+推荐使用与 `os.raise` 等价的内置接口 `raise`,用法与 `os.raise` 一致
+:::
+
+## os.raiselevel
+
+- 与 [os.raise](#os-raise) 类似但是可以指定异常等级
+
+```lua
+-- 抛出一个带 "an error occurred" 信息的异常
+os.raise(3, "an error occurred")
+```
+
+## os.features
+
+- 获取系统特性
+
+## os.getenvs
+
+- 获取所有当前系统变量
+
+```lua
+local envs = os.getenvs()
+-- home directory (on linux)
+print(envs["HOME"])
+```
+
+## os.setenvs
+
+- 使用给定系统变量替换当前所有系统变量,并返回旧系统变量
+
+## os.addenvs
+
+- 向当前系统变量添加新变量,并且返回所有旧系统变量
+
+```lua
+os.setenvs({EXAMPLE = "a/path"}) -- add a custom variable to see addenvs impact on it
+
+local oldenvs = os.addenvs({EXAMPLE = "some/path/"})
+print(os.getenvs()["EXAMPLE"]) --got some/path/;a/path
+print(oldenvs["EXAMPLE"]) -- got a/path
+```
+
+## os.joinenvs
+
+- 拼接系统变量,与 [os.addenvs](#os-addenvs) 类似,但是不会对当前环境变量产生影响,若第二个参数为 `nil`,则使用原有环境变量
+
+```lua
+-- os.joinenvs(envs, oldenvs)
+--
+-- @param envs      table 类型,新插入的环境变量
+--
+-- @param oldenvs   table 类型,被插入的环境变量,若为 nil, 则为原有环境变量
+--
+-- @return          table 类型,拼接后的环境变量
+local envs0 = {CUSTOM = "a/path"}
+local envs1 = {CUSTOM = "some/path/"}
+print(os.joinenvs(envs0, envs1)) -- result is : { CUSTION = "a/path;some/path/" }
+```
+
+## os.setenvp
+
+- 使用给定分隔符设置环境变量
+
+## os.workingdir
+
+- 获取工作目录
+
+## os.isroot
+
+- 判断xmake是否以管理员权限运行
+
+## os.fscase
+
+- 判断操作系统的文件系统是否大小写敏感
+
+## os.term
+
+- 获取当前终端 (windows-terminal, vscode, xterm, ...)
+
+## os.shell
+
+- 获取当前shell (pwsh, cmd, bash, zsh, ...)
+
+## os.cpuinfo
+
+- 获取当前CPU信息
+
+```lua
+print(os.cpuinfo())
+-- probably got {
+--   march = "Alder Lake",
+--   model = 154,
+--   ncpu = 20,
+--   model_name = "12th Gen Intel(R) Core(TM) i9-12900H",
+--   usagerate = 0.041839182376862,
+--   vendor = "GenuineIntel",
+--   family = 6
+-- }
+print(os.cpuinfo("march")) -- probably got "Alder Lake"
+```
+
+## os.meminfo
+
+- 获取内存信息
+
+```lua
+print(os.meminfo())
+-- probably got {
+--   pagesize = 4096,
+--   usagerate = 0.60694103194103,
+--   availsize = 12798,
+--   totalsize = 32560
+-- }
+print(os.meminfo("pagesize")) -- probably got 4096
+```
+
+## os.default_njob
+
+- 获取默认编译任务数

+ 0 - 0
docs/zh/api/scripts/native_modules.md → docs/zh/api/scripts/native-modules.md


+ 0 - 0
docs/zh/api/scripts/option_instance.md → docs/zh/api/scripts/option-instance.md


+ 0 - 0
docs/zh/api/scripts/package_instance.md → docs/zh/api/scripts/package-instance.md


+ 0 - 0
docs/zh/api/scripts/target_instance.md → docs/zh/api/scripts/target-instance.md


+ 12 - 4
docs/zh/config.ts

@@ -139,10 +139,18 @@ function descriptionApiGuide(): DefaultTheme.SidebarItem[] {
 
 function scriptsApiGuide(): DefaultTheme.SidebarItem[] {
   return [
-    { text: '目标实例', link: '/target_instance' },
-    { text: '选项实例', link: '/option_instance' },
-    { text: '包实例', link: '/package_instance' },
-    { text: '原生模块', link: '/native_modules' }
+    { text: '目标实例', link: '/target-instance' },
+    { text: '选项实例', link: '/option-instance' },
+    { text: '包实例', link: '/package-instance' },
+    {
+      text: '内建模块',
+      collapsed: false,
+      items: [
+        { text: 'import', link: '/builtin-modules/import' },
+        { text: 'os', link: '/builtin-modules/os' },
+      ]
+    },
+    { text: '原生模块', link: '/native-modules' }
   ]
 }