native_modules.html 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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/#/manual/native_modules">https://xmake.io/#/manual/native_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>Native modules can be used in the build workflow.</p>
  86. <h3 id="nativemodule">Native module</h3>
  87. <p>We know that in xmake, you can import some lua modules through the import interface for use in the script domain. However, if the operation of some modules is time-consuming, then lua implementation is not an ideal choice.<br>Therefore, in the new version, we have added support for the native lua module, which can be implemented through native to achieve speed-up optimization. Moreover, importing and using the module is as simple as the lua module.</p>
  88. <p>When using native modules, xmake will perform two stages of compilation. First, it will automatically compile the native module, and then import the module into lua as a library or binary. For users, they only need to call import to import.</p>
  89. <h4 id="definedynamiclibrarymodule">Define dynamic library module</h4>
  90. <p>The advantage of the dynamic library module is that it not only achieves performance acceleration through native, but also avoids the creation of additional sub-processes for each call, making it more lightweight and further improving the speed.</p>
  91. <p>We can first define a dynamic library module, which fully supports all C APIs of Lua, so we can also directly introduce some third-party open source Lua native modules for use.</p>
  92. <p>Here we also have a complete example of importing the lua-cjson module for reference: <a href="https://github.com/xmake-io/xmake/tree/master/tests/projects/other/native_module_cjson">native_module_cjson</a></p>
  93. <p>First, we first implement the shared native code, so the interface is exported through the lua API.</p>
  94. <p>./modules/foo/foo.c</p>
  95. <pre><code class="lang-c++">#include <xmi.h>
  96. static int c_add(lua_State* lua) {
  97. int a = lua_tointeger(lua, 1);
  98. int b = lua_tointeger(lua, 2);
  99. lua_pushinteger(lua, a + b);
  100. return 1;
  101. }
  102. static int c_sub(lua_State* lua) {
  103. int a = lua_tointeger(lua, 1);
  104. int b = lua_tointeger(lua, 2);
  105. lua_pushinteger(lua, a - b);
  106. return 1;
  107. }
  108. int luaopen(foo, lua_State* lua) {
  109. //Collect add and sub
  110. static const luaL_Reg funcs[] = {
  111. {"add", c_add},
  112. {"sub", c_sub},
  113. {NULL, NULL}
  114. };
  115. lua_newtable(lua);
  116. // pass function list
  117. luaL_setfuncs(lua, funcs, 0);
  118. return 1;
  119. }
  120. </code></pre>
  121. <p>Notice here that we have included an interface header file of <code>xmi.h</code>. In fact, we can also directly introduce <code>lua.h</code> and <code>luaconf.h</code>. The effect is the same, but it will provide better cross-platform performance. , it will automatically handle the differences between lua/luajit and versions internally.</p>
  122. <p>Then, we configure <code>add_rules("modules.shared")</code> to compile as a shared native module without introducing any other dependencies.</p>
  123. <p>Even Lua dependencies do not need to be introduced, because the xmake main program has exported all Lua interfaces and can be used directly, so the entire module is very lightweight.</p>
  124. <p>./modules/foo/xmake.lua</p>
  125. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  126. target("foo")
  127. -- Specify the target as the library lua module
  128. add_rules("module.shared")
  129. add_files("foo.c")
  130. </code></pre>
  131. <h4 id="definebinarymodule">Define binary module</h4>
  132. <p>In addition to the dynamic library module, we also provide the import of another binary module. It is actually an executable file. Every time the module interface is called, a child process will be called.</p>
  133. <p>So what are the benefits of it? Although it is not as efficient as the dynamic library module, its module implementation is simpler. There is no need to call the lua API. It only needs to process the parameter data and output the return value through stdout.</p>
  134. <p>In addition, compared to binary distribution, it is distributed through source code, so it also solves the cross-platform problem.</p>
  135. <p>Whether to use a dynamic library module or a binary module depends on your needs. If you want a simple implementation, you can consider a binary module. If you want to be efficient, use a dynamic library module.</p>
  136. <p>In addition, if you need to speed up through parallel execution, you can also use binary modules.</p>
  137. <p>./modules/bar/bar.cpp</p>
  138. <pre><code class="lang-c++">#include <stdio.h>
  139. #include <stdlib.h>
  140. #include <cstdlib>
  141. int main(int argc, char** argv) {
  142. int a = atoi(argv[1]);
  143. int b = atoi(argv[2]);
  144. printf("%d", a + b);
  145. return 0;
  146. }
  147. </code></pre>
  148. <p>./modules/bar/xmake.lua</p>
  149. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  150. target("add")
  151. -- Specify the target as a binary lua module
  152. add_rules("module.binary")
  153. add_files("bar.cpp")
  154. </code></pre>
  155. <h4 id="importnativemodule">Import native module</h4>
  156. <p>For module import, we only need to call import, which is exactly the same as importing lua modules.</p>
  157. <p>./xmake.lua</p>
  158. <pre><code class="lang-lua">add_rules("mode.debug", "mode.release")
  159. --Add native modules in the ./modules directory
  160. add_moduledirs("modules")
  161. target("test")
  162. set_kind("phony")
  163. on_load(function(target)
  164. import("foo", {always_build = true})
  165. import("bar")
  166. print("foo: 1 + 1 = %s", foo.add(1, 1))
  167. print("foo: 1 - 1 = %s", foo.sub(1, 1))
  168. print("bar: 1 + 1 = %s", bar.add(1, 1))
  169. end)
  170. </code></pre>
  171. <p>Since the construction of the plug-in module is completely independent from the main project, the native module will only be built once. If you want to trigger incremental plug-in compilation, you need to configure <code>always_build = true</code>, so that xmake will detect it every time Check whether the plug-in code has been changed. If so, the plug-in will be automatically incrementally built.</p>
  172. <p>The first execution effect is as follows:</p>
  173. <pre><code class="lang-bash">ruki-2:native_module ruki$ xmake
  174. [50%]: cache compiling.release src/foo.c
  175. [50%]: cache compiling.release src/bar.c
  176. [75%]: linking.release libmodule_foo.dylib
  177. [75%]: linking.release module_bar
  178. [100%]: build ok, spent 1.296s
  179. foo: 1 + 1 = 2
  180. foo: 1 - 1 = 0
  181. bar: 1 + 1 = 2
  182. [100%]: build ok, spent 0.447s
  183. </code></pre>
  184. <p>When executed for the second time, the plug-in will not be built and the module can be used directly:</p>
  185. <pre><code class="lang-bash">ruki-2:native_module ruki$ xmake
  186. foo: 1 + 1 = 2
  187. foo: 1 - 1 = 0
  188. bar: 1 + 1 = 2
  189. [100%]: build ok, spent 0.447s
  190. </code></pre>
  191. <h4 id="useascodegen">Use as codegen</h4>
  192. <p>Through the new native module feature, we can also use it to implement auto-codegen, and then continue to execute the subsequent compilation process based on the automatically generated code.</p>
  193. <p>There is also a complete example here for reference: <a href="https://github.com/xmake-io/xmake/tree/master/tests/projects/other/autogen_shared_module">autogen_shared_module</a>.</p>
  194. </article>
  195. </body>
  196. </html>