跳转到内容

os

系统操作模块,属于内置模块,无需使用import导入,可直接脚本域调用其接口。

此模块也是lua的原生模块,xmake在其基础上进行了扩展,提供更多实用的接口。

注意

os 模块里面只有部分readonly接口(例如:os.getenv, os.arch)是可以在描述域中使用,其他接口只能在脚本域中使用,例如:os.cp, os.rm

os.cp

  • 复制文件或目录

行为和shell中的cp命令类似,支持路径通配符匹配(使用的是lua模式匹配),支持多文件复制,以及内置变量支持。

例如:

lua
os.cp("$(scriptdir)/*.h", "$(builddir)/inc")
os.cp("$(projectdir)/src/test/**.h", "$(builddir)/inc")

上面的代码将:当前xmake.lua目录下的所有头文件、工程源码test目录下的头文件全部复制到$(builddir)输出目录中。

其中$(scriptdir), $(projectdir) 这些变量是xmake的内置变量,具体详情见:内置变量的相关文档。

*.h**.h中的匹配模式,跟add_files中的类似,前者是单级目录匹配,后者是递归多级目录匹配。

此接口同时支持目录的递归复制,例如:

lua
-- 递归复制当前目录到临时目录
os.cp("$(curdir)/test/", "$(tmpdir)/test")

上面的复制,会把所有文件全部展开复制到指定目录,丢失源目录层级,如果要按保持原有的目录结构复制,可以设置rootdir参数:

lua
os.cp("src/**.h", "/tmp/", {rootdir = "src"})

上面的脚本可以按src根目录,将src下的所有子文件保持目录结构复制过去。

注意

尽量使用os.cp接口,而不是os.run("cp .."),这样更能保证平台一致性,实现跨平台构建描述。

2.5.7 下,新增 {symlink = true} 参数,在复制文件时候保留符号链接。

lua
os.cp("/xxx/foo", "/xxx/bar", {symlink = true})

os.mv

  • 移动重命名文件或目录

os.cp的使用类似,同样支持多文件移动操作和模式匹配,例如:

lua
-- 移动文件到临时目录
os.mv("$(builddir)/test1", "$(tmpdir)")

-- 文件移动不支持批量操作,也就是文件重命名
os.mv("$(builddir)/libtest.a", "$(builddir)/libdemo.a")

os.rm

  • 删除文件或目录树

支持递归删除目录,批量删除操作,以及模式匹配和内置变量,例如:

lua
os.rm("$(builddir)/inc/**.h")
os.rm("$(builddir)/lib/")

os.trycp

  • 尝试复制文件或目录

os.cp类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。

lua
if os.trycp("file", "dest/file") then
end

os.trymv

  • 尝试移动文件或目录

os.mv类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。

lua
if os.trymv("file", "dest/file") then
end

os.tryrm

  • 尝试删除文件或目录

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", "$(builddir)/inc")

os.isdir

  • 判断是否为目录

如果目录不存在,则返回false

lua
if os.isdir("src") then
    -- ...
end

os.isfile

  • 判断是否为文件

如果文件不存在,则返回false

lua
if os.isfile("$(builddir)/libxxx.a") then
    -- ...
end

os.exists

  • 判断文件或目录是否存在

如果文件或目录不存在,则返回false

lua
-- 判断目录存在
if os.exists("$(builddir)") then
    -- ...
end

-- 判断文件存在
if os.exists("$(builddir)/libxxx.a") then
    -- ...
end

os.dirs

  • 遍历获取指定目录下的所有目录

支持add_files中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:

lua
-- 递归遍历获取所有子目录
for _, dir in ipairs(os.dirs("$(builddir)/inc/**")) do
    print(dir)
end

os.files

  • 遍历获取指定目录下的所有文件

支持add_files中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:

lua
-- 非递归遍历获取所有子文件
for _, filepath in ipairs(os.files("$(builddir)/inc/*.h")) do
    print(filepath)
end

os.filedirs

  • 遍历获取指定目录下的所有文件和目录

支持add_files中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:

lua
-- 递归遍历获取所有子文件和目录
for _, filedir in ipairs(os.filedirs("$(builddir)/**")) do
    print(filedir)
end

os.run

  • 安静运行原生shell命令

用于执行第三方的shell命令,但不会回显输出,仅仅在出错后,高亮输出错误信息。

此接口支持参数格式化、内置变量,例如:

lua
-- 格式化参数传入
os.run("echo hello %s!", "xmake")

-- 列举构建目录文件
os.run("ls -l $(builddir)")

注意

使用此接口执行shell命令,容易使构建跨平台性降低,对于os.run("cp ..")这种尽量使用os.cp代替 如果必须使用此接口运行shell程序,请自行使用config.plat接口判断平台支持。

os.runv

  • 安静运行原生shell命令,带参数列表

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接口类似,唯一的不同是,此接口执行shell程序时,是带回显输出的,一般调试的时候用的比较多

os.execv

  • 回显运行原生shell命令,带参数列表

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 参数,来支持重定向输入文件。

注意

stdout/stderr/stdin 可以同时支持:文件路径、文件对象、管道对象等三种类型值。

另外,如果想在这次执行中临时设置和改写一些环境变量,可以传递envs参数,里面的环境变量设置会替换已有的设置,但是不影响外层的执行环境,只影响当前命令。

我们也可以通过os.getenvs()接口获取当前所有的环境变量,然后改写部分后传入envs参数。

os.iorun

  • 安静运行原生shell命令并获取输出内容

os.run接口类似,唯一的不同是,此接口执行shell程序后,会获取shell程序的执行结果,相当于重定向输出。

可同时获取stdout, stderr中的内容,例如:

lua
local outdata, errdata = os.iorun("echo hello xmake!")

os.iorunv

  • 安静运行原生shell命令并获取输出内容,带参数列表

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)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。

lua
print(path.join(os.tmpdir(), "file.txt"))

等价于:

lua
print("$(tmpdir)/file.txt")

os.tmpfile

  • 获取临时文件路径

用于获取生成一个临时文件路径,仅仅是个路径,文件需要自己创建。

os.curdir

  • 获取当前目录路径

$(curdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。

用法参考:os.tmpdir

os.filesize

  • 获取文件大小
lua
print(os.filesize("/tmp/a"))

os.scriptdir

  • 获取当前描述脚本的路径

$(scriptdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。

用法参考:os.tmpdir

os.programdir

  • 获取xmake安装主程序脚本目录

$(programdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。

os.programfile

  • 获取xmake可执行文件路径

os.projectdir

  • 获取工程主目录

$(projectdir)结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。

os.arch

  • 获取当前系统架构

也就是当前主机系统的默认架构,例如我在linux x86_64上执行xmake进行构建,那么返回值是:x86_64

os.host

  • 获取当前主机的操作系统

$(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.raise

  • 抛出一个异常并且中止当前脚本运行
lua
-- 抛出一个带 "an error occurred" 信息的异常
os.raise("an error occurred")

注意

推荐使用与 os.raise 等价的内置接口 raise,用法与 os.raise 一致

os.raiselevel

  • 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 类似,但是不会对当前环境变量产生影响,若第二个参数为 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

  • 获取默认编译任务数