builtin_modules.html 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>xmake</title>
  6. <link rel="icon" href="/assets/img/favicon.ico">
  7. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  8. <meta name="description" content="Description">
  9. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  10. <link href="/assets/npm/github-markdown/github-markdown.min.css" rel="stylesheet">
  11. <style>
  12. .markdown-body {
  13. box-sizing: border-box;
  14. min-width: 200px;
  15. max-width: 980px;
  16. margin: 0 auto;
  17. padding: 45px;
  18. }
  19. @media (max-width: 767px) {
  20. .markdown-body {
  21. padding: 15px;
  22. }
  23. }
  24. </style>
  25. </head>
  26. <body>
  27. <article class="markdown-body">
  28. <h4>This is a mirror page, please see the original page: </h4><a href="https://xmake.io/#/zh-cn/manual/builtin_modules">https://xmake.io/#/zh-cn/manual/builtin_modules</a>
  29. <div id="wwads-panel" class="wwads-cn wwads-vertical wwads-sticky" data-id="239" style="max-width:180px;bottom:20px;right:20px;width:200px;height:260px;background:#fff;position:fixed"></div>
  30. </br>
  31. <script type="text/javascript" charset="UTF-8" src="https://cdn.wwads.cn/js/makemoney.js" async></script>
  32. <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CE7I52QU&placement=xmakeio" id="_carbonads_js"></script>
  33. <style>
  34. #carbonads {
  35. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu,
  36. Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
  37. }
  38. #carbonads {
  39. display: flex;
  40. max-width: 330px;
  41. background-color: hsl(0, 0%, 98%);
  42. box-shadow: 0 1px 4px 1px hsla(0, 0%, 0%, .1);
  43. }
  44. #carbonads a {
  45. color: inherit;
  46. text-decoration: none;
  47. }
  48. #carbonads a:hover {
  49. color: inherit;
  50. }
  51. #carbonads span {
  52. position: relative;
  53. display: block;
  54. overflow: hidden;
  55. }
  56. #carbonads .carbon-wrap {
  57. display: flex;
  58. }
  59. .carbon-img {
  60. display: block;
  61. margin: 0;
  62. line-height: 1;
  63. }
  64. .carbon-img img {
  65. display: block;
  66. }
  67. .carbon-text {
  68. font-size: 13px;
  69. padding: 10px;
  70. line-height: 1.5;
  71. text-align: left;
  72. }
  73. .carbon-poweredby {
  74. display: block;
  75. padding: 8px 10px;
  76. background: repeating-linear-gradient(-45deg, transparent, transparent 5px, hsla(0, 0%, 0%, .025) 5px, hsla(0, 0%, 0%, .025) 10px) hsla(203, 11%, 95%, .4);
  77. text-align: center;
  78. text-transform: uppercase;
  79. letter-spacing: .5px;
  80. font-weight: 600;
  81. font-size: 9px;
  82. line-height: 1;
  83. }
  84. </style>
  85. <p>在自定义脚本、插件脚本、任务脚本、平台扩展、模板扩展等脚本代码中使用,也就是在类似下面的代码块中,可以使用这些模块接口:</p>
  86. <pre><code class="lang-lua">on_run(function (target)
  87. print("hello xmake!")
  88. end)
  89. </code></pre>
  90. <p>!> 为了保证外层的描述域尽可能简洁、安全,一般不建议在这个域使用接口和模块操作api,因此大部分模块接口只能脚本域使用,来实现复杂功能。</br><br>当然少部分只读的内置接口还是可以在描述域使用的,具体见下表:</p>
  91. <p>在描述域使用接口调用的实例如下,一般仅用于条件控制:</p>
  92. <pre><code class="lang-lua">-- 扫描当前xmake.lua目录下的所有子目录,以每个目录的名字定义一个task任务
  93. for _, taskname in ipairs(os.dirs("*"), path.basename) do
  94. task(taskname)
  95. on_run(function ()
  96. end)
  97. end
  98. </code></pre>
  99. <p>上面所说的脚本域、描述域主要是指:</p>
  100. <pre><code class="lang-lua">-- 描述域
  101. target("test")
  102. -- 描述域
  103. set_kind("static")
  104. add_files("src/*.c")
  105. on_run(function (target)
  106. -- 脚本域
  107. end)
  108. -- 描述域
  109. </code></pre>
  110. <h3 id="import">import</h3>
  111. <h4 id="">导入扩展摸块</h4>
  112. <p>import的主要用于导入xmake的扩展类库以及一些自定义的类库模块,一般用于:</p>
  113. <ul>
  114. <li>自定义脚本(<a href="/mirror/zh-cn/manual/project_target.html#targeton_build">on_build</a>, <a href="/mirror/zh-cn/manual/project_target.html#targeton_run">on_run</a> ..)</li>
  115. <li>插件开发</li>
  116. <li>模板开发</li>
  117. <li>平台扩展</li>
  118. <li>自定义任务task</li>
  119. </ul>
  120. <p>导入机制如下:</p>
  121. <ol>
  122. <li>优先从当前脚本目录下导入</li>
  123. <li>再从扩展类库中导入</li>
  124. </ol>
  125. <p>导入的语法规则:</p>
  126. <p>基于<code>.</code>的类库路径规则,例如:</p>
  127. <pre><code class="lang-lua">import("core.base.option")
  128. import("core.base.task")
  129. function main()
  130. -- 获取参数选项
  131. print(option.get("version"))
  132. -- 运行任务和插件
  133. task.run("hello")
  134. end
  135. </code></pre>
  136. <p>导入当前目录下的自定义模块:</p>
  137. <p>目录结构:</p>
  138. <pre><code>plugin
  139. - xmake.lua
  140. - main.lua
  141. - modules
  142. - hello1.lua
  143. - hello2.lua
  144. </code></pre><p>在main.lua中导入modules</p>
  145. <pre><code class="lang-lua">import("modules.hello1")
  146. import("modules.hello2")
  147. </code></pre>
  148. <p>导入后就可以直接使用里面的所有公有接口,私有接口用<code>_</code>前缀标示,表明不会被导出,不会被外部调用到。。</p>
  149. <p>除了当前目录,我们还可以导入其他指定目录里面的类库,例如:</p>
  150. <pre><code class="lang-lua">import("hello3", {rootdir = "/home/xxx/modules"})
  151. </code></pre>
  152. <p>为了防止命名冲突,导入后还可以指定的别名:</p>
  153. <pre><code class="lang-lua">import("core.platform.platform", {alias = "p"})
  154. function main()
  155. -- 这样我们就可以使用p来调用platform模块的plats接口,获取所有xmake支持的平台列表了
  156. utils.dump(p.plats())
  157. end
  158. </code></pre>
  159. <p>import不仅可以导入类库,还支持导入的同时作为继承导入,实现模块间的继承关系</p>
  160. <pre><code class="lang-lua">import("xxx.xxx", {inherit = true})
  161. </code></pre>
  162. <p>这样导入的不是这个模块的引用,而是导入的这个模块的所有公有接口本身,这样就会跟当前模块的接口进行合并,实现模块间的继承。</p>
  163. <p>2.1.5版本新增两个新属性:<code>import("xxx.xxx", {try = true, anonymous = true})</code></p>
  164. <p>try为true,则导入的模块不存在的话,仅仅返回nil,并不会抛异常后中断xmake.<br>anonymous为true,则导入的模块不会引入当前作用域,仅仅在import接口返回导入的对象引用。</p>
  165. <h4 id="">自定义扩展模块</h4>
  166. <p>通过 import 我们除了可以导入 xmake 内置的很多扩展模块,还可以导入用户自己定义的扩展模块。</p>
  167. <p>只需要将自己的模块放到工程目录下,按照上文介绍的导入方式进行导入即可。</p>
  168. <p>那么,如果去定义模块呢?xmake 对模块的编写规范是有一套约定规则的,并没有沿用 lua 原生的 require 导入机制,并不需要在模块中使用 return 来全局返回它。</p>
  169. <p>假如我们有一个模块文件 foo.lua,它的内容如下:</p>
  170. <pre><code class="lang-lua">function _foo(a, b)
  171. return a + b
  172. end
  173. function add(a, b)
  174. _foo(a, b)
  175. end
  176. function main(a, b)
  177. add(a, b)
  178. end
  179. </code></pre>
  180. <p>其中 main 为入口函数,可选,如果设置,模块 foo 可以直接被调用,例如:</p>
  181. <pre><code class="lang-lua">import("foo")
  182. foo(1, 2)
  183. </code></pre>
  184. <p>或者直接这样:</p>
  185. <pre><code class="lang-lua">import("foo")(1, 2)
  186. </code></pre>
  187. <p>其他不带下划线的为 public 模块接口函数,例如 add。</p>
  188. <pre><code class="lang-lua">import("foo")
  189. foo.add(1, 2)
  190. </code></pre>
  191. <p>而里面带下划线前缀的 <code>_foo</code> 是私有函数,模块内部使用,不对外导出,所以在外面用户是不能够调用它的。</p>
  192. <h3 id="inherit">inherit</h3>
  193. <h4 id="">导入并继承基类模块</h4>
  194. <p>这个等价于<a href="#import">import</a>接口的<code>inherit</code>模式,也就是:</p>
  195. <pre><code class="lang-lua">import("xxx.xxx", {inherit = true})
  196. </code></pre>
  197. <p>用<code>inherit</code>接口的话,会更简洁些:</p>
  198. <pre><code class="lang-lu">inherit("xxx.xxx")
  199. </code></pre>
  200. <p>使用实例,可以参看xmake的tools目录下的脚本:<a href="#https://github.com/xmake-io/xmake/blob/master/xmake/tools/clang.lua">clang.lua</a></p>
  201. <p>这个就是clang工具模块继承了gcc的部分实现。</p>
  202. <h3 id="trycatchfinally">try-catch-finally</h3>
  203. <h4 id="">异常捕获</h4>
  204. <p>lua原生并没有提供try-catch的语法来捕获异常处理,但是提供了<code>pcall/xpcall</code>等接口,可在保护模式下执行lua函数。</p>
  205. <p>因此,可以通过封装这两个接口,来实现try-catch块的捕获机制。</p>
  206. <p>我们可以先来看下,封装后的try-catch使用方式:</p>
  207. <pre><code class="lang-lua">try
  208. {
  209. -- try 代码块
  210. function ()
  211. error("error message")
  212. end,
  213. -- catch 代码块
  214. catch
  215. {
  216. -- 发生异常后,被执行
  217. function (errors)
  218. print(errors)
  219. end
  220. }
  221. }
  222. </code></pre>
  223. <p>上面的代码中,在try块内部认为引发了一个异常,并且抛出错误消息,在catch中进行了捕获,并且将错误消息进行输出显示。</p>
  224. <p>而finally的处理,这个的作用是对于<code>try{}</code>代码块,不管是否执行成功,都会执行到finally块中</p>
  225. <p>也就说,其实上面的实现,完整的支持语法是:<code>try-catch-finally</code>模式,其中catch和finally都是可选的,根据自己的实际需求提供</p>
  226. <p>例如:</p>
  227. <pre><code class="lang-lua">try
  228. {
  229. -- try 代码块
  230. function ()
  231. error("error message")
  232. end,
  233. -- catch 代码块
  234. catch
  235. {
  236. -- 发生异常后,被执行
  237. function (errors)
  238. print(errors)
  239. end
  240. },
  241. -- finally 代码块
  242. finally
  243. {
  244. -- 最后都会执行到这里
  245. function (ok, errors)
  246. -- 如果try{}中存在异常,ok为true,errors为错误信息,否则为false,errors为try中的返回值
  247. end
  248. }
  249. }
  250. </code></pre>
  251. <p>或者只有finally块:</p>
  252. <pre><code class="lang-lua">try
  253. {
  254. -- try 代码块
  255. function ()
  256. return "info"
  257. end,
  258. -- finally 代码块
  259. finally
  260. {
  261. -- 由于此try代码没发生异常,因此ok为true,errors为返回值: "info"
  262. function (ok, errors)
  263. end
  264. }
  265. }
  266. </code></pre>
  267. <p>处理可以在finally中获取try里面的正常返回值,其实在仅有try的情况下,也是可以获取返回值的:</p>
  268. <pre><code class="lang-lua">-- 如果没发生异常,result 为返回值:"xxxx",否则为nil
  269. local result = try
  270. {
  271. function ()
  272. return "xxxx"
  273. end
  274. }
  275. </code></pre>
  276. <p>在xmake的自定义脚本、插件开发中,也是完全基于此异常捕获机制</p>
  277. <p>这样使得扩展脚本的开发非常的精简可读,省去了繁琐的<code>if err ~= nil then</code>返回值判断,在发生错误时,xmake会直接抛出异常进行中断,然后高亮提示详细的错误信息。</p>
  278. <p>例如:</p>
  279. <pre><code class="lang-lua">target("test")
  280. set_kind("binary")
  281. add_files("src/*.c")
  282. -- 在编译完ios程序后,对目标程序进行ldid签名
  283. after_build(function (target))
  284. os.run("ldid -S %s", target:targetfile())
  285. end
  286. </code></pre>
  287. <p>只需要一行<code>os.run</code>就行了,也不需要返回值判断是否运行成功,因为运行失败后,xmake会自动抛异常,中断程序并且提示错误</p>
  288. <p>如果你想在运行失败后,不直接中断xmake,继续往下运行,可以自己加个try快就行了:</p>
  289. <pre><code class="lang-lua">target("test")
  290. set_kind("binary")
  291. add_files("src/*.c")
  292. after_build(function (target))
  293. try
  294. {
  295. function ()
  296. os.run("ldid -S %s", target:targetfile())
  297. end
  298. }
  299. end
  300. </code></pre>
  301. <p>如果还想捕获出错信息,可以再加个catch:</p>
  302. <pre><code class="lang-lua">target("test")
  303. set_kind("binary")
  304. add_files("src/*.c")
  305. after_build(function (target))
  306. try
  307. {
  308. function ()
  309. os.run("ldid -S %s", target:targetfile())
  310. end,
  311. catch
  312. {
  313. function (errors)
  314. print(errors)
  315. end
  316. }
  317. }
  318. end
  319. </code></pre>
  320. <p>不过一般情况下,在xmake中写自定义脚本,是不需要手动加try-catch的,直接调用各种api,出错后让xmake默认的处理程序接管,直接中断就行了。。</p>
  321. <h3 id="pairs">pairs</h3>
  322. <h4 id="">用于遍历字典</h4>
  323. <p>这个是lua原生的内置api,在xmake中,在原有的行为上对其进行了一些扩展,来简化一些日常的lua遍历代码。</p>
  324. <p>先看下默认的原生写法:</p>
  325. <pre><code class="lang-lua">local t = {a = "a", b = "b", c = "c", d = "d", e = "e", f = "f"}
  326. for key, val in pairs(t) do
  327. print("%s: %s", key, val)
  328. end
  329. </code></pre>
  330. <p>这对于通常的遍历操作就足够了,但是如果我们相对其中每个遍历出来的元素,获取其大写,我们可以这么写:</p>
  331. <pre><code class="lang-lua">for key, val in pairs(t, function (v) return v:upper() end) do
  332. print("%s: %s", key, val)
  333. end
  334. </code></pre>
  335. <p>甚至传入一些参数到第二个<code>function</code>中,例如:</p>
  336. <pre><code class="lang-lua">for key, val in pairs(t, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do
  337. print("%s: %s", key, val)
  338. end
  339. </code></pre>
  340. <h3 id="ipairs">ipairs</h3>
  341. <h4 id="">用于遍历数组</h4>
  342. <p>这个是lua原生的内置api,在xmake中,在原有的行为上对其进行了一些扩展,来简化一些日常的lua遍历代码。</p>
  343. <p>先看下默认的原生写法:</p>
  344. <pre><code class="lang-lua">for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}) do
  345. print("%d %s", idx, val)
  346. end
  347. </code></pre>
  348. <p>扩展写法类似<a href="#pairs">pairs</a>接口,例如:</p>
  349. <pre><code class="lang-lua">for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}, function (v) return v:upper() end) do
  350. print("%d %s", idx, val)
  351. end
  352. for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do
  353. print("%d %s", idx, val)
  354. end
  355. </code></pre>
  356. <p>这样可以简化<code>for</code>块代码的逻辑,例如我要遍历指定目录,获取其中的文件名,但不包括路径,就可以通过这种扩展方式,简化写法:</p>
  357. <pre><code class="lang-lua">for _, filename in ipairs(os.dirs("*"), path.filename) do
  358. -- ...
  359. end
  360. </code></pre>
  361. <h3 id="print">print</h3>
  362. <h4 id="">换行打印终端日志</h4>
  363. <p>此接口也是lua的原生接口,xmake在原有行为不变的基础上也进行了扩展,同时支持:格式化输出、多变量输出。</p>
  364. <p>先看下原生支持的方式:</p>
  365. <pre><code class="lang-lua">print("hello xmake!")
  366. print("hello", "xmake!", 123)
  367. </code></pre>
  368. <p>并且同时还支持扩展的格式化写法:</p>
  369. <pre><code class="lang-lua">print("hello %s!", "xmake")
  370. print("hello xmake! %d", 123)
  371. </code></pre>
  372. <p>xmake会同时支持这两种写法,内部会去自动智能检测,选择输出行为。</p>
  373. <h3 id="printf">printf</h3>
  374. <h4 id="">无换行打印终端日志</h4>
  375. <p>类似<a href="#print">print</a>接口,唯一的区别就是不换行。</p>
  376. <h3 id="cprint">cprint</h3>
  377. <h4 id="">换行彩色打印终端日志</h4>
  378. <p>行为类似<a href="#print">print</a>,区别就是此接口还支持彩色终端输出,并且支持<code>emoji</code>字符输出。</p>
  379. <p>例如:</p>
  380. <pre><code class="lang-lua"> cprint(&#39;${bright}hello xmake&#39;)
  381. cprint(&#39;${red}hello xmake&#39;)
  382. cprint(&#39;${bright green}hello ${clear}xmake&#39;)
  383. cprint(&#39;${blue onyellow underline}hello xmake${clear}&#39;)
  384. cprint(&#39;${red}hello ${magenta}xmake&#39;)
  385. cprint(&#39;${cyan}hello ${dim yellow}xmake&#39;)
  386. </code></pre>
  387. <p>显示结果如下:</p>
  388. <p><img src="https://tboox.org/static/img/xmake/cprint_colors.png" alt="cprint_colors"></p>
  389. <p>跟颜色相关的描述,都放置在 <code>${ }</code> 里面,可以同时设置多个不同的属性,例如:</p>
  390. <pre><code> ${bright red underline onyellow}
  391. </code></pre><p>表示:高亮红色,背景黄色,并且带下滑线</p>
  392. <p>所有这些描述,都会影响后面一整行字符,如果只想显示部分颜色的文字,可以在结束位置,插入<code>${clear}</code>清楚前面颜色描述</p>
  393. <p>例如:</p>
  394. <pre><code> ${red}hello ${clear}xmake
  395. </code></pre><p>这样的话,仅仅hello是显示红色,其他还是正常默认黑色显示。</p>
  396. <p>其他颜色属于,我这里就不一一介绍,直接贴上xmake代码里面的属性列表吧:</p>
  397. <pre><code class="lang-lua"> colors.keys =
  398. {
  399. -- 属性
  400. reset = 0 -- 重置属性
  401. , clear = 0 -- 清楚属性
  402. , default = 0 -- 默认属性
  403. , bright = 1 -- 高亮
  404. , dim = 2 -- 暗色
  405. , underline = 4 -- 下划线
  406. , blink = 5 -- 闪烁
  407. , reverse = 7 -- 反转颜色
  408. , hidden = 8 -- 隐藏文字
  409. -- 前景色
  410. , black = 30
  411. , red = 31
  412. , green = 32
  413. , yellow = 33
  414. , blue = 34
  415. , magenta = 35
  416. , cyan = 36
  417. , white = 37
  418. -- 背景色
  419. , onblack = 40
  420. , onred = 41
  421. , ongreen = 42
  422. , onyellow = 43
  423. , onblue = 44
  424. , onmagenta = 45
  425. , oncyan = 46
  426. , onwhite = 47
  427. </code></pre>
  428. <p>除了可以色彩高亮显示外,如果你的终端是在macosx下,lion以上的系统,xmake还可以支持emoji表情的显示哦,对于不支持系统,会<br>忽略显示,例如:</p>
  429. <pre><code class="lang-lua"> cprint("hello xmake${beer}")
  430. cprint("hello${ok_hand} xmake")
  431. </code></pre>
  432. <p>上面两行代码,我打印了一个homebrew里面经典的啤酒符号,下面那行打印了一个ok的手势符号,是不是很炫哈。。</p>
  433. <p><img src="https://tboox.org/static/img/xmake/cprint_emoji.png" alt="cprint_emoji"></p>
  434. <p>所有的emoji表情,以及xmake里面对应的key,都可以通过<a href="http://www.emoji-cheat-sheet.com/">emoji符号</a>里面找到。。</p>
  435. <p>2.1.7版本支持24位真彩色输出,如果终端支持的话:</p>
  436. <pre><code class="lang-lua">import("core.base.colors")
  437. if colors.truecolor() then
  438. cprint("${255;0;0}hello")
  439. cprint("${on;255;0;0}hello${clear} xmake")
  440. cprint("${bright 255;0;0 underline}hello")
  441. cprint("${bright on;255;0;0 0;255;0}hello${clear} xmake")
  442. end
  443. </code></pre>
  444. <p>xmake对于truecolor的检测支持,是通过<code>$COLORTERM</code>环境变量来实现的,如果你的终端支持truecolor,可以手动设置此环境变量,来告诉xmake启用truecolor支持。</p>
  445. <p>可以通过下面的命令来启用和测试:</p>
  446. <pre><code class="lang-bash">$ export COLORTERM=truecolor
  447. $ xmake --version
  448. </code></pre>
  449. <p>2.1.7版本可通过<code>COLORTERM=nocolor</code>来禁用色彩输出。</p>
  450. <h3 id="cprintf">cprintf</h3>
  451. <h4 id="">无换行彩色打印终端日志</h4>
  452. <p>此接口类似<a href="#cprint">cprint</a>,区别就是不换行输出。</p>
  453. <h3 id="format">format</h3>
  454. <h4 id="">格式化字符串</h4>
  455. <p>如果只是想格式化字符串,不进行输出,可以使用这个接口,此接口跟<a href="#stringformat">string.format</a>接口等价,只是个接口名简化版。</p>
  456. <pre><code class="lang-lua">local s = format("hello %s", xmake)
  457. </code></pre>
  458. <h3 id="vformat">vformat</h3>
  459. <h4 id="">格式化字符串,支持内置变量转义</h4>
  460. <p>此接口跟<a href="#format">format</a>接口类似,只是增加对内置变量的获取和转义支持。</p>
  461. <pre><code class="lang-lua">local s = vformat("hello %s $(mode) $(arch) $(env PATH)", xmake)
  462. </code></pre>
  463. <h3 id="raise">raise</h3>
  464. <h4 id="">抛出异常中断程序</h4>
  465. <p>如果想在自定义脚本、插件任务中中断xmake运行,可以使用这个接口抛出异常,如果上层没有显示调用<a href="#try-catch-finally">try-catch</a>捕获的话,xmake就会中断执行,并且显示出错信息。</p>
  466. <pre><code class="lang-lua">if (errors) raise(errors)
  467. </code></pre>
  468. <p>如果在try块中抛出异常,就会在catch和finally中进行errors信息捕获,具体见:<a href="#try-catch-finally">try-catch</a></p>
  469. <h3 id="os">os</h3>
  470. <p>系统操作模块,属于内置模块,无需使用<a href="#import">import</a>导入,可直接脚本域调用其接口。</p>
  471. <p>此模块也是lua的原生模块,xmake在其基础上进行了扩展,提供更多实用的接口。</p>
  472. <p>!> os模块里面只有部分readonly接口(例如:<code>os.getenv</code>, <code>os.arch</code>)是可以在描述域中使用,其他接口只能在脚本域中使用,例如:<code>os.cp</code>, <code>os.rm</code>等</p>
  473. <table>
  474. <thead>
  475. <tr>
  476. <th>接口</th>
  477. <th>描述</th>
  478. <th>支持版本</th>
  479. </tr>
  480. </thead>
  481. <tbody>
  482. <tr>
  483. <td><a href="#oscp">os.cp</a></td>
  484. <td>复制文件或目录</td>
  485. <td>>= 2.0.1</td>
  486. </tr>
  487. <tr>
  488. <td><a href="#osmv">os.mv</a></td>
  489. <td>移动重命名文件或目录</td>
  490. <td>>= 2.0.1</td>
  491. </tr>
  492. <tr>
  493. <td><a href="#osrm">os.rm</a></td>
  494. <td>删除文件或目录树</td>
  495. <td>>= 2.0.1</td>
  496. </tr>
  497. <tr>
  498. <td><a href="#ostrycp">os.trycp</a></td>
  499. <td>尝试复制文件或目录</td>
  500. <td>>= 2.1.6</td>
  501. </tr>
  502. <tr>
  503. <td><a href="#ostrymv">os.trymv</a></td>
  504. <td>尝试移动重命名文件或目录</td>
  505. <td>>= 2.1.6</td>
  506. </tr>
  507. <tr>
  508. <td><a href="#ostryrm">os.tryrm</a></td>
  509. <td>尝试删除文件或目录树</td>
  510. <td>>= 2.1.6</td>
  511. </tr>
  512. <tr>
  513. <td><a href="#oscd">os.cd</a></td>
  514. <td>进入指定目录</td>
  515. <td>>= 2.0.1</td>
  516. </tr>
  517. <tr>
  518. <td><a href="#osrmdir">os.rmdir</a></td>
  519. <td>删除目录树</td>
  520. <td>>= 2.0.1</td>
  521. </tr>
  522. <tr>
  523. <td><a href="#osmkdir">os.mkdir</a></td>
  524. <td>创建指定目录</td>
  525. <td>>= 2.0.1</td>
  526. </tr>
  527. <tr>
  528. <td><a href="#osisdir">os.isdir</a></td>
  529. <td>判断目录是否存在</td>
  530. <td>>= 2.0.1</td>
  531. </tr>
  532. <tr>
  533. <td><a href="#osisfile">os.isfile</a></td>
  534. <td>判断文件是否存在</td>
  535. <td>>= 2.0.1</td>
  536. </tr>
  537. <tr>
  538. <td><a href="#osexists">os.exists</a></td>
  539. <td>判断文件或目录是否存在</td>
  540. <td>>= 2.0.1</td>
  541. </tr>
  542. <tr>
  543. <td><a href="#osdirs">os.dirs</a></td>
  544. <td>遍历获取指定目录下的所有目录</td>
  545. <td>>= 2.0.1</td>
  546. </tr>
  547. <tr>
  548. <td><a href="#osfiles">os.files</a></td>
  549. <td>遍历获取指定目录下的所有文件</td>
  550. <td>>= 2.0.1</td>
  551. </tr>
  552. <tr>
  553. <td><a href="#osfiledirs">os.filedirs</a></td>
  554. <td>遍历获取指定目录下的所有文件或目录</td>
  555. <td>>= 2.0.1</td>
  556. </tr>
  557. <tr>
  558. <td><a href="#osrun">os.run</a></td>
  559. <td>安静运行程序</td>
  560. <td>>= 2.0.1</td>
  561. </tr>
  562. <tr>
  563. <td><a href="#osrunv">os.runv</a></td>
  564. <td>安静运行程序,带参数列表</td>
  565. <td>>= 2.1.5</td>
  566. </tr>
  567. <tr>
  568. <td><a href="#osexec">os.exec</a></td>
  569. <td>回显运行程序</td>
  570. <td>>= 2.0.1</td>
  571. </tr>
  572. <tr>
  573. <td><a href="#osexecv">os.execv</a></td>
  574. <td>回显运行程序,带参数列表</td>
  575. <td>>= 2.1.5</td>
  576. </tr>
  577. <tr>
  578. <td><a href="#osiorun">os.iorun</a></td>
  579. <td>运行并获取程序输出内容</td>
  580. <td>>= 2.0.1</td>
  581. </tr>
  582. <tr>
  583. <td><a href="#osiorunv">os.iorunv</a></td>
  584. <td>运行并获取程序输出内容,带参数列表</td>
  585. <td>>= 2.1.5</td>
  586. </tr>
  587. <tr>
  588. <td><a href="#osgetenv">os.getenv</a></td>
  589. <td>获取环境变量</td>
  590. <td>>= 2.0.1</td>
  591. </tr>
  592. <tr>
  593. <td><a href="#ossetenv">os.setenv</a></td>
  594. <td>设置环境变量</td>
  595. <td>>= 2.0.1</td>
  596. </tr>
  597. <tr>
  598. <td><a href="#ostmpdir">os.tmpdir</a></td>
  599. <td>获取临时目录路径</td>
  600. <td>>= 2.0.1</td>
  601. </tr>
  602. <tr>
  603. <td><a href="#ostmpfile">os.tmpfile</a></td>
  604. <td>获取临时文件路径</td>
  605. <td>>= 2.0.1</td>
  606. </tr>
  607. <tr>
  608. <td><a href="#oscurdir">os.curdir</a></td>
  609. <td>获取当前目录路径</td>
  610. <td>>= 2.0.1</td>
  611. </tr>
  612. <tr>
  613. <td><a href="#osfilesize">os.filesize</a></td>
  614. <td>获取文件大小</td>
  615. <td>>= 2.1.9</td>
  616. </tr>
  617. <tr>
  618. <td><a href="#osscriptdir">os.scriptdir</a></td>
  619. <td>获取脚本目录路径</td>
  620. <td>>= 2.0.1</td>
  621. </tr>
  622. <tr>
  623. <td><a href="#osprogramdir">os.programdir</a></td>
  624. <td>获取xmake安装主程序脚本目录</td>
  625. <td>>= 2.1.5</td>
  626. </tr>
  627. <tr>
  628. <td><a href="#osprogramfile">os.programfile</a></td>
  629. <td>获取xmake可执行文件路径</td>
  630. <td>>= 2.1.5</td>
  631. </tr>
  632. <tr>
  633. <td><a href="#osprojectdir">os.projectdir</a></td>
  634. <td>获取工程主目录</td>
  635. <td>>= 2.1.5</td>
  636. </tr>
  637. <tr>
  638. <td><a href="#osarch">os.arch</a></td>
  639. <td>获取当前系统架构</td>
  640. <td>>= 2.0.1</td>
  641. </tr>
  642. <tr>
  643. <td><a href="#oshost">os.host</a></td>
  644. <td>获取当前主机系统</td>
  645. <td>>= 2.0.1</td>
  646. </tr>
  647. <tr>
  648. <td><a href="#ossubhost">os.subhost</a></td>
  649. <td>获取子系统</td>
  650. <td>>= 2.3.1</td>
  651. </tr>
  652. <tr>
  653. <td><a href="#ossubarch">os.subarch</a></td>
  654. <td>获取子系统架构</td>
  655. <td>>= 2.3.1</td>
  656. </tr>
  657. <tr>
  658. <td><a href="#osis_host">os.is_host</a></td>
  659. <td>判断给定系统是否正确</td>
  660. <td>>= 2.3.1</td>
  661. </tr>
  662. <tr>
  663. <td><a href="#osis_arch">os.is_arch</a></td>
  664. <td>判断给定架构是否正确</td>
  665. <td>>= 2.3.1</td>
  666. </tr>
  667. <tr>
  668. <td><a href="#osis_subhost">os.is_subhost</a></td>
  669. <td>判断给定子系统是否正确</td>
  670. <td>>= 2.3.1</td>
  671. </tr>
  672. <tr>
  673. <td><a href="#osis_subarch">os.is_subarch</a></td>
  674. <td>判断子系统架构是否正确</td>
  675. <td>>= 2.3.1</td>
  676. </tr>
  677. <tr>
  678. <td><a href="#osln">os.ln</a></td>
  679. <td>创建指向文件或文件夹的符号链接</td>
  680. <td>>= 2.2.2</td>
  681. </tr>
  682. <tr>
  683. <td><a href="#osreadlink">os.readlink</a></td>
  684. <td>读取符号链接</td>
  685. <td>>= 2.2.2</td>
  686. </tr>
  687. <tr>
  688. <td><a href="#osraise">os.raise</a></td>
  689. <td>抛出一个异常并中止脚本运行</td>
  690. <td>>= 2.2.8</td>
  691. </tr>
  692. <tr>
  693. <td><a href="#osraiselevel">os.raiselevel</a></td>
  694. <td>抛出一个异常并中止脚本运行</td>
  695. <td>>= 2.2.8</td>
  696. </tr>
  697. <tr>
  698. <td><a href="#osfeatures">os.features</a></td>
  699. <td>获取系统特性</td>
  700. <td>>= 2.3.1</td>
  701. </tr>
  702. <tr>
  703. <td><a href="#osgetenvs">os.getenvs</a></td>
  704. <td>获取所有环境变量</td>
  705. <td>>= 2.2.6</td>
  706. </tr>
  707. <tr>
  708. <td><a href="#ossetenvs">os.setenvs</a></td>
  709. <td>替换当前所有环境变量</td>
  710. <td>>= 2.2.6</td>
  711. </tr>
  712. <tr>
  713. <td><a href="#osaddenvs">os.addenvs</a></td>
  714. <td>向当前环境变量中添加新值</td>
  715. <td>>= 2.5.6</td>
  716. </tr>
  717. <tr>
  718. <td><a href="#osjoinenvs">os.joinenvs</a></td>
  719. <td>拼接环境变量</td>
  720. <td>>= 2.5.6</td>
  721. </tr>
  722. <tr>
  723. <td><a href="#ossetenvp">os.setenvp</a></td>
  724. <td>使用给定分隔符设置环境变量</td>
  725. <td>>= 2.1.5</td>
  726. </tr>
  727. <tr>
  728. <td><a href="#osaddenvp">os.addenvp</a></td>
  729. <td>使用给定分隔符向环境变量添加新值</td>
  730. <td>>= 2.1.5</td>
  731. </tr>
  732. <tr>
  733. <td><a href="#osworkingdir">os.workingdir</a></td>
  734. <td>获取工作路径</td>
  735. <td>>= 2.1.9</td>
  736. </tr>
  737. <tr>
  738. <td><a href="#osisroot">os.isroot</a></td>
  739. <td>判断当前xmake是否以管理员权限运行</td>
  740. <td>>= 2.1.9</td>
  741. </tr>
  742. <tr>
  743. <td><a href="#osfscase">os.fscase</a></td>
  744. <td>判断当前系统的文件系统是否大小写敏感</td>
  745. <td>>= 2.1.9</td>
  746. </tr>
  747. <tr>
  748. <td><a href="#osterm">os.term</a></td>
  749. <td>获取当前终端</td>
  750. <td>>= 2.7.3</td>
  751. </tr>
  752. <tr>
  753. <td><a href="#osshell">os.shell</a></td>
  754. <td>获取当前shell</td>
  755. <td>>= 2.7.3</td>
  756. </tr>
  757. <tr>
  758. <td><a href="#oscpuinfo">os.cpuinfo</a></td>
  759. <td>获取CPU信息</td>
  760. <td>>= 2.1.5</td>
  761. </tr>
  762. <tr>
  763. <td><a href="#osmeminfo">os.meminfo</a></td>
  764. <td>获取内存信息</td>
  765. <td>>= 2.1.5</td>
  766. </tr>
  767. <tr>
  768. <td><a href="#osdefault_njob">os.default_njob</a></td>
  769. <td>获取默认编译任务数</td>
  770. <td>>= 2.5.8</td>
  771. </tr>
  772. </tbody>
  773. </table>
  774. <h4 id="oscp">os.cp</h4>
  775. <ul>
  776. <li>复制文件或目录</li>
  777. </ul>
  778. <p>行为和shell中的<code>cp</code>命令类似,支持路径通配符匹配(使用的是lua模式匹配),支持多文件复制,以及内置变量支持。</p>
  779. <p>例如:</p>
  780. <pre><code class="lang-lua">os.cp("$(scriptdir)/*.h", "$(buildir)/inc")
  781. os.cp("$(projectdir)/src/test/**.h", "$(buildir)/inc")
  782. </code></pre>
  783. <p>上面的代码将:当前<code>xmake.lua</code>目录下的所有头文件、工程源码test目录下的头文件全部复制到<code>$(buildir)</code>输出目录中。</p>
  784. <p>其中<code>$(scriptdir)</code>, <code>$(projectdir)</code> 这些变量是xmake的内置变量,具体详情见:<a href="#内置变量">内置变量</a>的相关文档。</p>
  785. <p>而<code>*.h</code>和<code>**.h</code>中的匹配模式,跟<a href="#targetadd_files">add_files</a>中的类似,前者是单级目录匹配,后者是递归多级目录匹配。</p>
  786. <p>此接口同时支持目录的<code>递归复制</code>,例如:</p>
  787. <pre><code class="lang-lua">-- 递归复制当前目录到临时目录
  788. os.cp("$(curdir)/test/", "$(tmpdir)/test")
  789. </code></pre>
  790. <p>上面的复制,会把所有文件全部展开复制到指定目录,丢失源目录层级,如果要按保持原有的目录结构复制,可以设置rootdir参数:</p>
  791. <pre><code class="lang-lua">os.cp("src/**.h", "/tmp/", {rootdir = "src"})
  792. </code></pre>
  793. <p>上面的脚本可以按<code>src</code>根目录,将src下的所有子文件保持目录结构复制过去。</p>
  794. <p>!> 尽量使用<code>os.cp</code>接口,而不是<code>os.run("cp ..")</code>,这样更能保证平台一致性,实现跨平台构建描述。</p>
  795. <p>2.5.7 下,新增 <code>{symlink = true}</code> 参数,在复制文件时候保留符号链接。</p>
  796. <pre><code class="lang-lua">os.cp("/xxx/foo", "/xxx/bar", {symlink = true})
  797. </code></pre>
  798. <h4 id="osmv">os.mv</h4>
  799. <ul>
  800. <li>移动重命名文件或目录</li>
  801. </ul>
  802. <p>跟<a href="#oscp">os.cp</a>的使用类似,同样支持多文件移动操作和模式匹配,例如:</p>
  803. <pre><code class="lang-lua">-- 移动文件到临时目录
  804. os.mv("$(buildir)/test1", "$(tmpdir)")
  805. -- 文件移动不支持批量操作,也就是文件重命名
  806. os.mv("$(buildir)/libtest.a", "$(buildir)/libdemo.a")
  807. </code></pre>
  808. <h4 id="osrm">os.rm</h4>
  809. <ul>
  810. <li>删除文件或目录树</li>
  811. </ul>
  812. <p>支持递归删除目录,批量删除操作,以及模式匹配和内置变量,例如:</p>
  813. <pre><code class="lang-lua">os.rm("$(buildir)/inc/**.h")
  814. os.rm("$(buildir)/lib/")
  815. </code></pre>
  816. <h4 id="ostrycp">os.trycp</h4>
  817. <ul>
  818. <li>尝试复制文件或目录</li>
  819. </ul>
  820. <p>跟<a href="#oscp">os.cp</a>类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。</p>
  821. <pre><code class="lang-lua">if os.trycp("file", "dest/file") then
  822. end
  823. </code></pre>
  824. <h4 id="ostrymv">os.trymv</h4>
  825. <ul>
  826. <li>尝试移动文件或目录</li>
  827. </ul>
  828. <p>跟<a href="#osmv">os.mv</a>类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。</p>
  829. <pre><code class="lang-lua">if os.trymv("file", "dest/file") then
  830. end
  831. </code></pre>
  832. <h4 id="ostryrm">os.tryrm</h4>
  833. <ul>
  834. <li>尝试删除文件或目录</li>
  835. </ul>
  836. <p>跟<a href="#osrm">os.rm</a>类似,唯一的区别就是,此接口操作失败不会抛出异常中断xmake,而是通过返回值标示是否执行成功。</p>
  837. <pre><code class="lang-lua">if os.tryrm("file") then
  838. end
  839. </code></pre>
  840. <h4 id="oscd">os.cd</h4>
  841. <ul>
  842. <li>进入指定目录</li>
  843. </ul>
  844. <p>这个操作用于目录切换,同样也支持内置变量,但是不支持模式匹配和多目录处理,例如:</p>
  845. <pre><code class="lang-lua">-- 进入临时目录
  846. os.cd("$(tmpdir)")
  847. </code></pre>
  848. <p>如果要离开进入之前的目录,有多种方式:</p>
  849. <pre><code class="lang-lua">-- 进入上级目录
  850. os.cd("..")
  851. -- 进入先前的目录,相当于:cd -
  852. os.cd("-")
  853. -- 进入目录前保存之前的目录,用于之后跨级直接切回
  854. local oldir = os.cd("./src")
  855. ...
  856. os.cd(oldir)
  857. </code></pre>
  858. <h4 id="osrmdir">os.rmdir</h4>
  859. <ul>
  860. <li>仅删除目录</li>
  861. </ul>
  862. <p>如果不是目录就无法删除。</p>
  863. <h4 id="osmkdir">os.mkdir</h4>
  864. <ul>
  865. <li>创建目录</li>
  866. </ul>
  867. <p>支持批量创建和内置变量,例如:</p>
  868. <pre><code class="lang-lua">os.mkdir("$(tmpdir)/test", "$(buildir)/inc")
  869. </code></pre>
  870. <h4 id="osisdir">os.isdir</h4>
  871. <ul>
  872. <li>判断是否为目录</li>
  873. </ul>
  874. <p>如果目录不存在,则返回false</p>
  875. <pre><code class="lang-lua">if os.isdir("src") then
  876. -- ...
  877. end
  878. </code></pre>
  879. <h4 id="osisfile">os.isfile</h4>
  880. <ul>
  881. <li>判断是否为文件</li>
  882. </ul>
  883. <p>如果文件不存在,则返回false</p>
  884. <pre><code class="lang-lua">if os.isfile("$(buildir)/libxxx.a") then
  885. -- ...
  886. end
  887. </code></pre>
  888. <h4 id="osexists">os.exists</h4>
  889. <ul>
  890. <li>判断文件或目录是否存在</li>
  891. </ul>
  892. <p>如果文件或目录不存在,则返回false</p>
  893. <pre><code class="lang-lua">-- 判断目录存在
  894. if os.exists("$(buildir)") then
  895. -- ...
  896. end
  897. -- 判断文件存在
  898. if os.exists("$(buildir)/libxxx.a") then
  899. -- ...
  900. end
  901. </code></pre>
  902. <h4 id="osdirs">os.dirs</h4>
  903. <ul>
  904. <li>遍历获取指定目录下的所有目录</li>
  905. </ul>
  906. <p>支持<a href="#targetadd_files">add_files</a>中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:</p>
  907. <pre><code class="lang-lua">-- 递归遍历获取所有子目录
  908. for _, dir in ipairs(os.dirs("$(buildir)/inc/**")) do
  909. print(dir)
  910. end
  911. </code></pre>
  912. <h4 id="osfiles">os.files</h4>
  913. <ul>
  914. <li>遍历获取指定目录下的所有文件</li>
  915. </ul>
  916. <p>支持<a href="#targetadd_files">add_files</a>中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:</p>
  917. <pre><code class="lang-lua">-- 非递归遍历获取所有子文件
  918. for _, filepath in ipairs(os.files("$(buildir)/inc/*.h")) do
  919. print(filepath)
  920. end
  921. </code></pre>
  922. <h4 id="osfiledirs">os.filedirs</h4>
  923. <ul>
  924. <li>遍历获取指定目录下的所有文件和目录</li>
  925. </ul>
  926. <p>支持<a href="#targetadd_files">add_files</a>中的模式匹配,支持递归和非递归模式遍历,返回的结果是一个table数组,如果获取不到,返回空数组,例如:</p>
  927. <pre><code class="lang-lua">-- 递归遍历获取所有子文件和目录
  928. for _, filedir in ipairs(os.filedirs("$(buildir)/**")) do
  929. print(filedir)
  930. end
  931. </code></pre>
  932. <h4 id="osrun">os.run</h4>
  933. <ul>
  934. <li>安静运行原生shell命令</li>
  935. </ul>
  936. <p>用于执行第三方的shell命令,但不会回显输出,仅仅在出错后,高亮输出错误信息。</p>
  937. <p>此接口支持参数格式化、内置变量,例如:</p>
  938. <pre><code class="lang-lua">-- 格式化参数传入
  939. os.run("echo hello %s!", "xmake")
  940. -- 列举构建目录文件
  941. os.run("ls -l $(buildir)")
  942. </code></pre>
  943. <p>!> 使用此接口执行shell命令,容易使构建跨平台性降低,对于<code>os.run("cp ..")</code>这种尽量使用<code>os.cp</code>代替。<br><br>如果必须使用此接口运行shell程序,请自行使用<a href="#config-plat">config.plat</a>接口判断平台支持。</p>
  944. <h4 id="osrunv">os.runv</h4>
  945. <ul>
  946. <li>安静运行原生shell命令,带参数列表</li>
  947. </ul>
  948. <p>跟<a href="#osrun">os.run</a>类似,只是传递参数的方式是通过参数列表传递,而不是字符串命令,例如:</p>
  949. <pre><code class="lang-lua">os.runv("echo", {"hello", "xmake!"})
  950. </code></pre>
  951. <p>另外,此接口也支持envs参数设置:</p>
  952. <pre><code class="lang-lua">os.runv("echo", {"hello", "xmake!"}, {envs = {PATH = "xxx;xx", CFLAGS = "xx"}})
  953. </code></pre>
  954. <h4 id="osexec">os.exec</h4>
  955. <ul>
  956. <li>回显运行原生shell命令</li>
  957. </ul>
  958. <p>与<a href="#osrun">os.run</a>接口类似,唯一的不同是,此接口执行shell程序时,是带回显输出的,一般调试的时候用的比较多</p>
  959. <h4 id="osexecv">os.execv</h4>
  960. <ul>
  961. <li>回显运行原生shell命令,带参数列表</li>
  962. </ul>
  963. <p>跟<a href="#osexec">os.exec</a>类似,只是传递参数的方式是通过参数列表传递,而不是字符串命令,例如:</p>
  964. <pre><code class="lang-lua">os.execv("echo", {"hello", "xmake!"})
  965. </code></pre>
  966. <p>另外,此接口还支持一个可选的参数,用于传递设置:重定向输出,执行环境变量设置,例如:</p>
  967. <pre><code class="lang-lua">os.execv("echo", {"hello", "xmake!"}, {stdout = outfile, stderr = errfile, envs = {PATH = "xxx;xx", CFLAGS = "xx"}}
  968. </code></pre>
  969. <p>其中,stdout和stderr参数用于传递重定向输出和错误输出,可以直接传入文件路径,也可以传入io.open打开的文件对象。</p>
  970. <p>v2.5.1 之后的版本,我们还支持设置 stdin 参数,来支持重定向输入文件。</p>
  971. <p>!> stdout/stderr/stdin 可以同时支持:文件路径、文件对象、管道对象等三种类型值。</p>
  972. <p>另外,如果想在这次执行中临时设置和改写一些环境变量,可以传递envs参数,里面的环境变量设置会替换已有的设置,但是不影响外层的执行环境,只影响当前命令。</p>
  973. <p>我们也可以通过<code>os.getenvs()</code>接口获取当前所有的环境变量,然后改写部分后传入envs参数。</p>
  974. <h4 id="osiorun">os.iorun</h4>
  975. <ul>
  976. <li>安静运行原生shell命令并获取输出内容</li>
  977. </ul>
  978. <p>与<a href="#osrun">os.run</a>接口类似,唯一的不同是,此接口执行shell程序后,会获取shell程序的执行结果,相当于重定向输出。</p>
  979. <p>可同时获取<code>stdout</code>, <code>stderr</code>中的内容,例如:</p>
  980. <pre><code class="lang-lua">local outdata, errdata = os.iorun("echo hello xmake!")
  981. </code></pre>
  982. <h4 id="osiorunv">os.iorunv</h4>
  983. <ul>
  984. <li>安静运行原生shell命令并获取输出内容,带参数列表</li>
  985. </ul>
  986. <p>跟<a href="#osiorun">os.iorun</a>类似,只是传递参数的方式是通过参数列表传递,而不是字符串命令,例如:</p>
  987. <pre><code class="lang-lua">local outdata, errdata = os.iorunv("echo", {"hello", "xmake!"})
  988. </code></pre>
  989. <p>另外,此接口也支持envs参数设置:</p>
  990. <pre><code class="lang-lua">local outdata, errdata = os.iorunv("echo", {"hello", "xmake!"}, {envs = {PATH = "xxx;xx", CFLAGS = "xx"}}
  991. </code></pre>
  992. <h4 id="osgetenv">os.getenv</h4>
  993. <ul>
  994. <li>获取系统环境变量</li>
  995. </ul>
  996. <pre><code class="lang-lua">print(os.getenv("PATH"))
  997. </code></pre>
  998. <h4 id="ossetenv">os.setenv</h4>
  999. <ul>
  1000. <li>设置系统环境变量</li>
  1001. </ul>
  1002. <pre><code class="lang-lua">os.setenv("HOME", "/tmp/")
  1003. </code></pre>
  1004. <h4 id="ostmpdir">os.tmpdir</h4>
  1005. <ul>
  1006. <li>获取临时目录</li>
  1007. </ul>
  1008. <p>跟<a href="#var-tmpdir">$(tmpdir)</a>结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。</p>
  1009. <pre><code class="lang-lua">print(path.join(os.tmpdir(), "file.txt"))
  1010. </code></pre>
  1011. <p>等价于:</p>
  1012. <pre><code class="lang-lua">print("$(tmpdir)/file.txt")
  1013. </code></pre>
  1014. <h4 id="ostmpfile">os.tmpfile</h4>
  1015. <ul>
  1016. <li>获取临时文件路径</li>
  1017. </ul>
  1018. <p>用于获取生成一个临时文件路径,仅仅是个路径,文件需要自己创建。</p>
  1019. <h4 id="oscurdir">os.curdir</h4>
  1020. <ul>
  1021. <li>获取当前目录路径</li>
  1022. </ul>
  1023. <p>跟<a href="#var-curdir">$(curdir)</a>结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。</p>
  1024. <p>用法参考:<a href="#ostmpdir">os.tmpdir</a>。</p>
  1025. <h4 id="osfilesize">os.filesize</h4>
  1026. <ul>
  1027. <li>获取文件大小</li>
  1028. </ul>
  1029. <pre><code class="lang-lua">print(os.filesize("/tmp/a"))
  1030. </code></pre>
  1031. <h4 id="osscriptdir">os.scriptdir</h4>
  1032. <ul>
  1033. <li>获取当前描述脚本的路径</li>
  1034. </ul>
  1035. <p>跟<a href="#var-scriptdir">$(scriptdir)</a>结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。</p>
  1036. <p>用法参考:<a href="#ostmpdir">os.tmpdir</a>。</p>
  1037. <h4 id="osprogramdir">os.programdir</h4>
  1038. <ul>
  1039. <li>获取xmake安装主程序脚本目录</li>
  1040. </ul>
  1041. <p>跟<a href="#var-programdir">$(programdir)</a>结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。</p>
  1042. <h4 id="osprogramfile">os.programfile</h4>
  1043. <ul>
  1044. <li>获取xmake可执行文件路径</li>
  1045. </ul>
  1046. <h4 id="osprojectdir">os.projectdir</h4>
  1047. <ul>
  1048. <li>获取工程主目录</li>
  1049. </ul>
  1050. <p>跟<a href="#var-projectdir">$(projectdir)</a>结果一致,只不过是直接获取返回一个变量,可以用后续字符串维护。</p>
  1051. <h4 id="osarch">os.arch</h4>
  1052. <ul>
  1053. <li>获取当前系统架构</li>
  1054. </ul>
  1055. <p>也就是当前主机系统的默认架构,例如我在<code>linux x86_64</code>上执行xmake进行构建,那么返回值是:<code>x86_64</code></p>
  1056. <h4 id="oshost">os.host</h4>
  1057. <ul>
  1058. <li>获取当前主机的操作系统</li>
  1059. </ul>
  1060. <p>跟<a href="#var-host">$(host)</a>结果一致,例如我在<code>linux x86_64</code>上执行xmake进行构建,那么返回值是:<code>linux</code></p>
  1061. <h4 id="ossubhost">os.subhost</h4>
  1062. <ul>
  1063. <li>获取当前子系统,如:在Windows上的msys、cygwin</li>
  1064. </ul>
  1065. <h4 id="ossubarch">os.subarch</h4>
  1066. <ul>
  1067. <li>获取子系统架构</li>
  1068. </ul>
  1069. <h4 id="osis_host">os.is_host</h4>
  1070. <ul>
  1071. <li>判断给定系统是否为当前系统</li>
  1072. </ul>
  1073. <h4 id="osis_arch">os.is_arch</h4>
  1074. <ul>
  1075. <li>判断给定架构是否为当前架构</li>
  1076. </ul>
  1077. <h4 id="osis_subhost">os.is_subhost</h4>
  1078. <ul>
  1079. <li>判断给定子系统是否为当前子系统</li>
  1080. </ul>
  1081. <h4 id="osis_subarch">os.is_subarch</h4>
  1082. <ul>
  1083. <li>判断给定子系统架构是否为当前子系统架构</li>
  1084. </ul>
  1085. <h4 id="osln">os.ln</h4>
  1086. <ul>
  1087. <li>为一个文件或目录创建符号链接</li>
  1088. </ul>
  1089. <pre><code class="lang-lua">-- 创建一个指向 "tmp.txt" 文件的符号链接 "tmp.txt.ln"
  1090. os.ln("xxx.txt", "xxx.txt.ln")
  1091. </code></pre>
  1092. <h4 id="osreadlink">os.readlink</h4>
  1093. <ul>
  1094. <li>读取符号链接内容</li>
  1095. </ul>
  1096. <h4 id="osraise">os.raise</h4>
  1097. <ul>
  1098. <li>抛出一个异常并且中止当前脚本运行</li>
  1099. </ul>
  1100. <pre><code class="lang-lua">-- 抛出一个带 "an error occurred" 信息的异常
  1101. os.raise("an error occurred")
  1102. </code></pre>
  1103. <p>!> 推荐使用与 <code>os.raise</code> 等价的内置接口 <code>raise</code>,用法与 <code>os.raise</code> 一致</p>
  1104. <h4 id="osraiselevel">os.raiselevel</h4>
  1105. <ul>
  1106. <li>与 <a href="#osraise">os.raise</a> 类似但是可以指定异常等级</li>
  1107. </ul>
  1108. <pre><code class="lang-lua">-- 抛出一个带 "an error occurred" 信息的异常
  1109. os.raise(3, "an error occurred")
  1110. </code></pre>
  1111. <h4 id="osfeatures">os.features</h4>
  1112. <ul>
  1113. <li>获取系统特性</li>
  1114. </ul>
  1115. <h4 id="osgetenvs">os.getenvs</h4>
  1116. <ul>
  1117. <li>获取所有当前系统变量</li>
  1118. </ul>
  1119. <pre><code class="lang-lua">local envs = os.getenvs()
  1120. -- home directory (on linux)
  1121. print(envs["HOME"])
  1122. </code></pre>
  1123. <h4 id="ossetenvs">os.setenvs</h4>
  1124. <ul>
  1125. <li>使用给定系统变量替换当前所有系统变量,并返回旧系统变量</li>
  1126. </ul>
  1127. <h4 id="osaddenvs">os.addenvs</h4>
  1128. <ul>
  1129. <li>向当前系统变量添加新变量,并且返回所有旧系统变量</li>
  1130. </ul>
  1131. <pre><code class="lang-lua">os.setenvs({EXAMPLE = "a/path"}) -- add a custom variable to see addenvs impact on it
  1132. local oldenvs = os.addenvs({EXAMPLE = "some/path/"})
  1133. print(os.getenvs()["EXAMPLE"]) --got some/path/;a/path
  1134. print(oldenvs["EXAMPLE"]) -- got a/path
  1135. </code></pre>
  1136. <h4 id="osjoinenvs">os.joinenvs</h4>
  1137. <ul>
  1138. <li>拼接系统变量,与 <a href="#osaddenvs">os.addenvs</a> 类似,但是不会对当前环境变量产生影响,若第二个参数为 <code>nil</code>,则使用原有环境变量</li>
  1139. </ul>
  1140. <pre><code class="lang-lua">-- os.joinenvs(envs, oldenvs)
  1141. --
  1142. -- @param envs table 类型,新插入的环境变量
  1143. --
  1144. -- @param oldenvs table 类型,被插入的环境变量,若为 nil, 则为原有环境变量
  1145. --
  1146. -- @return table 类型,拼接后的环境变量
  1147. local envs0 = {CUSTOM = "a/path"}
  1148. local envs1 = {CUSTOM = "some/path/"}
  1149. print(os.joinenvs(envs0, envs1)) -- result is : { CUSTION = "a/path;some/path/" }
  1150. </code></pre>
  1151. <h4 id="ossetenvp">os.setenvp</h4>
  1152. <ul>
  1153. <li>使用给定分隔符设置环境变量</li>
  1154. </ul>
  1155. <h4 id="osworkingdir">os.workingdir</h4>
  1156. <ul>
  1157. <li>获取工作目录</li>
  1158. </ul>
  1159. <h4 id="osisroot">os.isroot</h4>
  1160. <ul>
  1161. <li>判断xmake是否以管理员权限运行</li>
  1162. </ul>
  1163. <h4 id="osfscase">os.fscase</h4>
  1164. <ul>
  1165. <li>判断操作系统的文件系统是否大小写敏感</li>
  1166. </ul>
  1167. <h4 id="osterm">os.term</h4>
  1168. <ul>
  1169. <li>获取当前终端 (windows-terminal, vscode, xterm, ...)</li>
  1170. </ul>
  1171. <h4 id="osshell">os.shell</h4>
  1172. <ul>
  1173. <li>获取当前shell (pwsh, cmd, bash, zsh, ...)</li>
  1174. </ul>
  1175. <h4 id="oscpuinfo">os.cpuinfo</h4>
  1176. <ul>
  1177. <li>获取当前CPU信息</li>
  1178. </ul>
  1179. <pre><code class="lang-lua">print(os.cpuinfo())
  1180. -- probably got {
  1181. -- march = "Alder Lake",
  1182. -- model = 154,
  1183. -- ncpu = 20,
  1184. -- model_name = "12th Gen Intel(R) Core(TM) i9-12900H",
  1185. -- usagerate = 0.041839182376862,
  1186. -- vendor = "GenuineIntel",
  1187. -- family = 6
  1188. -- }
  1189. print(os.cpuinfo("march")) -- probably got "Alder Lake"
  1190. </code></pre>
  1191. <h4 id="osmeminfo">os.meminfo</h4>
  1192. <ul>
  1193. <li>获取内存信息</li>
  1194. </ul>
  1195. <pre><code class="lang-lua">print(os.meminfo())
  1196. -- probably got {
  1197. -- pagesize = 4096,
  1198. -- usagerate = 0.60694103194103,
  1199. -- availsize = 12798,
  1200. -- totalsize = 32560
  1201. -- }
  1202. print(os.meminfo("pagesize")) -- probably got 4096
  1203. </code></pre>
  1204. <h4 id="osdefault_njob">os.default_njob</h4>
  1205. <ul>
  1206. <li>获取默认编译任务数</li>
  1207. </ul>
  1208. <h3 id="winos">winos</h3>
  1209. <p>windows 系统操作模块,属于内置模块,无需使用<a href="#import">import</a>导入,可直接脚本域调用其接口。</p>
  1210. <table>
  1211. <thead>
  1212. <tr>
  1213. <th>接口</th>
  1214. <th>描述</th>
  1215. <th>支持版本</th>
  1216. </tr>
  1217. </thead>
  1218. <tbody>
  1219. <tr>
  1220. <td><a href="#winosversion">winos.version</a></td>
  1221. <td>获取 windows 系统版本</td>
  1222. <td>>= 2.3.1</td>
  1223. </tr>
  1224. <tr>
  1225. <td><a href="#winosregistry_keys">winos.registry_keys</a></td>
  1226. <td>获取注册表建列表</td>
  1227. <td>>= 2.5.1</td>
  1228. </tr>
  1229. <tr>
  1230. <td><a href="#winosregistry_values">winos.registry_values</a></td>
  1231. <td>获取注册表值名列表</td>
  1232. <td>>= 2.5.1</td>
  1233. </tr>
  1234. <tr>
  1235. <td><a href="#winosregistry_query">winos.registry_query</a></td>
  1236. <td>获取注册表建值</td>
  1237. <td>>= 2.3.1</td>
  1238. </tr>
  1239. </tbody>
  1240. </table>
  1241. <h4 id="winosversion">winos.version</h4>
  1242. <ul>
  1243. <li>获取 windows 系统版本</li>
  1244. </ul>
  1245. <p>返回的版本是 semver 语义版本对象</p>
  1246. <pre><code class="lang-lua">if winos.version():ge("win7") then
  1247. -- ...
  1248. end
  1249. if winos.version():ge("6.1") then
  1250. -- ...
  1251. end
  1252. </code></pre>
  1253. <p>并且,还可以支持对 windows 版本名的直接判断,映射规则如下:</p>
  1254. <pre><code>
  1255. nt4 = "4.0"
  1256. win2k = "5.0"
  1257. winxp = "5.1"
  1258. ws03 = "5.2"
  1259. win6 = "6.0"
  1260. vista = "6.0"
  1261. ws08 = "6.0"
  1262. longhorn = "6.0"
  1263. win7 = "6.1"
  1264. win8 = "6.2"
  1265. winblue = "6.3"
  1266. win81 = "6.3"
  1267. win10 = "10.0"
  1268. </code></pre><h4 id="winosregistry_keys">winos.registry_keys</h4>
  1269. <ul>
  1270. <li>获取注册表建列表</li>
  1271. </ul>
  1272. <p>支持通过模式匹配的方式,遍历获取注册表键路径列表,<code>*</code> 为单级路径匹配,<code>**</code> 为递归路径匹配。</p>
  1273. <pre><code class="lang-lua">local keypaths = winos.registry_keys("HKEY_LOCAL_MACHINE\\SOFTWARE\\*\\Windows NT\\*\\CurrentVersion\\AeDebug")
  1274. for _, keypath in ipairs(keypaths) do
  1275. print(winos.registry_query(keypath .. ";Debugger"))
  1276. end
  1277. </code></pre>
  1278. <h4 id="winosregistry_values">winos.registry_values</h4>
  1279. <ul>
  1280. <li>获取注册表值名列表</li>
  1281. </ul>
  1282. <p>支持通过模式匹配的方式,获取指定键路径的值名列表,<code>;</code> 之后的就是指定的键名模式匹配字符串。</p>
  1283. <pre><code class="lang-lua">local valuepaths = winos.registry_values("HKEY_LOCAL_MACHINE\\SOFTWARE\\xx\\AeDebug;Debug*")
  1284. for _, valuepath in ipairs(valuepaths) do
  1285. print(winos.registry_query(valuepath))
  1286. end
  1287. </code></pre>
  1288. <h4 id="winosregistry_query">winos.registry_query</h4>
  1289. <ul>
  1290. <li>获取注册表建值</li>
  1291. </ul>
  1292. <p>获取指定注册表建路径下的值,如果没有指定值名,那么获取键路径默认值</p>
  1293. <pre><code class="lang-lua">local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug")
  1294. local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug;Debugger")
  1295. </code></pre>
  1296. <h3 id="macos">macos</h3>
  1297. <p>macOS 系统操作模块,属于内置模块,无需使用<a href="#import">import</a>导入,可直接脚本域调用其接口。</p>
  1298. <table>
  1299. <thead>
  1300. <tr>
  1301. <th>接口</th>
  1302. <th>描述</th>
  1303. <th>支持版本</th>
  1304. </tr>
  1305. </thead>
  1306. <tbody>
  1307. <tr>
  1308. <td><a href="#macosversion">macos.version</a></td>
  1309. <td>获取 macOS 系统版本</td>
  1310. <td>>= 2.3.1</td>
  1311. </tr>
  1312. </tbody>
  1313. </table>
  1314. <h4 id="macosversion">macos.version</h4>
  1315. <ul>
  1316. <li>获取 macOS 系统版本</li>
  1317. </ul>
  1318. <p>返回的版本是 semver 语义版本对象</p>
  1319. <pre><code class="lang-lua">if macos.version():ge("10.0") then
  1320. -- ...
  1321. end
  1322. </code></pre>
  1323. <h3 id="linuxos">linuxos</h3>
  1324. <p>linux 系统操作模块,属于内置模块,无需使用<a href="#import">import</a>导入,可直接脚本域调用其接口。</p>
  1325. <table>
  1326. <thead>
  1327. <tr>
  1328. <th>接口</th>
  1329. <th>描述</th>
  1330. <th>支持版本</th>
  1331. </tr>
  1332. </thead>
  1333. <tbody>
  1334. <tr>
  1335. <td><a href="#linuxosname">linuxos.name</a></td>
  1336. <td>获取 linux 系统发行版名称</td>
  1337. <td>>= 2.5.2</td>
  1338. </tr>
  1339. <tr>
  1340. <td><a href="#linuxosversion">linuxos.version</a></td>
  1341. <td>获取 linux 系统版本</td>
  1342. <td>>= 2.5.2</td>
  1343. </tr>
  1344. <tr>
  1345. <td><a href="#linuxoskernelver">linuxos.kernelver</a></td>
  1346. <td>获取 linux 系统内核版本</td>
  1347. <td>>= 2.5.2</td>
  1348. </tr>
  1349. </tbody>
  1350. </table>
  1351. <h4 id="linuxosname">linuxos.name</h4>
  1352. <ul>
  1353. <li>获取 linux 系统发行版名称</li>
  1354. </ul>
  1355. <p>我们也可以通过下面的命令,快速获取查看</p>
  1356. <pre><code class="lang-bash">xmake l linuxos.name
  1357. </code></pre>
  1358. <p>目前支持的一些名称有:</p>
  1359. <ul>
  1360. <li>ubuntu</li>
  1361. <li>debian</li>
  1362. <li>archlinux</li>
  1363. <li>manjaro</li>
  1364. <li>linuxmint</li>
  1365. <li>centos</li>
  1366. <li>fedora</li>
  1367. <li>opensuse</li>
  1368. </ul>
  1369. <h4 id="linuxosversion">linuxos.version</h4>
  1370. <ul>
  1371. <li>获取 linux 系统版本</li>
  1372. </ul>
  1373. <p>返回的版本是 semver 语义版本对象</p>
  1374. <pre><code class="lang-lua">if linux.version():ge("10.0") then
  1375. -- ...
  1376. end
  1377. </code></pre>
  1378. <h4 id="linuxoskernelver">linuxos.kernelver</h4>
  1379. <ul>
  1380. <li>获取 linux 系统内核版本</li>
  1381. </ul>
  1382. <p>返回的也是语义版本对象,也可以执行 <code>xmake l linuxos.kernelver</code> 快速查看</p>
  1383. <h3 id="io">io</h3>
  1384. <p>io操作模块,扩展了lua内置的io模块,提供更多易用的接口。</p>
  1385. <table>
  1386. <thead>
  1387. <tr>
  1388. <th>接口</th>
  1389. <th>描述</th>
  1390. <th>支持版本</th>
  1391. </tr>
  1392. </thead>
  1393. <tbody>
  1394. <tr>
  1395. <td><a href="#ioopen">io.open</a></td>
  1396. <td>打开文件用于读写</td>
  1397. <td>>= 2.0.1</td>
  1398. </tr>
  1399. <tr>
  1400. <td><a href="#ioload">io.load</a></td>
  1401. <td>从指定路径文件反序列化加载所有table内容</td>
  1402. <td>>= 2.0.1</td>
  1403. </tr>
  1404. <tr>
  1405. <td><a href="#iosave">io.save</a></td>
  1406. <td>序列化保存所有table内容到指定路径文件</td>
  1407. <td>>= 2.0.1</td>
  1408. </tr>
  1409. <tr>
  1410. <td><a href="#io.readfile">io.readfile</a></td>
  1411. <td>从指定路径文件读取所有内容</td>
  1412. <td>>= 2.1.3</td>
  1413. </tr>
  1414. <tr>
  1415. <td><a href="#io.writefile">io.writefile</a></td>
  1416. <td>写入所有内容到指定路径文件</td>
  1417. <td>>= 2.1.3</td>
  1418. </tr>
  1419. <tr>
  1420. <td><a href="#iogsub">io.gsub</a></td>
  1421. <td>全文替换指定路径文件的内容</td>
  1422. <td>>= 2.0.1</td>
  1423. </tr>
  1424. <tr>
  1425. <td><a href="#iotail">io.tail</a></td>
  1426. <td>读取和显示文件的尾部内容</td>
  1427. <td>>= 2.0.1</td>
  1428. </tr>
  1429. <tr>
  1430. <td><a href="#iocat">io.cat</a></td>
  1431. <td>读取和显示文件的所有内容</td>
  1432. <td>>= 2.0.1</td>
  1433. </tr>
  1434. <tr>
  1435. <td><a href="#ioprint">io.print</a></td>
  1436. <td>带换行格式化输出内容到文件</td>
  1437. <td>>= 2.0.1</td>
  1438. </tr>
  1439. <tr>
  1440. <td><a href="#ioprintf">io.printf</a></td>
  1441. <td>无换行格式化输出内容到文件</td>
  1442. <td>>= 2.0.1</td>
  1443. </tr>
  1444. <tr>
  1445. <td><a href="#iolines">io.lines</a></td>
  1446. <td>读取文件的所有行</td>
  1447. <td>>= 2.2.9</td>
  1448. </tr>
  1449. <tr>
  1450. <td><a href="#iostdfile">io.stdfile</a></td>
  1451. <td>获取标准输入输出文件</td>
  1452. <td>>= 2.2.9</td>
  1453. </tr>
  1454. <tr>
  1455. <td><a href="#ioopenlock">io.openlock</a></td>
  1456. <td>创建一把文件锁</td>
  1457. <td>>= 2.2.9</td>
  1458. </tr>
  1459. <tr>
  1460. <td><a href="#ioreplace">io.replace</a></td>
  1461. <td>根据表达式替换文件内容</td>
  1462. <td>>= 2.3.8</td>
  1463. </tr>
  1464. </tbody>
  1465. </table>
  1466. <h4 id="ioopen">io.open</h4>
  1467. <ul>
  1468. <li>打开文件用于读写</li>
  1469. </ul>
  1470. <p>这个是属于lua的原生接口,详细使用可以参看lua的官方文档:<a href="https://www.lua.org/pil/21.2.html">The Complete I/O Model</a></p>
  1471. <p>如果要读取文件所有内容,可以这么写:</p>
  1472. <pre><code class="lang-lua">local file = io.open("$(tmpdir)/file.txt", "r")
  1473. if file then
  1474. local data = file:read("*all")
  1475. file:close()
  1476. end
  1477. </code></pre>
  1478. <p>或者可以使用<a href="#io.readfile">io.readfile</a>更加快速地读取。</p>
  1479. <p>如果要写文件,可以这么操作:</p>
  1480. <pre><code class="lang-lua">-- 打开文件:w 为写模式, a 为追加写模式
  1481. local file = io.open("xxx.txt", "w")
  1482. if file then
  1483. -- 用原生的lua接口写入数据到文件,不支持格式化,无换行,不支持内置变量
  1484. file:write("hello xmake\n")
  1485. -- 用xmake扩展的接口写入数据到文件,支持格式化,无换行,不支持内置变量
  1486. file:writef("hello %s\n", "xmake")
  1487. -- 使用xmake扩展的格式化传参写入一行,带换行符,并且支持内置变量
  1488. file:print("hello %s and $(buildir)", "xmake")
  1489. -- 使用xmake扩展的格式化传参写入一行,无换行符,并且支持内置变量
  1490. file:printf("hello %s and $(buildir) \n", "xmake")
  1491. -- 关闭文件
  1492. file:close()
  1493. end
  1494. </code></pre>
  1495. <h4 id="ioload">io.load</h4>
  1496. <ul>
  1497. <li>从指定路径文件反序列化加载所有table内容</li>
  1498. </ul>
  1499. <p>可以从文件中加载序列化好的table内容,一般与<a href="#iosave">io.save</a>配合使用,例如:</p>
  1500. <pre><code class="lang-lua">-- 加载序列化文件的内容到table
  1501. local data = io.load("xxx.txt")
  1502. if data then
  1503. -- 在终端中dump打印整个table中内容,格式化输出
  1504. utils.dump(data)
  1505. end
  1506. </code></pre>
  1507. <h4 id="iosave">io.save</h4>
  1508. <ul>
  1509. <li>序列化保存所有table内容到指定路径文件</li>
  1510. </ul>
  1511. <p>可以序列化存储table内容到指定文件,一般与<a href="#ioload">io.load</a>配合使用,例如:</p>
  1512. <pre><code class="lang-lua">io.save("xxx.txt", {a = "a", b = "b", c = "c"})
  1513. </code></pre>
  1514. <p>存储结果为:</p>
  1515. <pre><code>{
  1516. ["b"] = "b"
  1517. , ["a"] = "a"
  1518. , ["c"] = "c"
  1519. }
  1520. </code></pre><h4 id="ioreadfile">io.readfile</h4>
  1521. <ul>
  1522. <li>从指定路径文件读取所有内容</li>
  1523. </ul>
  1524. <p>可在不打开文件的情况下,直接读取整个文件的内容,更加的方便,例如:</p>
  1525. <pre><code class="lang-lua">local data = io.readfile("xxx.txt")
  1526. </code></pre>
  1527. <h4 id="iowritefile">io.writefile</h4>
  1528. <ul>
  1529. <li>写入所有内容到指定路径文件</li>
  1530. </ul>
  1531. <p>可在不打开文件的情况下,直接写入整个文件的内容,更加的方便,例如:</p>
  1532. <pre><code class="lang-lua">io.writefile("xxx.txt", "all data")
  1533. </code></pre>
  1534. <h4 id="iogsub">io.gsub</h4>
  1535. <ul>
  1536. <li>全文替换指定路径文件的内容</li>
  1537. </ul>
  1538. <p>类似<a href="#stringgsub">string.gsub</a>接口,全文模式匹配替换内容,不过这里是直接操作文件,例如:</p>
  1539. <pre><code class="lang-lua">-- 移除文件所有的空白字符
  1540. io.gsub("xxx.txt", "%s+", "")
  1541. </code></pre>
  1542. <h4 id="iotail">io.tail</h4>
  1543. <ul>
  1544. <li>读取和显示文件的尾部内容</li>
  1545. </ul>
  1546. <p>读取文件尾部指定行数的数据,并显示,类似<code>cat xxx.txt | tail -n 10</code>命令,例如:</p>
  1547. <pre><code class="lang-lua">-- 显示文件最后10行内容
  1548. io.tail("xxx.txt", 10)
  1549. </code></pre>
  1550. <h4 id="iocat">io.cat</h4>
  1551. <ul>
  1552. <li>读取和显示文件的所有内容</li>
  1553. </ul>
  1554. <p>读取文件的所有内容并显示,类似<code>cat xxx.txt</code>命令,例如:</p>
  1555. <pre><code class="lang-lua">io.cat("xxx.txt")
  1556. </code></pre>
  1557. <h4 id="ioprint">io.print</h4>
  1558. <ul>
  1559. <li>带换行格式化输出内容到文件</li>
  1560. </ul>
  1561. <p>直接格式化传参输出一行字符串到文件,并且带换行,例如:</p>
  1562. <pre><code class="lang-lua">io.print("xxx.txt", "hello %s!", "xmake")
  1563. </code></pre>
  1564. <h4 id="ioprintf">io.printf</h4>
  1565. <ul>
  1566. <li>无换行格式化输出内容到文件</li>
  1567. </ul>
  1568. <p>直接格式化传参输出一行字符串到文件,不带换行,例如:</p>
  1569. <pre><code class="lang-lua">io.printf("xxx.txt", "hello %s!\n", "xmake")
  1570. </code></pre>
  1571. <h4 id="iolines">io.lines</h4>
  1572. <ul>
  1573. <li>读取文件的所有行</li>
  1574. </ul>
  1575. <p>根据文件名返回该文件的所有行的内容</p>
  1576. <pre><code class="lang-lua">local lines = io.lines("xxx.txt")
  1577. for line in lines do
  1578. print(line)
  1579. end
  1580. </code></pre>
  1581. <h4 id="iostdfile">io.stdfile</h4>
  1582. <ul>
  1583. <li>获取标准输入输出文件</li>
  1584. </ul>
  1585. <p>根据文件名返回标准输入输出文件</p>
  1586. <pre><code class="lang-lua">-- 标准输入
  1587. io.stdin
  1588. -- 标准输出
  1589. io.stdout
  1590. -- 标准错误
  1591. io.stderr
  1592. </code></pre>
  1593. <h4 id="ioopenlock">io.openlock</h4>
  1594. <ul>
  1595. <li>创建一把文件锁</li>
  1596. </ul>
  1597. <p>为给定的文件返回一个文件锁对象</p>
  1598. <pre><code class="lang-lua">local lock = io.openlock("xxx.txt")
  1599. lock:lock()
  1600. lock:unlock()
  1601. lock:close()
  1602. </code></pre>
  1603. <h4 id="ioreplace">io.replace</h4>
  1604. <ul>
  1605. <li>根据表达式替换文件内容</li>
  1606. </ul>
  1607. <p>根据表达式和参数对文件进行全文替换</p>
  1608. <pre><code class="lang-lua">io.replace(filepath, pattern, replace, opt)
  1609. io.replace("xxx.txt", "test", "xmake", { plain = true, encoding = "UTF-8" })
  1610. io.replace("xxx.txt", "%d[^\n]*", "xmake")
  1611. </code></pre>
  1612. <p>关于参数 <code>opt</code> 成员的解释:</p>
  1613. <blockquote>
  1614. <p>.plain: 若为 true,使用pattern进行简单匹配;为 false,则进行模式匹配;</p>
  1615. <p>.encoding: 指定文件编码格式</p>
  1616. </blockquote>
  1617. <h3 id="path">path</h3>
  1618. <p>路径操作模块,实现跨平台的路径操作,这是xmake的一个自定义的模块。</p>
  1619. <table>
  1620. <thead>
  1621. <tr>
  1622. <th>接口</th>
  1623. <th>描述</th>
  1624. <th>支持版本</th>
  1625. </tr>
  1626. </thead>
  1627. <tbody>
  1628. <tr>
  1629. <td><a href="#pathjoin">path.join</a></td>
  1630. <td>拼接路径</td>
  1631. <td>>= 2.0.1</td>
  1632. </tr>
  1633. <tr>
  1634. <td><a href="#pathtranslate">path.translate</a></td>
  1635. <td>转换路径到当前平台的路径风格</td>
  1636. <td>>= 2.0.1</td>
  1637. </tr>
  1638. <tr>
  1639. <td><a href="#pathbasename">path.basename</a></td>
  1640. <td>获取路径最后不带后缀的文件名</td>
  1641. <td>>= 2.0.1</td>
  1642. </tr>
  1643. <tr>
  1644. <td><a href="#pathfilename">path.filename</a></td>
  1645. <td>获取路径最后带后缀的文件名</td>
  1646. <td>>= 2.0.1</td>
  1647. </tr>
  1648. <tr>
  1649. <td><a href="#pathextension">path.extension</a></td>
  1650. <td>获取路径的后缀名</td>
  1651. <td>>= 2.0.1</td>
  1652. </tr>
  1653. <tr>
  1654. <td><a href="#pathdirectory">path.directory</a></td>
  1655. <td>获取路径的目录名</td>
  1656. <td>>= 2.0.1</td>
  1657. </tr>
  1658. <tr>
  1659. <td><a href="#pathrelative">path.relative</a></td>
  1660. <td>转换成相对路径</td>
  1661. <td>>= 2.0.1</td>
  1662. </tr>
  1663. <tr>
  1664. <td><a href="#pathabsolute">path.absolute</a></td>
  1665. <td>转换成绝对路径</td>
  1666. <td>>= 2.0.1</td>
  1667. </tr>
  1668. <tr>
  1669. <td><a href="#pathis_absolute">path.is_absolute</a></td>
  1670. <td>判断是否为绝对路径</td>
  1671. <td>>= 2.0.1</td>
  1672. </tr>
  1673. <tr>
  1674. <td><a href="#pathsplitenv">path.splitenv</a></td>
  1675. <td>分割环境变量中的路径</td>
  1676. <td>>= 2.2.7</td>
  1677. </tr>
  1678. </tbody>
  1679. </table>
  1680. <h4 id="pathjoin">path.join</h4>
  1681. <ul>
  1682. <li>拼接路径</li>
  1683. </ul>
  1684. <p>将多个路径项进行追加拼接,由于<code>windows/unix</code>风格的路径差异,使用api来追加路径更加跨平台,例如:</p>
  1685. <pre><code class="lang-lua">print(path.join("$(tmpdir)", "dir1", "dir2", "file.txt"))
  1686. </code></pre>
  1687. <p>上述拼接在unix上相当于:<code>$(tmpdir)/dir1/dir2/file.txt</code>,而在windows上相当于:<code>$(tmpdir)\\dir1\\dir2\\file.txt</code></p>
  1688. <p>如果觉得这样很繁琐,不够清晰简洁,可以使用:<a href="path-translate">path.translate</a>方式,格式化转换路径字符串到当前平台支持的格式。</p>
  1689. <h4 id="pathtranslate">path.translate</h4>
  1690. <ul>
  1691. <li>转换路径到当前平台的路径风格</li>
  1692. </ul>
  1693. <p>格式化转化指定路径字符串到当前平台支持的路径风格,同时支持<code>windows/unix</code>格式的路径字符串参数传入,甚至混合传入,例如:</p>
  1694. <pre><code class="lang-lua">print(path.translate("$(tmpdir)/dir/file.txt"))
  1695. print(path.translate("$(tmpdir)\\dir\\file.txt"))
  1696. print(path.translate("$(tmpdir)\\dir/dir2//file.txt"))
  1697. </code></pre>
  1698. <p>上面这三种不同格式的路径字符串,经过<code>translate</code>规范化后,就会变成当前平台支持的格式,并且会去掉冗余的路径分隔符。</p>
  1699. <h4 id="pathbasename">path.basename</h4>
  1700. <ul>
  1701. <li>获取路径最后不带后缀的文件名</li>
  1702. </ul>
  1703. <pre><code class="lang-lua">print(path.basename("$(tmpdir)/dir/file.txt"))
  1704. </code></pre>
  1705. <p>显示结果为:<code>file</code></p>
  1706. <h4 id="pathfilename">path.filename</h4>
  1707. <ul>
  1708. <li>获取路径最后带后缀的文件名</li>
  1709. </ul>
  1710. <pre><code class="lang-lua">print(path.filename("$(tmpdir)/dir/file.txt"))
  1711. </code></pre>
  1712. <p>显示结果为:<code>file.txt</code></p>
  1713. <h4 id="pathextension">path.extension</h4>
  1714. <ul>
  1715. <li>获取路径的后缀名</li>
  1716. </ul>
  1717. <pre><code class="lang-lua">print(path.extensione("$(tmpdir)/dir/file.txt"))
  1718. </code></pre>
  1719. <p>显示结果为:<code>.txt</code></p>
  1720. <h4 id="pathdirectory">path.directory</h4>
  1721. <ul>
  1722. <li>获取路径的目录名</li>
  1723. </ul>
  1724. <pre><code class="lang-lua">print(path.directory("$(tmpdir)/dir/file.txt"))
  1725. </code></pre>
  1726. <p>显示结果为:<code>$(tmpdir)/dir</code></p>
  1727. <h4 id="pathrelative">path.relative</h4>
  1728. <ul>
  1729. <li>转换成相对路径</li>
  1730. </ul>
  1731. <pre><code class="lang-lua">print(path.relative("$(tmpdir)/dir/file.txt", "$(tmpdir)"))
  1732. </code></pre>
  1733. <p>显示结果为:<code>dir/file.txt</code></p>
  1734. <p>第二个参数是指定相对的根目录,如果不指定,则默认相对当前目录:</p>
  1735. <pre><code class="lang-lua">os.cd("$(tmpdir)")
  1736. print(path.relative("$(tmpdir)/dir/file.txt"))
  1737. </code></pre>
  1738. <p>这样结果是一样的。</p>
  1739. <h4 id="pathabsolute">path.absolute</h4>
  1740. <ul>
  1741. <li>转换成绝对路径</li>
  1742. </ul>
  1743. <pre><code class="lang-lua">print(path.absolute("dir/file.txt", "$(tmpdir)"))
  1744. </code></pre>
  1745. <p>显示结果为:<code>$(tmpdir)/dir/file.txt</code></p>
  1746. <p>第二个参数是指定相对的根目录,如果不指定,则默认相对当前目录:</p>
  1747. <pre><code class="lang-lua">os.cd("$(tmpdir)")
  1748. print(path.absolute("dir/file.txt"))
  1749. </code></pre>
  1750. <p>这样结果是一样的。</p>
  1751. <h4 id="pathis_absolute">path.is_absolute</h4>
  1752. <ul>
  1753. <li>判断是否为绝对路径</li>
  1754. </ul>
  1755. <pre><code class="lang-lua">if path.is_absolute("/tmp/file.txt") then
  1756. -- 如果是绝对路径
  1757. end
  1758. </code></pre>
  1759. <h4 id="pathsplitenv">path.splitenv</h4>
  1760. <ul>
  1761. <li>分割环境变量中的路径</li>
  1762. </ul>
  1763. <pre><code class="lang-lua">local pathes = path.splitenv(vformat("$(env PATH)"))
  1764. -- for windows
  1765. local pathes = path.splitenv("C:\\Windows;C:\\Windows\\System32")
  1766. -- got { "C:\\Windows", "C:\\Windows\\System32" }
  1767. -- for *nix
  1768. local pathes = path.splitenv("/usr/bin:/usr/local/bin")
  1769. -- got { "/usr/bin", "/usr/local/bin" }
  1770. </code></pre>
  1771. <p>结果为一个包含了输入字符串中路径的数组。</p>
  1772. <h3 id="table">table</h3>
  1773. <p>table属于lua原生提供的模块,对于原生接口使用可以参考:<a href="https://www.lua.org/manual/5.1/manual.html#5.5">lua官方文档</a></p>
  1774. <p>xmake中对其进行了扩展,增加了一些扩展接口:</p>
  1775. <table>
  1776. <thead>
  1777. <tr>
  1778. <th>接口</th>
  1779. <th>描述</th>
  1780. <th>支持版本</th>
  1781. </tr>
  1782. </thead>
  1783. <tbody>
  1784. <tr>
  1785. <td><a href="#tablejoin">table.join</a></td>
  1786. <td>合并多个table并返回</td>
  1787. <td>>= 2.0.1</td>
  1788. </tr>
  1789. <tr>
  1790. <td><a href="#tablejoin2">table.join2</a></td>
  1791. <td>合并多个table到第一个table</td>
  1792. <td>>= 2.0.1</td>
  1793. </tr>
  1794. <tr>
  1795. <td><a href="#tableunique">table.unique</a></td>
  1796. <td>对table中的内容进行去重</td>
  1797. <td>>= 2.0.1</td>
  1798. </tr>
  1799. <tr>
  1800. <td><a href="#tableslice">table.slice</a></td>
  1801. <td>获取table的切片</td>
  1802. <td>>= 2.0.1</td>
  1803. </tr>
  1804. </tbody>
  1805. </table>
  1806. <h4 id="tablejoin">table.join</h4>
  1807. <ul>
  1808. <li>合并多个table并返回</li>
  1809. </ul>
  1810. <p>可以将多个table里面的元素进行合并后,返回到一个新的table中,例如:</p>
  1811. <pre><code class="lang-lua">local newtable = table.join({1, 2, 3}, {4, 5, 6}, {7, 8, 9})
  1812. </code></pre>
  1813. <p>结果为:<code>{1, 2, 3, 4, 5, 6, 7, 8, 9}</code></p>
  1814. <p>并且它也支持字典的合并:</p>
  1815. <pre><code class="lang-lua">local newtable = table.join({a = "a", b = "b"}, {c = "c"}, {d = "d"})
  1816. </code></pre>
  1817. <p>结果为:<code>{a = "a", b = "b", c = "c", d = "d"}</code></p>
  1818. <h4 id="tablejoin2">table.join2</h4>
  1819. <ul>
  1820. <li>合并多个table到第一个table</li>
  1821. </ul>
  1822. <p>类似<a href="#table.join">table.join</a>,唯一的区别是,合并的结果放置在第一个参数中,例如:</p>
  1823. <pre><code class="lang-lua">local t = {0, 9}
  1824. table.join2(t, {1, 2, 3})
  1825. </code></pre>
  1826. <p>结果为:<code>t = {0, 9, 1, 2, 3}</code></p>
  1827. <h4 id="tableunique">table.unique</h4>
  1828. <ul>
  1829. <li>对table中的内容进行去重</li>
  1830. </ul>
  1831. <p>去重table的元素,一般用于数组table,例如:</p>
  1832. <pre><code class="lang-lua">local newtable = table.unique({1, 1, 2, 3, 4, 4, 5})
  1833. </code></pre>
  1834. <p>结果为:<code>{1, 2, 3, 4, 5}</code></p>
  1835. <h4 id="tableslice">table.slice</h4>
  1836. <ul>
  1837. <li>获取table的切片</li>
  1838. </ul>
  1839. <p>用于提取数组table的部分元素,例如:</p>
  1840. <pre><code class="lang-lua">-- 提取第4个元素后面的所有元素,结果:{4, 5, 6, 7, 8, 9}
  1841. table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4)
  1842. -- 提取第4-8个元素,结果:{4, 5, 6, 7, 8}
  1843. table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4, 8)
  1844. -- 提取第4-8个元素,间隔步长为2,结果:{4, 6, 8}
  1845. table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4, 8, 2)
  1846. </code></pre>
  1847. <h4 id="tablecontains">table.contains</h4>
  1848. <ul>
  1849. <li>判断 table 中包含指定的值</li>
  1850. </ul>
  1851. <pre><code class="lang-lua">if table.contains(t, 1, 2, 3) then
  1852. -- ...
  1853. end
  1854. </code></pre>
  1855. <p>只要 table 中包含 1, 2, 3 里面任意一个值,则返回 true</p>
  1856. <h4 id="tableorderkeys">table.orderkeys</h4>
  1857. <ul>
  1858. <li>获取有序的 key 列表</li>
  1859. </ul>
  1860. <p><code>table.keys(t)</code> 返回的 key 列表顺序是随机的,想要获取有序 key 列表,可以用这个接口。</p>
  1861. <h3 id="string">string</h3>
  1862. <p>字符串模块为lua原生自带的模块,具体使用见:<a href="https://www.lua.org/manual/5.1/manual.html#5.4">lua官方手册</a></p>
  1863. <p>xmake中对其进行了扩展,增加了一些扩展接口:</p>
  1864. <table>
  1865. <thead>
  1866. <tr>
  1867. <th>接口</th>
  1868. <th>描述</th>
  1869. <th>支持版本</th>
  1870. </tr>
  1871. </thead>
  1872. <tbody>
  1873. <tr>
  1874. <td><a href="#stringstartswith">string.startswith</a></td>
  1875. <td>判断字符串开头是否匹配</td>
  1876. <td>>= 1.0.1</td>
  1877. </tr>
  1878. <tr>
  1879. <td><a href="#stringendswith">string.endswith</a></td>
  1880. <td>判断字符串结尾是否匹配</td>
  1881. <td>>= 1.0.1</td>
  1882. </tr>
  1883. <tr>
  1884. <td><a href="#stringsplit">string.split</a></td>
  1885. <td>分割字符串</td>
  1886. <td>>= 1.0.1</td>
  1887. </tr>
  1888. <tr>
  1889. <td><a href="#stringtrim">string.trim</a></td>
  1890. <td>去掉字符串左右空白字符</td>
  1891. <td>>= 1.0.1</td>
  1892. </tr>
  1893. <tr>
  1894. <td><a href="#stringltrim">string.ltrim</a></td>
  1895. <td>去掉字符串左边空白字符</td>
  1896. <td>>= 1.0.1</td>
  1897. </tr>
  1898. <tr>
  1899. <td><a href="#stringrtrim">string.rtrim</a></td>
  1900. <td>去掉字符串右边空白字符</td>
  1901. <td>>= 1.0.1</td>
  1902. </tr>
  1903. </tbody>
  1904. </table>
  1905. <h4 id="stringstartswith">string.startswith</h4>
  1906. <ul>
  1907. <li>判断字符串开头是否匹配</li>
  1908. </ul>
  1909. <pre><code class="lang-lua">local s = "hello xmake"
  1910. if s:startswith("hello") then
  1911. print("match")
  1912. end
  1913. </code></pre>
  1914. <h4 id="stringendswith">string.endswith</h4>
  1915. <ul>
  1916. <li>判断字符串结尾是否匹配</li>
  1917. </ul>
  1918. <pre><code class="lang-lua">local s = "hello xmake"
  1919. if s:endswith("xmake") then
  1920. print("match")
  1921. end
  1922. </code></pre>
  1923. <h4 id="stringsplit">string.split</h4>
  1924. <ul>
  1925. <li>分割字符串</li>
  1926. </ul>
  1927. <p>v2.2.7版本对这个接口做了改进,以下是对2.2.7之后版本的使用说明。</p>
  1928. <p>按模式匹配分割字符串,忽略空串,例如:</p>
  1929. <pre><code class="lang-lua">("1\n\n2\n3"):split(&#39;\n&#39;) => 1, 2, 3
  1930. ("abc123123xyz123abc"):split(&#39;123&#39;) => abc, xyz, abc
  1931. ("abc123123xyz123abc"):split(&#39;[123]+&#39;) => abc, xyz, abc
  1932. </code></pre>
  1933. <p>按纯文本匹配分割字符串,忽略空串(省去了模式匹配,会提升稍许性能),例如:</p>
  1934. <pre><code class="lang-lua">("1\n\n2\n3"):split(&#39;\n&#39;, {plain = true}) => 1, 2, 3
  1935. ("abc123123xyz123abc"):split(&#39;123&#39;, {plain = true}) => abc, xyz, abc
  1936. </code></pre>
  1937. <p>按模式匹配分割字符串,严格匹配,不忽略空串,例如:</p>
  1938. <pre><code class="lang-lua">("1\n\n2\n3"):split(&#39;\n&#39;, {strict = true}) => 1, , 2, 3
  1939. ("abc123123xyz123abc"):split(&#39;123&#39;, {strict = true}) => abc, , xyz, abc
  1940. ("abc123123xyz123abc"):split(&#39;[123]+&#39;, {strict = true}) => abc, xyz, abc
  1941. </code></pre>
  1942. <p>按纯文本匹配分割字符串,严格匹配,不忽略空串(省去了模式匹配,会提升稍许性能),例如:</p>
  1943. <pre><code class="lang-lua">("1\n\n2\n3"):split(&#39;\n&#39;, {plain = true, strict = true}) => 1, , 2, 3
  1944. ("abc123123xyz123abc"):split(&#39;123&#39;, {plain = true, strict = true}) => abc, , xyz, abc
  1945. </code></pre>
  1946. <p>限制分割块数</p>
  1947. <pre><code class="lang-lua">("1\n\n2\n3"):split(&#39;\n&#39;, {limit = 2}) => 1, 2\n3
  1948. ("1.2.3.4.5"):split(&#39;%.&#39;, {limit = 3}) => 1, 2, 3.4.5
  1949. </code></pre>
  1950. <h4 id="stringtrim">string.trim</h4>
  1951. <ul>
  1952. <li>去掉字符串左右空白字符</li>
  1953. </ul>
  1954. <pre><code class="lang-lua">string.trim(" hello xmake! ")
  1955. </code></pre>
  1956. <p>结果为:"hello xmake!"</p>
  1957. <h4 id="stringltrim">string.ltrim</h4>
  1958. <ul>
  1959. <li>去掉字符串左边空白字符</li>
  1960. </ul>
  1961. <pre><code class="lang-lua">string.ltrim(" hello xmake! ")
  1962. </code></pre>
  1963. <p>结果为:"hello xmake! "</p>
  1964. <h4 id="stringrtrim">string.rtrim</h4>
  1965. <ul>
  1966. <li>去掉字符串右边空白字符</li>
  1967. </ul>
  1968. <pre><code class="lang-lua">string.rtrim(" hello xmake! ")
  1969. </code></pre>
  1970. <p>结果为:" hello xmake!"</p>
  1971. <h3 id="coroutine">coroutine</h3>
  1972. <p>协程模块是lua原生自带的模块,具使用见:<a href="https://www.lua.org/manual/5.1/manual.html#5.2">lua官方手册</a></p>
  1973. <h3 id="signal">signal</h3>
  1974. <p>2.9.1 新增了信号注册接口,我们可以在 lua 层,注册 SIGINT 等信号处理函数,来定制化响应逻辑。</p>
  1975. <h4 id="signalregister">signal.register</h4>
  1976. <ul>
  1977. <li>注册信号处理器</li>
  1978. </ul>
  1979. <p>目前仅仅支持 SIGINT 信号的处理,同时它也是支持 windows 等主流平台的。</p>
  1980. <pre><code class="lang-lua">import("core.base.signal")
  1981. function main()
  1982. signal.register(signal.SIGINT, function (signo)
  1983. print("signal.SIGINT(%d)", signo)
  1984. end)
  1985. io.read()
  1986. end
  1987. </code></pre>
  1988. <p>这对于当一些子进程内部屏蔽了 SIGINT,导致卡死不退出,即使用户按了 <code>Ctrl+C</code> 退出了 xmake 进程,它也没有退出时候,<br>我们就可以通过这种方式去强制退掉它。</p>
  1989. <pre><code class="lang-lua">import("core.base.process")
  1990. import("core.base.signal")
  1991. function main()
  1992. local proc
  1993. signal.register(signal.SIGINT, function (signo)
  1994. print("sigint")
  1995. if proc then
  1996. proc:kill()
  1997. end
  1998. end)
  1999. proc = process.open("./trap.sh")
  2000. if proc then
  2001. proc:wait()
  2002. proc:close()
  2003. end
  2004. end
  2005. </code></pre>
  2006. <p>关于这个问题的背景,可以参考:<a href="https://github.com/xmake-io/xmake/issues/4889">#4889</a></p>
  2007. <h4 id="signalignore">signal.ignore</h4>
  2008. <ul>
  2009. <li>忽略某个信号</li>
  2010. </ul>
  2011. <p>我们也可以通过 <code>signal.ignore</code> 这个接口,去忽略屏蔽某个信号的处理。</p>
  2012. <pre><code class="lang-lua">signal.ignore(signal.SIGINT)
  2013. </code></pre>
  2014. <h4 id="signalreset">signal.reset</h4>
  2015. <ul>
  2016. <li>重置某个信号</li>
  2017. </ul>
  2018. <p>我们也可以清除某个信号的处理函数,回退到默认的处理逻辑。</p>
  2019. <pre><code class="lang-lua">signal.reset(signal.SIGINT)
  2020. </code></pre>
  2021. </article>
  2022. </body>
  2023. </html>