Ver Fonte

add autogen.md

ruki há 6 meses atrás
pai
commit
8c826f3c3f
3 ficheiros alterados com 132 adições e 0 exclusões
  1. 1 0
      docs/config.ts
  2. 1 0
      docs/zh/config.ts
  3. 130 0
      docs/zh/examples/cpp/autogen.md

+ 1 - 0
docs/config.ts

@@ -262,6 +262,7 @@ function examplesSidebar(): DefaultTheme.SidebarItem[] {
         { text: 'CppFront Programs', link: 'cpp/cppfront' },
         { text: 'Cosmocc Programs', link: 'cpp/cosmocc' },
         { text: 'Merge Static Libraries', link: 'cpp/merge-static-libraries' },
+        { text: 'Autogen Programs', link: 'cpp/autogen' },
       ]
     },
     {

+ 1 - 0
docs/zh/config.ts

@@ -343,6 +343,7 @@ function examplesSidebar(): DefaultTheme.SidebarItem[] {
         { text: 'CppFront 程序', link: 'cpp/cppfront' },
         { text: 'Cosmocc 程序', link: 'cpp/cosmocc' },
         { text: '合并静态库', link: 'cpp/merge-static-libraries' },
+        { text: '自动代码生成', link: 'cpp/autogen' },
       ]
     },
     {

+ 130 - 0
docs/zh/examples/cpp/autogen.md

@@ -0,0 +1,130 @@
+# 自动代码生成 {#autogen}
+
+很多时候,我们需要在编译之前对代码做一些预处理和自动生成,然后将生成的代码参与到后续的编译中去。
+
+而随着 Xmake 的不断迭代,对代码生成特性的支持也在不断更新和改进。目前支持以下几种方式。
+
+## 最简单的方式
+
+这种方式最为简单直接,只需要在构建之前生成代码后,强制通过 `add_files` 添加进来。
+
+由于 add_files 默认不会添加不存在的文件,所以需要配置 `always_added = true` 去强制添加,即使文件当前还不存在。
+
+```lua
+add_rules("mode.debug", "mode.release")
+
+target("test")
+    set_kind("binary")
+    add_files("$(builddir)/autogen.cpp", {always_added = true})
+    before_build(function (target)
+        io.writefile("$(builddir)/autogen.cpp", [[
+#include <iostream>
+using namespace std;
+int main(int argc, char** argv) {
+    cout << "hello world!" << endl;
+    return 0;
+}
+        ]])
+    end)
+```
+
+这种方式有很多的局限,很多场景下不太使用,但胜在比较简单。
+
+## 依赖目标生成
+
+有时候,我们生成代码,需要通过执行项目中某个目标程序来完成,这个时候我们需要通过下面的方式来实现。
+
+```lua
+add_rules("mode.debug", "mode.release")
+
+rule("autogen")
+    set_extensions(".in")
+    before_buildcmd_file(function (target, batchcmds, sourcefile, opt)
+        local sourcefile_cx = path.join(target:autogendir(), "rules", "autogen", path.basename(sourcefile) .. ".cpp")
+        local objectfile = target:objectfile(sourcefile_cx)
+        table.insert(target:objectfiles(), objectfile)
+
+        batchcmds:show_progress(opt.progress, "${color.build.object}compiling.autogen %s", sourcefile)
+        batchcmds:mkdir(path.directory(sourcefile_cx))
+        batchcmds:vrunv(target:dep("autogen"):targetfile(), {sourcefile, sourcefile_cx})
+        batchcmds:compile(sourcefile_cx, objectfile)
+
+        batchcmds:add_depfiles(sourcefile, target:dep("autogen"):targetfile())
+        batchcmds:set_depmtime(os.mtime(objectfile))
+        batchcmds:set_depcache(target:dependfile(objectfile))
+    end)
+
+target("autogen")
+    set_default(false)
+    set_kind("binary")
+    set_plat(os.host()) ----- 生成当前主机平台程序
+    set_arch(os.arch())
+    add_files("src/autogen.cpp")
+    set_languages("c++11")
+    set_policy("build.fence", true) ----- 禁用源码间并行编译
+
+target("test")
+    set_kind("binary")
+    add_deps("autogen")
+    add_rules("autogen")
+    add_files("src/main.cpp")
+    add_files("src/*.in")
+```
+
+我们需要先配置一个 autogen 的目标程序,它是一个可以在当前编译平台能够运行的程序,因此需要配置 `set_plat(os.host())` 强制作为主机平台来编译。
+
+另外,我们需要配置 `build.fence` 策略,禁用源码间并行编译,让 autogen 目标的源码总是优先编译完成,提前完成 autogen 可执行程序的生成。
+
+然后,我们配置一个自定义规则,在构建之前,去调用 autogen 目标程序去生成源码,并直接将生成的源码编译出对象文件,插入到后续的链接中去。
+
+完整例子见:[autogen_codedep](https://github.com/xmake-io/xmake/blob/dev/tests/projects/other/autogen/autogen_codedep/xmake.lua)
+
+## 通过原生模块来生成
+
+我们新增了原生模块开发的特性,通过这个特性,即使不通过定义额外的 autogen 目标程序,也可以通过原生模块来生成代码。
+
+关于原生模块的开发,可以参考文档:[Native 模块开发](/zh/api/scripts/native-modules)。
+
+```lua
+add_rules("mode.debug", "mode.release")
+
+add_moduledirs("modules")
+
+rule("autogen")
+    set_extensions(".in")
+    before_build_file(function (target, sourcefile, opt)
+        import("utils.progress")
+        import("core.project.depend")
+        import("core.tool.compiler")
+        import("autogen.foo", {always_build = true})
+
+        local sourcefile_cx = path.join(target:autogendir(), "rules", "autogen", path.basename(sourcefile) .. ".cpp")
+        local objectfile = target:objectfile(sourcefile_cx)
+        table.insert(target:objectfiles(), objectfile)
+
+        depend.on_changed(function ()
+            progress.show(opt.progress, "${color.build.object}compiling.autogen %s", sourcefile)
+            os.mkdir(path.directory(sourcefile_cx))
+            foo.generate(sourcefile, sourcefile_cx)
+            compiler.compile(sourcefile_cx, objectfile, {target = target})
+        end, {dependfile = target:dependfile(objectfile),
+              files = sourcefile,
+              changed = target:is_rebuilt()})
+    end)
+
+target("test")
+    set_kind("binary")
+    add_rules("autogen")
+    add_files("src/main.cpp")
+    add_files("src/*.in")
+```
+
+完整例子见:[Native 模块自动生成](https://github.com/xmake-io/xmake/blob/dev/tests/projects/other/autogen/autogen_shared_module/xmake.lua)。
+
+## Prepare 阶段生成
+
+Xmake 3.x 之后,我们新增了 `on_prepare` 和 `on_prepare_files` 接口,实现两阶段编译,在 Prepare 阶段,我们可以专门用于处理源码生成和预处理。
+
+它会在所有的 `on_build` 和 `on_build_files` 接口之前被执行。
+
+关于 Prepare 的相关接口说明,见文档:[Prepare 接口手册](/zh/api/description/project-target.html#on-prepare)。