global_interfaces.html 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  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/global_interfaces">https://xmake.io/#/zh-cn/manual/global_interfaces</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>全局接口影响整个工程描述,被调用后,后面被包含进来的所有子<code>xmake.lua</code>都会受影响。</p>
  86. <h3 id="includes">includes</h3>
  87. <h4 id="">添加子工程文件和目录</h4>
  88. <p>我们能够使用此接口添加工程子文件(xmake.lua)或者带有xmake.lua的工程子目录。</p>
  89. <pre><code>projectdir
  90. - subdirs
  91. - xmake.lua
  92. - src
  93. </code></pre><p>添加子工程目录:</p>
  94. <pre><code class="lang-lua">includes("subdirs")
  95. target("test")
  96. set_kind("binary")
  97. add_files("src/*.c")
  98. </code></pre>
  99. <p>或者添加子工程文件:</p>
  100. <pre><code class="lang-lua">includes("subdirs/xmake.lua")
  101. target("test")
  102. set_kind("binary")
  103. add_files("src/*.c")
  104. </code></pre>
  105. <p>我们也可以通过模式匹配的方式,递归添加多个工程子目录文件:</p>
  106. <pre><code class="lang-lua">includes("**/xmake.lua")
  107. target("test")
  108. set_kind("binary")
  109. add_files("src/*.c")
  110. </code></pre>
  111. <p>2.8.5 版本可以 includes 包含内置的一些辅助配置脚本,例如:</p>
  112. <pre><code class="lang-lua">includes("@builtin/check")
  113. </code></pre>
  114. <p>会引入内置提供的一些检测辅助接口。</p>
  115. <p>还有</p>
  116. <pre><code class="lang-lua">includes("@builtin/qt")
  117. </code></pre>
  118. <p>会引入一些内置的 Qt 相关辅助接口。</p>
  119. <p>其中 <code>@builtin</code> 是告诉 xmake 从内置的 includes 目录中引入配置脚本。</p>
  120. <p>也就是这个路径下的配置文件:<a href="https://github.com/xmake-io/xmake/tree/master/xmake/includes">includes</a></p>
  121. <p>我们可以向上面那样,按目录整个引入,也可以引入单个配置文件,例如:</p>
  122. <pre><code class="lang-lua">includes("@builtin/check/check_cfuncs.lua")
  123. </code></pre>
  124. <p>仅仅引入 check 目录下 check_cfuncs 相关的辅助脚本。</p>
  125. <p>而通过 <code>@builtin</code> 我们就能很好的区分是引入当前用户工程目录下的文件,还是 xmake 安装目录下的内置文件。</p>
  126. <h3 id="set_project">set_project</h3>
  127. <h4 id="">设置工程名</h4>
  128. <p>设置工程名,在doxygen自动文档生成插件、工程文件生成插件中会用到,一般设置在xmake.lua的最开头,当然放在其他地方也是可以的</p>
  129. <pre><code class="lang-lua">-- 设置工程名
  130. set_project("tbox")
  131. -- 设置工程版本
  132. set_version("1.5.1")
  133. </code></pre>
  134. <h3 id="set_version">set_version</h3>
  135. <h4 id="">设置工程版本</h4>
  136. <p>设置项目版本,可以放在 xmake.lua 任何地方,一般放在最开头,例如:</p>
  137. <pre><code class="lang-lua">set_version("1.5.1")
  138. </code></pre>
  139. <p>2.1.7 版本支持 buildversion 的配置:</p>
  140. <pre><code class="lang-lua">set_version("1.5.1", {build = "%Y%m%d%H%M"})
  141. </code></pre>
  142. <p>我们也能够添加版本宏定义到头文件,请参考:<a href="/mirror/manual/project_target.html#add-template-configuration-files">add_configfiles</a></p>
  143. <p>!> 我们可以全局设置版本,但现在我们也可以在 target 域去单独设置它。</p>
  144. <p>2.8.2 版本新增了 soname 版本支持,用于控制 so/dylib 动态库的版本兼容性控制。</p>
  145. <p>我们可以配置 soname 的版本后缀名称,xmake 会在编译、安装动态库的时候,自动生成符号链接,执行指定版本的动态库。</p>
  146. <p>例如,如果我们配置:</p>
  147. <pre><code class="lang-lua">set_version("1.0.1", {soname = true})
  148. </code></pre>
  149. <p>xmake 会自动解析版本号的 major 版本作为 soname 版本,生成的结构如下:</p>
  150. <pre><code>└── lib
  151. ├── libfoo.1.0.1.dylib
  152. ├── libfoo.1.dylib -> libfoo.1.0.1.dylib
  153. └── libfoo.dylib -> libfoo.1.dylib
  154. </code></pre><p>当然,我们也可以指定 soname 到特定的版本命名:</p>
  155. <pre><code class="lang-lua">set_version("1.0.1", {soname = "1.0"}) -> libfoo.so.1.0, libfoo.1.0.dylib
  156. set_version("1.0.1", {soname = "1"}) -> libfoo.so.1, libfoo.1.dylib
  157. set_version("1.0.1", {soname = "A"}) -> libfoo.so.A, libfoo.A.dylib
  158. set_version("1.0.1", {soname = ""}) -> libfoo.so, libfoo.dylib
  159. </code></pre>
  160. <p>而如果没设置 soname,那么默认不开启 soname 版本兼容控制:</p>
  161. <pre><code class="lang-lua">set_version("1.0.1") -> libfoo.so, libfoo.dylib
  162. </code></pre>
  163. <h3 id="set_xmakever">set_xmakever</h3>
  164. <h4 id="xmake">设置最小xmake版本</h4>
  165. <p>用于处理xmake版本兼容性问题,如果项目的<code>xmake.lua</code>,通过这个接口设置了最小xmake版本支持,那么用户环境装的xmake低于要求的版本,就会提示错误。</p>
  166. <p>一般情况下,建议默认对其进行设置,这样对用户比较友好,如果<code>xmake.lua</code>中用到了高版本的api接口,用户那边至少可以知道是否因为版本不对导致的构建失败。</p>
  167. <p>设置如下:</p>
  168. <pre><code class="lang-lua">-- 设置最小版本为:2.1.0,低于此版本的xmake编译此工程将会提示版本错误信息
  169. set_xmakever("2.1.0")
  170. </code></pre>
  171. <h3 id="add_moduledirs">add_moduledirs</h3>
  172. <h4 id="">添加模块目录</h4>
  173. <p>xmake内置的扩展模块都在<code>xmake/modules</code>目录下,可通过<a href="#import">import</a>来导入他们,如果自己在工程里面实现了一些扩展模块,<br>可以放置在这个接口指定的目录下,import也就会能找到,并且优先进行导入。</p>
  174. <h3 id="add_plugindirs">add_plugindirs</h3>
  175. <h4 id="">添加插件目录</h4>
  176. <p>xmake内置的插件都是放在<code>xmake/plugins</code>目录下,但是对于用户自定义的一些特定工程的插件,如果不想放置在xmake安装目录下,那么可以在<code>xmake.lua</code>中进行配置指定的其他插件路径。</p>
  177. <pre><code class="lang-lua">-- 将当前工程下的plugins目录设置为自定义插件目录
  178. add_plugindirs("$(projectdir)/plugins")
  179. </code></pre>
  180. <p>这样,xmake在编译此工程的时候,也就加载这些插件。</p>
  181. <h3 id="get_config">get_config</h3>
  182. <h4 id="">获取给定的配置值</h4>
  183. <p>此接口从2.2.2版本开始引入,用于快速获取给定的配置值,可用于描述域。</p>
  184. <pre><code class="lang-lua">if get_config("myconfig") == "xxx" then
  185. add_defines("HELLO")
  186. end
  187. </code></pre>
  188. <h3 id="set_config">set_config</h3>
  189. <h4 id="">设置给定的默认配置值</h4>
  190. <p>此接口从2.2.2版本开始引入,用于快速在xmake.lua中设置一个默认配置值,仅用于描述域。</p>
  191. <p>之前很多配置,包括编译工具链,构建目录等只能通过<code>$ xmake f --name=value</code>的方式来配置,如果我们想写死在xmake.lua提供一个默认值,就可以通过下面的方式来配置:</p>
  192. <pre><code class="lang-lua">set_config("name", "value")
  193. set_config("buildir", "other/buildir")
  194. set_config("cc", "gcc")
  195. set_config("ld", "g++")
  196. </code></pre>
  197. <p>不过,我们还是可以通过<code>$ xmake f --name=value</code>的方式,去修改xmake.lua中的默认配置。</p>
  198. <h3 id="add_requires">add_requires</h3>
  199. <h4 id="">添加需要的依赖包</h4>
  200. <p>xmake的依赖包管理是完全支持语义版本选择的,例如:"~1.6.1",对于语义版本的具体描述见:<a href="https://semver.org/">https://semver.org/</a></p>
  201. <h5 id="">语义版本</h5>
  202. <pre><code class="lang-lua">add_requires("tbox 1.6.*", "pcre 8.x", "libpng ^1.18")
  203. add_requires("libpng ~1.16", "zlib 1.1.2 || >=1.2.11 <1.3.0")
  204. </code></pre>
  205. <p>目前xmake使用的语义版本解析器是<a href="https://github.com/uael">uael</a>贡献的<a href="https://github.com/uael/sv">sv</a>库,里面也有对版本描述写法的详细说明,可以参考下:<a href="https://github.com/uael/sv#versions">版本描述说明</a></p>
  206. <h5 id="">最近版本</h5>
  207. <p>当然,如果我们对当前的依赖包的版本没有特殊要求,那么可以直接这么写:</p>
  208. <pre><code class="lang-lua">add_requires("tbox", "libpng", "zlib")
  209. </code></pre>
  210. <p>默认,没设置版本号,xmake 会选取最近版本的包,等价于 <code>add_requires("zlib latest")</code></p>
  211. <h5 id="">分支选择</h5>
  212. <p>这会使用已知的最新版本包,或者是master分支的源码编译的包,如果当前包有git repo地址,我们也能指定特定分支版本:</p>
  213. <pre><code class="lang-lua">add_requires("tbox master")
  214. add_requires("tbox dev")
  215. </code></pre>
  216. <p>如果指定的依赖包当前平台不支持,或者编译安装失败了,那么xmake会编译报错,这对于有些必须要依赖某些包才能工作的项目,这是合理的。<br>但是如果有些包是可选的依赖,即使没有也可以正常编译使用的话,可以设置为可选包:</p>
  217. <h5 id="gitcommit">Git commit 选择</h5>
  218. <p>2.6.5 版本,我们可以对 git 维护的包直接指定 git commit 来选择版本。</p>
  219. <pre><code class="lang-lua">add_requires("tbox e807230557aac69e4d583c75626e3a7ebdb922f8")
  220. </code></pre>
  221. <h5 id="">可选包</h5>
  222. <pre><code class="lang-lua">add_requires("zlib", {optional = true})
  223. </code></pre>
  224. <h5 id="">禁用系统包</h5>
  225. <p>默认的设置,xmake会去优先检测系统库是否存在(如果没设置版本要求),如果用户完全不想使用系统库以及第三方包管理提供的库,那么可以设置:</p>
  226. <pre><code class="lang-lua">add_requires("zlib", {system = false})
  227. </code></pre>
  228. <h5 id="">禁用包校验</h5>
  229. <p>默认包安装,对于下载的包都是会去自动校验完整性,避免被篡改,但是如果安装一些未知新版本的包,就不行了。</p>
  230. <p>用户可以通过 <code>{verify = false}</code> 强行禁用包完整性校验来临时安装他们(但通常不推荐这么做)。</p>
  231. <pre><code class="lang-lua">add_requires("zlib", {verify = false})
  232. </code></pre>
  233. <h5 id="">使用调试包</h5>
  234. <p>如果我们想同时源码调试依赖包,那么可以设置为使用debug版本的包(当然前提是这个包支持debug编译):</p>
  235. <pre><code class="lang-lua">add_requires("zlib", {debug = true})
  236. </code></pre>
  237. <p>如果当前包还不支持debug编译,可在仓库中提交修改编译规则,对debug进行支持,例如:</p>
  238. <pre><code class="lang-lua">package("openssl")
  239. on_install("linux", "macosx", function (package)
  240. os.vrun("./config %s --prefix=\"%s\"", package:debug() and "--debug" or "", package:installdir())
  241. os.vrun("make -j4")
  242. os.vrun("make install")
  243. end)
  244. </code></pre>
  245. <h5 id="">作为私有包使用</h5>
  246. <p>如果这个包,我们仅仅用于包定义,不想对外默认导出 links/linkdirs 信息,可以作为私有包提供。</p>
  247. <p>这通常对于做包时候,很有用。</p>
  248. <pre><code class="lang-lua">package("test")
  249. add_deps("zlib", {private = true})
  250. on_install(function (package)
  251. local zlib = package:dep("zlib"):fetch()
  252. -- TODO
  253. end)
  254. </code></pre>
  255. <p>如果自己定义的一个 test 包,私有依赖一个 zlib 包,等待 zlib 安装完成后,获取里面的包文件信息做进一步处理安装,但是 zlib 包本身不会再对外导出 links/linkdirs。</p>
  256. <p>尽管,<code>add_requires</code> 也支持这个选项,但是不对外导出 links/linkdirs,所以通常不会去这么用,仅仅对于做包很有帮助。</p>
  257. <h5 id="">使用动态库</h5>
  258. <p>默认的包安装的是静态库,如果要启用动态库,可以配置如下:</p>
  259. <pre><code class="lang-lua">add_requires("zlib", {configs = {shared = true}})
  260. </code></pre>
  261. <p>!> 当然,前提是这个包的定义里面,有对 <code>package:config("shared")</code> 判断处理,官方 xmake-repo 仓库里面,通常都是严格区分支持的。</p>
  262. <h5 id="pic">禁用 pic 支持</h5>
  263. <p>默认安装的 linux 包,都是开启 pic 编译的,这对于动态库中依赖静态库非常有用,但如果想禁用 pic,也是可以的。</p>
  264. <pre><code class="lang-lua">add_requires("zlib", {configs = {pic = false}})
  265. </code></pre>
  266. <h5 id="vsruntime">vs runtime 设置</h5>
  267. <p>默认安装的 windows 包是采用 msvc/MT 编译的,如果要切换到 MD,可以配置如下:</p>
  268. <pre><code class="lang-lua">add_requires("zlib", {configs = {vs_runtime = "MD"}})
  269. </code></pre>
  270. <p>另外,还支持:MT, MTd, MD, MDd 四种选项。</p>
  271. <p>如果依赖的包很多,每个配置切换一遍非常的麻烦,我们也可以通过 <code>set_runtimes</code> 全局设置切换,对所有依赖包生效。</p>
  272. <pre><code class="lang-lua">set_runtimes("MD")
  273. add_requires("zlib", "pcre2", "mbedtls")
  274. </code></pre>
  275. <h5 id="">特定配置包</h5>
  276. <p>某些包在编译时候有各种编译选项,我们也可以传递进来:</p>
  277. <pre><code class="lang-lua">add_requires("boost", {configs = {context = true, coroutine = true}})
  278. </code></pre>
  279. <p>比如上面,安装的 boost 包,是启用了它内部的一些子模块特性(带有协程模块支持的包)。</p>
  280. <p>当然,具体支持哪些配置,每个包都是不同的,可以通过 <code>xmake require --info boost</code> 命令查看里面的 configs 部分列表。</p>
  281. <p>因为,每个包定义里面,都会有自己的配置选项,并且通过 <code>package:config("coroutine")</code> 在安装时候去判断启用它们。</p>
  282. <h5 id="">安装第三方管理器的包</h5>
  283. <p>目前支持安装下面这些第三方包管理器中包。</p>
  284. <ul>
  285. <li>Conan (conan::openssl/1.1.1g)</li>
  286. <li>Conda (conda::libpng 1.3.67)</li>
  287. <li>Vcpkg (vcpkg::ffmpeg)</li>
  288. <li>Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)</li>
  289. <li>Pacman on archlinux/msys2 (pacman::libcurl)</li>
  290. <li>Apt on ubuntu/debian (apt::zlib1g-dev)</li>
  291. <li>Clib (clib::<a href="mailto:clibs/[email protected]">clibs/[email protected]</a>)</li>
  292. <li>Dub (dub::log 0.4.3)</li>
  293. <li>Portage on Gentoo/Linux (portage::libhandy)</li>
  294. </ul>
  295. <p>例如添加conan的依赖包:</p>
  296. <pre><code class="lang-lua">add_requires("conan::zlib/1.2.11", {alias = "zlib", debug = true})
  297. add_requires("conan::openssl/1.1.1g", {alias = "openssl",
  298. configs = {options = "OpenSSL:shared=True"}})
  299. target("test")
  300. set_kind("binary")
  301. add_files("src/*.c")
  302. add_packages("openssl", "zlib")
  303. </code></pre>
  304. <p>执行xmake进行编译后:</p>
  305. <pre><code class="lang-console">ruki:test_package ruki$ xmake
  306. checking for the architecture ... x86_64
  307. checking for the Xcode directory ... /Applications/Xcode.app
  308. checking for the SDK version of Xcode ... 10.14
  309. note: try installing these packages (pass -y to skip confirm)?
  310. -> conan::zlib/1.2.11 (debug)
  311. -> conan::openssl/1.1.1g
  312. please input: y (y/n)
  313. => installing conan::zlib/1.2.11 .. ok
  314. => installing conan::openssl/1.1.1g .. ok
  315. [ 0%]: cache compiling.release src/main.c
  316. [100%]: linking.release test
  317. </code></pre>
  318. <p>关于这个的完整介绍和所有第三方包的安装使用,可以参考文档:<a href="https://xmake.io/#/zh-cn/package/remote_package?id=%e7%ac%ac%e4%b8%89%e6%96%b9%e4%be%9d%e8%b5%96%e5%8c%85%e5%ae%89%e8%a3%85">第三方依赖包安装</a></p>
  319. <h5 id="">另一种简化的配置语法</h5>
  320. <p>我们通常使用的常用配置语法:</p>
  321. <pre><code class="lang-lua">add_requires("boost >=1.78.0", {configs = {iostreams = true, system = true, thread = true}})
  322. </code></pre>
  323. <p>对于大部分 boolean 配置,我们可以通过下面的写法,去简化配置。</p>
  324. <pre><code class="lang-lua">add_requires("boost[iostreams,system,thread] >=1.78.0")
  325. </code></pre>
  326. <p>这对于 <code>xrepo install</code> 独立 cli 命令下带复杂配置的安装,会省事不少,用户可以根据自己的喜好需求,选择使用。</p>
  327. <pre><code class="lang-console">xrepo install boost[iostreams,system,thread]
  328. </code></pre>
  329. <p>另外,除了 boolean 配置,还支持 string 和 array 配置值。boolean 值,也可以设置 <code>=n/y</code> 去禁用和启用。</p>
  330. <pre><code class="lang-lua">add_requires("boost[iostreams,system,thread,key=value] >=1.78.0")
  331. add_requires("boost[iostreams=y,thread=n] >=1.78.0")
  332. add_requires("ffmpeg[shared,debug,codecs=[foo,bar,zoo]]")
  333. </code></pre>
  334. <h3 id="add_requireconfs">add_requireconfs</h3>
  335. <h4 id="">设置指定依赖包的配置</h4>
  336. <p>这是 v2.5.1 之后的版本新增的接口,我们可以用它来对 <code>add_requires()</code> 定义的包和它的依赖包的配置进行扩充和改写,它有下面几种用法。</p>
  337. <h5 id="">扩充指定包的配置</h5>
  338. <p>这是基本用法,比如我们已经通过 <code>add_requires("zlib")</code> 声明了一个包,想要在后面对这个 zlib 的配置进行扩展,改成动态库编译,可以通过下面的方式配置。</p>
  339. <pre><code class="lang-lua">add_requires("zlib")
  340. add_requireconfs("zlib", {configs = {shared = true}})
  341. </code></pre>
  342. <p>它等价于</p>
  343. <pre><code class="lang-lua">add_requires("zlib", {configs = {shared = true}})
  344. </code></pre>
  345. <h5 id="">设置通用的默认配置</h5>
  346. <p>上面的用法,我们还看不出有什么实际用处,但如果依赖多了就能看出效果了,比如下面这样:</p>
  347. <pre><code class="lang-lua">add_requires("zlib", {configs = {shared = true}})
  348. add_requires("pcre", {configs = {shared = true}})
  349. add_requires("libpng", {configs = {shared = true}})
  350. add_requires("libwebp", {configs = {shared = true}})
  351. add_requires("libcurl", {configs = {shared = false}})
  352. </code></pre>
  353. <p>是不是非常繁琐,如果我们用上 <code>add_requireconfs</code> 来设置默认配置,就可以极大的简化成下面的配置:</p>
  354. <pre><code class="lang-lua">add_requireconfs("*", {configs = {shared = true}})
  355. add_requires("zlib")
  356. add_requires("pcre")
  357. add_requires("libpng")
  358. add_requires("libwebp")
  359. add_requires("libcurl", {configs = {shared = false}})
  360. </code></pre>
  361. <p>上面的配置,我们通过 <code>add_requireconfs("*", {configs = {shared = true}})</code> 使用模式匹配的方式,设置所有的依赖包默认走动态库编译安装。</p>
  362. <p>但是,我们又通过 <code>add_requires("libcurl", {configs = {shared = false}})</code> 将 libcurl 进行了特殊配置,强制走静态库编译安装。</p>
  363. <p>最终的配置结果为:zlib/pcre/libpng/libwebp 是 shared 库,libcurl 是静态库。</p>
  364. <p>我们通过模式匹配的方式,可以将一些每个包的常用配置都放置到统一的 <code>add_requireconfs</code> 中去预先配置好,极大简化每个 <code>add_requires</code> 的定义。</p>
  365. <p>!> 默认情况下,对于相同的配置,xmake 会优先使用 add_requires 中的配置,而不是 add_requireconfs。</p>
  366. <p>如果 <code>add_requires("zlib 1.2.11")</code> 中设置了版本,就会优先使用 add_requires 的配置,完全忽略 add_requireconfs 里面的版本配置,当然我们也可以通过 override 来完全重写 <code>add_requires</code> 中指定的版本。</p>
  367. <pre><code class="lang-lua">add_requires("zlib 1.2.11")
  368. add_requireconfs("zlib", {override = true, version = "1.2.10"})
  369. </code></pre>
  370. <h5 id="">改写包依赖配置</h5>
  371. <p>其实 <code>add_requireconfs</code> 最大的用处是可以让用户改写安装包的特定依赖包的配置。</p>
  372. <p>什么意思呢,比如我们项目中集成使用 libpng 这个包,并且使用了动态库版本,但是 libpng 内部依赖的 zlib 库其实还是静态库版本。</p>
  373. <pre><code class="lang-lua">add_requires("libpng", {configs = {shared = true}})
  374. </code></pre>
  375. <p>那如果我们想让 libpng 依赖的 zlib 包也改成动态库编译,应该怎么配置呢?这就需要 <code>add_requireconfs</code> 了。</p>
  376. <pre><code class="lang-lua">add_requires("libpng", {configs = {shared = true}})
  377. add_requireconfs("libpng.zlib", {configs = {shared = true}})
  378. </code></pre>
  379. <p>通过 <code>libpng.zlib</code> 依赖路径的写法,指定内部某个依赖,改写内部依赖配置。</p>
  380. <p>如果依赖路径很深,比如 <code>foo -> bar -> xyz</code> 的依赖链,我们可以写成:<code>foo.bar.xyz</code></p>
  381. <p>我们也可以改写 libpng 依赖的内部 zlib 库版本:</p>
  382. <pre><code class="lang-lua">add_requires("libpng")
  383. add_requireconfs("libpng.zlib", {override = true, version = "1.2.10"})
  384. </code></pre>
  385. <h5 id="">级联依赖的模式匹配</h5>
  386. <p>如果一个包的依赖非常多,且依赖层次也很深,怎么办呢,比如 libwebp 这个包,它的依赖有:</p>
  387. <pre><code>libwebp
  388. - libpng
  389. - zlib
  390. - cmake
  391. - libjpeg
  392. - libtiff
  393. - zlib
  394. - giflib
  395. - cmake
  396. </code></pre><p>如果我想改写 libwebp 里面的所有的依赖库都加上特定配置,那么挨个配置,就会非常繁琐,这个时候就需要 <code>add_requireconfs()</code> 的递归依赖模式匹配来支持了。</p>
  397. <pre><code class="lang-lua">add_requires("libwebp")
  398. add_requireconfs("libwebp.**|cmake", {configs = {cxflags = "-DTEST"}})
  399. </code></pre>
  400. <p>上面的配置,我们将 libwebp 中所以的库依赖就额外加上了 <code>-DTEST</code> 来编译,但是 cmake 依赖属于构建工具依赖,我们可以通过 <code>|xxx</code> 的方式排除它。</p>
  401. <p>这里的模式匹配写法,与 <code>add_files()</code> 非常类似。</p>
  402. <p>我们在给几个例子,比如这回我们只改写 libwebp 下单级的依赖配置,启用调试库:</p>
  403. <pre><code class="lang-lua">add_requires("libwebp")
  404. add_requireconfs("libwebp.*|cmake", {debug = true})
  405. </code></pre>
  406. <h3 id="add_repositories">add_repositories</h3>
  407. <h4 id="">添加依赖包仓库</h4>
  408. <p>如果需要的包不在官方仓库<a href="https://github.com/xmake-io/xmake-repo">xmake-repo</a>中,我们可以提交贡献代码到仓库进行支持。<br>但如果有些包仅用于个人或者私有项目,我们可以建立一个私有仓库repo,仓库组织结构可参考:<a href="https://github.com/xmake-io/xmake-repo">xmake-repo</a></p>
  409. <p>比如,现在我们有一个一个私有仓库repo:<a href="mailto:`[email protected]">`[email protected]</a>:myrepo/xmake-repo.git`</p>
  410. <p>我们可以通过此接口来添加:</p>
  411. <pre><code class="lang-lua">add_repositories("my-repo [email protected]:myrepo/xmake-repo.git")
  412. </code></pre>
  413. <p>如果我们只是想添加一两个私有包,这个时候特定去建立一个git repo太小题大做了,我们可以直接把包仓库放置项目里面,例如:</p>
  414. <pre><code>projectdir
  415. - myrepo
  416. - packages
  417. - t/tbox/xmake.lua
  418. - z/zlib/xmake.lua
  419. - src
  420. - main.c
  421. - xmake.lua
  422. </code></pre><p>上面myrepo目录就是自己的私有包仓库,内置在自己的项目里面,然后在xmake.lua里面添加一下这个仓库位置:</p>
  423. <pre><code class="lang-lua">add_repositories("my-repo myrepo")
  424. </code></pre>
  425. <p>这个可以参考<a href="https://github.com/tboox/benchbox">benchbox</a>项目,里面就内置了一个私有仓库。</p>
  426. <p>注:其中 myrepo 是 xmake 命令执行目录的相对路径,它不会自动根据配置文件所在目录自动转换,如果想要设置到相对于当前 xmake.lua 文件的路径,可以通过 rootdir 参数指定。</p>
  427. <pre><code class="lang-lua">add_repositories("my-repo myrepo", {rootdir = os.scriptdir()})
  428. </code></pre>
  429. <p>不过这个参数设置只有 v2.5.7 以上版本才支持。</p>
  430. <h3 id="set_defaultplat">set_defaultplat</h3>
  431. <h4 id="">设置默认的编译平台</h4>
  432. <p>v2.5.6 以上版本才支持,用于设置工程默认的编译平台,如果没有设置,默认平台跟随当前系统平台,也就是 os.host()。</p>
  433. <p>比如,在 macOS 上默认编译平台是 macosx,如果当前项目是 ios 项目,那么可以设置默认编译平台为 iphoneos。</p>
  434. <pre><code class="lang-lua">set_defaultplat("iphoneos")
  435. </code></pre>
  436. <p>它等价于,<code>xmake f -p iphoneos</code>。</p>
  437. <h3 id="set_defaultarchs">set_defaultarchs</h3>
  438. <h4 id="">设置默认的编译架构</h4>
  439. <p>v2.5.6 以上版本才支持,用于设置工程默认的编译架构,如果没有设置,默认平台跟随当前系统架构,也就是 os.arch()。</p>
  440. <pre><code class="lang-lua">set_defaultplat("iphoneos")
  441. set_defaultarchs("arm64")
  442. </code></pre>
  443. <p>它等价于,<code>xmake f -p iphoneos -a arm64</code>。</p>
  444. <p>我们也可以设置多个平台下的默认架构。</p>
  445. <pre><code class="lang-lua">set_defaultarchs("iphoneos|arm64", "windows|x64")
  446. </code></pre>
  447. <p>在 iphoneos 上默认编译 arm64 架构,在 windows 上默认编译 x64 架构。</p>
  448. <h3 id="set_defaultmode">set_defaultmode</h3>
  449. <h4 id="">设置默认的编译模式</h4>
  450. <p>v2.5.6 以上版本才支持,用于设置工程默认的编译模式,如果没有设置,默认是 release 模式编译。</p>
  451. <pre><code class="lang-lua">set_defaultmode("releasedbg")
  452. </code></pre>
  453. <p>它等价于,<code>xmake f -m releasedbg</code>。</p>
  454. <h3 id="set_allowedplats">set_allowedplats</h3>
  455. <h4 id="">设置允许编译的平台列表</h4>
  456. <p>v2.5.6 以上版本才支持,用于设置工程支持的编译平台列表,如果用户指定了其他平台,会提示错误,这通常用于限制用户指定错误的无效平台。</p>
  457. <p>如果没有设置,那么没有任何平台限制。</p>
  458. <pre><code class="lang-lua">set_allowedplats("windows", "mingw")
  459. </code></pre>
  460. <p>设置当前项目仅仅支持 windows 和 mingw 平台。</p>
  461. <h3 id="set_allowedarchs">set_allowedarchs</h3>
  462. <h4 id="">设置允许编译的平台架构</h4>
  463. <p>v2.5.6 以上版本才支持,用于设置工程支持的编译架构列表,如果用户指定了其他架构,会提示错误,这通常用于限制用户指定错误的无效架构。</p>
  464. <p>如果没有设置,那么没有任何架构限制。</p>
  465. <pre><code class="lang-lua">set_allowedarchs("x64", "x86")
  466. </code></pre>
  467. <p>当前项目,仅仅支持 x64/x86 平台。</p>
  468. <p>我们也可以同时指定多个平台下允许的架构列表。</p>
  469. <pre><code class="lang-lua">set_allowedarchs("windows|x64", "iphoneos|arm64")
  470. </code></pre>
  471. <p>设置当前项目在 windows 上仅仅支持 x64 架构,并且在 iphoneos 上仅仅支持 arm64 架构。</p>
  472. <h3 id="set_allowedmodes">set_allowedmodes</h3>
  473. <h4 id="">设置允许的编译模式列表</h4>
  474. <p>v2.5.6 以上版本才支持,用于设置工程支持的编译模式列表,如果用户指定了其他模式,会提示错误,这通常用于限制用户指定错误的无效模式。</p>
  475. <p>如果没有设置,那么没有任何模式限制。</p>
  476. <pre><code class="lang-lua">set_allowedmodes("release", "releasedbg")
  477. </code></pre>
  478. <p>设置当前项目仅仅支持 release/releasedbg 两个编译模式。</p>
  479. <h3 id="namespace">namespace</h3>
  480. <p>进入命名空间,xmake 2.9.8 版本支持,可以用于隔离子工程的重名 target,option 等各种域名冲突。</p>
  481. <h4 id="target">隔离 target</h4>
  482. <p>对于命名空间内部的 target 访问,完全可以按现有的方式,不加任何命名空间,直接访问,而跨命名空间访问,则需要指定 <code>namespace::</code> 去指定。</p>
  483. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  484. namespace("ns1", function ()
  485. target("foo")
  486. set_kind("static")
  487. add_files("src/foo.cpp")
  488. namespace("ns2", function()
  489. target("bar")
  490. set_kind("static")
  491. add_files("src/bar.cpp")
  492. end)
  493. target("test")
  494. set_kind("binary")
  495. add_deps("foo", "ns2::bar")
  496. add_files("src/main.cpp")
  497. end)
  498. </code></pre>
  499. <p>我们指定构建特定 target 时,也可以通过命名空间来定位。</p>
  500. <pre><code class="lang-bash">$ xmake build -r ns1::test
  501. [ 33%]: cache compiling.release ns1::ns2::src/bar.cpp
  502. [ 41%]: cache compiling.release ns1::src/foo.cpp
  503. [ 50%]: cache compiling.release ns1::src/main.cpp
  504. [ 58%]: archiving.release ns1::ns2::libbar.a
  505. [ 75%]: archiving.release ns1::libfoo.a
  506. [ 91%]: linking.release ns1::test
  507. [100%]: build ok, spent 1.325s
  508. </code></pre>
  509. <p>另外,命名空间也能隔离根域的配置,每个命名空间都有独立子根域,可以单独设置全局配置。</p>
  510. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  511. add_defines("ROOT")
  512. namespace("ns1", function ()
  513. add_defines("NS1_ROOT")
  514. target("foo")
  515. set_kind("static")
  516. add_files("src/foo.cpp")
  517. add_defines("FOO")
  518. namespace("ns2", function ()
  519. add_defines("NS2_ROOT")
  520. target("bar")
  521. set_kind("static")
  522. add_files("src/bar.cpp")
  523. add_defines("BAR")
  524. end)
  525. end)
  526. target("test")
  527. set_kind("binary")
  528. add_deps("ns1::foo", "ns1::ns2::bar")
  529. add_files("src/main.cpp")
  530. add_defines("TEST")
  531. </code></pre>
  532. <p>我们还可以隔离 includes 引入的子工程。</p>
  533. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  534. add_defines("ROOT")
  535. namespace("ns1", function ()
  536. add_defines("NS1_ROOT")
  537. target("foo")
  538. set_kind("static")
  539. add_files("src/foo.cpp")
  540. add_defines("FOO")
  541. includes("src")
  542. end)
  543. target("test")
  544. set_kind("binary")
  545. add_deps("ns1::foo", "ns1::ns2::bar")
  546. add_files("src/main.cpp")
  547. add_defines("TEST")
  548. </code></pre>
  549. <h4 id="option">隔离 option</h4>
  550. <pre><code class="lang-bash">$ xmake f --opt0=y
  551. $ xmake f --ns1::opt1=y
  552. $ xmake f --ns1::ns2::opt2=y
  553. </code></pre>
  554. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  555. option("opt0", {default = true, defines = "OPT0", description = "option0"})
  556. namespace("ns1", function ()
  557. option("opt1", {default = true, defines = "NS1_OPT1", description = "option1"})
  558. target("foo")
  559. set_kind("static")
  560. add_files("src/foo.cpp")
  561. add_options("opt1")
  562. namespace("ns2", function()
  563. option("opt2", {default = true, defines = "NS2_OPT2", description = "option2"})
  564. target("bar")
  565. set_kind("static")
  566. add_files("src/bar.cpp")
  567. add_options("opt2")
  568. end)
  569. target("test")
  570. set_kind("binary")
  571. add_deps("foo", "ns2::bar")
  572. add_files("src/main.cpp")
  573. add_options("opt0", "opt1", "ns2::opt2")
  574. end)
  575. </code></pre>
  576. <h4 id="rule">隔离 rule</h4>
  577. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  578. rule("rule0")
  579. on_load(function (target)
  580. target:add("defines", "RULE0")
  581. end)
  582. namespace("ns1", function ()
  583. rule("rule1")
  584. on_load(function (target)
  585. target:add("defines", "NS1_RULE1")
  586. end)
  587. target("foo")
  588. set_kind("static")
  589. add_files("src/foo.cpp")
  590. add_rules("rule1")
  591. namespace("ns2", function()
  592. rule("rule2")
  593. on_load(function (target)
  594. target:add("defines", "NS2_RULE2")
  595. end)
  596. target("bar")
  597. set_kind("static")
  598. add_files("src/bar.cpp")
  599. add_rules("rule2")
  600. end)
  601. target("test")
  602. set_kind("binary")
  603. add_deps("foo", "ns2::bar")
  604. add_files("src/main.cpp")
  605. add_rules("rule0", "rule1", "ns2::rule2")
  606. end)
  607. </code></pre>
  608. <h4 id="task">隔离 task</h4>
  609. <pre><code class="lang-bash">xmake task0
  610. xmake ns1::task1
  611. xmake ns1::ns2::task2
  612. </code></pre>
  613. <pre><code class="lang-lua">task("task0")
  614. set_menu {options = {}}
  615. on_run(function ()
  616. print("task0")
  617. end)
  618. namespace("ns1", function ()
  619. task("task1")
  620. set_menu {options = {}}
  621. on_run(function ()
  622. print("NS1_TASK1")
  623. end)
  624. namespace("ns2", function()
  625. task("task2")
  626. set_menu {options = {}}
  627. on_run(function ()
  628. print("NS2_TASK2")
  629. end)
  630. end)
  631. end)
  632. </code></pre>
  633. <h4 id="toolchain">隔离 toolchain</h4>
  634. <pre><code class="lang-lua">
  635. toolchain("toolchain0")
  636. on_load(function (toolchain)
  637. toolchain:add("defines", "TOOLCHAIN0")
  638. end)
  639. namespace("ns1", function ()
  640. toolchain("toolchain1")
  641. on_load(function (toolchain)
  642. toolchain:add("defines", "NS1_TOOLCHAIN1")
  643. end)
  644. target("foo")
  645. set_kind("static")
  646. add_files("src/foo.cpp")
  647. set_toolchains("toolchain1")
  648. namespace("ns2", function()
  649. toolchain("toolchain2")
  650. on_load(function (toolchain)
  651. toolchain:add("defines", "NS2_TOOLCHAIN2")
  652. end)
  653. target("bar")
  654. set_kind("static")
  655. add_files("src/bar.cpp")
  656. set_toolchains("toolchain2")
  657. end)
  658. target("test")
  659. set_kind("binary")
  660. add_deps("foo", "ns2::bar")
  661. add_files("src/main.cpp")
  662. set_toolchains("toolchain0", "toolchain1", "ns2::toolchain2")
  663. end)
  664. </code></pre>
  665. <h4 id="package">隔离 package</h4>
  666. <pre><code class="lang-lua">
  667. add_requires("package0", {system = false})
  668. package("package0")
  669. on_load(function (package)
  670. package:add("defines", "PACKAGE0")
  671. end)
  672. on_install(function (package) end)
  673. namespace("ns1", function ()
  674. add_requires("package1", {system = false})
  675. package("package1")
  676. on_load(function (package)
  677. package:add("defines", "NS1_PACKAGE1")
  678. end)
  679. on_install(function (package) end)
  680. target("foo")
  681. set_kind("static")
  682. add_files("src/foo.cpp")
  683. add_packages("package1")
  684. namespace("ns2", function()
  685. add_requires("package2", {system = false})
  686. package("package2")
  687. on_load(function (package)
  688. package:add("defines", "NS2_PACKAGE2")
  689. end)
  690. on_install(function (package) end)
  691. target("bar")
  692. set_kind("static")
  693. add_files("src/bar.cpp")
  694. add_packages("package2")
  695. end)
  696. target("test")
  697. set_kind("binary")
  698. add_deps("foo", "ns2::bar")
  699. add_files("src/main.cpp")
  700. add_packages("package0", "package1", "ns2::package2")
  701. end)
  702. </code></pre>
  703. <h3 id="namespace_end">namespace_end</h3>
  704. <p>结束当前的命名空间。</p>
  705. <pre><code class="lang-lua">namespace("test")
  706. target("hello")
  707. add_files("src/*.c")
  708. namespace_end()
  709. </code></pre>
  710. <p>除了使用 namespace_end,我们也可以使用下面的语法,来结束命名空间,并且对 LSP 更加友好,具体使用哪种方式,根据用户自己的需求和喜好决定。</p>
  711. <pre><code class="lang-lua">namespace("test", function ()
  712. target("hello")
  713. add_files("src/*.c")
  714. end)
  715. </code></pre>
  716. </article>
  717. </body>
  718. </html>