Xmake v2.7.3 发布,包组件和 C++ 模块增量构建支持( 三 )

C++ 模块构建改进增量构建支持原本以为 Xmake 对 C++ 模块已经支持的比较完善了,后来才发现,它的增量编译还无法正常工作 。
因此,这个版本 Xmake 对 C++ 模块的增量编译也做了很好的支持,尽管支持过程还是花了很多精力的 。
我分析了下,各家的编译器对生成带模块的 include 依赖信息格式(*.d),差异还是非常大的 。
gcc 的格式最复杂,不过我还是将它支持上了 。
build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o: src/foo.mpp\build/.objs/dependence/linux/x86_64/release/src/foo.mpp.ogcm.cache/foo.gcm: bar.c++m cat.c++m\foo.c++m: gcm.cache/foo.gcm\.PHONY: foo.c++m\gcm.cache/foo.gcm:|build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o\CXX_IMPORTS += bar.c++m cat.c++m\clang 的格式兼容性最好,没有做任何特殊改动就支持了 。
build//hello.pcm:/usr/lib/llvm-15/lib/clang/15.0.2/include/module.modulemapsrc/hello.mpp\msvc 的格式扩展性比较好,解析和支持起来比较方便:
{"Version": "1.2","Data": {"Source": "c:\users\ruki\desktop\user_headerunit\src\main.cpp","ProvidedModule": "","Includes": [],"ImportedModules": [{"Name": "hello","BMI": "c:\users\ruki\desktop\user_headerunit\src\hello.ifc"}],"ImportedHeaderUnits": [{"Header": "c:\users\ruki\desktop\user_headerunit\src\header.hpp","BMI": "c:\users\ruki\desktop\user_headerunit\src\header.hpp.ifc"}]}}循环依赖检测支持由于模块之间是存在依赖关系的,因此如果有几个模块之间存在循环依赖引用,那么是无法编译通过的 。
但是之前的版本中,Xmake 无法检测到这种情况,遇到循环依赖,编译就会卡死,没有任何提示信息,这对用户非常不友好 。
而新版本中,我们对这种情况做了改进,增加了模块的循环依赖检测,编译时候会出现以下错误提示,方便用户定位问题:
$ xmake[0%]: generating.cxx.module.deps Foo.mpp[0%]: generating.cxx.module.deps Foo2.mpp[0%]: generating.cxx.module.deps Foo3.mpp[0%]: generating.cxx.module.deps main.cpperror: circular modules dependency(Foo2, Foo, Foo3, Foo2) detected!-> module(Foo2) in Foo2.mpp-> module(Foo) in Foo.mpp-> module(Foo3) in Foo3.mpp-> module(Foo2) in Foo2.mpp更加 LSP 友好的语法格式我们默认约定的域配置语法,尽管非常简洁,但是对自动格式化缩进和 IDE 不是很友好,如果你格式化配置,缩进就完全错位了 。
target("foo")set_kind("binary")add_files("src/*.cpp")另外,如果两个 target 之间配置了一些全局的配置,那么它不能自动结束当前 target 作用域,用户需要显式调用 target_end()
target("foo")set_kind("binary")add_files("src/*.cpp")target_end()add_defines("ROOT")target("bar")set_kind("binary")add_files("src/*.cpp")虽然,上面我们提到,可以使用 do end 模式来解决自动缩进问题,但是需要 target_end() 的问题还是存在 。
target("foo") doset_kind("binary")add_files("src/*.cpp")endtarget_end()add_defines("ROOT")target("bar") doset_kind("binary")add_files("src/*.cpp")end因此,在新版本中,我们提供了一种更好的可选域配置语法,来解决自动缩进,target 域隔离问题,例如:
target("foo", function ()set_kind("binary")add_files("src/*.cpp")end)add_defines("ROOT")target("bar", function ()set_kind("binary")add_files("src/*.cpp")end)foo 和 bar 两个域是完全隔离的,我们即使在它们中间配置其他设置,也不会影响它们,另外,它还对 LSP 非常友好,即使一键格式化,也不会导致缩进混乱 。
注:这仅仅只是一只可选的扩展语法,现有的配置语法还是完全支持的,用户可以根据自己的需求喜好,来选择合适的配置语法 。

经验总结扩展阅读