Xmake v2.8.5 发布,支持链接排序和单元测试
Xmake 是一个基于 Lua 的轻量级跨平台构建工具。
它非常的轻量,没有任何依赖,因为它内置了 Lua 运行时。
它使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能快速入门,能够让用户把更多的精力集中在实际的项目开发上。
我们能够使用它像 Make/Ninja 那样可以直接编译项目,也可以像 CMake/Meson 那样生成工程文件,另外它还有内置的包管理系统来帮助用户解决 C/C++ 依赖库的集成使用问题。
目前,Xmake 主要用于 C/C++ 项目的构建,但是同时也支持其他 native 语言的构建,可以实现跟 C/C++ 进行混合编译,同时编译速度也是非常的快,可以跟 Ninja 持平。
Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache
尽管不是很准确,但我们还是可以把 Xmake 按下面的方式来理解:
Xmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache
- 项目源码
- 官方文档
- 入门课程
新特性介绍
在介绍新特性之前,我们有一个好消息要告诉大家,Xmake 最近进入了 Debian 的官方仓库:https://packages.debian.org/sid/xmake,
等到明年4月份 Ubuntu 24.04 发布,我们应该就能直接通过 apt install xmake 命令去快速安装 Xmake 了。
同时也感谢 @Lance Lin 的帮助,他全程帮助我们维护并上传 Xmake 包到 Debian 仓库,真的非常感谢!
接下来,我们来介绍下 2.8.5 版本引入的一些改动,这个版本带来了很多的新特性,尤其是对链接排序,链接组的支持,还有对 xmake test 内置单元测试的支持。
另外,我们还新增了 Apple XROS 平台的构建支持,可以用于构建苹果新的 VisionOS 上的程序,还有我们还提供了更加灵活通用的 check_sizeof 检测接口,用于快速检测类型的大小。
链接重排序支持
这是一个存在了两年多的需求,主要用于调整 target 内部的链接顺序。
由于 xmake 提供了 add_links, add_deps, add_packages, add_options 接口,可以配置目标、依赖,包和选项中的链接,尽管 add_links 本身的链接顺序可以根据添加顺序来调整。
但是 links,deps 和 packages 之间的链接顺序,只能按固定顺序生成,无法灵活调整,这对于一些复杂的项目,就有点显得力不从心了。
而我们在这个版本,彻底解决了这个问题,新增了 add_linkorders 接口,可用于配置目标、依赖、包、选项、链接组引入的各种链接顺序。
更多详情和背景,请见:#1452
排序链接
为了更加灵活的调整 target 内部的各种链接顺序,我们可以通过 add_linkorders 这个新接口来实现,例如:
add_links("a", "b", "c", "d", "e")
-- e -> b -> a
add_linkorders("e", "b", "a")
-- e -> d
add_linkorders("e", "d")
add_links 是配置的初始链接顺序,然后我们通过 add_linkorders 配置了两个局部链接依赖 e -> b -> a 和 e -> d 后。
xmake 内部就会根据这些配置,生成 DAG 图,通过拓扑排序的方式,生成最终的链接顺序,提供给链接器。
当然,如果存在循环依赖,产生了环,它也会提供警告信息。
排序链接和链接组
另外,对于循环依赖,我们也可以通过 add_linkgroups 配置链接组的方式也解决。
并且 add_linkorders 也能够对链接组进行排序。
add_links("a", "b", "c", "d", "e")
add_linkgroups("c", "d", {name = "foo", group = true})
add_linkorders("e", "linkgroup::foo")
如果要排序链接组,我们需要对每个链接组取个名,{name = "foo"} ,然后就能在 add_linkorders 里面通过 linkgroup::foo 去引用配置了。
排序链接和frameworks
我们也可以排序链接和 macOS/iPhoneOS 的 frameworks。
add_links("a", "b", "c", "d", "e")
add_frameworks("Foundation", "CoreFoundation")
add_linkorders("e", "framework::CoreFoundation")
完整例子
相关的完整例子,我们可以看下:
add_rules("mode.debug", "mode.release")add_requires("libpng")target("bar")set_kind("shared")add_files("src/foo.cpp")add_linkgroups("m", "pthread", {whole = true})target("foo")set_kind("static")add_files("src/foo.cpp")add_packages("libpng", {public = true})target("demo")set_kind("binary")add_deps("foo")add_files("src/main.cpp")if is_plat("linux", "macosx") thenadd_syslinks("pthread", "m", "dl")endif is_plat("macosx") thenadd_frameworks("Foundation", "CoreFoundation")endadd_linkorders("framework::Foundation", "png16", "foo")add_linkorders("dl", "linkgroup::syslib")add_linkgroups("m", "pthread", {name = "syslib", group = true})
完整工程在:linkorders example
链接组支持
另外,这个版本,我们还新增了链接组的原生支持,它目前主要用于 linux 平台的编译,仅支持 gcc/clang 编译器。
需要注意的是 gcc/clang 里面的链接组概念主要特指:-Wl,--start-group
而 Xmake 对齐进行了封装,做了进一步抽象,并且不仅仅用于处理 -Wl,--start-group,还可以处理 -Wl,--whole-archive 和 -Wl,-Bstatic。
下面我们会一一对其进行讲解。
更多详情见:#1452
–start-group 支持
-Wl,--start-group 和 -Wl,--end-group 是用于处理复杂库依赖关系的链接器选项,确保链接器可以解决符号依赖并成功连接多个库。
在 xmake 中,我们可以通过下面的方式实现:
add_linkgroups("a", "b", {group = true})
它会对应生成 -Wl,--start-group -la -lb -Wl,--end-group 链接选项。
如果 a 和 b 库之间有符号的循环依赖,也不会报链接错误,能够正常链接成功。
对于不支持的平台和编译,会退化成 -la -lb
–whole-archive 支持
--whole-archive 是一个链接器选项,通常用于处理静态库。
它的作用是告诉链接器将指定的静态库中的所有目标文件都包含到最终可执行文件中,而不仅仅是满足当前符号依赖的目标文件。
这可以用于确保某些库的所有代码都被链接,即使它们在当前的符号依赖关系中没有直接引用。
更多信息,可以参考 gcc/clang 的文档。
在 xmake 中,我们可以通过下面的方式实现:
add_linkgroups("a", "b", {whole = true})
它会对应生成 -Wl,--whole-archive -la -lb -Wl,--no-whole-archive 链接选项。
对于不支持的平台和编译,会退化成 -la -lb
另外,我们可以同时配置 group/whole:
add_linkgroups("a", "b", {whole = true, group = true})
-Bstatic 支持
-Bstatic 也是用于编译器(如gcc)的选项,用于指示编译器在链接时只使用静态库而不使用共享库。
更多信息,可以参考 gcc/clang 的文档。
在 xmake 中,我们可以通过下面的方式实现:
add_linkgroups("a", "b", {static = true})
它会对应生成 -Wl,-Bstatic -la -lb -Wl,-Bdynamic 链接选项。
单元测试支持
新版本中,我们还增加了一个内置的测试命令:xmake test,我们只需要在需要测试的 target 上通过 add_tests 配置一些测试用例,就可以自动执行测试。
即使当前 target 被设置成了 set_default(false),在执行测试的时候,xmake 也还是会先自动编译它们,然后自动运行所有的测试。
我们可以先看个整体的例子,大概知道下它是怎么样子的。
add_rules("mode.debug", "mode.release")for _, file in ipairs(os.files("src/test_*.cpp")) dolocal name = path.basename(file)target(name)set_kind("binary")set_default(false)add_files("src/" .. name .. ".cpp")add_tests("default")add_tests("args", {runargs = {"foo", "bar"}})add_tests("pass_output", {trim_output = true, runargs = "foo", pass_outputs = "hello foo"})add_tests("fail_output", {fail_outputs = {"hello2 .*", "hello xmake"}})
end
这个例子,自动扫描源码目录下的 test_*.cpp 源文件,然后每个文件自动创建一个测试目标,它被设置成了 set_default(false),也就是正常情况下,默认不会编译它们。
但是,如果执行 xmake test 进行测试,它们就会被自动编译,然后测试运行,运行效果如下:
ruki-2:test ruki$ xmake test
running tests ...
[ 2%]: test_1/args .................................... passed 7.000s
[ 5%]: test_1/default .................................... passed 5.000s
[ 8%]: test_1/fail_output .................................... passed 5.000s
[ 11%]: test_1/pass_output .................................... passed 6.000s
[ 13%]: test_2/args .................................... passed 7.000s
[ 16%]: test_2/default .................................... passed 6.000s
[ 19%]: test_2/fail_output .................................... passed 6.000s
[ 22%]: test_2/pass_output .................................... passed 6.000s
[ 25%]: test_3/args .................................... passed 7.000s
[ 27%]: test_3/default .................................... passed 7.000s
[ 30%]: test_3/fail_output .................................... passed 6.000s
[ 33%]: test_3/pass_output .................................... passed 6.000s
[ 36%]: test_4/args .................................... passed 6.000s
[ 38%]: test_4/default .................................... passed 6.000s
[ 41%]: test_4/fail_output .................................... passed 5.000s
[ 44%]: test_4/pass_output .................................... passed 6.000s
[ 47%]: test_5/args .................................... passed 5.000s
[ 50%]: test_5/default .................................... passed 6.000s
[ 52%]: test_5/fail_output .................................... failed 6.000s
[ 55%]: test_5/pass_output .................................... failed 5.000s
[ 58%]: test_6/args .................................... passed 7.000s
[ 61%]: test_6/default .................................... passed 6.000s
[ 63%]: test_6/fail_output .................................... passed 6.000s
[ 66%]: test_6/pass_output .................................... passed 6.000s
[ 69%]: test_7/args .................................... failed 6.000s
[ 72%]: test_7/default .................................... failed 7.000s
[ 75%]: test_7/fail_output .................................... failed 6.000s
[ 77%]: test_7/pass_output .................................... failed 5.000s
[ 80%]: test_8/args .................................... passed 7.000s
[ 83%]: test_8/default .................................... passed 6.000s
[ 86%]: test_8/fail_output .................................... passed 6.000s
[ 88%]: test_8/pass_output .................................... failed 5.000s
[ 91%]: test_9/args .................................... passed 6.000s
[ 94%]: test_9/default .................................... passed 6.000s
[ 97%]: test_9/fail_output .................................... passed 6.000s
[100%]: test_9/pass_output .................................... passed 6.000s80% tests passed, 7 tests failed out of 36, spent 0.242s

我们也可以执行 xmake test -vD 查看详细的测试失败的错误信息:

运行指定测试目标
我们也可以指定运行指定 target 的某个测试:
$ xmake test targetname/testname
或者按模式匹配的方式,运行一个 target 的所有测试,或者一批测试:
$ xmake test targetname/*
$ xmake test targetname/foo*
也可以运行所有 target 的同名测试:
$ xmake test */testname
并行化运行测试
其实,默认就是并行化运行的,但是我们可以通过 -jN 调整运行的并行度。
$ xmake test -jN
分组运行测试
$ xmake test -g "foo"
$ xmake test -g "foo*"
添加测试到目标(无参数)
如果没有配置任何参数,仅仅配置了测试名到 add_tests,那么仅仅测试这个目标程序的是否会运行失败,根据退出代码来判断是否通过测试。
target("test")add_tests("testname")
配置运行参数
我们也可以通过 {runargs = {"arg1", "arg2"}} 的方式,给 add_tests 配置指定测试需要运行的参数。
另外,一个 target 可以同时配置多个测试用例,每个测试用例可独立运行,互不冲突。
target("test")add_tests("testname", {runargs = "arg1"})add_tests("testname", {runargs = {"arg1", "arg2"}})
如果我们没有配置 runargs 到 add_tests,那么我们也会尝试从被绑定的 target 中,获取 set_runargs 设置的运行参数。
target("test")add_tests("testname")set_runargs("arg1", "arg2")
配置运行目录
我们也可以通过 rundir 设置测试运行的当前工作目录,例如:
target("test")add_tests("testname", {rundir = os.projectdir()})
如果我们没有配置 rundir 到 add_tests,那么我们也会尝试从被绑定的 target 中,获取 set_rundir 设置的运行目录。
target("test")add_tests("testname")set_rundir("$(projectdir)")
配置运行环境
我们也可以通过 runenvs 设置一些运行时候的环境变量,例如:
target("test")add_tests("testname", {runenvs = {LD_LIBRARY_PATH = "/lib"}})
如果我们没有配置 runenvs 到 add_tests,那么我们也会尝试从被绑定的 target 中,获取 add_runenvs 设置的运行环境。
target("test")add_tests("testname")add_runenvs("LD_LIBRARY_PATH", "/lib")
匹配输出结果
默认情况下,xmake test 会根据测试运行的退出代码是否为 0,来判断是否测试通过。
当然,我们也可以通过配置测试运行的输出结果是否满足我们的指定的匹配模式,来判断是否测试通过。
主要通过这两个参数控制:
| 参数 | 说明 |
|---|---|
| pass_outputs | 如果输出匹配,则测试通过 |
| fail_outputs | 如果输出匹配,则测试失败 |
传入 pass_outputs 和 fail_outputs 的是一个 lua 匹配模式的列表,但模式稍微做了一些简化,比如对 * 的处理。
如果要匹配成功,则测试通过,可以这么配置:
target("test")add_tests("testname1", {pass_outputs = "hello"})add_tests("testname2", {pass_outputs = "hello *"})add_tests("testname3", {pass_outputs = {"hello", "hello *"}})
如果要匹配成功,则测试失败,可以这么配置:
target("test")add_tests("testname1", {fail_outputs = "hello"})add_tests("testname2", {fail_outputs = "hello *"})add_tests("testname3", {fail_outputs = {"hello", "hello *"}})
我们也可以同时配置它们:
target("test")add_tests("testname", {pass_outputs = "foo", fail_outputs = "hello"})
由于一些测试输出的结果,尾部会有一些换行什么的空白字符,干扰匹配模式,我们可以再配置 trim_output = true,先截断空白字符后,再做匹配。
target("test")add_tests("testname", {trim_output = true, pass_outputs = "foo", fail_outputs = "hello"})
我们还可以配置 {plain = true} 是禁用 lua 模式匹配,仅仅做最基础的平坦文本匹配。
target("test")add_tests("testname", {plain = true, pass_outputs = "foo", fail_outputs = "hello"})
配置测试组
我们也可以通过 group = "foo" 来配置一个测试组,进行分组测试:
target("test")add_tests("testname1", {group = "foo"})add_tests("testname2", {group = "foo"})add_tests("testname3", {group = "bar"})add_tests("testname4", {group = "bae"})
其中 testname1/testname2 是一个组 foo,另外两个是在另外一个组。
然后,我们就可以使用 xmake test -g groupname 来进行分组测试了。
$ xmake test -g "foo"
$ xmake test -g "foo*"
!> 运行分组,也是支持模式匹配的。
另外,如果没有设置 group 参数给 add_tests,我们也可以默认获取绑定到 target 的组名。
target("test")add_tests("testname")set_group("foo")
自定义测试脚本
我们还新增了 before_test, on_test 和 after_test 配置脚本,用户可以在 rule 和 target 域,自定义配置它们实现定制化的测试执行。
target("test")on_test(function (target, opt)print(opt.name, opt.runenvs, opt.runargs, opt.pass_outputs)-- do test-- ...-- passedreturn true-- failiedreturn false, errorsend)
其中,opt 里面可以获取到所有传入 add_tests 的参数,我们在 on_test 里面自定义测试逻辑,然后返回 true 就是测试通过,返回 false 就是测试失败,然后继续返回测试失败的错误信息。
自动化构建
由于测试目标在正常开发构建阶段,通常是不需要被构建的,因此我们会设置 set_default(false)。
target("test")add_tests("testname")set_default(false)
但是运行 xmake test 进行测试时候,这些测试对应的 target 还是会被自动构建,确保能够被运行。
$ xmake test
[ 25%]: cache compiling.release src/main.cpp
[ 50%]: linking.release test
running tests ...
[100%]: test/testname .................................... passed 6.000s100% tests passed, 0 tests failed out of 1, spent 0.006s
首次测试失败就终止
默认情况下,xmake test 会等到所有测试都运行完,不管里面有多少是没通过的。
而有时候,我们想在第一个测试没通过,就直接中断测试,那么我们可以通过下面的配置启用:
set_policy("test.return_zero_on_failure", true)
测试失败返回0
默认情况下,只要有一个测试没通过,等到 xmake test 运行完成,它都会返回非0退出代码,这对于一些 CI 环境非常有用,可以中断 CI 的其他脚本继续运行。
然后触发信号告诉 CI,我们需要生成测试报告和告警了。
然后,如果我们想要压制这种行为,可以强制将 xmake test 的退出代码总是设置成 0。
set_policy("test.return_zero_on_failure", true)
仅仅测试编译
有时候,我们仅仅想要测试代码是否通过编译,或者没有通过编译,不需要运行它们,那么可以通过配置 build_should_pass 和 build_should_fail 来实现。
target("test_10")set_kind("binary")set_default(false)add_files("src/compile.cpp")add_tests("compile_fail", {build_should_fail = true})target("test_11")set_kind("binary")set_default(false)add_files("src/compile.cpp")add_tests("compile_pass", {build_should_pass = true})
这通常用于一些测试代码中带有 static_assert 的场景,例如:
template <typename T>
bool foo(T val) {if constexpr (std::is_same_v<T, int>) {printf("int!\n");} else if constexpr (std::is_same_v<T, float>) {printf("float!\n");} else {static_assert(false, "unsupported type");}
}int main(int, char**) {foo("BAD");return 0;
}
配置额外的代码编译
我们还可以在配置测试用例的时候,对每个测试配置额外需要编译的代码,以及一些宏定义,实现内联测试。
xmake 会为每个测试单独编译一个独立的可执行程序去运行它,但这并不会影响到 target 在生产环境的编译结果。
target("test_13")set_kind("binary")set_default(false)add_files("src/test_1.cpp")add_tests("stub_1", {files = "tests/stub_1.cpp", defines = "STUB_1"})target("test_14")set_kind("binary")set_default(false)add_files("src/test_2.cpp")add_tests("stub_2", {files = "tests/stub_2.cpp", defines = "STUB_2"})target("test_15")set_kind("binary")set_default(false)add_files("src/test_1.cpp")add_tests("stub_n", {files = "tests/stub_n*.cpp", defines = "STUB_N"})
以 doctest 为例,我们可以在不修改任何 main.cpp 的情况下,外置单元测试:
add_rules("mode.debug", "mode.release")add_requires("doctest")target("doctest")set_kind("binary")add_files("src/*.cpp")for _, testfile in ipairs(os.files("tests/*.cpp")) doadd_tests(path.basename(testfile), {files = testfile,remove_files = "src/main.cpp",languages = "c++11",packages = "doctest",defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"})end
定义 DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 会引入额外的 main 入口函数,因此我们需要配置 remove_files 去移除已有的 main.cpp 文件。
运行效果如下:
ruki-2:doctest ruki$ xmake test
running tests ...
[ 50%]: doctest/test_1 .................................... failed 0.009s
[100%]: doctest/test_2 .................................... passed 0.009s50% tests passed, 1 tests failed out of 2, spent 0.019s
ruki-2:doctest ruki$ xmake test -v
running tests ...
[ 50%]: doctest/test_1 .................................... failed 0.026s
[doctest] doctest version is "2.4.11"
[doctest] run with "--help" for options
===============================================================================
tests/test_1.cpp:7:
TEST CASE: testing the factorial functiontests/test_1.cpp:8: ERROR: CHECK( factorial(1) == 10 ) is NOT correct!values: CHECK( 1 == 10 )===============================================================================
[doctest] test cases: 1 | 0 passed | 1 failed | 0 skipped
[doctest] assertions: 4 | 3 passed | 1 failed |
[doctest] Status: FAILURE!run failed, exit code: 1
[100%]: doctest/test_2 .................................... passed 0.010s50% tests passed, 1 tests failed out of 2, spent 0.038s
测试动态库
通常,add_tests 仅用于对可执行程序进行运行测试,运行动态库需要有一个额外的 main 主入口,因此我们需要额外配置一个可执行程序去加载它,例如:
target("doctest_shared")set_kind("shared")add_files("src/foo.cpp")for _, testfile in ipairs(os.files("tests/*.cpp")) doadd_tests(path.basename(testfile), {kind = "binary",files = testfile,languages = "c++11",packages = "doctest",defines = "DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN"})end
通过 kind = "binary" 可以将每个单元测试改为 binary 可执行程序,并通过 DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 引入 main 入口函数。
这样就能实现动态库目标中外置可运行的单元测试。
新增类型大小检测
在先前的版本中,我们可以通过 check_csnippets 和 output = true 的方式,来实现类型检测。
check_csnippets("INT_SIZE", 'printf("%d", sizeof(int)); return 0;', {output = true, number = true})
但是这种方式,是通过尝试运行测试代码,然后获取运行输出结果,提取类型大小信息。
这对于交叉编译,就不适用了。
在 2.8.5 版本中,我们新增了 check_sizeof 辅助接口,可以通过直接解析测试程序的二进制文件,提取类型大小信息。
由于不需要运行测试,这种方式不仅可以支持交叉编译,而且对检测效率也有极大的提升,使用也更加的简单。
includes("@builtin/check")target("test")set_kind("static")add_files("*.cpp")check_sizeof("LONG_SIZE", "long")check_sizeof("STRING_SIZE", "std::string", {includes = "string"})
$ xmake f -c
checking for LONG_SIZE ... 8
checking for STRING_SIZE ... 24
另外,我也可以通过 target:check_sizeof 在脚本域进行检测。
新增 Apple XROS 平台
苹果在 Xcode15 中新增了 visionOS 设备的构建支持,因此我们也在第一时间对其进行了支持,只需要执行:
$ xmake f -p applexros
$ xmake
就可以完成 visionOS/XROS 平台的构建。
支持代码合并
最后,我们还提供了一个小工具模块,它可以用于快速合并指定 target 里面的所有 c/c++ 和 头文件源码到单个源文件。
会生成类似 sqlite3.c 的这种单源码文件,用户可以根据自己的实际需求来决定是否使用这个功能。
而在做合并的时候,Xmake 会将内部 includes 头文件全部展开,并生成 DAG,通过拓扑排序引入。
默认它会处理所有 target 的合并,例如:
$ xmake l cli.amalgamate
build/tbox.c generated!
build/tbox.h generated!
我们也可以指定合并需要的目标:
$ xmake l cli.amalgamate tbox
build/tbox.c generated!
build/tbox.h generated!
也可以在合并每个源文件时候,指定一个自定义的 unique ID 的宏定义,来处理符号冲突问题。
$ xmake l cli.amalgamate -u MY_UNIQUEU_ID
build/tbox.c generated!
build/tbox.h generated!
如果多个源文件内部有重名符号,就可以判断这个 MY_UNIQUEU_ID 宏是否被定义,如果定义了,说明是在单文件中,就自己在源码中处理下重名符号。
#ifdef MY_UNIQUEU_ID// do some thing
#endif
我们也可以指定输出位置:
$ xmake l cli.amalgamate -o /xxx
/xxx/tbox.c generated!
/xxx/tbox.h generated!
新增 windows.manifest.uac 策略
通过这个策略,我们可以快速方便的设置并启用 Windows UAC。
它支持以下几个 Level:
- invoker: asInvoker
- admin: requireAdministrator
- highest: highestAvailable
例如:
set_policy("windows.manifest.uac", "admin")
它等价于设置
if is_plat("windows") thenadd_ldflags("/manifest:embed", {"/manifestuac:level='requireAdministrator' uiAccess='false'"}, {force = true, expand = false})
end
但是更加方便简洁,并且不需要判断平台,其他平台自动忽略。
我们也可以通过 windows.manifest.uac.ui 策略,设置 Windows UAC 的 uiAccess,如果没有设置它,默认是 false。
set_policy("windows.manifest.uac.ui", true)
更新日志
新特性
- #1452: 支持链接顺序调整,链接组
- #1438: 支持代码 amalgamation
- #3381: 添加
xmake test支持 - #4276: 支持自定义域 API
- #4286: 添加 Apple XROS 支持
- #4345: 支持检测类型大小 sizeof
- #4369: 添加 windows.manifest.uac 策略
改进
- #4284: 改进内置 includes 模块
Bugs 修复
- #4256: 为 vsxmake 生成器修复 c++ modules intellisense
https://tboox.org/cn/2023/11/05/xmake-update-v2.8.5/
相关文章:
Xmake v2.8.5 发布,支持链接排序和单元测试
Xmake 是一个基于 Lua 的轻量级跨平台构建工具。 它非常的轻量,没有任何依赖,因为它内置了 Lua 运行时。 它使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好&#x…...
红队专题-从零开始VC++C/S远程控制软件RAT-MFC-远程控制软件总结
红队专题 招募六边形战士队员[30]远控班第一期课程与远控总结 招募六边形战士队员 一起学习 代码审计、安全开发、web攻防、逆向等。。。 私信联系 [30]远控班第一期课程与远控总结 一.Bug修复(1)生成路径(2)显示系统版本号二.内存泄露(1)如何检查内存泄露 #define CRTDBG_…...
MyBatis与SQL实用技巧 实用语法
数据库SQL技巧 数值转字符 <select id"getMaterialsList" resultType"java.util.Map">selectmaterial_id materialId,material_name materialName,unit, specification, CONVERT(unit_price,CHAR) unitPricefrom trace_agriculture_materialwhere …...
更好的理解c++中的虚函数和静态多态以及动态多态
1.虚函数(Virtual Function) 在c 中, 虚函数是定义在基类中的函数,但是它可以在派生类中进行重写(Override) 。 通过在基类中通过virtual 关键字声明函数 , 你创建了一个可以在任何派生类中特别实现的接口…...
MybatisPlus之新增操作并返回主键ID
在应用mybatisplus持久层框架的项目中,经常遇到执行新增操作后需要获取主键ID的场景,下面将分析及测试过程记录分享出来。 1、MybatisPlus新增方法 持久层新增方法源码如下: public interface BaseMapper<T> extends Mapper<T> …...
工程(十四)——ubuntu20.04 PL-VINS
博主创建了一个科研互助群Q:772356582,欢迎大家加入讨论。这是一个科研互助群,主要围绕机器人,无人驾驶,无人机方面的感知定位,决策规划,以及论文发表经验,以方便大家很好很快的科研…...
C复习-结构struct+bit field+union
参考: 里科《C和指针》 结构的声明 struct {int a;char b; } x; struct {int a;char b; } y[20], *z;// 会报错,因为z和x虽然都没有名字,但是并不是一个东西 z &x;struct SIMPLE {int a;char b; }; // 这样就对了,因为名字匹…...
1 快速了解Paimon数据湖核心原理及架构
1.1 什么是Apache Paimon Apache Paimon的前身属于Flink的子项目:Flink Table Store。 目前业内主流的数据湖存储项目都是面向批处理场景设计的,在数据更新处理时效上无法满足流式数据湖的需求,因此Flink社区在2022年的时候内部孵化了 …...
chrome v3开发插件实现所有网站允许跨域
场景: chrome 插件 升级到v3后,原来修改请求响应都变成异步,即无法同步拦截来修改请求响应。 在v3中也不支持修改请求响应内容。 问题:如何在chrome v3中允许其他网站跨域呢。 方式一:禁用chrome跨域,禁…...
unity Holoens2开发,使用Vuforia识别实体或图片 触发交互
建议:先看官方文档 我使用的utniy 版本:Unity 2021.3.6f1 官方建议:混合现实工具包简介 - 设置项目并使用手势交互 - Training | Microsoft Learn 配置了正确工具的 Windows 10 或 11 电脑Windows 10 SDK 10.0.18362.0 或更高版本安装了 U…...
从零开始搭建微服务(一)
构建项目父工程 添加公共核心模块 安装nacos 安装nacos nacos 文档地址: https://nacos.io/zh-cn/docs/what-is-nacos.html 本文使用版本2.2.2 下载地址:https://github.com/alibaba/nacos/archive/refs/tags/2.2.2.zip 使用nacos 我们下载是源代码 解…...
一种可以实现安全便捷文件摆渡的跨网文件安全交换软件
为了保护数据的安全性和完整性,很多企业都采用了内外网物理隔离的方式,防止核心数据泄露或被恶意篡改。然而,这也给企业内部或与外部合作伙伴之间的文件交换带来了很多不便和挑战。如何在保证数据安全的前提下,实现跨网文件的快速…...
『 MySQL数据库 』数据库基础之表的基本操作
文章目录 创建表🗡查看表🗡✒ 查看表内所有信息(描述\表结构等)✒ 根据条件查看表内数据✒ 查看表的具体详细信息: 修改表🗡✒ 修改表名:✒ 修改表的存储引擎、编码集(字符集和校验集):✒ 表内插入数据:insert into✒ 在表中新添一个字段(列)…...
如何提高40%的Docker构建时间
1. 背景 在产品开发中构建docker镜像,随着时间的推移,会变得越来越大,构建时间也越来越长。我的目标是构建时间不超过 5 分钟。 2. 遵循Dockerfile的最佳实践 我们首先确保Dockerfile文件遵循Docker官方的最佳实践,具体做法有: 尽量使用官方的基础镜像,Docker推荐使用…...
真正解决jellyfin硬解码转码
前段时间入手一个DS423集成显卡UHD600,搭了一个jellyfin,发现网上关于硬解码的教程基本都存在问题,没有真正解决我的硬解码问题。经过一系列分析修改,最终实现硬解码。先贴效果图: 下载安装jellyfin这里就不叙述&#…...
声音训练数据集哪里找?中文、英文
一般找数据集的都是需要训练底膜的,大家git上找的开源项目大多是预训练模型。预训练就是别人已经训练好的底膜,你在他的基础上进行调整。而我们训练如果他这个模型不理想是需要训练底膜的。 找的方式是从git开源上找 中文 推荐MockingBird,…...
springboot中如何同时操作同一功能
问题描述 测试阶段,由于存在某一功能的同时操作,该功能还是入库逻辑,此时若不进行处理,会造成插入表中多条重复数据,为此该问题需要修复。 解决办法 在接口开始进行对是否存在某个key值的判断,若不存在&…...
YOLOWeeds: 用于棉花生产系统中多类杂草检测的 YOLO 目标检测器的新基准
YOLOWeeds: A novel benchmark of YOLO object detectors for multi-class weed detection in cotton production systems 摘要1、介绍2、总结 摘要 过度依赖除草剂控制杂草,加速了杂草的抗除草剂进化,引起了对环境、食品安全和人类健康的日益关注。自动…...
Vue3:自定义图标选择器(包含 SVG 图标封装)
文章目录 一、准备工作(在 Vue3 中使用 SVG)二、封装 SVG三、封装图标选择器四、Demo 效果预览: 一、准备工作(在 Vue3 中使用 SVG) 本文参考:https://blog.csdn.net/houtengyang/article/details/1290431…...
NIO讲解
一:什么是NIO? 二:NIO三大组件 1. channel channel 有一点类似于 stream,它就是读写数据的双向通道,可以从 channel 将数据读入 buffer,也可以将 buffer 的数据写入 channel,而之前的 stream 要么是输入…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
