此版本耗时四个多月,对包依赖管理进行了重构改进,官方仓库新增了mysql,ffmpeg等常用依赖包,并且新增了大量新特性。
关于新特性的详细说明,可以看下下面的官方文档,或者看下相关文章介绍:xmake v2.2.5新特性详解
关于新特性的详细说明见文章下文。
string.serialize
和string.deserialize
去序列化,反序列化对象,函数以及其他类型xmake g --menu
去图形化配置全局选项target:installdir()
和set_installdir()
接口add_platformdirs
接口,用户现在可以自定义扩展编译平台add_installfiles
接口到target去自定义安装文件add_requires
和find_package
使其支持对第三方包管理的集成支持find_packages("pcre2", "zlib")
去同时查找多个依赖包,不需要通过import导入即可直接调用add_configfiles
和set_configvar
xmake project
插件,新增CMakelist.txt生成支持private, public, interface
属性设置去继承target配置add_configs()
添加和传递用户自定义配置到package()
add_headerfiles
接口去改进头文件的设置includes()
添加一些内置的辅助函数,例如:check_cfuncs
xmake update dev
xmake f/g --mingw=xxx
配置选线,并且改进find_mingw检测option.add_features
, option.add_cxxsnippets
和 option.add_csnippets
add_option_xxx
lib.detect.find_package
增加对conan包管理器的支持lib.detect.find_package
并且添加内建的find_packages("zlib 1.x", "openssl", {xxx = ...})
接口set_modes()
作为废弃接口, 我们使用add_rules("mode.debug", "mode.release")
来替代它target:set
, target:add
并且添加target:del
去动态修改target配置qt_add_static_plugins()
接口去支持静态Qt sdk此版本主要是对远程依赖包管理进行了一些改进,并且新增了很多小特性,并且此版本已经可以支持通过xmake update
来自我更新升级了,以后升级xmake将会更加方便。
关于新特性的详细说明见文章下文。
xmake plugin --help
add_syslinks
接口去设置系统库依赖,分离与add_links
添加的库依赖之间的链接顺序xmake l time xmake [--rebuild]
去记录编译耗时xmake f --vs_sdkver=10.0.15063.0
去改变windows sdk版本lib.luajit.ffi
和lib.luajit.jit
扩展模块xmake update
命令实现自我更新-D
和--diagnosis
去替换--backtrace
,改进诊断信息显示add_packages("xxx", {links = {}})
LTUI是一个基于lua的跨平台字符终端UI界面库。
此框架源于xmake中图形化菜单配置的需求,类似linux kernel的menuconf去配置编译参数,因此基于curses和lua实现了一整套跨平台的字符终端ui库。 而样式风格基本上完全参照的kconfig-frontends,当然用户也可以自己定制不同的ui风格。
$ luarocks install ltui
我们需要先安装跨平台构建工具:xmake
$ xmake
历经四个多月,xmake终于更新了新版本v2.2.2,并且上线了重量级功能:原生支持的远程依赖包管理。
而这个特性,其实我陆陆续续写了将近一年的时间,才初步完成,对于此特性的开发进展和历史,有兴趣的同学可以看下相关issues:#69。
目前的实现效果如下,完全一致的语义版本依赖描述:
完全一致的跨平台构建行为,一键xmake编译:
完整的项目描述:
add_requires("tbox 1.6.*", "libpng ~1.16", "zlib")
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("tbox", "libpng", "zlib")
我先简单介绍下我做这个功能的背景:
我们在写C/C++程序的时候,对于第三方依赖库的使用一直是一个老大难问题,因为每个依赖库的构建系统不同、代码平台支持力度的差异,导致没法像其他高级语言那样有方便好用的包管理支持。
虽然现在已经有了homebrew, vcpkg等包管理工具来解决这一问题,但是多少都有一些局限性,例如:
对于目前现有的跨平台构建工具,都缺少内置的包管理支持,像cmake仅提供了find_package
去查找系统包,虽然可以和vcpkg等第三方包管理配合使用,但我个人觉得并不是很方便。
这会使得项目的其他用户在编译的时候,额外要求去安装vcpkg或者安装依赖库到系统上才行,对于pc平台还好弄些,对于iphoneos, android等平台的依赖库,用户就要折腾上一会了。
而xmake的理念就是:真正的一致维护, 真正的一键编译
xmake
命令,即可编译通过。而cmake还需要生成额外的第三方IDE工程文件,即使cmakelist.txt相同,但是构建、维护体验上对用户来讲都不可能保证完全一致,毕竟还受限于vc/make此类工具。
之前在对tbox的协程库中增加了基于IOCP的io处理,期间踩了不少的坑,这边就做个简单记录吧,省的到时候忘记了,自己看不懂自己这个代码 (= =)
WSARecv/WSASend在lpNumberOfBytesRecv和overlap同时被设置的情况下,如果它们的io操作立即返回成功,并且lpNumberOfBytesRecv里面也已经获取到了实际的io处理字节数,但是io event还会被放到完成队列,需要调用GetQueuedCompletionStatus去获取。
之前就被这个坑了很久,我原本想既然如果WASRecv已经立即完成,那么没必要再去通过GetQueuedCompletionStatus等待了,我可以直接快速返回处理结果,减少不必要的协程等待和切换。
然而经过实测发现,实时并非如此,即时我这次立即从recv返回出去不再等待了,等到下次recv如果是pending状态的话,有可能等待到的是上次处理成功的io event,蛋疼。。
为了进一步了解其机制,我翻了下官方文档,里面对lpNumberOfBytesRecvd有如下说明:
lpNumberOfBytesRecvd
A pointer to the number, in bytes, of data received by this call if the receive operation completes immediately.
Use NULL for this parameter if the lpOverlapped parameter is not NULL to avoid potentially erroneous results. This parameter can be NULL only if the lpOverlapped parameter is not NULL.
大概得意思就是告诉我们,如果lpNumberOfBytesRecvd和lpOverlapped同时被设置,可能会有潜在的问题(估计多半就是我遇到的坑吧),所以看文档这意思,估计是建议我们在传入lpOverlapped的情况下,尽量不要设置lpNumberOfBytesRecvd,传NULL就好。
但是这不是我想要的结果,我还是希望能够快速处理WSARecv立即成功返回的情况,没必要每次都切换协程去等待io event。
一种办法是调用两次WSARecv,一次不传lpOverlapped,直接尝试读取,如果成功立即返回结果,读不到的话,再通过lpOverlapped送入完成队列,去队列化等待事件完成。
另外一种办法就是每次GetQueuedCompletionStatus的时候去忽略之前已经成功处理和返回的时间对象。
不过这两种我试了下,都不是很理想,处理起来比较复杂,效率也不高,那有没有其他更好的办法呢,我翻了下golang源码中对于iocp的处理,终于找到了解决办法。(果然还是golang给力)
poll/fd_windows.go里面有这么字段代码和注释说明:
// This package uses the SetFileCompletionNotificationModes Windows
// API to skip calling GetQueuedCompletionStatus if an IO operation
// completes synchronously. There is a known bug where
// SetFileCompletionNotificationModes crashes on some systems (see
// https://support.microsoft.com/kb/2568167 for details).
var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use
原来golang是用了SetFileCompletionNotificationModes API去设置iocp端口在每次GetQueuedCompletionStatus等待io事件的时候,去直接内部忽略已经立即成功返回的io事件,也就是说如果WSARecv如果立即成功返回,那么不会再队列化io event了。
这个好呀,正是我想要的东西,而且用起来也很简单,只需要:
SetFileCompletionNotificationModes(socket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);