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 要么是输入…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...