1 Star 0 Fork 11

coder_lw / wiki

forked from deepinwiki / wiki 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
xmake.md 24.51 KB
一键复制 编辑 原始数据 按行查看 历史
htqx 提交于 2021-07-04 18:17 . 大量本地更新

[TOC]

xmake 构建系统介绍

前言

什么是构建系统。 程序源代码需要通过脚本按部就班的编译成程序,这构建程序的过程,或者说是工具,就叫构建系统。你可以不懂开发程序,但是使用 linux 难免要编译和构建软件,因为很多开源免费的软件,都是只是提供源代码,让你自己构建的。

构建系统有很多,比如古老的 autotools 和 make, 然后比较新潮的 cmake 和 ninja 。但是他们都有一个问题,就是——复杂。

有没有一种比较简单的构建系统? 我不知道,但是这个 xmake 是国人开发的,应该比较适合国人的使用习惯。尝试一下。

xmake

功能概要

xmake cli 工具的功能有:

  1. create:创建项目
  2. update(u):更新xmake
  3. intstall(i)/uninstall(u): 安装卸载程序
  4. build(b)/clean(c): 生成/清理程序
  5. package(p):打包
  6. run(r): 运行程序
  7. require(q): 处理依赖项
  8. global(g)/config(f): 设置全局/项目配置

其余杂项:

  1. show:显示项目信息
  2. doxygen:创建文档
  3. repo:管理软件仓库
  4. service:分布式编译服务
  5. project:生成第三方项目文件
  6. lua(l):执行 lua 脚本
  7. plugin:管理插件
  8. macro(m):运行宏
  9. app2ipa:生成 .ipa
  10. echo:输出文字(测试用)

配置方法

xmake 使用一个 xmake.lua 作为构建的配置文件,但并非所有配置都需要在配置文件中设置,xmake 通过命令直接配置大部分参数(自动识别大部分设置)。

  1. xmake g:全局设置
  2. ./xmake.lua:项目文件配置
  3. xmake f:命令行配置
    1. ./.xmake/linux/x86_64/xmake.conf:命令行临时配置保存的位置

命令解析

xmake 基本命令包括:创建项目(create)、构建(build/b)、打包(package/p)、清理(clean/c)、组件依赖(require/q)、运行(run/r)、安装(install/i)、卸载(uninstall/u)、配置(config/f)、全局配置(global/g)、更新(update)。

扩展命令:插件(plugin)、存储库(repo)、回显(echo)、信息(show)、项目转换(project)、宏(macro/m)、分布式编译服务(service)、文档(doxygen)、 转换ipa(app2ipa)、脚本(lua/l)

简要说明:

  1. xmake : 对当前文件夹进行智能判断,同时生成 xmake.lua 构建脚本文件,然后构建程序。对于简单的源代码目录,可以智能识别和构建成功。
  2. xmake create -l c -P ./hello myproj: 生成新工程文件,-l c 指定 c 语言, -P ./hello 指定项目目录,myproj 项目名称(target 项目目标)。
    1. -l 语言(c++、objc、swift、zig、go、c、cuda、objc++、rust、dlang、fortran)
    2. -t 工程模板
      1. console 普通可执行工程
      2. static 静态库
      3. shared 共享库
      4. qt.xxx Qt工程
      5. tbox.xxx
      6. xcode.xxx
      7. xmake.cli
    3. ./xxx 项目文件夹
    4. yyy 项目目标
  3. xmake run/r -d hello: 运行程序目标 hello, -d 调试运行
  4. xmake config/f -p linux -a x86_64 : 配置项目, -p 目标系统, -a cpu架构
    1. 交叉编译
      1. -plat(p) 目标平台:cross、cygwin、mingw、wasm、macosx、bsd、windows、msys、watchos、linux、android、iphoneos
      2. -arch(a) 目标 cpu 架构:i386、x86_64、arm、arm64、 2. armeabi、armeabi-v7a、arm64-v8a、armv7、armv7s、arm64-v8a、mips、mips64、mipsel、mips64el、riscv、riscv64、s390x、ppc、ppc64、sh4、wasm32
      3. --sdk 工具链目录(交叉编译)
      4. --bin 编译工具目录
      5. --cross 交叉编译前缀
      6. --target_os 目标平台
      7. --toolchain 工具链 cross/llvm/sdcc/gcc 等
      8. --host 主机平台
      9. --frameworks 框架
    2. 链接器
      1. --ld 链接器
        1. --ldflags 链接器参数
        2. --links 链接库
        3. --syslinks 系统链接库
    3. 动态链接
      1. --sh 共享库链接器
        1. --shflags 动态库程序链接参数
    4. 静态链接
      1. --ar 静态库归档器
        1. --arflags 静态库程序链接参数
    5. 预处理器/编译器/汇编器/调试器/缓冲器
      1. --cc c语言编译器
        1. --cflags c语言编译参数
      2. --cxx c++语言编译器
        1. --cxxflags c++语言编译参数
      3. --as 汇编器
        1. --asflags 汇编器编译参数
      4. --cpp c 预处理器
      5. --debugger 调试器
      6. --ccache 编译缓冲器
    6. 搜索目录
      1. --includedirs 头文件目录
      2. --linkdirs 链接库目录
      3. --pkg_searchdirs 依赖搜索路径
      4. --frameworkdirs 框架目录
      5. --vcpkg vcpkg 目录
    7. --require 依赖项 y/n
    8. --verbose(v) 打印配置信息
      1. --diagnosis(D) 打印调试信息(出错的时候)
    9. --clean(c) 清除当前配
    10. --mode(m) 编译模式 release/debug
    11. --kind(k) 目标类型 static/shared/binary
    12. --menu 启动菜单配置(如果有)
    13. --trybuild 尝试启动第三方构建系统:auto/make/autotools/cmake/scons/meson/bazel/ninja/msbuild/xcodebuild/ndkbuild
      1. --tryconfig 第三方构建系统参数
    14. --buildir(o) 构建输出目录
  5. xmake global/g --ndk=~/android-ndk/ :修改全局配置,--ndk 修改默认目录
    1. -v : 查看配置信息
  6. xmake clean/c --all : 清除构建的文件,--all 所有
  7. xmake package/p : 打包
  8. xmake require/q zlib: 安装外部包 zlib 到本项目
  9. xmake build: 构建
  10. xmake repo --add myrepo git@github.com:myrepo/xmake-repo.git: 添加私有仓库
  11. xmake l -l: 运行lua脚本,-l 列出内置脚本
  12. xmake install/i : 安装
  13. xmake uninstall/u : 卸载
  14. xmake update : 更新 xmake
  15. xmake macro/m --begin: 运行宏, --begin 开始记录
  16. xmake plugin : 插件
  17. xmake doxygen : 文档
  18. xmake project -k cmake : 生成第三方构建系统配置(make,cmake,ninja,vs,vsxmake)

项目目录结构

hello   # 工程目录
├── src  # 源代码目录
│   └── main.c # 源代码文件
└── xmake.lua # 工程脚本

多级配置:子目录下的 xmake.lua 自动继承上级父目录的 xmake.lua 相关设置(公共部分)。

交叉编译器配置目录

# 编译器应该遵从这个目录布局
toolchains_sdkdir/ # 支持交叉编译的编译器目录
├── bin
│   ├── arm-linux-armeabi-gcc # 带有平台和架构前缀的工具
│   └── arm-linux-armeabi-ld
├── include
│   └── xxx.h
└── lib
    └── libxxx.a

常见编译工具:

  1. ar 静态库
  2. as 汇编器
  3. cpp 预处理器
  4. strip 裁剪符号
  5. nm 查看导出符号
  6. ld 链接器
  7. c++ 编译器
  8. gcc 编译器
  9. g++ 编译器

配置文件概要

xmake.lua 是 xmake 项目的主要配置文件,类似 make 构建系统中的 Makefile。xmake.lua 相对 Makefile 的优势,主要体现在这个配置文件比较好理解。尤其因为这个作者是中国人,思维模式比较符合国人的习惯。

它使用一种叫 lua 的语言编写,Lua 是一种轻量小巧的脚本语言。具体看案例,将来深入也可以学一下 lua。

-- xmake.lua 简单样例
target("test") -- 项目目标,一个项目可以有多个目标,每个目标就是一组构建方案
    set_kind("binary") -- 对应 cli 配置中的 --kind
    add_files("src/*.c") -- 添加源文件,表示 src 子目录下的所有 c 源文件

-- 也可以将以上改成合并成一行的写法
target("test2",{kind="binary", files="src/*.c"})

区区三行,就是一个完整的配置文件,这就是 xmake 简洁的地方。

xmake 对配置语法做了两种分类:

  1. 描述域:通过描述性语法配置八成以上的内容
  2. 脚本域:需要通过脚本代码来编程特殊的需求

以上就是个配置域的简单例子,只需要简单设置相关参数的值即可。target 就是一个配置域,set_kind、add_files 就是这个域的配置项,不同的 target 有各自的配置项设置。

配置域类型:

  1. target: 目标,相当于工程中的子工程
  2. option: 编译选项
  3. task: 任务/插件
  4. package:包定义

脚本域:本质就是定义在特定时期自动运行的函数。因为设置在特定时期自动调用,所以它有明确的执行流程。

配置域可能被构建系统多次扫描和执行,虽然配置域也能编写简单的脚本流程,但基于以上理由应该尽量避免,尤其是编写复杂的脚本。

包管理

xmake 工程可以设定多个子目标(target),也可以有子目录(子项目),但是以上设计对于更加独立的依赖项目来说,是不方便的。这就要使用到包管理方法。

被依赖的包,它实际并非是本项目的子项目,因为它也能是其他工程的依赖项,所以并非是内部关系。

xmake p # 打包 build/xxx.pkg/...
xmake p -o packages # 打包并输出到 packages 子目录
tree packages # 包的目录结构
packages/
└── test2.pkg # 包名.pkg
    ├── linux # plat
    │   └── i386 # arch
    │       └── lib # lib,只有库类型才会打包
    │           └── release # mode
    │               └── libtest2.a # test2 静态库
    └── xmake.lua # 包的配置信息

设置包依赖:

add_packagedirs("packages") -- 包的搜索路径

target(test2_demo) -- 测试项目
    set_kind("binary")
    add_packages("test2") -- 依赖 test2 包
    add_files("src/main.c")

包的配置信息:

-- test2.pkg/xmake.lua
option("test2")
    set_showmenu(true)
    set_category("package") -- 类别
    add_links("test2") -- 链接
    add_linkdirs("$(plat)/$(arch)/lib/$(mode)") -- 库目录
    add_includedirs("$(plat)/$(arch)/include") -- 头文件目录

可见,当添加包依赖的时候,自动添加库目录和头文件,还有链接的库等参数。

包的种类:

  1. 本地包:以上是本地包
  2. 系统包:第三方的包,通过 find_packages 函数自动识别和生成包的相关信息
    1. conan
    2. vcpkg
    3. homebrew
    4. pkg-config
  3. 远程包:使用 xrepo 管理的软件仓库中的包
# 尝试搜索第三方的 openssl 包
xmake l find_packages openssl

可能得到信息:

{ 
  { 
    links = { 
      "crypto" 
    },
    version = "1.1.1h" 
  } 
}

三种包中,本地包是基础的,系统包是为了兼容性考虑,而真正值得注意的是远程包,因为它试图实现一个自动管理的软件仓库。如果我们的依赖项都能自动管理,那么构建软件就是一件相对轻松的事情。

xmake 包管理的逻辑图: img

xrepo 软件仓库

xmake 远程包和本地包的组织方式是完全不同的。

从概念上讲,本地包是二进制包,而远程包是脚本包。脚本下载源码(或二进制包),然后按步骤编译,再安装到系统里面,这就是远程包做的任务。

目录结构:

xmake-repo/
└── packages
    ├── t
    │   └── tbox
    │       └── xmake.lua
    └── z
        └── zlib
            └── xmake.lua

可见仓库里面的包并不包含源码或二进制文件。

仓库包的 xmake.lua 只允许 package 配置域:

package("zlib") -- 包名
    set_homepage("xxx") -- 官网
    set_description("") -- 描述信息
    set_kind("") -- 包类型,和本地包不同的是,可以支持可执行程序
    set_urls() -- 下载链接
    add_urls() -- 不同版本的下载链接/镜像源
    add_versions() -- 可选版本和 sha256 散列值
    add_patches() -- 补丁
    add_links() -- 链接参数
    add_configs() -- 提供给外部的配置接口
    add_defines() -- 提供给外部的定义
    on_load() -- 脚本域,动态更改基本的设置
    on_install() -- 编译
    on_test() -- 测试

使用仓库的包:

-- test2/xmake.lua
add_requires("test2") -- 依赖项

target("test_demo")
    add_packages("test2")
    set_kind("binary")
    add_files("src/main.c")

运作机制概要:

  1. repo: 首先从一个官方或者私人的仓库中读取信息,得到构建脚本 xmake.lua
  2. url:根据版本下载源代码
  3. install:编译代码,并安装到 ~/.xmake/packages 这个本地目录
  4. kind: 用户项目读取包信息,如果是库包,他就自动添加链接库
  5. exe:最终生成应用程序

仓库可以是:

  1. 官方:xmake-repo https://gitee.com/tboox/xmake-repo.git master
  2. 本地:my-repo myrepo
# 添加一个项目内部的仓库
xmake repo --add my-repo myrepo 
# 添加一个外部的全局的本地仓库
xrepo add-repo g-repo /home/htqx/grepo
# 也可以是 git 远程仓库

源码包可以是 xmake 项目,也可以是第三方项目。但是 xmake 原生项目会简单很多。不过现在还不支持自动生成源码包,需要自己打包源码。同样的,也不支持从本地包自动转换成远程包。

案例一

将普通 xmake 项目源代码打包成远程包规格。

# 这是一个标准模板项目
xmake create -t static -l c test2
tree test2 # 例子项目
test2
├── src
│   ├── interface.c
│   ├── interface.h
│   └── main.c
└── xmake.lua
cd test2
tar -uvf test2-1.0.0.tar xmake.lua src # 打包源码和 xmake.lua
sha256sum test2-1.0.0.tar # 获取源码包的哈希值,用在远程包的配置上
mkdir -pv ../myrepo/packages/t/test2 # 创建仓库目录
nano ../myrepo/packages/t/test2/xmake.lua # 编写远程包脚本

远程包脚本:

-- xmake.lua
package("test2")
        set_urls("/test2-$(version).tar") -- 本地填写绝对路径
        add_versions("1.0.0","8c9f08f7a47248a9a8a2733583e7016ed8c2c9dafc57eb6f24ff0f3988dea932") -- 版本号,sha256 哈希值,虽然作者说是可选的,但我测试是必要的
        on_install(function(package)
                import("package.tools.xmake").install(package)
        end)

真实项目中,这个应该是个 git 地址,这里用了一个虚假的地址。但路径不存在没关系,可以指定搜索目录:

xmake g --pkg_searchdirs = /home/htqx/Documents/xmake/test2

当下载不了的时候,会在这个目录搜索源码包。

# 用户程序的例子:
cd ..
xmake create -l c test1 # 新创建一个测试项目
cd test1
nano xmake.lua # 修改用户程序的配置
-- xmake.lua
add_rules("mode.debug", "mode.release")

add_repositories("my-repo $(projectdir)/../myrepo") -- 仓库
add_requires("test2 1.0.0",{verify=false}) -- 依赖包,1.0.0 表示版本(可省略),verify 参数表示不验证 sha256 散列值(本人测试没用)

target("test1")
    set_kind("binary")
    add_packages("test2") -- 导入当前项目目标中,即自动添加链接库等参数
    add_files("src/main.c")

案例二

我在想既然本地包那么简单就自动生成了,为啥远程包要如此麻烦?能不能从本地包转换到远程包?这个案例手动转换一下:

# 紧跟上个案例,在 test1 同级目录
xmake create -t shared -l c test3
cd test3
xmake p # 构建二进制包,build/test3.pkg/...
cd build
tar -cvf test3-1.0.0.tar test3.pkg # 打包二进制包
sha256sum test3-1.0.0.tar # 获取哈希值
cp test3-1.0.0.tar ../test2 # 拷贝到源码搜索目录下
mkdir -pv ../myrepo/packages/t/test3/ # 在本地仓库创建 test3 目录
nano ../myrepo/packages/t/test3/xmake.lua # 编写远程包脚本
package("test3")
        set_urls("/test3.pkg-$(version).tar")
        add_versions("1.0.0","1998d892e68ae0a3d8f851c946ab3d637ed6cb030171e893e9958f33e304dfc5")
        add_linkdirs("$(plat)/$(arch)/lib/$(mode)") -- 修改库地址
--      add_includedirs("$(plat)/$(arch)/include") -- 经过测试,并不支持修改头文件位置

        on_install(function(package)

                import("package.tools.xmake").install(package)
                os.cp("$(plat)",package:installdir("")) -- 复制二进制包的内容到安装目录
                os.cp("$(plat)/$(arch)/include/*",package:installdir("include")) -- 复制二进制包的头文件到默认的头文件文件夹

        end)

转换并不完美,主要是头文件位置不能修改。我不能理解为何作者不统一本地包和远程包的安装目录结构,本地包设计能支持交叉编译,而远程包的目录结构只有一层 /lib 和 /include 。

建议作者可以自动生成远程包,因为这本来就是一件比较简单,却又经常要用的,重复性很高的任务。另外,编写脚本过程中,我找不到安装目录路径的关联变量。

使用方法是一样的,这里就不演示了。有用的命令:

xmake q --info test3 # 显示远程包的安装信息
xmake q -l # 列出项目安装的包
xmake q -f # 强制重新安装包,比如更新了包
xmake -v # 构建并查看详细输出
xmake f -v # 查看当前配置结果
xmake f -c # 清除当前临时配置

xmake 插件

插件目录:

  1. xmake/plugins:主程序目录
  2. ~/.xmake/plugins:用户目录
  3. add_plugindirs("./plugins"):当前项目
mkdir -p plugins/hello
nano plugins/hello/xmake.lua # 编写插件
nano xmake.lua # 当前项目配置中添加插件目录 add_plugindirs("./plugins")
-- ./plugins/hello/xmake.lua
task("hello")
    set_category("plugin")
    on_run(function()
        print("hello xmake!")
    end)
    set_menu{
        usage = "xmake hello [option]",
        description="hello xmake!",
        options={}
    }
    --👅🇨🇳🔯

语法参考

xmake.lua 语法结构

  1. 配置域
    1. target
      1. set_kind 目标编译类型
        1. binary
        2. static
        3. shared
      2. set_strip 裁剪符号信息
        1. debug
        2. all
      3. set_enabled 启用目标
      4. set_default 默认目标
      5. set_options 关联选项
      6. set_symbols 符号信息
        1. debug
        2. hidden
      7. set_basename 目标文件名
      8. set_filename 目标文件全名
      9. set_warnings 警告级别
        1. none
        2. less
        3. more
        4. all
        5. everything
        6. error 将警告视为错误
      10. set_optimize 优化级别
        1. none
        2. fast
        3. faster
        4. fastest 最快速度
        5. smallest 最小化代码
        6. aggressive 过度优化
      11. set_languages 语言标准
        1. ansi
        2. c89
        3. c99
        4. cxx98
        5. cxx11
        6. cxx14
        7. cxx1z
        8. cxx17
      12. set_targetdir 目标目录
      13. set_objectdir 对象文件目录
      14. set_dependir 编译依赖文件目录
      15. add_imports 导入扩展模块
      16. add_rules 导入规则
      17. set_pcheader c预编译头文件文件
      18. set_pcxxheader c++预编译头文件
      19. add_deps 工程依赖
        1. inherit 继承
        2. public 公共配置
        3. private 私有配置
        4. interface 继承者专属
      20. add_links 链接库
      21. add_syslinks 系统链接库
      22. add_files 源代码(支持过滤模式)
      23. del_files 排除的源代码
      24. add_linkdirs 链接库目录
      25. add_rpathdirs 动态链接库目录
      26. add_includedirs 头文件目录
      27. add_defines 宏定义
      28. add_undefines 取消宏定义
      29. add_cflags c编译器选项
      30. add_cxflags c/c++编译器选项
      31. add_cxxflags c++编译器选项
      32. add_asflags 汇编器选项
      33. add_ldflags 链接器选项
      34. add_arflags 静态库链接选项
      35. add_shflags 动态库链接选项
        1. "-Wl,-soname,libxxx.so.1" soname参数
        2. "-Wl,-rpath=$$ORIGIN/../lib" 共享库搜索路径
      36. add_packages 包依赖
      37. add_frameworks 链接框架
      38. add_frameworkdirs 框架目录
      39. set_toolchain 工具链目录
      40. set_values 设置扩展配置值
      41. add_values 添加扩展配置值
      42. set_rundir 运行目录
      43. set_runenvs 运行环境变量
      44. set_installdir 设置安装目录
      45. add_installfiles 添加安装文件
      46. add_headerfiles 添加安装头文件
      47. set_configdir 设置模板配置文件输出目录
      48. set_configvar 设置模板配置变量
      49. set_configfiles 添加模板配置文件
    2. option
    3. task
      1. on_run 运行函数
      2. set_menu 设置菜单
        1. usage 用法说明
        2. description 备注
        3. options 选项
    4. package 定义私有仓库的包
      1. set_homepage 包官方主页
      2. set_description 描述
      3. set_kind 包类型
      4. set_urls 包源代码地址
      5. add_urls 添加包源代码地址
      6. add_versions 版本
      7. add_patches 补丁
      8. add_links 链接配置
      9. add_syslinks 系统库链接
      10. add_frameworks 系统框架
      11. add_linkdirs 链接目录
      12. add_includedirs 头文件目录
      13. add_defines 宏
      14. add_configs 自定义配置
      15. on_load
      16. on_install
      17. on_test
  2. 脚本域
    1. on_load 目标加载
    2. on_link 链接脚本
    3. on_build 编译脚本
    4. on_build_file 单文件编译
    5. on_build_files 多文件编译
    6. on_clean 清理脚本
    7. on_package 打包脚本
    8. on_install 安装脚本
    9. on_uninstall 卸载脚本
    10. on_run 运行脚本
    11. after_xxx 之后
    12. before_xxx 之前

lua api

  1. 配置域
    1. pairs 遍历字典
    2. ipairs 遍历数组
    3. print 打印消息
    4. format 格式化字符串
    5. os 系统模块
    6. path 路径模块
    7. table 数组和字典模块
    8. string 字符串模块
  2. 脚本域
    1. 全部配置域api
    2. val 获取内置变量的值
    3. import 导入扩展模块
    4. inherit 导入并继承基类模块
    5. try-catch-finally 异常捕获
    6. printf 无换行打印
    7. cprint 换行彩色打印
    8. cprintf 无换行彩色打印
    9. vformat 内置变换格式化字符串
    10. raise 抛出异常
    11. io 文件模块
    12. process 进程模块
    13. coroutine 协程模块
    14. find_packages 查找依赖包
  3. 条件判断
    1. is_os
    2. is_arch
    3. is_plat
    4. is_host
    5. is_mode
    6. is_kind
    7. is_config
    8. has_config
    9. has_package
  4. 内置变量
    1. $(os) 系统
    2. $(host) 本机
    3. $(tmpdir) 临时目录
    4. $(curdir) 当前目录
    5. $(buildir) 构建目录
    6. $(scriptdir) 工程描述脚本目录
    7. $(globaldir) 全局配置目录
    8. $(configdir) 本地配置目录
    9. $(programdir) xmake目录
    10. $(projectdir) 工程根目录
    11. $(shell) shell命令
    12. $(env) 外部环境变量
    13. $(reg) 注册表
  5. 外部模块
    1. core.base.option
    2. core.base.global
    3. core.base.task
    4. core.tool.linker
    5. core.tool.compiler
    6. core.project.config
    7. core.project.project
    8. core.language.language
    9. core.platform.platform
    10. core.platform.environment

全局接口

  1. add_requires 配置外部依赖包(官方xmake-repo,且支持第三方包管理系统,pkg-config、brew、vcpkg、conan、clib)
  2. includes 添加紫工程文件和目录
  3. set_modes 设置编译模式
  4. set_version 设置工程版本
  5. set_project 设置工程名
  6. set_xmakever 设置xmake版本
  7. add_subdirs 添加子工程目录
  8. add_subfiles 添加子工程文件
  9. add_moduledirs 添加扩展模块
  10. add_plugindirs 添加插件目录
  11. add_packagedirs 添加包目录
  12. set_config 设置默认配置
  13. get_config 获取默认配置
  14. add_repositories 添加依赖包仓库

参考

  1. lua 菜鸟教程:https://www.runoob.com/lua/lua-tutorial.html
  2. xmake 官方文档:https://xmake.io
  3. lua 教程:https://www.w3cschool.cn/lua
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/coder_lw/wiki.git
git@gitee.com:coder_lw/wiki.git
coder_lw
wiki
wiki
master

搜索帮助

Bbcd6f05 5694891 0cc6727d 5694891