# 更新日志
## master (开发中)
### 新特性
* [#7398](https://github.com/xmake-io/xmake/pull/7398): 添加 C# 语言和 dotnet 工具链支持
* [#7410](https://github.com/xmake-io/xmake/pull/7410): 添加 C# 和 C/C++ 通过 P/Invoke 互操作支持
* [#7360](https://github.com/xmake-io/xmake/pull/7360): 支持自定义模板
* [#7367](https://github.com/xmake-io/xmake/pull/7367): 添加 `xmake create --list` 和远程模板分发
* [#7313](https://github.com/xmake-io/xmake/pull/7313): 添加 `build.release.strip` 策略
* [#7333](https://github.com/xmake-io/xmake/pull/7333): 添加 `winos.file_signature` 函数
* [#7336](https://github.com/xmake-io/xmake/pull/7336): 添加运行 wasi 目标支持
* [#7346](https://github.com/xmake-io/xmake/pull/7346): 添加 nnd 调试器支持
* [#7366](https://github.com/xmake-io/xmake/pull/7366): 添加 tarxz 打包格式
### 改进
* [#7309](https://github.com/xmake-io/xmake/pull/7309): 保持包源信息
* [#7310](https://github.com/xmake-io/xmake/pull/7310): 改进检测提示
* [#7311](https://github.com/xmake-io/xmake/pull/7311): 改进 Xcode 工具链
* [#7312](https://github.com/xmake-io/xmake/pull/7312): 改进 binutils 支持 wasm
* [#7320](https://github.com/xmake-io/xmake/pull/7320): 添加 haiku ci
* [#7329](https://github.com/xmake-io/xmake/pull/7329): 改进 qt deploy 对 macapp 的支持
* [#7349](https://github.com/xmake-io/xmake/pull/7349): 改进 C++ 模块的 clang/gcc embed-dir 处理
* [#7368](https://github.com/xmake-io/xmake/pull/7368): 迁移模板到仓库
* [#7383](https://github.com/xmake-io/xmake/pull/7383): 拆分 zig 工具链为 zig/zigcc
* [#7384](https://github.com/xmake-io/xmake/pull/7384): 改进 find_hdk
* [#7387](https://github.com/xmake-io/xmake/pull/7387): 在进度中显示目标名称
* [#7391](https://github.com/xmake-io/xmake/pull/7391): 改进通过 vcpkg features 查找包
* [#7392](https://github.com/xmake-io/xmake/pull/7392): 修复 zig 共享库
* [#7396](https://github.com/xmake-io/xmake/pull/7396): 改进 vcpkg
* [#7399](https://github.com/xmake-io/xmake/pull/7399): 扩展格式化到 C++ 模块
* [#7409](https://github.com/xmake-io/xmake/pull/7409): 改进 Windows 上的 ldc
### Bugs 修复
* [#7299](https://github.com/xmake-io/xmake/pull/7299): 修复 vcpkg 依赖处理
* [#7316](https://github.com/xmake-io/xmake/pull/7316): 修复 components 拼写错误
* [#7318](https://github.com/xmake-io/xmake/pull/7318): 更新 tbox 修复 tolower/toupper
* [#7339](https://github.com/xmake-io/xmake/pull/7339): 更新 tbox 修复 win7 启动进程问题
* [#7344](https://github.com/xmake-io/xmake/pull/7344): 修复 swig jar 包模块
* [#7345](https://github.com/xmake-io/xmake/pull/7345): 修复检测 clang 信息
* [#7341](https://github.com/xmake-io/xmake/pull/7341): 修复 WASM QT 6.9
* [#7356](https://github.com/xmake-io/xmake/pull/7356): 修复 issue #7354
* [#7371](https://github.com/xmake-io/xmake/pull/7371): 修复测试详细输出
* [#7386](https://github.com/xmake-io/xmake/pull/7386): 修复安装脚本与 coreutils 9.10 的不兼容
* [#7393](https://github.com/xmake-io/xmake/pull/7393): 修复构建目标验证
## v3.0.7
### 新特性
* [#7178](https://github.com/xmake-io/xmake/pull/7178): 改进 Verilator 构建文件解析,从 cmake 格式切换到 json 格式
* [#7186](https://github.com/xmake-io/xmake/pull/7186): 添加 Alpine CI 支持
* [#7187](https://github.com/xmake-io/xmake/pull/7187): 为 CUDA 架构添加后缀支持
* [#7190](https://github.com/xmake-io/xmake/pull/7190): Nix 包管理器:添加语义化版本控制并改进版本选择
* [#7189](https://github.com/xmake-io/xmake/pull/7189): 添加包方案(package schemes)支持
* [#7208](https://github.com/xmake-io/xmake/pull/7208): 支持 Qt SDK 动态 mkspec 选择
* [#7219](https://github.com/xmake-io/xmake/pull/7219): 添加 cli.iconv 模块
* [#7235](https://github.com/xmake-io/xmake/pull/7235): 添加字符串大小写转换函数:lower 和 upper
* [#7246](https://github.com/xmake-io/xmake/pull/7246): 添加 utf8 模块
* [#7268](https://github.com/xmake-io/xmake/pull/7268): 为 Nim 源文件添加依赖文件生成
* [#7269](https://github.com/xmake-io/xmake/pull/7269): 为 zig 工具链添加交叉编译的目标架构验证
* [#7274](https://github.com/xmake-io/xmake/pull/7274): 添加 os.access 函数用于文件访问检查
* [#7284](https://github.com/xmake-io/xmake/pull/7284): 添加 `--stdin` 支持
* [#7293](https://github.com/xmake-io/xmake/pull/7293): 添加在浏览器中运行 wasm 目标的支持
* [#7300](https://github.com/xmake-io/xmake/pull/7300): 为安装/卸载添加 libdir、includedir、bindir 支持
* [#7295](https://github.com/xmake-io/xmake/pull/7295): 支持测试输出文件
### 改进
* [#7203](https://github.com/xmake-io/xmake/pull/7203): 改进 MinGW 工具链
* [#7206](https://github.com/xmake-io/xmake/pull/7206): WDK:为 KMDF 包含路径添加共享目录
* [#7214](https://github.com/xmake-io/xmake/pull/7214): 改进警告输出
* [#7216](https://github.com/xmake-io/xmake/pull/7216): 改进依赖锁定(requirelock)
* [#7223](https://github.com/xmake-io/xmake/pull/7223): 改进 NuGet 库文件匹配,采用基于分数的选择机制
* [#7226](https://github.com/xmake-io/xmake/pull/7226): 改进 clang-tidy 查找
* [#7232](https://github.com/xmake-io/xmake/pull/7232): 改进链接器脚本配置
* [#7237](https://github.com/xmake-io/xmake/pull/7237): 更新 tbox 库以支持大小写敏感
* [#7240](https://github.com/xmake-io/xmake/pull/7240): 改进 Verilator 标志处理
* [#7258](https://github.com/xmake-io/xmake/pull/7258): 改进 Qt xpack 打包
* [#7262](https://github.com/xmake-io/xmake/pull/7262): 改进预编译头文件(PCH)与其他目标的并发处理
* [#7260](https://github.com/xmake-io/xmake/pull/7260): 改进 Free Pascal 编译器支持
* [#7270](https://github.com/xmake-io/xmake/pull/7270): 改进方案版本选择机制
* [#7272](https://github.com/xmake-io/xmake/pull/7272): 增强 Nim 对共享库和 rpath 处理的支持
* [#7273](https://github.com/xmake-io/xmake/pull/7273): 改进 io.read 和 io.readfile 函数
* [#7267](https://github.com/xmake-io/xmake/pull/7267): 通过检查父进程增强 Linux 的 shell 检测
* [#7278](https://github.com/xmake-io/xmake/pull/7278): 改进 os.isexec 函数
* [#7283](https://github.com/xmake-io/xmake/pull/7283): 增强 compile_commands 支持并添加测试用例
* [#7285](https://github.com/xmake-io/xmake/pull/7285): 改进 Windows 的 cmd/powershell shell 检测
* [#7286](https://github.com/xmake-io/xmake/pull/7286): 检测 VS 时检查长环境变量值
* [#7280](https://github.com/xmake-io/xmake/pull/7280): 仅在交叉编译时添加目标标志
* [#7290](https://github.com/xmake-io/xmake/pull/7290): 改进 vcvars 处理
* [#7302](https://github.com/xmake-io/xmake/pull/7302): 改进运行进程错误处理
* [#7306](https://github.com/xmake-io/xmake/pull/7306): 改进远程构建,支持多主机配置和 `--host` 选项
* [#7298](https://github.com/xmake-io/xmake/pull/7298): 为 Windows DLL 的 foo/main 示例添加初始实现
### Bugs 修复
* [#7210](https://github.com/xmake-io/xmake/pull/7210): 修复包版本问题
* [#7213](https://github.com/xmake-io/xmake/pull/7213): 修复导入文件的安装目录问题
* [#7231](https://github.com/xmake-io/xmake/pull/7231): 修复模块支持中的标志获取问题
* [#7245](https://github.com/xmake-io/xmake/pull/7245): 修复方案版本选择问题
* [#7259](https://github.com/xmake-io/xmake/pull/7259): 修复 C++ 函数符号导出问题
* [#7266](https://github.com/xmake-io/xmake/pull/7266): 修复预编译头文件扩展名问题
* [#7282](https://github.com/xmake-io/xmake/pull/7282): find_cuda:回滚破坏性变更
* [#7294](https://github.com/xmake-io/xmake/pull/7294): 修复包工具链问题
* [#7296](https://github.com/xmake-io/xmake/pull/7296): 修复 emsdk 查找问题
* [#7202](https://github.com/xmake-io/xmake/pull/7202): 修复 getfenv 函数
## v3.0.6
### 新特性
* [#7141](https://github.com/xmake-io/xmake/pull/7141): 支持禁用 Android 原生应用 glue
* [#7139](https://github.com/xmake-io/xmake/pull/7139): 添加 Android 原生应用构建支持
* [#7127](https://github.com/xmake-io/xmake/pull/7127): 为 binutils 添加 deplibs 支持
* [#7120](https://github.com/xmake-io/xmake/pull/7120): 为 binutils 添加 extractlib 支持
* [#7106](https://github.com/xmake-io/xmake/pull/7106): 为 MSVC 添加 `/std:c++23preview` 支持
* [#7105](https://github.com/xmake-io/xmake/pull/7105): 为 glsl/hlsl2spv 添加 `bin2obj` 支持
* [#7103](https://github.com/xmake-io/xmake/pull/7103): 添加 `bin2obj` 规则(比 `bin2c` 更快)
* [#7096](https://github.com/xmake-io/xmake/pull/7096): 添加 Flang 工具链支持
* [#7094](https://github.com/xmake-io/xmake/pull/7094): 添加 `xmake check syntax` 支持
* [#7091](https://github.com/xmake-io/xmake/pull/7091): 为 MSVC 添加动态调试支持
* [#7083](https://github.com/xmake-io/xmake/pull/7083): 添加对 CUDA 11~13 的支持
* [#7071](https://github.com/xmake-io/xmake/pull/7071): 添加 Qt 打包支持
* [#7064](https://github.com/xmake-io/xmake/pull/7064): 添加 AppImage xpack 格式用于 Linux 应用程序打包
* [#7062](https://github.com/xmake-io/xmake/pull/7062): 添加 dmg xpack 格式用于 macOS 应用程序打包
### 改进
* [#7149](https://github.com/xmake-io/xmake/pull/7149): 改进 binutils 优化 rpath 解析
* [#7148](https://github.com/xmake-io/xmake/pull/7148): 更新 Zig 示例
* [#7145](https://github.com/xmake-io/xmake/pull/7145): 改进 Clang/LLVM 运行时支持
* [#7136](https://github.com/xmake-io/xmake/pull/7136): 改进 clang-cl 依赖文件生成
* [#7135](https://github.com/xmake-io/xmake/pull/7135): 改进 `xrepo env` 以添加会话 ID
* [#7155](https://github.com/xmake-io/xmake/pull/7155): 重构 Windows 上 clang-cl 的 ASan 支持(改进运行库链接、链接器标志、完善 PATH/CMAKE_LINKER_TYPE 配置、精简工具链)
* [#7109](https://github.com/xmake-io/xmake/pull/7109): 改进 binutils 以从二进制文件读取符号
* [#7102](https://github.com/xmake-io/xmake/pull/7102): 改进 bin2c 规则
* [#7098](https://github.com/xmake-io/xmake/pull/7098): 重构并改进 Golang 支持
* [#7095](https://github.com/xmake-io/xmake/pull/7095): 将 target/package/toolchain:memcache 标记为公开
* [#7093](https://github.com/xmake-io/xmake/pull/7093): 改进镜像仓库 URL
* [#7088](https://github.com/xmake-io/xmake/pull/7088): 改进 C++/ObjC 规则
* [#7087](https://github.com/xmake-io/xmake/pull/7087): 为策略 `package.download.http_headers` 添加类型约束
* [#7069](https://github.com/xmake-io/xmake/pull/7069): 为 LLVM 工具链保存 Qt 规则
* [#7061](https://github.com/xmake-io/xmake/pull/7061): 更新 CI 配置
* [#7039](https://github.com/xmake-io/xmake/pull/7039): 更新 macOS CI
### Bugs 修复
* [#7132](https://github.com/xmake-io/xmake/pull/7132): 修复带有 ASan 的 clang-cl 工具链
* [#7125](https://github.com/xmake-io/xmake/pull/7125): 修复 cosmocc CI
* [#7124](https://github.com/xmake-io/xmake/pull/7124): 修复 Clang 工具链的默认 MSVC 运行时
* [#7112](https://github.com/xmake-io/xmake/pull/7112): 修复 Windows 上的目录切换
* [#7104](https://github.com/xmake-io/xmake/pull/7104): 修复项目生成器的准备工作
* [#7092](https://github.com/xmake-io/xmake/pull/7092): 修复 Solaris 构建
* [#7086](https://github.com/xmake-io/xmake/pull/7086): 修复 Qt QML 规则中的 targetdir
* [#7085](https://github.com/xmake-io/xmake/pull/7085): 修复 Clang 工具链的 CMake 标志
* [#7084](https://github.com/xmake-io/xmake/pull/7084): 修复 pacman find_package
* [#7082](https://github.com/xmake-io/xmake/pull/7082): 修复 Clang CUDA 标志检查
* [#7081](https://github.com/xmake-io/xmake/pull/7081): 修复 `get_headerunit_key`
* [#7074](https://github.com/xmake-io/xmake/pull/7074): 修复 libc++ 找不到 std 模块
* [#7067](https://github.com/xmake-io/xmake/pull/7067): 修复交叉编译工具链的 get_stdmodules
## v3.0.5
### 新特性
* [#7055](https://github.com/xmake-io/xmake/pull/7055): 添加 Solaris 平台支持 (i386, x86_64)
* [#7054](https://github.com/xmake-io/xmake/pull/7054): 添加更多 BSD 系统支持 (NetBSD, OpenBSD, DragonflyBSD)
* [#6929](https://github.com/xmake-io/xmake/pull/6929): 添加 GCC 15 工具链支持
* [#6967](https://github.com/xmake-io/xmake/pull/6967): 为 C++ 和 Objective-C 添加 Swift 互操作支持
* [#6964](https://github.com/xmake-io/xmake/pull/6964): 支持通过 cuda_sdkver 参数指定 CUDA SDK 版本
* [#6963](https://github.com/xmake-io/xmake/pull/6963): 为交叉编译添加 libtool 补丁支持
* [#6974](https://github.com/xmake-io/xmake/pull/6974): 支持多行刷新进度输出显示
* [#7024](https://github.com/xmake-io/xmake/pull/7024): 为 `xmake show -t target` 命令添加 JSON 格式输出
* [#7025](https://github.com/xmake-io/xmake/pull/7025): 添加 XML 模块,支持解析和编码功能
* [#6989](https://github.com/xmake-io/xmake/pull/6989): 为 os API 添加异步操作支持
### 改进
* [#6924](https://github.com/xmake-io/xmake/pull/6924): 改进工具链配置,支持 add_toolchains("name[configs]") 语法
* [#6935](https://github.com/xmake-io/xmake/pull/6935): 重构工具链:将 gcc/clang 的注册与定义分离
* [#6942](https://github.com/xmake-io/xmake/pull/6942): 改进文件读取性能
* [#6946](https://github.com/xmake-io/xmake/pull/6946): 为 Clang 工具链添加 LLD 链接器支持
* [#6970](https://github.com/xmake-io/xmake/pull/6970): 改进 TTY 处理和输出显示
* [#6977](https://github.com/xmake-io/xmake/pull/6977): 重构 Xcode 工具链,并将其集成到针对 Apple 设备的 LLVM 工具链中
* [#6987](https://github.com/xmake-io/xmake/pull/6987): 添加 Ghostty 终端检测支持
* [#7003](https://github.com/xmake-io/xmake/pull/7003): 限制在包配置中获取构建环境变量
* [#7008](https://github.com/xmake-io/xmake/pull/7008): 统一代码格式风格
* [#7004](https://github.com/xmake-io/xmake/pull/7004): 使用 -r 标志时跳过重建包和 std 模块
* [#7019](https://github.com/xmake-io/xmake/pull/7019): 改进 xmake.sh/configure 脚本并添加 Ninja 生成器支持
* [#7023](https://github.com/xmake-io/xmake/pull/7023): 更新 Qt TypeScript 规则
* [#7022](https://github.com/xmake-io/xmake/pull/7022): 使 zig-cc 工具链继承自 clang
* [#7027](https://github.com/xmake-io/xmake/pull/7027): 改进 graph 模块性能
* [#7031](https://github.com/xmake-io/xmake/pull/7031): 改进 require 解析功能
* [#7032](https://github.com/xmake-io/xmake/pull/7032): 改进符号提取功能
* [#6952](https://github.com/xmake-io/xmake/pull/6952): 为测试添加实时输出支持
* [#6998](https://github.com/xmake-io/xmake/pull/6998): 更新 tbox 库以支持 process/argv
* [#7037](https://github.com/xmake-io/xmake/pull/7037): 改进 xmake format 功能
* [#7038](https://github.com/xmake-io/xmake/pull/7038): 改进 clang-tidy 输出处理
### Bugs 修复
* [#6926](https://github.com/xmake-io/xmake/pull/6926): 修复在 Windows 上加载包含 Unicode 字符的主脚本路径问题
* [#6931](https://github.com/xmake-io/xmake/pull/6931): 修复 C++ 模块:当工具链的 clang-scan-deps 未安装时,自动回退到系统级的 clang-scan-deps
* [#6937](https://github.com/xmake-io/xmake/pull/6937): 修复目标任务处理问题
* [#6954](https://github.com/xmake-io/xmake/pull/6954): 修复 vsxmake/vs 生成器的模块支持问题
* [#6955](https://github.com/xmake-io/xmake/pull/6955): 修复包中构建号的排序问题
* [#6956](https://github.com/xmake-io/xmake/pull/6956): 修复使用不支持 depfile 的 zigcc 链接器导致的构建失败
* [#6959](https://github.com/xmake-io/xmake/pull/6959): 修复在动态链接场景下使用 zigcc 与 autotools 的问题
* [#6983](https://github.com/xmake-io/xmake/pull/6983): 修复模块:为模块重用场景去除 sanitizer 标志
* [#6984](https://github.com/xmake-io/xmake/pull/6984): 修复已安装的 CMake 导入文件中的 libdir 路径问题
* [#6993](https://github.com/xmake-io/xmake/pull/6993): 修复 xmake 测试模块相关问题
* [#6992](https://github.com/xmake-io/xmake/pull/6992): 修复模块:为 clang get_cpp_library_name 添加所有支持的平台
* [#6999](https://github.com/xmake-io/xmake/pull/6999): 修复 rootdir 处理问题
* [#7002](https://github.com/xmake-io/xmake/pull/7002): 修复 asn1c:将生成的输出文件作为系统头文件包含
* [#6996](https://github.com/xmake-io/xmake/pull/6996): 修复 Nimble find_package 以使用最新的包列表格式
* [#7012](https://github.com/xmake-io/xmake/pull/7012): 修复稀疏检出处理问题
* [#7013](https://github.com/xmake-io/xmake/pull/7013): 修复打包时移除依赖项的问题
* [#7017](https://github.com/xmake-io/xmake/pull/7017): 修复 lock_packages 的拼写错误
* [#7016](https://github.com/xmake-io/xmake/pull/7016): 修复 vsxmake 中的项目默认配置问题
* [#7018](https://github.com/xmake-io/xmake/pull/7018): 修复构建顺序:仅在禁用依赖链接继承时才禁用构建顺序
* [#7035](https://github.com/xmake-io/xmake/pull/7035): 通过更新 tbox 修复进程重定向问题
## v3.0.4
### 新特性
* [#6864](https://github.com/xmake-io/xmake/pull/6864): 为 `format` 任务添加默认文件过滤器
* [#6843](https://github.com/xmake-io/xmake/pull/6843): 改进 clang-tidy 支持
* [#6861](https://github.com/xmake-io/xmake/pull/6861): 重写 Nix 包管理器支持
* [#6850](https://github.com/xmake-io/xmake/pull/6850): 添加包 API 检查
* [#6874](https://github.com/xmake-io/xmake/pull/6874): 为项目包添加 scriptdir
* [#6876](https://github.com/xmake-io/xmake/pull/6876): 添加 versionfiles 检查器
* [#6884](https://github.com/xmake-io/xmake/pull/6884): 在 msys2 上添加 msystem 支持
* [#6891](https://github.com/xmake-io/xmake/pull/6891): 添加协程信号量
* [#6894](https://github.com/xmake-io/xmake/pull/6894): 为 clang 工具链添加 llvm-nm
* [#6918](https://github.com/xmake-io/xmake/pull/6918): 为 os.cp 添加 copy_if_different 支持
### 改进
* [#6846](https://github.com/xmake-io/xmake/pull/6846): 改进 cmake 默认标志
* [#6849](https://github.com/xmake-io/xmake/pull/6849): 改进 jobgraph
* [#6859](https://github.com/xmake-io/xmake/pull/6859): 改进检查目标标志
* [#6858](https://github.com/xmake-io/xmake/pull/6858): 修改配置标志顺序
* [#6854](https://github.com/xmake-io/xmake/pull/6854): 改进 os.curdir/os.cd
* [#6866](https://github.com/xmake-io/xmake/pull/6866): 改进 os.getenvs
* [#6867](https://github.com/xmake-io/xmake/pull/6867): 确保通用选项总是被插入
* [#6870](https://github.com/xmake-io/xmake/pull/6870): chore(vcpkg): 提升 vcpkg 的默认 baseline
* [#6880](https://github.com/xmake-io/xmake/pull/6880): 更新 cmake_importfiles.lua
* [#6872](https://github.com/xmake-io/xmake/pull/6872): 改进哈希
* [#6886](https://github.com/xmake-io/xmake/pull/6886): 减少 jobgraph 中的任务数
* [#6890](https://github.com/xmake-io/xmake/pull/6890): 更新 cmake_importfiles.lua
* [#6892](https://github.com/xmake-io/xmake/pull/6892): 改进 runjobs 以减少协程调度所花费的时间
* [#6896](https://github.com/xmake-io/xmake/pull/6896): 添加哈希测试
* [#6904](https://github.com/xmake-io/xmake/pull/6904): 改进 clang 以支持 msvc 环境
* [#6915](https://github.com/xmake-io/xmake/pull/6915): 改进为二进制文件导出 def 规则
### Bugs 修复
* [#6844](https://github.com/xmake-io/xmake/pull/6844): 修复自动生成的 .pc 文件中的版本
* [#6851](https://github.com/xmake-io/xmake/pull/6851): 修复查找 clang-scan-deps
* [#6857](https://github.com/xmake-io/xmake/pull/6857): 修复在交叉编译中使用 cmake 的 rc 编译器
* [#6809](https://github.com/xmake-io/xmake/pull/6809): fix(C++ modules) 修复 stdmodule 优先级
* [#6882](https://github.com/xmake-io/xmake/pull/6882): 修复:以确定性顺序写入包清单 manifest.pathenvs
* [#6888](https://github.com/xmake-io/xmake/pull/6888): 修复 clang 工具链包
* [#6889](https://github.com/xmake-io/xmake/pull/6889): 修复 os.getenvs 兼容性
* [#6900](https://github.com/xmake-io/xmake/pull/6900): package.tools.xmake: 修复策略未被传递的问题
* [#6901](https://github.com/xmake-io/xmake/pull/6901): package download: 如果禁用,则不获取子模块
* [#6907](https://github.com/xmake-io/xmake/pull/6907): package download: 如果禁用,则不获取子模块 (分支版本)
## v3.0.3
### 新特性
* [#6778](https://github.com/xmake-io/xmake/pull/6778): 添加 build.linker.output
* [#6779](https://github.com/xmake-io/xmake/pull/6779): 添加 #embed 和 embedirs 支持
* [#6787](https://github.com/xmake-io/xmake/pull/6787): 支持 vs2026
* [#6785](https://github.com/xmake-io/xmake/pull/6785): 为 wdk 规则支持 clang 和 llvm
* [#6791](https://github.com/xmake-io/xmake/pull/6791): 添加 Nix 包管理器支持
* [#6800](https://github.com/xmake-io/xmake/pull/6800): 为 xrepo env 支持 nushell
* [#6796](https://github.com/xmake-io/xmake/pull/6796): 启用不完整 wdk 的支持
### 改进
* [#6765](https://github.com/xmake-io/xmake/pull/6765): 改进 bin2c 使用原生线程
* [#6771](https://github.com/xmake-io/xmake/pull/6771): 修复 find gcc/gxx 缓存
* [#6777](https://github.com/xmake-io/xmake/pull/6777): 修复 cmake 的可执行文件路径
* [#6783](https://github.com/xmake-io/xmake/pull/6783): 修复 build.c++.modules.std 策略
* [#6744](https://github.com/xmake-io/xmake/pull/6744): 当提供 --verbose 或 --diagnosis 时使用文件来存储 requires 标志
* [#6780](https://github.com/xmake-io/xmake/pull/6780): 添加基准测试并优化配置/构建目标
* [#6784](https://github.com/xmake-io/xmake/pull/6784): 继续优化构建目标速度
* [#6793](https://github.com/xmake-io/xmake/pull/6793): 使用 musl 避免 glibc 版本问题
* [#6788](https://github.com/xmake-io/xmake/pull/6788): 改进 clang 增量构建
* [#6811](https://github.com/xmake-io/xmake/pull/6811): 改进 clang-tidy
* [#6810](https://github.com/xmake-io/xmake/pull/6810): 改进 cmake 的默认标志
* [#6801](https://github.com/xmake-io/xmake/pull/6801): 更改 gcc 和 clang 的编译器优先级
* [#6819](https://github.com/xmake-io/xmake/pull/6819): 改进 show target
* [#6817](https://github.com/xmake-io/xmake/pull/6817): 改进构建速度
* [#6822](https://github.com/xmake-io/xmake/pull/6822): 优先使用环境变量而不是仓库缓存
* [#6824](https://github.com/xmake-io/xmake/pull/6824): 改进 has_flags
* [#6832](https://github.com/xmake-io/xmake/pull/6832): 优化代码签名
### Bugs 修复
* [#6808](https://github.com/xmake-io/xmake/pull/6808): 修复 xrepo env
* [#6821](https://github.com/xmake-io/xmake/pull/6821): 清理未定义的 vsvers
* [#6818](https://github.com/xmake-io/xmake/pull/6818): 修复 nix-shell 环境中的 Nix 包检测
* [#6798](https://github.com/xmake-io/xmake/pull/6798): 为 msvc 的 strippeable_flags 添加 external
## v3.0.2
### 新特性
* [#6755](https://github.com/xmake-io/xmake/issues/6755): 添加原生线程支持
* [#6641](https://github.com/xmake-io/xmake/pull/6641): 为 `target/config` 添加 `pkgenvs`
* [#6644](https://github.com/xmake-io/xmake/pull/6644): 支持使用 clang 编译 .def 文件
* [#6695](https://github.com/xmake-io/xmake/pull/6695): 为 inf2cat 添加 `/uselocaltime` 参数
* [#6709](https://github.com/xmake-io/xmake/pull/6709): 支持 wasm64 架构
* [#6737](https://github.com/xmake-io/xmake/pull/6737): 为 cython 规则添加 python 存根文件扩展
### 改进
* [#6651](https://github.com/xmake-io/xmake/pull/6651): 改进依赖文件
* [#6656](https://github.com/xmake-io/xmake/pull/6656): 使构建工具支持传入 `opt.targets`
* [#6688](https://github.com/xmake-io/xmake/pull/6688): 改进安装目标
* [#6692](https://github.com/xmake-io/xmake/pull/6692): 改进 protobuf 测试
* [#6714](https://github.com/xmake-io/xmake/pull/6714): 改进 C++ 模块测试
* [#6719](https://github.com/xmake-io/xmake/pull/6719): 改进 comax 配置
* [#6725](https://github.com/xmake-io/xmake/pull/6725): 改进 `target:extrafiles`
### Bugs 修复
* [#6648](https://github.com/xmake-io/xmake/pull/6648): 修复(qt.qmltyperegistrar): 收集 metatypes 信息
* [#6661](https://github.com/xmake-io/xmake/pull/6661): 通过设置 "--tries=1" 修复 `_ping_via_wget` 长时间阻塞的问题
* [#6665](https://github.com/xmake-io/xmake/pull/6665): 修复 cmake/mingw
* [#6674](https://github.com/xmake-io/xmake/pull/6674): 尝试修复包中的 linkgroups
* [#6686](https://github.com/xmake-io/xmake/pull/6686): 修复编译器缓存
* [#6698](https://github.com/xmake-io/xmake/pull/6698): 修复(C++ 模块) 处理空模块
* [#6699](https://github.com/xmake-io/xmake/pull/6699): 修复(C++ 模块) 修复删除模块文件时 xmake 不更新模块映射器的问题
* [#6706](https://github.com/xmake-io/xmake/pull/6706): 修复 CUDA 13 的 `find_cudadevices`
* [#6707](https://github.com/xmake-io/xmake/pull/6707): 修复(C++ 模块) 修复 sourcebatch 缓存
* [#6712](https://github.com/xmake-io/xmake/pull/6712): 修复(C++ 模块) 修复禁用的目标被配置用于模块编译的问题
* [#6713](https://github.com/xmake-io/xmake/pull/6713): 修复(C++ 模块) 修复非 .cpp 文件从 `c++.build` sourcebatch 中被窃取的问题
* [#6715](https://github.com/xmake-io/xmake/pull/6715): 修复(C++ 模块) 修复公共剔除模块错误地发出警告的问题
* [#6718](https://github.com/xmake-io/xmake/pull/6718): 忽略 pch 标志
* [#6732](https://github.com/xmake-io/xmake/pull/6732): 修复: android ndk rust link-args
* [#6735](https://github.com/xmake-io/xmake/pull/6735): 修复(qt.qmltyperegistrar): 扩展依赖项以进行重建
* [#6738](https://github.com/xmake-io/xmake/pull/6738): 修复 protobuf 的目标依赖
* [#6741](https://github.com/xmake-io/xmake/pull/6741): 修复 vsxmake 选项
* [#6747](https://github.com/xmake-io/xmake/pull/6747): `meminfo.c`: < 10.7 版本上没有 `vmstat.compressor_page_count`
## v3.0.1
### 新特性
* [#4810](https://github.com/xmake-io/xmake/issues/4810): 添加新的原生 Xcode 工程生成插件
### Bugs 修复
* [#6592](https://github.com/xmake-io/xmake/pull/6592): 修复 object 目标的链接问题
* [#6586](https://github.com/xmake-io/xmake/issues/6586): 修复 build.fence 策略
* [#6600](https://github.com/xmake-io/xmake/issues/6600): 修复 compile_commands 生成器
* [#6621](https://github.com/xmake-io/xmake/issues/6621): 修复 android ndk r17c 构建失败问题
* [#6635](https://github.com/xmake-io/xmake/discussions/6635): 修复 batchcmds 导致的 qt/moc 增量构建问题
## v3.0.0
### 新特性
* [#5926](https://github.com/xmake-io/xmake/issues/5926): 添加 MIDL 支持
* [#6414](https://github.com/xmake-io/xmake/pull/6414): 添加 platform.windows.subsystem 规则
* [#5527](https://github.com/xmake-io/xmake/issues/5527): 切换到 3.0 行为策略
### 改进
* [#6202](https://github.com/xmake-io/xmake/issues/6202): 改进 rule API 和构建顺序支持,提供统一 jobgraph 调度
* [#5624](https://github.com/xmake-io/xmake/discussions/5624): `xmake run` 运行默认自动构建
* [#5526](https://github.com/xmake-io/xmake/discussions/5526): msvc 默认切换到 MD/MDd 运行时
* [#5545](https://github.com/xmake-io/xmake/discussions/5545): 构建 cmake 包,默认使用 Ninja 生成器
* [#6355](https://github.com/xmake-io/xmake/pull/6355): 支持自定义 implib 路径和访问
* [#6373](https://github.com/xmake-io/xmake/pull/6373): 改进 c++ modules 支持
* [#6376](https://github.com/xmake-io/xmake/issues/6476): 改进 vsxmake 生成器,支持命名空间
* [#6209](https://github.com/xmake-io/xmake/pull/6209): 添加 jobgraph 支持
* [#6361](https://github.com/xmake-io/xmake/pull/6361): 重命名 buildir 到 builddir
## v2.9.9
### 新特性
* [#6137](https://github.com/xmake-io/xmake/issues/6137): IDE 整合
* [#6138](https://github.com/xmake-io/xmake/issues/6138): 使用 libxmake/xmake APIs 去构建二进制
* [#6154](https://github.com/xmake-io/xmake/issues/6154): 添加 kotlin native 构建支持和包依赖集成支持
* [#6279](https://github.com/xmake-io/xmake/pull/6279): 添加 msvc midl 支持
### 改进
* [#6182](https://github.com/xmake-io/xmake/pull/6182): 改进 clang/clang-cl 支持 msstl 模块
* [#6281](https://github.com/xmake-io/xmake/pull/6281): 支持 Verilator 动态库
* [#6270](https://github.com/xmake-io/xmake/pull/6270): 改进 conan 生成器
* [#6243](https://github.com/xmake-io/xmake/pull/6243): 改进 llvm 工具链对交叉编译的支持
* 三方包安装支持 CMake 4.0
### Bugs 修复
* [#6292](https://github.com/xmake-io/xmake/issues/6292): 修复 namespace 问题
## v2.9.8
### 新特性
* [#5994](https://github.com/xmake-io/xmake/issues/5994): 分析进程执行性能
* [#5995](https://github.com/xmake-io/xmake/pull/5995): 为 vs generator 添加 profile 支持
* [#5949](https://github.com/xmake-io/xmake/pull/5949): 添加 nodejs.module 规则
* [#3380](https://github.com/xmake-io/xmake/issues/3380): 添加命名空间支持
* [#5945](https://github.com/xmake-io/xmake/issues/5945): 检测 pkgconfig/cmake 导入文件
* [#6054](https://github.com/xmake-io/xmake/issues/6054): 为 linux 添加 xmake bundle 包
* [#6071](https://github.com/xmake-io/xmake/issues/6071): 改进 git 包下载,支持仅仅 clone 指定子目录
* [#5163](https://github.com/xmake-io/xmake/issues/5163): 支持 TI-CGT C2000/C6000 编译器
* [#5344](https://github.com/xmake-io/xmake/issues/5344): 支持 IAR ARM C/C++ 编译器
* [#5554](https://github.com/xmake-io/xmake/issues/5554): 添加自定义未知工具链支持
### 改进
* [#6056](https://github.com/xmake-io/xmake/pull/6056): 添加 CI 去构建发布 windows arm64 版本。
* [#6097](https://github.com/xmake-io/xmake/pull/6097): 添加 qt_host 支持交叉编译 Qt 项目
* [#6120](https://github.com/xmake-io/xmake/issues/6120): 改进 configfiles 添加自定义预处理支持
* [#6088](https://github.com/xmake-io/xmake/issues/6088): 改进 configfiles 去生成导出宏
### Bugs 修复
* [#272](https://github.com/tboox/tbox/issues/272): 修复 msvc + /O1 时候,错误的编译器优化导致 xmake 加载卡住
* [#6089](https://github.com/tboox/tbox/issues/6089): 修复 depend.is_changed
## v2.9.7
### 新特性
* [#5813](https://github.com/xmake-io/xmake/pull/5813): 为 rule 添加 `before_config` 和 `after_config`
* [#5848](https://github.com/xmake-io/xmake/issues/5848): 支持自定义 MSVC 构建工具, PortableBuildTools 和 msvc-wine
* [#5880](https://github.com/xmake-io/xmake/pull/5880): 支持使用 msvc 包去构建工程
* [#5884](https://github.com/xmake-io/xmake/issues/5884): 为包添加自定义安装提示
* [#5894](https://github.com/xmake-io/xmake/issues/5894): 添加 package.merge_staticlibs 策略去合并包安装的静态库
* [#5948](https://github.com/xmake-io/xmake/pull/5948): 添加 `lua.native-object` 规则
* [#5911](https://github.com/xmake-io/xmake/issues/5911): 支持 nuget 包集成
### 改进
* [#5817](https://github.com/xmake-io/xmake/pull/5817): 改进安装包的默认 pic 配置
* [#5869](https://github.com/xmake-io/xmake/pull/5869): 为 gcc 添加 libstdc++ 标准库模块的支持
* [#5923](https://github.com/xmake-io/xmake/pull/5923): 解决包依赖链中版本和配置冲突
### Bugs 修复
* [#5856](https://github.com/xmake-io/xmake/issues/5856): 修复 c++modules 在 clang 下的编译
* [#5858](https://github.com/xmake-io/xmake/issues/5858): 修复 gcc 的头文件预编译问题
## v2.9.6
### 新特性
* [#5527](https://github.com/xmake-io/xmake/issues/5527): 添加 `set_policy("compatibility.version", "3.0")` 提前预览体验 3.0 特性
* [#5649](https://github.com/xmake-io/xmake/pull/5649): 添加 `package.check_fcsnippets`
### 改进
* [#5631](https://github.com/xmake-io/xmake/pull/5631): 为 `add_linkgroups` 添加 `as_needed`
* [#5702](https://github.com/xmake-io/xmake/issues/5702): 改进 hash 模块
* [#5688](https://github.com/xmake-io/xmake/pull/5688): 改进 hashset
* [#5711](https://github.com/xmake-io/xmake/issues/5711): 为 sdcc 支持解析 include 依赖
* [#5727](https://github.com/xmake-io/xmake/issues/5727): 为 add_requires 改进 configs 配置
* [#5762](https://github.com/xmake-io/xmake/pull/5762): 改进 bin2c 速度
### Bugs 修复
* [#5645](https://github.com/xmake-io/xmake/issues/5645): 修复 `xmake watch` 在 linux 无法监听递归文件问题
* [#5686](https://github.com/xmake-io/xmake/pull/5686): 修复模块扫描
## v2.9.5
### 新特性
* [#5462](https://github.com/xmake-io/xmake/pull/5462): 添加 `xmake l cli.bisect`
* [#5488](https://github.com/xmake-io/xmake/pull/5488): 支持使用 cosmocc 去构建 xmake 自身二进制
* [#5491](https://github.com/xmake-io/xmake/pull/5491): 支持提供内嵌 lua 文件的单个 xmake 二进制文件
* [#5580](https://github.com/xmake-io/xmake/issues/5580): 添加 `@builtin/xrepo` 辅助模块,为 `xrepo env shell` 实现快速设置环境变量
### 改进
* [#5507](https://github.com/xmake-io/xmake/issues/5507): 改进 git clone 下载速度
* [#5536](https://github.com/xmake-io/xmake/pull/5536): 在 swig 模式中添加 jar 生成支持
* [#5573](https://github.com/xmake-io/xmake/issues/5573): 改进 vsxmake generator 性能
* [#5601](https://github.com/xmake-io/xmake/issues/5601): 改进 utils.symbols.export_all 规则去过滤源文件路径
### Bugs 修复
* [#4750](https://github.com/xmake-io/xmake/issues/4750): 修复 compile_commands 生成器,支持 `xmake tests`
* [#5465](https://github.com/xmake-io/xmake/pull/5465): 修复 package requires lock
* [#4760](https://github.com/xmake-io/xmake/issues/4760): 修复 distcc 分布式编译问题
## v2.9.4
### 新特性
* [#5278](https://github.com/xmake-io/xmake/issues/5278): 添加 `build.intermediate_directory` 策略去禁用中间目录生成
* [#5313](https://github.com/xmake-io/xmake/issues/5313): 添加 windows arm/arm64ec 支持
* [#5296](https://github.com/xmake-io/xmake/issues/5296): 添加 Intel LLVM Fortran 编译器支持
* [#5384](https://github.com/xmake-io/xmake/issues/5384): 为包添加 `add_bindirs` 配置支持
### 改进
* [#5280](https://github.com/xmake-io/xmake/issues/5280): 添加缺失的 C++20 Modules 文件扩展
* [#5251](https://github.com/xmake-io/xmake/issues/5251): 为 windows installer 更新内置的 7z/curl
* [#5286](https://github.com/xmake-io/xmake/issues/5286): 改进 json 支持16进制解析
* [#5302](https://github.com/xmake-io/xmake/pull/5302): 改进 Vala 支持
* [#5335](https://github.com/xmake-io/xmake/pull/5335): 改进 `xmake install` 和 `xpack`,添加 `set_prefixdir` 接口
* [#5387](https://github.com/xmake-io/xmake/pull/5387): 改进 `xmake test`
* [#5376](https://github.com/xmake-io/xmake/pull/5376): 改进 C++ module 对象列表处理和 moduleonly 包支持
### Bugs 修复
* [#5288](https://github.com/xmake-io/xmake/issues/5288): 修复 `xmake test` 对 Unity Build 的支持
* [#5270](https://github.com/xmake-io/xmake/issues/5270): 修复 gcc/clang 对 pch 的支持
* [#5276](https://github.com/xmake-io/xmake/issues/5276): 修复查找 vc6 环境
* [#5259](https://github.com/xmake-io/xmake/issues/5259): 修复命令补全失效问题
## v2.9.3
### 新特性
* [#4637](https://github.com/xmake-io/xmake/issues/4637): 为 xpack 添加 mix 支持
* [#5107](https://github.com/xmake-io/xmake/issues/5107): 为 xpack 添加 deb 支持
* [#5148](https://github.com/xmake-io/xmake/issues/5148): 为包添加 on_source 配置域
### 改进
* [#5156](https://github.com/xmake-io/xmake/issues/5156): 改进安装 cargo 包
### 问题修复
* [#5176](https://github.com/xmake-io/xmake/pull/5176): 修复 VS toolset v144 支持
## v2.9.2
### 新特性
* [#5005](https://github.com/xmake-io/xmake/pull/5005): 显示所有 API
* [#5003](https://github.com/xmake-io/xmake/issues/5003): 添加 build.fence 策略
* [#5060](https://github.com/xmake-io/xmake/issues/5060): 支持 Verilator 静态库目标构建
* [#5074](https://github.com/xmake-io/xmake/pull/5074): 添加 `xrepo download` 命令去快速下载包源码
* [#5086](https://github.com/xmake-io/xmake/issues/5986): 添加包检测支持
* [#5103](https://github.com/xmake-io/xmake/pull/5103): 添加 qt ts 构建支持
* [#5104](https://github.com/xmake-io/xmake/pull/5104): 改进 find_program,在 windows 上调用 where 改进查找
### 改进
* [#5077](https://github.com/xmake-io/xmake/issues/5077): 当构建 x86 目标时,使用 x64 的 msvc 编译工具
* [#5109](https://github.com/xmake-io/xmake/issues/5109): 改进 add_rpathdirs 支持 runpath/rpath 切换
* [#5132](https://github.com/xmake-io/xmake/pull/5132): 改进 ifort/icc/icx 在 windows 上的支持
### Bugs 修复
* [#5059](https://github.com/xmake-io/xmake/issues/5059): 修复加载大量 targets 时候卡住
* [#5029](https://github.com/xmake-io/xmake/issues/5029): 修复在 termux 上崩溃问题
## v2.9.1
### 新特性
* [#4874](https://github.com/xmake-io/xmake/pull/4874): 添加鸿蒙 SDK 支持
* [#4889](https://github.com/xmake-io/xmake/issues/4889): 添加 signal 模块 去注册信号处理
* [#4925](https://github.com/xmake-io/xmake/issues/4925): 添加 native 模块支持
* [#4938](https://github.com/xmake-io/xmake/issues/4938): 增加对 cppfront/h2 的支持
### 改进
* 改进包管理,支持切换 clang-cl
* [#4893](https://github.com/xmake-io/xmake/issues/4893): 改进 rc 头文件依赖检测
* [#4928](https://github.com/xmake-io/xmake/issues/4928): 改进构建和链接速度,增量编译时候效果更加明显
* [#4931](https://github.com/xmake-io/xmake/pull/4931): 更新 pdcurses
* [#4973](https://github.com/xmake-io/xmake/issues/4973): 改进选择脚本的匹配模式
### Bugs 修复
* [#4882](https://github.com/xmake-io/xmake/issues/4882): 修复安装组依赖问题
* [#4877](https://github.com/xmake-io/xmake/issues/4877): 修复 xpack 打包时,unit build 编译失败问题
* [#4887](https://github.com/xmake-io/xmake/issues/4887): 修复 object 依赖链接
## v2.8.9
### 新特性
* [#4843](https://github.com/xmake-io/xmake/issues/4843): 添加 check_bigendian 接口实现大小端探测
### 改进
* [#4798](https://github.com/xmake-io/xmake/issues/4798): 改进 wasi sdk 检测
* [#4772](https://github.com/xmake-io/xmake/issues/4772): 改进 tools.cmake 去兼容支持 vs2022 preview (v144)
* [#4813](https://github.com/xmake-io/xmake/issues/4813): 添加 gb2312 编码
* [#4864](https://github.com/xmake-io/xmake/issues/4864): 改进抽取符号,支持 gdb 断点调试
* [#4831](https://github.com/xmake-io/xmake/issues/4831): 改进 target:fileconfig() 支持 headerfiles
* [#4846](https://github.com/xmake-io/xmake/issues/4846): 改进进度显示,解决顺序错乱问题
### Bugs 修复
* 修复 select_script 的脚本模式匹配
* [#4763](https://github.com/xmake-io/xmake/issues/4763): 修复 {force = true}
* [#4807](https://github.com/xmake-io/xmake/issues/4807): 修复 nimble::find_package
* [#4857](https://github.com/xmake-io/xmake/issues/4857): 修复对 -P/-F 等基础选项的解析
## v2.8.8
### 改进
* 添加 `package:check_sizeof()`
### Bugs 修复
* [#4774](https://github.com/xmake-io/xmake/issues/4774): 修复 Android NDK r26b 上的 strip 支持
* [#4769](https://github.com/xmake-io/xmake/issues/4769): 修复交叉编译工具链问题
* [#4776](https://github.com/xmake-io/xmake/issues/4776): 修复 soname
* [#4638](https://github.com/xmake-io/xmake/issues/4638): 修复 vsxmake generator
## v2.8.7
### 新特性
* [#4544](https://github.com/xmake-io/xmake/issues/4544): 改进 `xmake test`,支持等待进程超时
* [#4606](https://github.com/xmake-io/xmake/pull/4606): 为 package 添加 `add_versionfiles` 接口
* [#4709](https://github.com/xmake-io/xmake/issues/4709): 添加 cosmocc 工具链支持
* [#4715](https://github.com/xmake-io/xmake/issues/4715): 在描述域添加 is_cross() 接口
* [#4747](https://github.com/xmake-io/xmake/issues/4747): 添加 `build.always_update_configfiles` 策略
### 改进
* [#4575](https://github.com/xmake-io/xmake/issues/4575): 检测无效的域参数
* 添加更多的 loong64 支持
* 改进 dlang/dmd 对 frameworks 的支持
* [#4571](https://github.com/xmake-io/xmake/issues/4571): 改进 `xmake test` 的输出支持
* [#4609](https://github.com/xmake-io/xmake/issues/4609): 改进探测 vs 构建工具环境
* [#4614](https://github.com/xmake-io/xmake/issues/4614): 改进支持 android ndk 26b
* [#4473](https://github.com/xmake-io/xmake/issues/4473): 默认启用警告输出
* [#4477](https://github.com/xmake-io/xmake/issues/4477): 改进 runtimes 去支持 libc++/libstdc++
* [#4657](https://github.com/xmake-io/xmake/issues/4657): 改进脚本的模式匹配
* [#4673](https://github.com/xmake-io/xmake/pull/4673): 重构模块支持
* [#4746](https://github.com/xmake-io/xmake/pull/4746): 为 cmake generator 添加原生 c++ modules 支持
### Bugs 修复
* [#4596](https://github.com/xmake-io/xmake/issues/4596): 修复远程构建缓存
* [#4689](https://github.com/xmake-io/xmake/issues/4689): 修复目标依赖继承
## v2.8.6
### 新特性
* 添加 `network.mode` 策略
* [#1433](https://github.com/xmake-io/xmake/issues/1433): 添加 `xmake pack` 命令去生成 NSIS/zip/tar.gz/rpm/srpm/runself 安装包
* [#4435](https://github.com/xmake-io/xmake/issues/4435): 为 UnityBuild 的组模式增加 batchsize 支持
* [#4485](https://github.com/xmake-io/xmake/pull/4485): 新增 package.install_locally 策略支持
* 新增 NetBSD 支持
### Changes
* [#4484](https://github.com/xmake-io/xmake/pull/4484): 改进 swig 规则
* 改进 Haiku 支持
### Bugs 修复
* [#4372](https://github.com/xmake-io/xmake/issues/4372): 修复 protobuf 规则
* [#4439](https://github.com/xmake-io/xmake/issues/4439): 修复 asn1c 规则
## v2.8.5
### 新特性
* [#1452](https://github.com/xmake-io/xmake/issues/1452): 支持链接顺序调整,链接组
* [#1438](https://github.com/xmake-io/xmake/issues/1438): 支持代码 amalgamation
* [#3381](https://github.com/xmake-io/xmake/issues/3381): 添加 `xmake test` 支持
* [#4276](https://github.com/xmake-io/xmake/issues/4276): 支持自定义域 API
* [#4286](https://github.com/xmake-io/xmake/pull/4286): 添加 Apple XROS 支持
* [#4345](https://github.com/xmake-io/xmake/issues/4345): 支持检测类型大小 sizeof
* [#4369](https://github.com/xmake-io/xmake/pull/4369): 添加 windows.manifest.uac 策略
### 改进
* [#4284](https://github.com/xmake-io/xmake/issues/4284): 改进内置 includes 模块
### Bugs 修复
* [#4256](https://github.com/xmake-io/xmake/issues/4256): 为 vsxmake 生成器修复 c++ modules intellisense
## v2.8.3
### 新特性
* [#4122](https://github.com/xmake-io/xmake/issues/4122): 支持 Lua 调试 (EmmyLua)
* [#4132](https://github.com/xmake-io/xmake/pull/4132): 支持 cppfront
* [#4147](https://github.com/xmake-io/xmake/issues/4147): 添加 hlsl2spv 规则
* 添加 lib.lua.package 模块
* [#4226](https://github.com/xmake-io/xmake/issues/4226): 新增 asan 相关策略和对包的支持
* 添加 `run.autobuild` 策略开启运行前自动构建
* 添加全局策略 `xmake g --policies=`
### 改进
* [#4119](https://github.com/xmake-io/xmake/issues/4119): 改进支持 emcc 工具链和 emscripten 包的整合
* [#4154](https://github.com/xmake-io/xmake/issues/4154): 添加 `xmake -r --shallow target` 去改进重建目标,避免重建所有依赖目标
* 添加全局 ccache 存储目录
* [#4137](https://github.com/xmake-io/xmake/issues/4137): 改进 Qt,支持 Qt6 for Wasm
* [#4173](https://github.com/xmake-io/xmake/issues/4173): 添加 recheck 参数到 on_config
* [#4200](https://github.com/xmake-io/xmake/pull/4200): 改进远程构建,支持调试本地 xmake 源码
* [#4209](https://github.com/xmake-io/xmake/issues/4209): 添加 extra 和 pedantic 警告
### Bugs 修复
* [#4110](https://github.com/xmake-io/xmake/issues/4110): 修复 extrafiles
* [#4115](https://github.com/xmake-io/xmake/issues/4115): 修复 compile_commands 生成器
* [#4199](https://github.com/xmake-io/xmake/pull/4199): 修复 compile_commands 生成器对 c++ modules 的支持
* 修复 os.mv 在 windows 上跨驱动盘失败问题
* [#4214](https://github.com/xmake-io/xmake/issues/4214): 修复 rust workspace 构建问题
## v2.8.2
### 新特性
* [#4002](https://github.com/xmake-io/xmake/issues/4002): 增加 soname 支持
* [#1613](https://github.com/xmake-io/xmake/issues/1613): 为 add_vectorexts 增加 avx512 和 sse4.2 支持
* [#2471](https://github.com/xmake-io/xmake/issues/2471): 添加 set_encodings API 去设置源文件和目标文件的编码
* [#4071](https://github.com/xmake-io/xmake/pull/4071): 支持 sdcc 的 stm8 汇编器
* [#4101](https://github.com/xmake-io/xmake/issues/4101): 为 c/c++ 添加 force includes
* [#2384](https://github.com/xmake-io/xmake/issues/2384): 为 vs/vsxmake 生成器添加 add_extrafiles 接口
### 改进
* [#3960](https://github.com/xmake-io/xmake/issues/3960): 改进 msys2/crt64 支持
* [#4032](https://github.com/xmake-io/xmake/pull/4032): 移除一些非常老的废弃接口
* 改进 tools.msbuild 升级 vcproj 文件
* 支持 add_requires("xmake::xxx") 包
* [#4049](https://github.com/xmake-io/xmake/issues/4049): 改进 Rust 支持交叉编译
* 改进 clang 下 c++ modules 支持
### Bugs 修复
* 修复 macOS/Linux 上子子进程无法快速退出问题
## v2.8.1
### 新特性
* [#3821](https://github.com/xmake-io/xmake/pull/3821): windows 安装器添加长路径支持选项
* [#3828](https://github.com/xmake-io/xmake/pull/3828): 添加 zypper 包管理器支持
* [#3871](https://github.com/xmake-io/xmake/issues/3871): 改进 tools.msbuild 支持对 vsproj 进行自动升级
* [#3148](https://github.com/xmake-io/xmake/issues/3148): 改进 protobuf 支持 grpc
* [#3889](https://github.com/xmake-io/xmake/issues/3889): add_links 支持库路径添加
* [#3912](https://github.com/orgs/xmake-io/issues/3912): 添加 set_pmxxheader 去支持 objc 预编译头
* add_links 支持库文件路径
### 改进
* [#3752](https://github.com/xmake-io/xmake/issues/3752): 改进 windows 上 os.getenvs 的获取
* [#3371](https://github.com/xmake-io/xmake/issues/3371): 改进 tools.cmake 支持使用 ninja 去构建 wasm 包
* [#3777](https://github.com/xmake-io/xmake/issues/3777): 改进从 pkg-config 中查找包
* [#3815](https://github.com/xmake-io/xmake/pull/3815): 改进 tools.xmake 支持为 windows 平台传递工具链
* [#3857](https://github.com/xmake-io/xmake/issues/3857): 改进生成 compile_commands.json
* [#3892](https://github.com/xmake-io/xmake/issues/3892): 改进包搜索,支持从描述中找包
* [#3916](https://github.com/xmake-io/xmake/issues/3916): 改进构建 swift 程序,支持模块间符号调用
* 更新 lua 运行时到 5.4.6
### Bugs 修复
* [#3755](https://github.com/xmake-io/xmake/pull/3755): 修复 find_tool 从 xmake/packages 中查找程序
* [#3787](https://github.com/xmake-io/xmake/issues/3787): 修复从 conan 2.x 中使用包
* [#3839](https://github.com/orgs/xmake-io/discussions/3839): 修复 conan 2.x 包的 vs_runtime 设置
## v2.7.9
### 新特性
* [#3613](https://github.com/xmake-io/xmake/issues/3613): 添加 `wasm.preloadfiles` 扩展配置
* [#3703](https://github.com/xmake-io/xmake/pull/3703): 支持 conan >=2.0.5
### 改进
* [#3669](https://github.com/xmake-io/xmake/issues/3669): 改进 cmake 生成器支持特定工具的 cxflags
* [#3679](https://github.com/xmake-io/xmake/issues/3679): 改进 `xrepo clean`
* [#3662](https://github.com/xmake-io/xmake/issues/3662): 改进 cmake/make 生成器去更好的支持 lex/yacc 工程
* [#3697](https://github.com/xmake-io/xmake/issues/3662): 改进 trybuild/cmake
* [#3730](https://github.com/xmake-io/xmake/issues/3730): 改进 c++modules 包安装,解决不同目录同名文件分发冲突问题
### Bugs 修复
* [#3596](https://github.com/xmake-io/xmake/issues/3596): 修复 check_cxxfuncs 和 check_cxxsnippets
* [#3603](https://github.com/xmake-io/xmake/issues/3603): 修复 xmake update 的无效 url
* [#3614](https://github.com/xmake-io/xmake/issues/3614): 修复 xmake run 对 Qt 环境的加载
* [#3628](https://github.com/xmake-io/xmake/issues/3628): 修复 msys2/mingw 下 os.exec 总是优先查找错误的可执行程序
* 修复 msys/mingw 下环境变量设置问题
## v2.7.8
### 新特性
* [#3518](https://github.com/xmake-io/xmake/issues/3518): 分析编译和链接性能
* [#3522](https://github.com/xmake-io/xmake/issues/3522): 为 target 添加 has_cflags, has_xxx 等辅助接口
* [#3537](https://github.com/xmake-io/xmake/issues/3537): 为 clang.tidy 检测器添加 `--fix` 自动修复
### 改进
* [#3433](https://github.com/xmake-io/xmake/issues/3433): 改进 QT 在 msys2/mingw64 和 wasm 上的构建支持
* [#3419](https://github.com/xmake-io/xmake/issues/3419): 支持 fish shell 环境
* [#3455](https://github.com/xmake-io/xmake/issues/3455): Dlang 增量编译支持
* [#3498](https://github.com/xmake-io/xmake/issues/3498): 改进绑定包虚拟环境
* [#3504](https://github.com/xmake-io/xmake/pull/3504): 添加 swig java 支持
* [#3508](https://github.com/xmake-io/xmake/issues/3508): 改进 trybuild/cmake 去支持工具链切换
* 为 msvc 禁用 build cache 加速,因为 msvc 的预处理器太慢,反而极大影响构建性能。
### Bugs 修复
* [#3436](https://github.com/xmake-io/xmake/issues/3436): 修复自动补全和 menuconf
* [#3463](https://github.com/xmake-io/xmake/issues/3463): 修复 c++modules 缓存问题
* [#3545](https://github.com/xmake-io/xmake/issues/3545): 修复 armcc 的头文件依赖解析
## v2.7.7
### 新特性
* 添加 Haiku 支持
* [#3326](https://github.com/xmake-io/xmake/issues/3326): 添加 `xmake check` 去检测工程代码 (clang-tidy) 和 API 参数配置
* [#3332](https://github.com/xmake-io/xmake/pull/3332): 在包中配置添加自定义 http headers
### 改进
* [#3318](https://github.com/xmake-io/xmake/pull/3318): 改进 dlang 工具链
* [#2591](https://github.com/xmake-io/xmake/issues/2591): 改进 target 配置来源分析
* 为 dmd/ldc2 改进 strip/optimization
* [#3342](https://github.com/xmake-io/xmake/issues/3342): 改进配置构建目录,支持外置目录构建,保持远吗目录更加干净
* [#3373](https://github.com/xmake-io/xmake/issues/3373): 为 clang-17 改进 std 模块支持
### Bugs 修复
* [#3317](https://github.com/xmake-io/xmake/pull/3317): 针对 Qt 工程,修复 lanuages 设置
* [#3321](https://github.com/xmake-io/xmake/issues/3321): 修复隔天 configfiles 重新生成导致重编问题
* [#3296](https://github.com/xmake-io/xmake/issues/3296): 修复 macOS arm64 上构建失败
## v2.7.6
### 新特性
* [#3228](https://github.com/xmake-io/xmake/pull/3228): C++ modules 的安装发布,以及从包中导入 C++ modules 支持
* [#3257](https://github.com/xmake-io/xmake/issues/3257): 增加对 iverilog 和 verilator 的支持
* 支持 xp 和 vc6.0
* [#3214](https://github.com/xmake-io/xmake/pull/3214): xrepo install 的自动补全支持
### 改进
* [#3255](https://github.com/xmake-io/xmake/pull/3225): 改进 clang libc++ 模块支持
* 支持使用 mingw 编译 xmake
* 改进 xmake 在 win xp 上的兼容性
* 如果外部依赖被启用,切换 json 模块到纯 lua 实现,移除对 lua-cjson 的依赖
### Bugs 修复
* [#3229](https://github.com/xmake-io/xmake/issues/3229): 修复 vs2015 下找不到 rc.exe 问题
* [#3271](https://github.com/xmake-io/xmake/issues/3271): 修复支持带有空格的宏定义
* [#3273](https://github.com/xmake-io/xmake/issues/3273): 修复 nim 链接错误
* [#3286](https://github.com/xmake-io/xmake/issues/3286): 修复 compile_commands 对 clangd 的支持
## v2.7.5
### 新特性
* [#3201](https://github.com/xmake-io/xmake/pull/3201): 为 xrepo 添加命令自动补全
* [#3233](https://github.com/xmake-io/xmake/issues/3233): 添加 MASM32 sdk 工具链
### 改进
* [#3216](https://github.com/xmake-io/xmake/pull/3216): 改进 intel one api toolkits 探测
* [#3020](https://github.com/xmake-io/xmake/issues/3020): 添加 `--lsp=clangd` 去改进 compile_commands.json 的生成
* [#3215](https://github.com/xmake-io/xmake/issues/3215): 添加 includedirs 和 defines 到 c51 编译器
* [#3251](https://github.com/xmake-io/xmake/issues/3251): 改进 zig and c 混合编译
### Bugs 修复
* [#3203](https://github.com/xmake-io/xmake/issues/3203): 修复 compile_commands
* [#3222](https://github.com/xmake-io/xmake/issues/3222): 修复 objc 的预编译头支持
* [#3240](https://github.com/xmake-io/xmake/pull/3240): 修复 `xmake run` 处理单个参数不正确问题
* [#3238](https://github.com/xmake-io/xmake/pull/3238): 修复 clang 构建 module 时候,并行写入 mapper 冲突问题
## v2.7.4
### 新特性
* [#3049](https://github.com/xmake-io/xmake/pull/3049): 添加 `xmake format` 插件
* 添加 `plugin.compile_commands.autoupdate` 规则
* [#3172](https://github.com/xmake-io/xmake/pull/3172): 添加 xmake.sh
* [#3168](https://github.com/xmake-io/xmake/pull/3168): 为 msvc 添加 C++23 标准模块支持
### 改进
* [#3056](https://github.com/xmake-io/xmake/issues/3056): 改进 Zig 支持
* [#3060](https://github.com/xmake-io/xmake/issues/3060): 改进支持 msys2 的环境探测
* [#3071](https://github.com/xmake-io/xmake/issues/3071): 为 llvm/clang 工具链支持 rc 编译
* [#3122](https://github.com/xmake-io/xmake/pull/3122): 改进 c++20 模块依赖图的源码分析,支持预处理
* [#3125](https://github.com/xmake-io/xmake/pull/3125): 增加私有 C++20 模块的编译支持
* [#3133](https://github.com/xmake-io/xmake/pull/3133): 增加 internal partitions 模块支持
* [#3146](https://github.com/xmake-io/xmake/issues/3146): 添加默认包组件支持
* [#3192](https://github.com/xmake-io/xmake/issues/3192): 为 auto complete 增加 json 输出支持
### Bugs 修复
* 修复 requires-lock 问题
* [#3065](https://github.com/xmake-io/xmake/issues/3065): 修复部分依赖包没有被安装的问题
* [#3082](https://github.com/xmake-io/xmake/issues/3082): 修复 build.ninja 生成器
* [#3092](https://github.com/xmake-io/xmake/issues/3092): 修复 xrepo add-repo 添加失败逻辑
* [#3013](https://github.com/xmake-io/xmake/issues/3013): 修复支持 windows UNC 路径
* [#2902](https://github.com/xmake-io/xmake/issues/2902): 修复文件被其他子进程占用问题
* [#3074](https://github.com/xmake-io/xmake/issues/3074): 修复 CMakelists 生成器链接参数设置不对问题
* [#3141](https://github.com/xmake-io/xmake/pull/3141): 修复 C++ 模块的导入顺序
* 修复 tools/xmake 包安装构建目录
* [#3159](https://github.com/xmake-io/xmake/issues/3159): 为 CLion 修复 compile_commands
## v2.7.3
### 新特性
* 一种新的可选域配置语法,对 LSP 友好,并且支持域隔离。
* [#2944](https://github.com/xmake-io/xmake/issues/2944): 为嵌入式工程添加 `gnu-rm.binary` 和 `gnu-rm.static` 规则和测试工程
* [#2636](https://github.com/xmake-io/xmake/issues/2636): 支持包组件
* 支持 msvc 的 armasm/armasm64
* [#3023](https://github.com/xmake-io/xmake/pull/3023): 改进 xmake run -d,添加 renderdoc 调试器支持
* [#3022](https://github.com/xmake-io/xmake/issues/3022): 为特定编译器添加 flags
* [#3025](https://github.com/xmake-io/xmake/pull/3025): 新增 C++ 异常接口配置
* [#3017](https://github.com/xmake-io/xmake/pull/3017): 支持 ispc 编译器规则
### 改进
* [#2925](https://github.com/xmake-io/xmake/issues/2925): 改进 doxygen 插件
* [#2948](https://github.com/xmake-io/xmake/issues/2948): 支持 OpenBSD
* 添加 `xmake g --insecure-ssl=y` 配置选项去禁用 ssl 证书检测
* [#2971](https://github.com/xmake-io/xmake/pull/2971): 使 vs/vsxmake 工程生成的结果每次保持一致
* [#3000](https://github.com/xmake-io/xmake/issues/3000): 改进 C++ 模块构建支持,实现增量编译支持
* [#3016](https://github.com/xmake-io/xmake/pull/3016): 改进 clang/msvc 去更好地支持 std 模块
### Bugs 修复
* [#2949](https://github.com/xmake-io/xmake/issues/2949): 修复 vs 分组
* [#2952](https://github.com/xmake-io/xmake/issues/2952): 修复 armlink 处理长命令失败问题
* [#2954](https://github.com/xmake-io/xmake/issues/2954): 修复 c++ module partitions 路径无效问题
* [#3033](https://github.com/xmake-io/xmake/issues/3033): 探测循环模块依赖
## v2.7.2
### 新特性
* [#2140](https://github.com/xmake-io/xmake/issues/2140): 支持 Windows Arm64
* [#2719](https://github.com/xmake-io/xmake/issues/2719): 添加 `package.librarydeps.strict_compatibility` 策略严格限制包依赖兼容性
* [#2810](https://github.com/xmake-io/xmake/pull/2810): 支持 os.execv 去执行 shell 脚本文件
* [#2817](https://github.com/xmake-io/xmake/pull/2817): 改进规则支持依赖顺序执行
* [#2824](https://github.com/xmake-io/xmake/pull/2824): 传递 cross-file 交叉编译环境给 meson.install 和 trybuild
* [#2856](https://github.com/xmake-io/xmake/pull/2856): xrepo 支持从当前指定源码目录调试程序
* [#2859](https://github.com/xmake-io/xmake/issues/2859): 改进对三方库的 trybuild 构建,利用 xmake-repo 仓库脚本更加智能化地构建三方库
* [#2879](https://github.com/xmake-io/xmake/issues/2879): 更好的动态创建和配置 target 和 rule
* [#2374](https://github.com/xmake-io/xmake/issues/2374): 允许 xmake 包中引入自定义规则
* 添加 clang-cl 工具链
### 改进
* [#2745](https://github.com/xmake-io/xmake/pull/2745): 改进 os.cp 支持符号链接复制
* [#2773](https://github.com/xmake-io/xmake/pull/2773): 改进 vcpkg 包安装,支持 freebsd 平台
* [#2778](https://github.com/xmake-io/xmake/pull/2778): 改进 xrepo.env 支持 target 的运行环境加载
* [#2783](https://github.com/xmake-io/xmake/issues/2783): 添加摘要算法选项到 WDK 的 signtool 签名工具
* [#2787](https://github.com/xmake-io/xmake/pull/2787): 改进 json 支持空数组
* [#2782](https://github.com/xmake-io/xmake/pull/2782): 改进查找 matlib sdk 和运行时
* [#2793](https://github.com/xmake-io/xmake/issues/2793): 改进 mconfdialog 配置操作体验
* [#2804](https://github.com/xmake-io/xmake/issues/2804): 安装依赖包支持 macOS arm64/x86_64 交叉编译
* [#2809](https://github.com/xmake-io/xmake/issues/2809): 改进 msvc 的编译优化选项
* 改进 trybuild 模式,为 meson/autoconf/cmake 提供更好的交叉编译支持
* [#2846](https://github.com/xmake-io/xmake/discussions/2846): 改进对 configfiles 的生成
* [#2866](https://github.com/xmake-io/xmake/issues/2866): 更好地控制 rule 规则执行顺序
### Bugs 修复
* [#2740](https://github.com/xmake-io/xmake/issues/2740): 修复 msvc 构建 C++ modules 卡死问题
* [#2875](https://github.com/xmake-io/xmake/issues/2875): 修复构建 linux 驱动错误
* [#2885](https://github.com/xmake-io/xmake/issues/2885): 修复 ccache 下,msvc 编译 pch 失败问题
## v2.7.1
### 新特性
* [#2555](https://github.com/xmake-io/xmake/issues/2555): 添加 fwatcher 模块和 `xmake watch` 插件命令
* 添加 `xmake service --pull 'build/**' outputdir` 命令去拉取远程构建服务器上的文件
* [#2641](https://github.com/xmake-io/xmake/pull/2641): 改进 C++20 模块, 支持 headerunits 和 project 生成
* [#2679](https://github.com/xmake-io/xmake/issues/2679): 支持 Mac Catalyst 构建
### 改进
* [#2576](https://github.com/xmake-io/xmake/issues/2576): 改进从 cmake 中查找包,提供更过灵活的可选配置
* [#2577](https://github.com/xmake-io/xmake/issues/2577): 改进 add_headerfiles(),增加 `{install = false}` 支持
* [#2603](https://github.com/xmake-io/xmake/issues/2603): 为 ccache 默认禁用 `-fdirectives-only`
* [#2580](https://github.com/xmake-io/xmake/issues/2580): 设置 stdout 到 line 缓冲输出
* [#2571](https://github.com/xmake-io/xmake/issues/2571): 改进分布式编译的调度算法,增加 cpu/memory 状态权重
* [#2410](https://github.com/xmake-io/xmake/issues/2410): 改进 cmakelists 生成
* [#2690](https://github.com/xmake-io/xmake/issues/2690): 改机传递 toolchains 到包
* [#2686](https://github.com/xmake-io/xmake/issues/2686): 改进 armcc/armclang 支持增量编译
* [#2562](https://github.com/xmake-io/xmake/issues/2562): 改进 rc.exe 对引用文件依赖的解析和增量编译支持
* 改进默认的并行构建任务数
### Bugs 修复
* [#2614](https://github.com/xmake-io/xmake/issues/2614): 为 msvc 修复构建 submodules2 测试工程
* [#2620](https://github.com/xmake-io/xmake/issues/2620): 修复构建缓存导致的增量编译问题
* [#2177](https://github.com/xmake-io/xmake/issues/2177): 修复 python.library 在 macOS 上段错误崩溃
* [#2708](https://github.com/xmake-io/xmake/issues/2708): 修复 mode.coverage 规则的链接错误
* 修复 ios/macOS framework 和 application 的 rpath 加载路径
## v2.6.9
### 新特性
* [#2474](https://github.com/xmake-io/xmake/issues/2474): 添加 icx 和 dpcpp 工具链
* [#2523](https://github.com/xmake-io/xmake/issues/2523): 改进对 LTO 的支持
* [#2527](https://github.com/xmake-io/xmake/issues/2527): 添加 set_runargs 接口
### 改进
* 改进 tools.cmake 支持 wasm 库构建
* [#2491](https://github.com/xmake-io/xmake/issues/2491): 如果服务器不可访问,自动回退到本地编译和缓存
* [#2514](https://github.com/xmake-io/xmake/issues/2514): 为工程生成器禁用 Unity Build
* [#2473](https://github.com/xmake-io/xmake/issues/2473): 改进 apt::find_package,支持从 pc 文件中查找
* [#2512](https://github.com/xmake-io/xmake/issues/2512): 改进远程服务支持超时配置
### Bugs 修复
* [#2488](https://github.com/xmake-io/xmake/issues/2488): 修复从 windows 到 linux 的远程编译路径问题
* [#2504](https://github.com/xmake-io/xmake/issues/2504): 修复在 msys2 上远程编译失败问题
* [#2525](https://github.com/xmake-io/xmake/issues/2525): 修复安装依赖包时候卡死问题
* [#2557](https://github.com/xmake-io/xmake/issues/2557): 修复 cmake.find_package 查找 links 错误
* 修复缓存导致的预处理文件路径冲突问题
## v2.6.8
### 新特性
* [#2447](https://github.com/xmake-io/xmake/pull/2447): 添加 qt.qmlplugin 规则和 qmltypesregistrar 支持
* [#2446](https://github.com/xmake-io/xmake/issues/2446): 支持 target 分组安装
* [#2469](https://github.com/xmake-io/xmake/issues/2469): 产生 vcpkg-configuration.json
### 改进
* 添加 `preprocessor.linemarkers` 策略去禁用 linemarkers 去加速 ccache/distcc
* [#2389](https://github.com/xmake-io/xmake/issues/2389): 改进 `xmake run` 支持并行运行目标程序
* [#2417](https://github.com/xmake-io/xmake/issues/2417): 切换 option/showmenu 的默认值,默认开启
* [#2440](https://github.com/xmake-io/xmake/pull/2440): 改进安装包的失败错误信息
* [#2438](https://github.com/xmake-io/xmake/pull/2438): 确保生成的 vsxmake 工程不会随机变动
* [#2434](https://github.com/xmake-io/xmake/issues/2434): 改进插件管理器,允许多插件管理
* [#2421](https://github.com/xmake-io/xmake/issues/2421): 改进配置选项菜单
* [#2425](https://github.com/xmake-io/xmake/issues/2425): 添加 `preprocessor.gcc.directives_only` 策略
* [#2455](https://github.com/xmake-io/xmake/issues/2455): 改进 emcc 的优化选项
* [#2467](https://github.com/xmake-io/xmake/issues/2467): 支持回退到原始文件编译,兼容 msvc 预处理器的一些问题
* [#2452](https://github.com/xmake-io/xmake/issues/2452): 添加 build.warning 策略
### Bugs 修复
* [#2435](https://github.com/xmake-io/xmake/pull/2435): 修复无法搜索带有 `.` 的包名
* [#2445](https://github.com/xmake-io/xmake/issues/2445): 修复 windows 上 ccache 构建失败问题
* [#2452](https://github.com/xmake-io/xmake/issues/2452): 修复 ccache 下,警告无法输出的问题
## v2.6.7
### 新特性
* [#2318](https://github.com/xmake-io/xmake/issues/2318): 添加 `xmake f --policies=` 配置参数去修改默认策略
### 改进
* 如果预编译包构建失败,自动回退到源码包构建
* [#2387](https://github.com/xmake-io/xmake/issues/2387): 改进 pkgconfig 和 find_package
* 添加 `build.ccache` 策略,用于在工程中配置编译缓存
### Bugs 修复
* [#2382](https://github.com/xmake-io/xmake/issues/2382): 修改 headeronly 包配置
* [#2388](https://github.com/xmake-io/xmake/issues/2388): 修复路径问题
* [#2385](https://github.com/xmake-io/xmake/issues/2385): 修复 cmake/find_package
* [#2395](https://github.com/xmake-io/xmake/issues/2395): 修复 c++ modules
* 修复 find_qt 问题
## v2.6.6
### 新特性
* [#2327](https://github.com/xmake-io/xmake/issues/2327): 支持 nvidia-hpc-sdk 工具链中的 nvc/nvc++/nvfortran 编译器
* 添加 path 实例接口
* [#2344](https://github.com/xmake-io/xmake/pull/2344): 添加 lz4 压缩模块
* [#2349](https://github.com/xmake-io/xmake/pull/2349): 添加 keil/c51 工程支持
* [#274](https://github.com/xmake-io/xmake/issues/274): 跨平台分布式编译支持
* 使用内置的本地缓存替代 ccache
### 改进
* [#2309](https://github.com/xmake-io/xmake/issues/2309): 远程编译支持用户授权验证
* 改进远程编译,增加对 lz4 压缩支持
### Bugs 修复
* 修复选择包版本时候 lua 栈不平衡导致的崩溃问题
## v2.6.5
### 新特性
* [#2138](https://github.com/xmake-io/xmake/issues/2138): 支持模板包
* [#2185](https://github.com/xmake-io/xmake/issues/2185): 添加 `--appledev=simulator` 去改进 Apple 模拟器目标编译支持
* [#2227](https://github.com/xmake-io/xmake/issues/2227): 改进 cargo 包,支持指定 Cargo.toml 文件
* 改进 `add_requires` 支持 git command 作为版本
* [#622](https://github.com/xmake-io/xmake/issues/622): 支持远程编译
* [#2282](https://github.com/xmake-io/xmake/issues/2282): 添加 `add_filegroups` 接口为 vs/vsxmake/cmake generator 增加文件组支持
### 改进
* [#2137](https://github.com/xmake-io/xmake/pull/2137): 改进 path 模块
* macOS 下,减少 50% 的 Xmake 二进制文件大小
* 改进 tools/autoconf,cmake 去更好地支持工具链切换
* [#2221](https://github.com/xmake-io/xmake/pull/2221): 改进注册表 api 去支持 unicode
* [#2225](https://github.com/xmake-io/xmake/issues/2225): 增加对 protobuf 的依赖分析和构建支持
* [#2265](https://github.com/xmake-io/xmake/issues/2265): 排序 CMakeLists.txt
* 改进 os.files 的文件遍历速度
### Bugs 修复
* [#2233](https://github.com/xmake-io/xmake/issues/2233): 修复 c++ modules 依赖
## v2.6.4
### 新特性
* [#2011](https://github.com/xmake-io/xmake/issues/2011): 支持继承和局部修改官方包,例如对现有的包更换 urls 和 versions
* 支持在 sparc, alpha, powerpc, s390x 和 sh4 上编译运行 xmake
* 为 package() 添加 on_download 自定义下载
* [#2021](https://github.com/xmake-io/xmake/issues/2021): 支持 Linux/Windows 下构建 Swift 程序
* [#2024](https://github.com/xmake-io/xmake/issues/2024): 添加 asn1c 支持
* [#2031](https://github.com/xmake-io/xmake/issues/2031): 为 add_files 增加 linker scripts 和 version scripts 支持
* [#2033](https://github.com/xmake-io/xmake/issues/2033): 捕获 ctrl-c 去打印当前运行栈,用于调试分析卡死问题
* [#2059](https://github.com/xmake-io/xmake/pull/2059): 添加 `xmake update --integrate` 命令去整合 shell
* [#2070](https://github.com/xmake-io/xmake/issues/2070): 添加一些内置的 xrepo env 环境配置
* [#2117](https://github.com/xmake-io/xmake/pull/2117): 支持为任意平台传递工具链到包
* [#2121](https://github.com/xmake-io/xmake/issues/2121): 支持导出指定的符号列表,可用于减少动态库的大小
### 改进
* [#2036](https://github.com/xmake-io/xmake/issues/2036): 改进 xrepo 支持从配置文件批量安装包,例如:`xrepo install xxx.lua`
* [#2039](https://github.com/xmake-io/xmake/issues/2039): 改进 vs generator 的 filter 目录展示
* [#2025](https://github.com/xmake-io/xmake/issues/2025): 支持为 phony 和 headeronly 目标生成 vs 工程
* 优化 vs 和 codesign 的探测速度
* [#2077](https://github.com/xmake-io/xmake/issues/2077): 改进 vs 工程生成器去支持 cuda
### Bugs 修复
* [#2005](https://github.com/xmake-io/xmake/issues/2005): 修复 path.extension
* [#2008](https://github.com/xmake-io/xmake/issues/2008): 修复 windows manifest 文件编译
* [#2016](https://github.com/xmake-io/xmake/issues/2016): 修复 vs project generator 里,对象文件名冲突导致的编译失败
## v2.6.3
### 新特性
* [#1298](https://github.com/xmake-io/xmake/issues/1928): 支持 vcpkg 清单模式安装包,实现安装包的版本选择
* [#1896](https://github.com/xmake-io/xmake/issues/1896): 添加 `python.library` 规则去构建 pybind 模块,并且支持 soabi
* [#1939](https://github.com/xmake-io/xmake/issues/1939): 添加 `remove_files`, `remove_headerfiles` 并且标记 `del_files` 作为废弃接口
* 将 on_config 作为正式的公开接口,用于 target 和 rule
* 添加 riscv32/64 支持
* [#1970](https://github.com/xmake-io/xmake/issues/1970): 添加 CMake wrapper 支持在 CMakelists 中去调用 xrepo 集成 C/C++ 包
* 添加内置的 github 镜像加速 pac 代理文件, `xmake g --proxy_pac=github_mirror.lua`
### 改进
* [#1923](https://github.com/xmake-io/xmake/issues/1923): 改进构建 linux 驱动,支持设置自定义 linux-headers 路径
* [#1962](https://github.com/xmake-io/xmake/issues/1962): 改进 armclang 工具链去支持构建 asm
* [#1959](https://github.com/xmake-io/xmake/pull/1959): 改进 vstudio 工程生成器
* [#1969](https://github.com/xmake-io/xmake/issues/1969): 添加默认的 option 描述
### Bugs 修复
* [#1875](https://github.com/xmake-io/xmake/issues/1875): 修复部署生成 Android Qt 程序包失败问题
* [#1973](https://github.com/xmake-io/xmake/issues/1973): 修复合并静态库
* [#1982](https://github.com/xmake-io/xmake/pull/1982): 修复 clang 下对 c++20 子模块的依赖构建
## v2.6.2
### 新特性
* [#1902](https://github.com/xmake-io/xmake/issues/1902): 支持构建 linux 内核驱动模块
* [#1913](https://github.com/xmake-io/xmake/issues/1913): 通过 group 模式匹配,指定构建和运行一批目标程序
### 改进
* [#1872](https://github.com/xmake-io/xmake/issues/1872): 支持转义 set_configvar 中字符串值
* [#1888](https://github.com/xmake-io/xmake/issues/1888): 改进 windows 安装器,避免错误删除其他安装目录下的文件
* [#1895](https://github.com/xmake-io/xmake/issues/1895): 改进 `plugin.vsxmake.autoupdate` 规则
* [#1893](https://github.com/xmake-io/xmake/issues/1893): 改进探测 icc 和 ifort 工具链
* [#1905](https://github.com/xmake-io/xmake/pull/1905): 改进 msvc 对 external 头文件搜索探测支持
* [#1904](https://github.com/xmake-io/xmake/pull/1904): 改进 vs201x 工程生成器
* 添加 `XMAKE_THEME` 环境变量去切换主题配置
* [#1907](https://github.com/xmake-io/xmake/issues/1907): 添加 `-f/--force` 参数使得 `xmake create` 可以在费控目录被强制创建
* [#1917](https://github.com/xmake-io/xmake/pull/1917): 改进 find_package 和配置
### Bugs 修复
* [#1885](https://github.com/xmake-io/xmake/issues/1885): 修复 package:fetch_linkdeps 链接顺序问题
* [#1903](https://github.com/xmake-io/xmake/issues/1903): 修复包链接顺序
## v2.6.1
### 新特性
* [#1799](https://github.com/xmake-io/xmake/issues/1799): 支持混合 Rust 和 C++ 程序,以及集成 Cargo 依赖库
* 添加 `utils.glsl2spv` 规则去编译 *.vert/*.frag shader 文件生成 spirv 文件和二进制 C 头文件
### 改进
* 默认切换到 Lua5.4 运行时
* [#1776](https://github.com/xmake-io/xmake/issues/1776): 改进 system::find_package,支持从环境变量中查找系统库
* [#1786](https://github.com/xmake-io/xmake/issues/1786): 改进 apt:find_package,支持查找 alias 包
* [#1819](https://github.com/xmake-io/xmake/issues/1819): 添加预编译头到 cmake 生成器
* 改进 C++20 Modules 为 msvc 支持 std 标准库
* [#1792](https://github.com/xmake-io/xmake/issues/1792): 添加自定义命令到 vs 工程生成器
* [#1835](https://github.com/xmake-io/xmake/issues/1835): 改进 MDK 程序构建支持,增加 `set_runtimes("microlib")`
* [#1858](https://github.com/xmake-io/xmake/issues/1858): 改进构建 c++20 modules,修复跨 target 构建问题
* 添加 $XMAKE_BINARY_REPO 和 $XMAKE_MAIN_REPO 仓库设置环境变量
* [#1865](https://github.com/xmake-io/xmake/issues/1865): 改进 openmp 工程
* [#1845](https://github.com/xmake-io/xmake/issues/1845): 为静态库安装 pdb 文件
### Bugs 修复
* 修复语义版本中解析带有 0 前缀的 build 字符串问题
* [#50](https://github.com/libbpf/libbpf-bootstrap/issues/50): 修复 rule 和构建 bpf 程序 bug
* [#1610](https://github.com/xmake-io/xmake/issues/1610): 修复 `xmake f --menu` 在 vscode 终端下按键无响应,并且支持 ConPTY 终端虚拟按键
## v2.5.9
### 新特性
* [#1736](https://github.com/xmake-io/xmake/issues/1736): 支持 wasi-sdk 工具链
* 支持 Lua 5.4 运行时
* 添加 gcc-8, gcc-9, gcc-10, gcc-11 工具链
* [#1623](https://github.com/xmake-io/xmake/issues/1632): 支持 find_package 从 cmake 查找包
* [#1747](https://github.com/xmake-io/xmake/issues/1747): 添加 `set_kind("headeronly")` 更好的处理 headeronly 库的安装
* [#1019](https://github.com/xmake-io/xmake/issues/1019): 支持 Unity build
* [#1438](https://github.com/xmake-io/xmake/issues/1438): 增加 `xmake l cli.amalgamate` 命令支持代码合并
* [#1765](https://github.com/xmake-io/xmake/issues/1756): 支持 nim 语言
* [#1762](https://github.com/xmake-io/xmake/issues/1762): 为 `xrepo env` 管理和切换指定的环境配置
* [#1767](https://github.com/xmake-io/xmake/issues/1767): 支持 Circle 编译器
* [#1753](https://github.com/xmake-io/xmake/issues/1753): 支持 Keil/MDK 的 armcc/armclang 工具链
* [#1774](https://github.com/xmake-io/xmake/issues/1774): 添加 table.contains api
* [#1735](https://github.com/xmake-io/xmake/issues/1735): 添加自定义命令到 cmake 生成器
* [#1781](https://github.com/xmake-io/xmake/issues/1781): 改进 get.sh 安装脚本支持 nixos
### 改进
* [#1528](https://github.com/xmake-io/xmake/issues/1528): 检测 c++17/20 特性
* [#1729](https://github.com/xmake-io/xmake/issues/1729): 改进 C++20 modules 对 clang/gcc/msvc 的支持,支持模块间依赖编译和并行优化
* [#1779](https://github.com/xmake-io/xmake/issues/1779): 改进 ml.exe/x86,移除内置的 `-Gd` 选项
## v2.5.8
### 新特性
* [#388](https://github.com/xmake-io/xmake/issues/388): Pascal 语言支持,可以使用 fpc 来编译 free pascal
* [#1682](https://github.com/xmake-io/xmake/issues/1682): 添加可选的额lua5.3 运行时替代 luajit,提供更好的平台兼容性。
* [#1622](https://github.com/xmake-io/xmake/issues/1622): 支持 Swig
* [#1714](https://github.com/xmake-io/xmake/issues/1714): 支持内置 cmake 等第三方项目的混合编译
* [#1715](https://github.com/xmake-io/xmake/issues/1715): 支持探测编译器语言标准特性,并且新增 `check_macros` 检测接口
* xmake 支持在 Loongarch 架构上运行
### 改进
* [#1618](https://github.com/xmake-io/xmake/issues/1618): 改进 vala 支持构建动态库和静态库程序
* 改进 Qt 规则去支持 Qt 4.x
* 改进 `set_symbols("debug")` 支持 clang/windows 生成 pdb 文件
* [#1638](https://github.com/xmake-io/xmake/issues/1638): 改进合并静态库
* 改进 on_load/after_load 去支持动态的添加 target deps
* [#1675](https://github.com/xmake-io/xmake/pull/1675): 针对 mingw 平台,重命名动态库和导入库文件名后缀
* [#1694](https://github.com/xmake-io/xmake/issues/1694): 支持在 set_configvar 中定义一个不带引号的字符串变量
* 改进对 Android NDK r23 的支持
* 为 `set_languages` 新增 `c++latest` 和 `clatest` 配置值
* [#1720](https://github.com/xmake-io/xmake/issues/1720): 添加 `save_scope` 和 `restore_scope` 去修复 `check_xxx` 相关接口
* [#1726](https://github.com/xmake-io/xmake/issues/1726): 改进 compile_commands 生成器去支持 nvcc
### Bugs 修复
* [#1671](https://github.com/xmake-io/xmake/issues/1671): 修复安装预编译包后,*.cmake 里面的一些不正确的绝对路径
* [#1689](https://github.com/xmake-io/xmake/issues/1689): 修复 vsxmake 插件的 unicode 字符显示和加载问题
## v2.5.7
### 新特性
* [#1534](https://github.com/xmake-io/xmake/issues/1534): 新增对 Vala 语言的支持
* [#1544](https://github.com/xmake-io/xmake/issues/1544): 添加 utils.bin2c 规则去自动从二进制资源文件产生 .h 头文件并引入到 C/C++ 代码中
* [#1547](https://github.com/xmake-io/xmake/issues/1547): option/snippets 支持运行检测模式,并且可以获取输出
* [#1567](https://github.com/xmake-io/xmake/issues/1567): 新增 xmake-requires.lock 包依赖锁定支持
* [#1597](https://github.com/xmake-io/xmake/issues/1597): 支持编译 metal 文件到 metallib,并改进 xcode.application 规则去生成内置的 default.metallib 到 app
### 改进
* [#1540](https://github.com/xmake-io/xmake/issues/1540): 更好更方便地编译自动生成的代码
* [#1578](https://github.com/xmake-io/xmake/issues/1578): 改进 add_repositories 去更好地支持相对路径
* [#1582](https://github.com/xmake-io/xmake/issues/1582): 改进安装和 os.cp 支持符号链接
### Bugs 修复
* [#1531](https://github.com/xmake-io/xmake/issues/1531): 修复 targets 加载失败的错误信息提示错误
## v2.5.6
### 新特性
* [#1483](https://github.com/xmake-io/xmake/issues/1483): 添加 `os.joinenvs()` 和改进包工具环境
* [#1523](https://github.com/xmake-io/xmake/issues/1523): 添加 `set_allowedmodes`, `set_allowedplats` 和 `set_allowedarchs`
* [#1523](https://github.com/xmake-io/xmake/issues/1523): 添加 `set_defaultmode`, `set_defaultplat` 和 `set_defaultarch`
### 改进
* 改进 vs/vsxmake 工程插件支持 vs2022
* [#1513](https://github.com/xmake-io/xmake/issues/1513): 改进 windows 预编译包的兼容性问题
* 改进 vcpkg 包在 windows 上的查找
* 改进对 Qt6 的支持
### Bugs 修复
* [#489](https://github.com/xmake-io/xmake-repo/pull/489): 修复 run os.execv 带有过长环境变量值出现的一些问题
## v2.5.5
### 新特性
* [#1421](https://github.com/xmake-io/xmake/issues/1421): 针对 target 目标,增加目标文件名的前缀,后缀和扩展名设置接口。
* [#1422](https://github.com/xmake-io/xmake/issues/1422): 支持从 vcpkg, conan 中搜索包
* [#1424](https://github.com/xmake-io/xmake/issues/1424): 设置 binary 作为默认的 target 目标类型
* [#1140](https://github.com/xmake-io/xmake/issues/1140): 支持安装时候,手动选择从第三包包管理器安装包
* [#1339](https://github.com/xmake-io/xmake/issues/1339): 改进 `xmake package` 去产生新的本地包格式,无缝集成 `add_requires`,并且新增生成远程包支持
* 添加 `appletvos` 编译平台支持, `xmake f -p appletvos`
* [#1437](https://github.com/xmake-io/xmake/issues/1437): 为包添加 headeronly 库类型去忽略 `vs_runtime`
* [#1351](https://github.com/xmake-io/xmake/issues/1351): 支持导入导出当前配置
* [#1454](https://github.com/xmake-io/xmake/issues/1454): 支持下载安装 windows 预编译包
### 改进
* [#1425](https://github.com/xmake-io/xmake/issues/1425): 改进 tools/meson 去加载 msvc 环境,并且增加一些内置配置。
* [#1442](https://github.com/xmake-io/xmake/issues/1442): 支持从 git url 去下载包资源文件
* [#1389](https://github.com/xmake-io/xmake/issues/1389): 支持添加工具链环境到 `xrepo env`
* [#1453](https://github.com/xmake-io/xmake/issues/1453): 支持 protobuf 规则导出头文件搜索目录
* 新增对 vs2022 的支持
### Bugs 修复
* [#1413](https://github.com/xmake-io/xmake/issues/1413): 修复查找包过程中出现的挂起卡死问题
* [#1420](https://github.com/xmake-io/xmake/issues/1420): 修复包检测和配置缓存
* [#1445](https://github.com/xmake-io/xmake/issues/1445): 修复 WDK 驱动签名错误
* [#1465](https://github.com/xmake-io/xmake/issues/1465): 修复缺失的链接目录
## v2.5.4
### 新特性
* [#1323](https://github.com/xmake-io/xmake/issues/1323): 支持从 apt 查找安装包,`add_requires("apt::zlib1g-dev")`
* [#1337](https://github.com/xmake-io/xmake/issues/1337): 添加环境变量去改进包安装和缓存目录
* [#1338](https://github.com/xmake-io/xmake/issues/1338): 支持导入导出已安装的包
* [#1087](https://github.com/xmake-io/xmake/issues/1087): 添加 `xrepo env shell` 并且支持从 `add_requires/xmake.lua` 加载包环境
* [#1313](https://github.com/xmake-io/xmake/issues/1313): 为 `add_requires/add_deps` 添加私有包支持
* [#1358](https://github.com/xmake-io/xmake/issues/1358): 支持设置镜像 url 站点加速包下载
* [#1369](https://github.com/xmake-io/xmake/pull/1369): 为 vcpkg 增加 arm/arm64 包集成支持,感谢 @fallending
* [#1405](https://github.com/xmake-io/xmake/pull/1405): 添加 portage 包管理器支持,感谢 @Phate6660
### 改进
* 改进 `find_package` 并且添加 `package:find_package` 接口在包定义中方便查找包
* 移除废弃的 `set_config_h` 和 `set_config_h_prefix` 接口
* [#1343](https://github.com/xmake-io/xmake/issues/1343): 改进搜索本地包文件
* [#1347](https://github.com/xmake-io/xmake/issues/1347): 针对 binary 包改进 vs_runtime 配置
* [#1353](https://github.com/xmake-io/xmake/issues/1353): 改进 del_files() 去加速匹配文件
* [#1349](https://github.com/xmake-io/xmake/issues/1349): 改进 xrepo env shell 支持,更好的支持 powershell
### Bugs 修复
* [#1380](https://github.com/xmake-io/xmake/issues/1380): 修复 `add_packages()` 失败问题
* [#1381](https://github.com/xmake-io/xmake/issues/1381): 修复添加本地 git 包源问题
* [#1391](https://github.com/xmake-io/xmake/issues/1391): 修复 cuda/nvcc 工具链
## v2.5.3
### 新特性
* [#1259](https://github.com/xmake-io/xmake/issues/1259): 支持 `add_files("*.def")` 添加 def 文件去导出 windows/dll 符号
* [#1267](https://github.com/xmake-io/xmake/issues/1267): 添加 `find_package("nvtx")`
* [#1274](https://github.com/xmake-io/xmake/issues/1274): 添加 `platform.linux.bpf` 规则去构建 linux/bpf 程序
* [#1280](https://github.com/xmake-io/xmake/issues/1280): 支持 fetchonly 包去扩展改进 find_package
* 支持自动拉取远程 ndk 工具链包和集成
* [#1268](https://github.com/xmake-io/xmake/issues/1268): 添加 `utils.install.pkgconfig_importfiles` 规则去安装 `*.pc` 文件
* [#1268](https://github.com/xmake-io/xmake/issues/1268): 添加 `utils.install.cmake_importfiles` 规则去安装 `*.cmake` 导入文件
* [#348](https://github.com/xmake-io/xmake-repo/pull/348): 添加 `platform.longpaths` 策略去支持 git longpaths
* [#1314](https://github.com/xmake-io/xmake/issues/1314): 支持安装使用 conda 包
* [#1120](https://github.com/xmake-io/xmake/issues/1120): 添加 `core.base.cpu` 模块并且改进 `os.cpuinfo()`
* [#1325](https://github.com/xmake-io/xmake/issues/1325): 为 `add_configfiles` 添加内建的 git 变量
### 改进
* [#1275](https://github.com/xmake-io/xmake/issues/1275): 改进 vsxmake 生成器,支持条件化编译 targets
* [#1290](https://github.com/xmake-io/xmake/pull/1290): 增加对 Android ndk r22 以上版本支持
* [#1311](https://github.com/xmake-io/xmake/issues/1311): 为 vsxmake 工程添加包 dll 路径,确保调试运行加载正常
### Bugs 修复
* [#1266](https://github.com/xmake-io/xmake/issues/1266): 修复在 `add_repositories` 中的 repo 相对路径
* [#1288](https://github.com/xmake-io/xmake/issues/1288): 修复 vsxmake 插件处理 option 配置问题
## v2.5.2
### 新特性
* [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-766481512): 支持 `zig cc` 和 `zig c++` 作为 c/c++ 编译器
* [#955](https://github.com/xmake-io/xmake/issues/955#issuecomment-768193083): 支持使用 zig 进行交叉编译
* [#1177](https://github.com/xmake-io/xmake/issues/1177): 改进终端和 color codes 探测
* [#1216](https://github.com/xmake-io/xmake/issues/1216): 传递自定义 includes 脚本给 xrepo
* 添加 linuxos 内置模块获取 linux 系统信息
* [#1217](https://github.com/xmake-io/xmake/issues/1217): 支持当编译项目时自动拉取工具链
* [#1123](https://github.com/xmake-io/xmake/issues/1123): 添加 `rule("utils.symbols.export_all")` 自动导出所有 windows/dll 中的符号
* [#1181](https://github.com/xmake-io/xmake/issues/1181): 添加 `utils.platform.gnu2mslib(mslib, gnulib)` 模块接口去转换 mingw/xxx.dll.a 到 msvc xxx.lib
* [#1246](https://github.com/xmake-io/xmake/issues/1246): 改进规则支持新的批处理命令去简化自定义规则实现
* [#1239](https://github.com/xmake-io/xmake/issues/1239): 添加 `add_extsources` 去改进外部包的查找
* [#1241](https://github.com/xmake-io/xmake/issues/1241): 支持为 windows 程序添加 .manifest 文件参与链接
* 支持使用 `xrepo remove --all` 命令去移除所有的包,并且支持模式匹配
* [#1254](https://github.com/xmake-io/xmake/issues/1254): 支持导出包配置给父 target,实现包配置的依赖继承
### 改进
* [#1226](https://github.com/xmake-io/xmake/issues/1226): 添加缺失的 Qt 头文件搜索路径
* [#1183](https://github.com/xmake-io/xmake/issues/1183): 改进 C++ 语言标准,以便支持 Qt6
* [#1237](https://github.com/xmake-io/xmake/issues/1237): 为 vsxmake 插件添加 qt.ui 文件
* 改进 vs/vsxmake 插件去支持预编译头文件和智能提示
* [#1090](https://github.com/xmake-io/xmake/issues/1090): 简化自定义规则
* [#1065](https://github.com/xmake-io/xmake/issues/1065): 改进 protobuf 规则,支持 compile_commands 生成器
* [#1249](https://github.com/xmake-io/xmake/issues/1249): 改进 vs/vsxmake 生成器去支持启动工程设置
* [#605](https://github.com/xmake-io/xmake/issues/605): 改进 add_deps 和 add_packages 直接的导出 links 顺序
* 移除废弃的 `add_defines_h_if_ok` and `add_defines_h` 接口
### Bugs 修复
* [#1219](https://github.com/xmake-io/xmake/issues/1219): 修复版本检测和更新
* [#1235](https://github.com/xmake-io/xmake/issues/1235): 修复 includes 搜索路径中带有空格编译不过问题
## v2.5.1
### 新特性
* [#1035](https://github.com/xmake-io/xmake/issues/1035): 图形配置菜单完整支持鼠标事件,并且新增滚动栏
* [#1098](https://github.com/xmake-io/xmake/issues/1098): 支持传递 stdin 到 os.execv 进行输入重定向
* [#1079](https://github.com/xmake-io/xmake/issues/1079): 为 vsxmake 插件添加工程自动更新插件,`add_rules("plugin.vsxmake.autoupdate")`
* 添加 `xmake f --vs_runtime=MT` 和 `set_runtimes("MT")` 去更方便的对 target 和 package 进行设置
* [#1032](https://github.com/xmake-io/xmake/issues/1032): 支持枚举注册表 keys 和 values
* [#1026](https://github.com/xmake-io/xmake/issues/1026): 支持对 vs/vsmake 工程增加分组设置
* [#1178](https://github.com/xmake-io/xmake/issues/1178): 添加 `add_requireconfs()` 接口去重写依赖包的配置
* [#1043](https://github.com/xmake-io/xmake/issues/1043): 为 luarocks 模块添加 `luarocks.module` 构建规则
* [#1190](https://github.com/xmake-io/xmake/issues/1190): 添加对 Apple Silicon (macOS ARM) 设备的支持
* [#1145](https://github.com/xmake-io/xmake/pull/1145): 支持在 windows 上安装部署 Qt 程序, 感谢 @SirLynix
### 改进
* [#1072](https://github.com/xmake-io/xmake/issues/1072): 修复并改进 cl 编译器头文件依赖信息
* 针对 ui 模块和 `xmake f --menu` 增加 utf8 支持
* 改进 zig 语言在 macOS 上的支持
* [#1135](https://github.com/xmake-io/xmake/issues/1135): 针对特定 target 改进多平台多工具链同时配置支持
* [#1153](https://github.com/xmake-io/xmake/issues/1153): 改进 llvm 工具链,针对 macos 上编译增加 isysroot 支持
* [#1071](https://github.com/xmake-io/xmake/issues/1071): 改进 vs/vsxmake 生成插件去支持远程依赖包
* 改进 vs/vsxmake 工程生成插件去支持全局的 `set_arch()` 设置
* [#1164](https://github.com/xmake-io/xmake/issues/1164): 改进 vsxmake 插件调试加载 console 程序
* [#1179](https://github.com/xmake-io/xmake/issues/1179): 改进 llvm 工具链,添加 isysroot
### Bugs 修复
* [#1091](https://github.com/xmake-io/xmake/issues/1091): 修复不正确的继承链接依赖
* [#1105](https://github.com/xmake-io/xmake/issues/1105): 修复 vsxmake 插件 c++ 语言标准智能提示错误
* [#1132](https://github.com/xmake-io/xmake/issues/1132): 修复 vsxmake 插件中配置路径被截断问题
* [#1142](https://github.com/xmake-io/xmake/issues/1142): 修复安装包的时候,出现git找不到问题
* 修复在 macOS Big Sur 上 macos.version 问题
* [#1084](https://github.com/xmake-io/xmake/issues/1084): 修复 `add_defines()` 中带有双引号和空格导致无法正确处理宏定义的问题
* [#1195](https://github.com/xmake-io/xmake/pull/1195): 修复 unicode 编码问题,改进 vs 环境查找和进程执行
## v2.3.9
### 新特性
* 添加新的 [xrepo](https://github.com/xmake-io/xrepo) 命令去管理安装 C/C++ 包
* 支持安装交叉编译的依赖包
* 新增musl.cc上的工具链支持
* [#1009](https://github.com/xmake-io/xmake/issues/1009): 支持忽略校验去安装任意版本的包,`add_requires("libcurl 7.73.0", {verify = false})`
* [#1016](https://github.com/xmake-io/xmake/issues/1016): 针对依赖包增加license兼容性检测
* [#1017](https://github.com/xmake-io/xmake/issues/1017): 支持外部/系统头文件支持 `add_sysincludedirs`,依赖包默认使用`-isystem`
* [#1020](https://github.com/xmake-io/xmake/issues/1020): 支持在 archlinux 和 msys2 上查找安装 pacman 包
* 改进 `xmake f --menu` 菜单配置,支持鼠标操作
### 改进
* [#997](https://github.com/xmake-io/xmake/issues/997): `xmake project -k cmake` 插件增加对 `set_languages` 的支持
* [#998](https://github.com/xmake-io/xmake/issues/998): 支持安装 windows-static-md 类型的 vcpkg 包
* [#996](https://github.com/xmake-io/xmake/issues/996): 改进 vcpkg 目录查找
* [#1008](https://github.com/xmake-io/xmake/issues/1008): 改进交叉编译工具链
* [#1030](https://github.com/xmake-io/xmake/issues/1030): 改进 xcode.framework and xcode.application 规则
* [#1051](https://github.com/xmake-io/xmake/issues/1051): 为 msvc 编译器添加 `edit` 和 `embed` 调试信息格式类型到 `set_symbols()`
* [#1062](https://github.com/xmake-io/xmake/issues/1062): 改进 `xmake project -k vs` 插件
## v2.3.8
### 新特性
* [#955](https://github.com/xmake-io/xmake/issues/955): 添加 Zig 空工程模板
* [#956](https://github.com/xmake-io/xmake/issues/956): 添加 Wasm 编译平台,并且支持 Qt/Wasm SDK
* 升级luajit到v2.1最新分支版本,并且支持mips64上运行xmake
* [#972](https://github.com/xmake-io/xmake/issues/972): 添加`depend.on_changed()`去简化依赖文件的处理
* [#981](https://github.com/xmake-io/xmake/issues/981): 添加`set_fpmodels()`去抽象化设置math/float-point编译优化模式
* [#980](https://github.com/xmake-io/xmake/issues/980): 添加对 Intel C/C++ 和 Fortran 编译器的全平台支持
* [#986](https://github.com/xmake-io/xmake/issues/986): 对16.8以上msvc编译器增加 `c11`/`c17` 支持
* [#979](https://github.com/xmake-io/xmake/issues/979): 添加对OpenMP的跨平台抽象配置。`add_rules("c++.openmp")`
### 改进
* [#958](https://github.com/xmake-io/xmake/issues/958): 改进mingw平台,增加对 llvm-mingw 工具链的支持,以及 arm64/arm 架构的支持
* 增加 `add_requires("zlib~xxx")` 模式使得能够支持同时安装带有多种配置的同一个包,作为独立包存在
* [#977](https://github.com/xmake-io/xmake/issues/977): 改进 find_mingw 在 windows 上的探测
* [#978](https://github.com/xmake-io/xmake/issues/978): 改进工具链的flags顺序
* 改进XCode工具链,支持macOS/arm64
### Bugs 修复
* [#951](https://github.com/xmake-io/xmake/issues/951): 修复 emcc (WebAssembly) 工具链在windows上的支持
* [#992](https://github.com/xmake-io/xmake/issues/992): 修复文件锁偶尔打开失败问题
## v2.3.7
### 新特性
* [#2941](https://github.com/microsoft/winget-pkgs/pull/2941): 支持通过 winget 来安装 xmake
* 添加 xmake-tinyc 安装包,内置tinyc编译器,支持windows上无msvc环境也可直接编译c代码
* 添加 tinyc 编译工具链
* 添加 emcc (emscripten) 编译工具链去编译 asm.js 和 WebAssembly
* [#947](https://github.com/xmake-io/xmake/issues/947): 通过 `xmake g --network=private` 配置设置私有网络模式,避免远程依赖包下载访问外网导致编译失败
### 改进
* [#907](https://github.com/xmake-io/xmake/issues/907): 改进msvc的链接器优化选项,生成更小的可执行程序
* 改进ubuntu下Qt环境的支持
* [#918](https://github.com/xmake-io/xmake/pull/918): 改进cuda11工具链的支持
* 改进Qt支持,对通过 ubuntu/apt 安装的Qt sdk也进行了探测支持,并且检测效率也优化了下
* 改进 CMake 工程文件生成器
* [#931](https://github.com/xmake-io/xmake/issues/931): 改进导出包,支持导出所有依赖包
* [#930](https://github.com/xmake-io/xmake/issues/930): 如果私有包定义没有版本定义,支持直接尝试下载包
* [#927](https://github.com/xmake-io/xmake/issues/927): 改进android ndk,支持arm/thumb指令模式切换
* 改进 trybuild/cmake 支持 Android/Mingw/iPhoneOS/WatchOS 工具链
### Bugs 修复
* [#903](https://github.com/xmake-io/xmake/issues/903): 修复vcpkg包安装失败问题
* [#912](https://github.com/xmake-io/xmake/issues/912): 修复自定义工具链
* [#914](https://github.com/xmake-io/xmake/issues/914): 修复部分aarch64设备上运行lua出现bad light userdata pointer问题
## v2.3.6
### 新特性
* 添加xcode工程生成器插件,`xmake project -k cmake` (当前采用cmake生成)
* [#870](https://github.com/xmake-io/xmake/issues/870): 支持gfortran编译器
* [#887](https://github.com/xmake-io/xmake/pull/887): 支持zig编译器
* [#893](https://github.com/xmake-io/xmake/issues/893): 添加json模块
* [#898](https://github.com/xmake-io/xmake/issues/898): 改进golang项目构建,支持交叉编译
* [#275](https://github.com/xmake-io/xmake/issues/275): 支持go包管理器去集成第三方go依赖包
* [#581](https://github.com/xmake-io/xmake/issues/581): 支持dub包管理器去集成第三方dlang依赖包
### 改进
* [#868](https://github.com/xmake-io/xmake/issues/868): 支持新的cl.exe的头文件依赖输出文件格式,`/sourceDependencies xxx.json`
* [#902](https://github.com/xmake-io/xmake/issues/902): 改进交叉编译工具链
## v2.3.5
### 新特性
* 添加`xmake show -l envs`去显示xmake内置的环境变量列表
* [#861](https://github.com/xmake-io/xmake/issues/861): 支持从指定目录搜索本地包去直接安装远程依赖包
* [#854](https://github.com/xmake-io/xmake/issues/854): 针对wget, curl和git支持全局代理设置
### 改进
* [#828](https://github.com/xmake-io/xmake/issues/828): 针对protobuf规则增加导入子目录proto文件支持
* [#835](https://github.com/xmake-io/xmake/issues/835): 改进mode.minsizerel模式,针对msvc增加/GL支持,进一步优化目标程序大小
* [#828](https://github.com/xmake-io/xmake/issues/828): protobuf规则支持import多级子目录
* [#838](https://github.com/xmake-io/xmake/issues/838#issuecomment-643570920): 支持完全重写内置的构建规则,`add_files("src/*.c", {rules = {"xx", override = true}})`
* [#847](https://github.com/xmake-io/xmake/issues/847): 支持rc文件的头文件依赖解析
* 改进msvc工具链,去除全局环境变量的依赖
* [#857](https://github.com/xmake-io/xmake/pull/857): 改进`set_toolchains()`支持交叉编译的时候,特定target可以切换到host工具链同时编译
### Bugs 修复
* 修复进度字符显示
* [#829](https://github.com/xmake-io/xmake/issues/829): 修复由于macOS大小写不敏感系统导致的sysroot无效路径问题
* [#832](https://github.com/xmake-io/xmake/issues/832): 修复find_packages在debug模式下找不到的问题
## v2.3.4
### 新特性
* [#630](https://github.com/xmake-io/xmake/issues/630): 支持*BSD系统,例如:FreeBSD, ..
* 添加wprint接口去显示警告信息
* [#784](https://github.com/xmake-io/xmake/issues/784): 添加`set_policy()`去设置修改一些内置的策略,比如:禁用自动flags检测和映射
* [#780](https://github.com/xmake-io/xmake/issues/780): 针对target添加set_toolchains/set_toolsets实现更完善的工具链设置,并且实现platform和toolchains分离
* [#798](https://github.com/xmake-io/xmake/issues/798): 添加`xmake show`插件去显示xmake内置的各种信息
* [#797](https://github.com/xmake-io/xmake/issues/797): 添加ninja主题风格,显示ninja风格的构建进度条,`xmake g --theme=ninja`
* [#816](https://github.com/xmake-io/xmake/issues/816): 添加mode.releasedbg和mode.minsizerel编译模式规则
* [#819](https://github.com/xmake-io/xmake/issues/819): 支持ansi/vt100终端字符控制
### 改进
* [#771](https://github.com/xmake-io/xmake/issues/771): 检测includedirs,linkdirs和frameworkdirs的输入有效性
* [#774](https://github.com/xmake-io/xmake/issues/774): `xmake f --menu`可视化配置菜单支持窗口大小Resize调整
* [#782](https://github.com/xmake-io/xmake/issues/782): 添加add_cxflags等配置flags自动检测失败提示
* [#808](https://github.com/xmake-io/xmake/issues/808): 生成cmakelists插件增加对add_frameworks的支持
* [#820](https://github.com/xmake-io/xmake/issues/820): 支持独立的工作目录和构建目录,保持项目目录完全干净
### Bugs 修复
* [#786](https://github.com/xmake-io/xmake/issues/786): 修复头文件依赖检测
* [#810](https://github.com/xmake-io/xmake/issues/810): 修复linux下gcc strip debug符号问题
## v2.3.3
### 新特性
* [#727](https://github.com/xmake-io/xmake/issues/727): 支持为android, ios程序生成.so/.dSYM符号文件
* [#687](https://github.com/xmake-io/xmake/issues/687): 支持编译生成objc/bundle程序
* [#743](https://github.com/xmake-io/xmake/issues/743): 支持编译生成objc/framework程序
* 支持编译bundle, framework程序,以及mac, ios应用程序,并新增一些工程模板
* 支持对ios应用程序打包生成ipa文件,以及代码签名支持
* 增加一些ipa打包、安装、重签名等辅助工具
* 添加xmake.cli规则来支持开发带有xmake/core引擎的lua扩展程序
### 改进
* [#750](https://github.com/xmake-io/xmake/issues/750): 改进qt.widgetapp规则,支持qt私有槽
* 改进Qt/android的apk部署,并且支持Qt5.14.0新版本sdk
## v2.3.2
### 新特性
* 添加powershell色彩主题用于powershell终端下背景色显示
* 添加`xmake --dry-run -v`命令去空运行构建,仅仅为了查看详细的构建命令
* [#712](https://github.com/xmake-io/xmake/issues/712): 添加sdcc平台,并且支持sdcc编译器
### 改进
* [#589](https://github.com/xmake-io/xmake/issues/589): 改进优化构建速度,支持跨目标间并行编译和link,编译速度和ninja基本持平
* 改进ninja/cmake工程文件生成器插件
* [#728](https://github.com/xmake-io/xmake/issues/728): 改进os.cp支持保留源目录结构层级的递归复制
* [#732](https://github.com/xmake-io/xmake/issues/732): 改进find_package支持查找homebrew/cmake安装的包
* [#695](https://github.com/xmake-io/xmake/issues/695): 改进采用android ndk最新的abi命名
### Bugs 修复
* 修复windows下link error显示问题
* [#718](https://github.com/xmake-io/xmake/issues/718): 修复依赖包下载在多镜像时一定概率缓存失效问题
* [#722](https://github.com/xmake-io/xmake/issues/722): 修复无效的包依赖导致安装死循环问题
* [#719](https://github.com/xmake-io/xmake/issues/719): 修复windows下主进程收到ctrlc后,.bat子进程没能立即退出的问题
* [#720](https://github.com/xmake-io/xmake/issues/720): 修复compile_commands生成器的路径转义问题
## v2.3.1
### 新特性
* [#675](https://github.com/xmake-io/xmake/issues/675): 支持通过设置强制将`*.c`作为c++代码编译, `add_files("*.c", {sourcekind = "cxx"})`。
* [#681](https://github.com/xmake-io/xmake/issues/681): 支持在msys/cygwin上编译xmake,以及添加msys/cygwin编译平台
* 添加socket/pipe模块,并且支持在协程中同时调度process/socket/pipe
* [#192](https://github.com/xmake-io/xmake/issues/192): 尝试构建带有第三方构建系统的项目,还支持autotools项目的交叉编译
* 启用gcc/clang的编译错误色彩高亮输出
* [#588](https://github.com/xmake-io/xmake/issues/588): 改进工程生成插件`xmake project -k ninja`,增加对build.ninja生成支持
### 改进
* [#665](https://github.com/xmake-io/xmake/issues/665): 支持 *nix style 的参数输入,感谢[@OpportunityLiu](https://github.com/OpportunityLiu)的贡献
* [#673](https://github.com/xmake-io/xmake/pull/673): 改进tab命令补全,增加对参数values的补全支持
* [#680](https://github.com/xmake-io/xmake/issues/680): 优化get.sh安装脚本,添加国内镜像源,加速下载
* 改进process调度器
* [#651](https://github.com/xmake-io/xmake/issues/651): 改进os/io模块系统操作错误提示
### Bugs 修复
* 修复增量编译检测依赖文件的一些问题
* 修复log输出导致xmake-vscode插件解析编译错误信息失败问题
* [#684](https://github.com/xmake-io/xmake/issues/684): 修复windows下android ndk的一些linker错误
## v2.2.9
### 新特性
* [#569](https://github.com/xmake-io/xmake/pull/569): 增加对c++模块的实验性支持
* 添加`xmake project -k xmakefile`生成器
* [620](https://github.com/xmake-io/xmake/issues/620): 添加全局`~/.xmakerc.lua`配置文件,对所有本地工程生效.
* [593](https://github.com/xmake-io/xmake/pull/593): 添加`core.base.socket`模块,为下一步远程编译和分布式编译做准备。
### 改进
* [#563](https://github.com/xmake-io/xmake/pull/563): 重构构建逻辑,将特定语言的构建抽离到独立的rules中去
* [#570](https://github.com/xmake-io/xmake/issues/570): 改进Qt构建,将`qt.application`拆分成`qt.widgetapp`和`qt.quickapp`两个构建规则
* [#576](https://github.com/xmake-io/xmake/issues/576): 使用`set_toolchain`替代`add_tools`和`set_tools`,解决老接口使用歧义,提供更加易理解的设置方式
* 改进`xmake create`创建模板工程
* [#589](https://github.com/xmake-io/xmake/issues/589): 改进默认的构建任务数,充分利用cpu core来提速整体编译速度
* [#598](https://github.com/xmake-io/xmake/issues/598): 改进`find_package`支持在macOS上对.tbd系统库文件的查找
* [#615](https://github.com/xmake-io/xmake/issues/615): 支持安装和使用其他arch和ios的conan包
* [#629](https://github.com/xmake-io/xmake/issues/629): 改进hash.uuid并且实现uuid v4
* [#639](https://github.com/xmake-io/xmake/issues/639): 改进参数解析器支持`-jN`风格传参
### Bugs 修复
* [#567](https://github.com/xmake-io/xmake/issues/567): 修复序列化对象时候出现的内存溢出问题
* [#566](https://github.com/xmake-io/xmake/issues/566): 修复安装远程依赖的链接顺序问题
* [#565](https://github.com/xmake-io/xmake/issues/565): 修复vcpkg包的运行PATH设置问题
* [#597](https://github.com/xmake-io/xmake/issues/597): 修复xmake require安装包时间过长问题
* [#634](https://github.com/xmake-io/xmake/issues/634): 修复mode.coverage构建规则,并且改进flags检测
## v2.2.8
### 新特性
* 添加protobuf c/c++构建规则
* [#468](https://github.com/xmake-io/xmake/pull/468): 添加对 Windows 的 UTF-8 支持
* [#472](https://github.com/xmake-io/xmake/pull/472): 添加`xmake project -k vsxmake`去更好的支持vs工程的生成,内部直接调用xmake来编译
* [#487](https://github.com/xmake-io/xmake/issues/487): 通过`xmake --files="src/*.c"`支持指定一批文件进行编译。
* 针对io模块增加文件锁接口
* [#513](https://github.com/xmake-io/xmake/issues/513): 增加对android/termux终端的支持,可在android设备上执行xmake来构建项目
* [#517](https://github.com/xmake-io/xmake/issues/517): 为target增加`add_cleanfiles`接口,实现快速定制化清理文件
* [#537](https://github.com/xmake-io/xmake/pull/537): 添加`set_runenv`接口去覆盖写入系统envs
### 改进
* [#257](https://github.com/xmake-io/xmake/issues/257): 锁定当前正在构建的工程,避免其他xmake进程同时对其操作
* 尝试采用/dev/shm作为os.tmpdir去改善构建过程中临时文件的读写效率
* [#542](https://github.com/xmake-io/xmake/pull/542): 改进vs系列工具链的unicode输出问题
* 对于安装的lua脚本,启用lua字节码存储,减少安装包大小(<2.4M),提高运行加载效率。
### Bugs 修复
* [#549](https://github.com/xmake-io/xmake/issues/549): 修复新版vs2019下检测环境会卡死的问题
## v2.2.7
### 新特性
* [#455](https://github.com/xmake-io/xmake/pull/455): 支持使用 clang 作为 cuda 编译器,`xmake f --cu=clang`
* [#440](https://github.com/xmake-io/xmake/issues/440): 为target/run添加`set_rundir()`和`add_runenvs()`接口设置
* [#443](https://github.com/xmake-io/xmake/pull/443): 添加命令行tab自动完成支持
* 为rule/target添加`on_link`,`before_link`和`after_link`阶段自定义脚本支持
* [#190](https://github.com/xmake-io/xmake/issues/190): 添加`add_rules("lex", "yacc")`规则去支持lex/yacc项目
### 改进
* [#430](https://github.com/xmake-io/xmake/pull/430): 添加`add_cugencodes()`api为cuda改进设置codegen
* [#432](https://github.com/xmake-io/xmake/pull/432): 针对cuda编译支持依赖分析检测(仅支持 CUDA 10.1+)
* [#437](https://github.com/xmake-io/xmake/issues/437): 支持指定更新源,`xmake update github:xmake-io/xmake#dev`
* [#438](https://github.com/xmake-io/xmake/pull/438): 支持仅更新脚本,`xmake update --scriptonly dev`
* [#433](https://github.com/xmake-io/xmake/issues/433): 改进cuda构建支持device-link设备代码链接
* [#442](https://github.com/xmake-io/xmake/issues/442): 改进tests测试框架
## v2.2.6
### 新特性
* [#380](https://github.com/xmake-io/xmake/pull/380): 添加导出compile_flags.txt
* [#382](https://github.com/xmake-io/xmake/issues/382): 简化域设置语法
* [#397](https://github.com/xmake-io/xmake/issues/397): 添加clib包集成支持
* [#404](https://github.com/xmake-io/xmake/issues/404): 增加Qt/Android编译支持,并且支持android apk生成和部署
* 添加一些Qt空工程模板,例如:`widgetapp_qt`, `quickapp_qt_static` and `widgetapp_qt_static`
* [#415](https://github.com/xmake-io/xmake/issues/415): 添加`--cu-cxx`配置参数到`nvcc/-ccbin`
* 为Android NDK添加`--ndk_stdcxx=y`和`--ndk_cxxstl=gnustl_static`参数选项
### 改进
* 改进远程依赖包管理,丰富包仓库
* 改进`target:on_xxx`自定义脚本,去支持匹配`android|armv7-a@macosx,linux|x86_64`模式
* 改进loadfile,优化启动速度,windows上启动xmake时间提速98%
### Bugs 修复
* [#400](https://github.com/xmake-io/xmake/issues/400): 修复qt项目c++语言标准设置无效问题
## v2.2.5
### 新特性
* 添加`string.serialize`和`string.deserialize`去序列化,反序列化对象,函数以及其他类型
* 添加`xmake g --menu`去图形化配置全局选项
* [#283](https://github.com/xmake-io/xmake/issues/283): 添加`target:installdir()`和`set_installdir()`接口
* [#260](https://github.com/xmake-io/xmake/issues/260): 添加`add_platformdirs`接口,用户现在可以自定义扩展编译平台
* [#310](https://github.com/xmake-io/xmake/issues/310): 新增主题设置支持,用户可随意切换和扩展主题样式
* [#318](https://github.com/xmake-io/xmake/issues/318): 添加`add_installfiles`接口到target去自定义安装文件
* [#339](https://github.com/xmake-io/xmake/issues/339): 改进`add_requires`和`find_package`使其支持对第三方包管理的集成支持
* [#327](https://github.com/xmake-io/xmake/issues/327): 实现对conan包管理的集成支持
* 添加内置API `find_packages("pcre2", "zlib")`去同时查找多个依赖包,不需要通过import导入即可直接调用
* [#320](https://github.com/xmake-io/xmake/issues/320): 添加模板配置文件相关接口,`add_configfiles`和`set_configvar`
* [#179](https://github.com/xmake-io/xmake/issues/179): 扩展`xmake project`插件,新增CMakelist.txt生成支持
* [#361](https://github.com/xmake-io/xmake/issues/361): 增加对vs2019 preview的支持
* [#368](https://github.com/xmake-io/xmake/issues/368): 支持`private, public, interface`属性设置去继承target配置
* [#284](https://github.com/xmake-io/xmake/issues/284): 通过`add_configs()`添加和传递用户自定义配置到`package()`
* [#319](https://github.com/xmake-io/xmake/issues/319): 添加`add_headerfiles`接口去改进头文件的设置
* [#342](https://github.com/xmake-io/xmake/issues/342): 为`includes()`添加一些内置的辅助函数,例如:`check_cfuncs`
### 改进
* 针对远程依赖包,改进版本和调试模式切换
* [#264](https://github.com/xmake-io/xmake/issues/264): 支持在windows上更新dev/master版本,`xmake update dev`
* [#293](https://github.com/xmake-io/xmake/issues/293): 添加`xmake f/g --mingw=xxx` 配置选线,并且改进find_mingw检测
* [#301](https://github.com/xmake-io/xmake/issues/301): 改进编译预处理头文件以及依赖头文件生成,编译速度提升30%
* [#322](https://github.com/xmake-io/xmake/issues/322): 添加`option.add_features`, `option.add_cxxsnippets` 和 `option.add_csnippets`
* 移除xmake 1.x的一些废弃接口, 例如:`add_option_xxx`
* [#327](https://github.com/xmake-io/xmake/issues/327): 改进`lib.detect.find_package`增加对conan包管理器的支持
* 改进`lib.detect.find_package`并且添加内建的`find_packages("zlib 1.x", "openssl", {xxx = ...})`接口
* 标记`set_modes()`作为废弃接口, 我们使用`add_rules("mode.debug", "mode.release")`来替代它
* [#353](https://github.com/xmake-io/xmake/issues/353): 改进`target:set`, `target:add` 并且添加`target:del`去动态修改target配置
* [#356](https://github.com/xmake-io/xmake/issues/356): 添加`qt_add_static_plugins()`接口去支持静态Qt sdk
* [#351](https://github.com/xmake-io/xmake/issues/351): 生成vs201x插件增加对yasm的支持
* 重构改进整个远程依赖包管理器,更加快速、稳定、可靠,并提供更多的常用包
### Bugs 修复
* 修复无法通过 `set_optimize()` 设置优化选项,如果存在`add_rules("mode.release")`的情况下
* [#289](https://github.com/xmake-io/xmake/issues/289): 修复在windows下解压gzip文件失败
* [#296](https://github.com/xmake-io/xmake/issues/296): 修复`option.add_includedirs`对cuda编译不生效
* [#321](https://github.com/xmake-io/xmake/issues/321): 修复PATH环境改动后查找工具不对问题
## v2.2.3
### 新特性
* [#233](https://github.com/xmake-io/xmake/issues/233): 对mingw平台增加windres的支持
* [#239](https://github.com/xmake-io/xmake/issues/239): 添加cparser编译器支持
* 添加插件管理器,`xmake plugin --help`
* 添加`add_syslinks`接口去设置系统库依赖,分离与`add_links`添加的库依赖之间的链接顺序
* 添加 `xmake l time xmake [--rebuild]` 去记录编译耗时
* [#250](https://github.com/xmake-io/xmake/issues/250): 添加`xmake f --vs_sdkver=10.0.15063.0`去改变windows sdk版本
* 添加`lib.luajit.ffi`和`lib.luajit.jit`扩展模块
* [#263](https://github.com/xmake-io/xmake/issues/263): 添加object目标类型,仅仅用于编译生成object对象文件
* [#269](https://github.com/xmake-io/xmake/issues/269): 每天第一次构建时候后台进程自动清理最近30天的临时文件
### 改进
* [#229](https://github.com/xmake-io/xmake/issues/229): 改进vs toolset选择已经vcproj工程文件生成
* 改进编译依赖,对源文件列表的改动进行依赖判断
* 支持解压*.xz文件
* [#249](https://github.com/xmake-io/xmake/pull/249): 改进编译进度信息显示格式
* [#247](https://github.com/xmake-io/xmake/pull/247): 添加`-D`和`--diagnosis`去替换`--backtrace`,改进诊断信息显示
* [#259](https://github.com/xmake-io/xmake/issues/259): 改进 on_build, on_build_file 和 on_xxx 等接口
* 改进远程包管理器,更加方便的包依赖配置切换
* 支持only头文件依赖包的安装
* 支持对包内置links的手动调整,`add_packages("xxx", {links = {}})`
### Bugs 修复
* 修复安装依赖包失败中断后的状态不一致性问题
## v2.2.2
### 新特性
* 新增fasm汇编器支持
* 添加`has_config`, `get_config`和`is_config`接口去快速判断option和配置值
* 添加`set_config`接口去设置默认配置
* 添加`$xmake --try`去尝试构建工程
* 添加`set_enabled(false)`去显示的禁用target
* [#69](https://github.com/xmake-io/xmake/issues/69): 添加远程依赖包管理, `add_requires("tbox ~1.6.1")`
* [#216](https://github.com/xmake-io/xmake/pull/216): 添加windows mfc编译规则
### 改进
* 改进Qt编译编译环境探测,增加对mingw sdk的支持
* 在自动扫描生成的xmake.lua中增加默认debug/release规则
* [#178](https://github.com/xmake-io/xmake/issues/178): 修改mingw平台下的目标名
* 对于`add_files()`在windows上支持大小写不敏感路径模式匹配
* 改进`detect.sdks.find_qt`对于Qt根目录的探测
* [#184](https://github.com/xmake-io/xmake/issues/184): 改进`lib.detect.find_package`支持vcpkg
* [#208](https://github.com/xmake-io/xmake/issues/208): 改进rpath对动态库的支持
* [#225](https://github.com/xmake-io/xmake/issues/225): 改进vs环境探测
### Bugs 修复
* [#177](https://github.com/xmake-io/xmake/issues/177): 修复被依赖的动态库target,如果设置了basename后链接失败问题
* 修复`$ xmake f --menu`中Exit问题以及cpu过高问题
* [#197](https://github.com/xmake-io/xmake/issues/197): 修复生成的vs201x工程文件带有中文路径乱码问题
* 修复WDK规则编译生成的驱动在Win7下运行蓝屏问题
* [#205](https://github.com/xmake-io/xmake/pull/205): 修复vcproj工程生成targetdir, objectdir路径设置不匹配问题
## v2.2.1
### 新特性
* [#158](https://github.com/xmake-io/xmake/issues/158): 增加对Cuda编译环境的支持
* 添加`set_tools`和`add_tools`接口为指定target目标设置编译工具链
* 添加内建规则:`mode.debug`, `mode.release`, `mode.profile`和`mode.check`
* 添加`is_mode`, `is_arch` 和`is_plat`内置接口到自定义脚本域
* 添加color256代码
* [#160](https://github.com/xmake-io/xmake/issues/160): 增加对Qt SDK编译环境的跨平台支持,并且增加`qt.console`, `qt.application`等规则
* 添加一些Qt工程模板
* [#169](https://github.com/xmake-io/xmake/issues/169): 支持yasm汇编器
* [#159](https://github.com/xmake-io/xmake/issues/159): 增加对WDK驱动编译环境支持
### 改进
* 添加FAQ到自动生成的xmake.lua文件,方便用户快速上手
* 支持Android NDK >= r14的版本
* 改进swiftc对warning flags的支持
* [#167](https://github.com/xmake-io/xmake/issues/167): 改进自定义规则:`rule()`
* 改进`os.files`和`os.dirs`接口,加速文件模式匹配
* [#171](https://github.com/xmake-io/xmake/issues/171): 改进Qt环境的构建依赖
* 在makefile生成插件中实现`make clean`
### Bugs 修复
* 修复无法通过`add_ldflags("xx", "xx", {force = true})`强制设置多个flags的问题
* [#157](https://github.com/xmake-io/xmake/issues/157): 修复pdb符号输出目录不存在情况下编译失败问题
* 修复对macho格式目标strip all符号失效问题
* [#168](https://github.com/xmake-io/xmake/issues/168): 修复生成vs201x工程插件,在x64下失败的问题
## v2.1.9
### 新特性
* 添加`del_files()`接口去从已添加的文件列表中移除一些文件
* 添加`rule()`, `add_rules()`接口实现自定义构建规则,并且改进`add_files("src/*.md", {rule = "markdown"})`
* 添加`os.filesize()`接口
* 添加`core.ui.xxx`等cui组件模块,实现终端可视化界面,用于实现跟用户进行短暂的交互
* 通过`xmake f --menu`实现可视化菜单交互配置,简化工程的编译配置
* 添加`set_values`接口到option
* 改进option,支持根据工程中用户自定义的option,自动生成可视化配置菜单
* 在调用api设置工程配置时以及在配置菜单中添加源文件位置信息
### 改进
* 改进交叉工具链配置,通过指定工具别名定向到已知的工具链来支持未知编译工具名配置, 例如: `xmake f --cc=gcc@ccmips.exe`
* [#151](https://github.com/xmake-io/xmake/issues/151): 改进mingw平台下动态库生成
* 改进生成makefile插件
* 改进检测错误提示
* 改进`add_cxflags`等flags api的设置,添加force参数,来禁用自动检测和映射,强制设置选项:`add_cxflags("-DTEST", {force = true})`
* 改进`add_files`的flags设置,添加force域,用于设置不带自动检测和映射的原始flags:`add_files("src/*.c", {force = {cxflags = "-DTEST"}})`
* 改进搜索工程根目录策略
* 改进vs环境探测,支持加密文件系统下vs环境的探测
* 升级luajit到最新2.1.0-beta3
* 增加对linux/arm, arm64的支持,可以在arm linux上运行xmake
* 改进vs201x工程生成插件,更好的includedirs设置支持
### Bugs 修复
* 修复依赖修改编译和链接问题
* [#151](https://github.com/xmake-io/xmake/issues/151): 修复`os.nuldev()`在mingw上传入gcc时出现问题
* [#150](https://github.com/xmake-io/xmake/issues/150): 修复windows下ar.exe打包过长obj列表参数,导致失败问题
* 修复`xmake f --cross`无法配置问题
* 修复`os.cd`到windows根路径问题
## v2.1.8
### 新特性
* 添加`XMAKE_LOGFILE`环境变量,启用输出到日志文件
* 添加对tinyc编译器的支持
### 改进
* 改进对IDE和编辑器插件的集成支持,例如:Visual Studio Code, Sublime Text 以及 IntelliJ IDEA
* 当生成新工程的时候,自动生成一个`.gitignore`文件,忽略一些xmake的临时文件和目录
* 改进创建模板工程,使用模板名代替模板id作为参数
* 改进macOS编译平台的探测,如果没有安装xcode也能够进行编译构建,如果有编译器的话
* 改进`set_config_header`接口,支持局部版本号设置,优先于全局`set_version`,例如:`set_config_header("config", {version = "2.1.8", build = "%Y%m%d%H%M"})`
### Bugs 修复
* [#145](https://github.com/xmake-io/xmake/issues/145): 修复运行target的当前目录环境
## v2.1.7
### 新特性
* 添加`add_imports`去为target,option和package的自定义脚本批量导入模块,简化自定义脚本
* 添加`xmake -y/--yes`去确认用户输入
* 添加`xmake l package.manager.install xxx`模块,进行跨平台一致性安装软件包
* 添加vscode编辑器插件支持,更加方便的使用xmake,[xmake-vscode](https://marketplace.visualstudio.com/items?itemName=tboox.xmake-vscode#overview)
* 添加`xmake macro ..`快速运行最近一次命令
### 改进
* 改进`cprint()`,支持24位真彩色输出
* 对`add_rpathdirs()`增加对`@loader_path`和`$ORIGIN`的内置变量支持,提供可迁移动态库加载
* 改进`set_version("x.x.x", {build = "%Y%m%d%H%M"})` 支持buildversion设置
* 移除docs目录,将其放置到独立xmake-docs仓库中,减少xmake.zip的大小,优化下载安装的效率
* 改进安装和卸载脚本,支持DESTDIR和PREFIX环境变量设置
* 通过缓存优化flags探测,加速编译效率
* 添加`COLORTERM=nocolor`环境变量开关,禁用彩色输出
* 移除`add_rbindings`和`add_bindings`接口
* 禁止在重定向的时候进行彩色输出,避免输出文件中带有色彩代码干扰
* 更新tbox工程模板
* 改进`lib.detect.find_program`模块接口
* 为windows cmd终端增加彩色输出
* 增加`-w|--warning`参数来启用实时警告输出
### Bugs 修复
* 修复`set_pcxxheader`编译没有继承flags配置问题
* [#140](https://github.com/xmake-io/xmake/issues/140): 修复`os.tmpdir()`在fakeroot下的冲突问题
* [#142](https://github.com/xmake-io/xmake/issues/142): 修复`os.getenv` 在windows上的中文编码问题
* 修复在带有空格路径的情况下,编译错误问题
* 修复setenv空值的崩溃问题
## v2.1.6
### 改进
* 改进`add_files`,支持对files粒度进行编译选项的各种配置,更加灵活。
* 从依赖的target和option中继承links和linkdirs。
* 改进`target.add_deps`接口,添加继承配置,允许手动禁止依赖继承,例如:`add_deps("test", {inherit = false})`
* 移除`tbox.pkg`二进制依赖,直接集成tbox源码进行编译
### Bugs 修复
* 修复目标级联依赖问题
* 修复`target:add`和`option:add`问题
* 修复在archlinux上的编译和安装问题
* 修复`/ZI`的兼容性问题,用`/Zi`替代
## v2.1.5
### 新特性
* [#83](https://github.com/xmake-io/xmake/issues/83): 添加 `add_csnippet`,`add_cxxsnippet`到`option`来检测一些编译器特性
* [#83](https://github.com/xmake-io/xmake/issues/83): 添加用户扩展模块去探测程序,库文件以及其他主机环境
* 添加`find_program`, `find_file`, `find_library`, `find_tool`和`find_package` 等模块接口
* 添加`net.*`和`devel.*`扩展模块
* 添加`val()`接口去获取内置变量,例如:`val("host")`, `val("env PATH")`, `val("shell echo hello")` and `val("reg HKEY_LOCAL_MACHINE\\XX;Value")`
* 增加对微软.rc资源文件的编译支持,当在windows上编译时,可以增加资源文件了
* 增加`has_flags`, `features`和`has_features`等探测模块接口
* 添加`option.on_check`, `option.after_check` 和 `option.before_check` 接口
* 添加`target.on_load`接口
* [#132](https://github.com/xmake-io/xmake/issues/132): 添加`add_frameworkdirs`接口
* 添加`lib.detect.has_xxx`和`lib.detect.find_xxx`接口
* 添加`add_moduledirs`接口在工程中定义和加载扩展模块
* 添加`includes`接口替换`add_subdirs`和`add_subfiles`
* [#133](https://github.com/xmake-io/xmake/issues/133): 改进工程插件,通过运行`xmake project -k compile_commands`来导出`compile_commands.json`
* 添加`set_pcheader`和`set_pcxxheader`去支持跨编译器预编译头文件,支持`gcc`, `clang`和`msvc`
* 添加`xmake f -p cross`平台用于交叉编译,并且支持自定义平台名
### 改进
* [#87](https://github.com/xmake-io/xmake/issues/87): 为依赖库目标自动添加:`includes` 和 `links`
* 改进`import`接口,去加载用户扩展模块
* [#93](https://github.com/xmake-io/xmake/pull/93): 改进 `xmake lua`,支持运行单行命令和模块
* 改进编译错误提示信息输出
* 改进`print`接口去更好些显示table数据
* [#111](https://github.com/xmake-io/xmake/issues/111): 添加`--root`通用选项去临时支持作为root运行
* [#113](https://github.com/xmake-io/xmake/pull/113): 改进权限管理,现在作为root运行也是非常安全的
* 改进`xxx_script`工程描述api,支持多平台模式选择, 例如:`on_build("iphoneos|arm*", function (target) end)`
* 改进内置变量,支持环境变量和注册表数据的获取
* 改进vstudio环境和交叉工具链的探测
* [#71](https://github.com/xmake-io/xmake/issues/71): 改进从环境变量中探测链接器和编译器
* 改进option选项检测,通过多任务检测,提升70%的检测速度
* [#129](https://github.com/xmake-io/xmake/issues/129): 检测链接依赖,如果源文件没有改变,就不必重新链接目标文件了
* 在vs201x工程插件中增加对`*.asm`文件的支持
* 标记`add_bindings`和`add_rbindings`为废弃接口
* 优化`xmake rebuild`在windows上的构建速度
* 将`core.project.task`模块迁移至`core.base.task`
* 将`echo` 和 `app2ipa` 插件迁移到 [xmake-plugins](https://github.com/xmake-io/xmake-plugins) 仓库
* 添加`set_config_header("config.h", {prefix = ""})` 代替 `set_config_h` 和 `set_config_h_prefix`
### Bugs 修复
* 修复`try-catch-finally`
* 修复解释器bug,解决当加载多级子目录时,根域属性设置不对
* [#115](https://github.com/xmake-io/xmake/pull/115): 修复安装脚本`get.sh`的路径问题
* 修复`import()`导入接口的缓存问题
## v2.1.4
### 新特性
* [#68](https://github.com/xmake-io/xmake/issues/68): 增加`$(programdir)`和`$(xmake)`内建变量
* 添加`is_host`接口去判断当前的主机环境
* [#79](https://github.com/xmake-io/xmake/issues/79): 增强`xmake lua`,支持交互式解释执行
### 改进
* 修改菜单选项颜色
* [#71](https://github.com/xmake-io/xmake/issues/71): 针对widows编译器改进优化选项映射
* [#73](https://github.com/xmake-io/xmake/issues/73): 尝试获取可执行文件路径来作为xmake的脚本目录
* 在`add_subdirs`中的子`xmake.lua`中,使用独立子作用域,避免作用域污染导致的干扰问题
* [#78](https://github.com/xmake-io/xmake/pull/78): 美化非全屏终端窗口下的`xmake --help`输出
* 避免产生不必要的`.xmake`目录,如果不在工程中的时候
### Bugs 修复
* [#67](https://github.com/xmake-io/xmake/issues/67): 修复 `sudo make install` 命令权限问题
* [#70](https://github.com/xmake-io/xmake/issues/70): 修复检测android编译器错误
* 修复临时文件路径冲突问题
* 修复`os.host`, `os.arch`等接口
* 修复根域api加载干扰其他子作用域问题
* [#77](https://github.com/xmake-io/xmake/pull/77): 修复`cprint`色彩打印中断问题
## v2.1.3
### 新特性
* [#65](https://github.com/xmake-io/xmake/pull/65): 为target添加`set_default`接口用于修改默认的构建所有targets行为
* 允许在工程子目录执行`xmake`命令进行构建,xmake会自动检测所在的工程根目录
* 添加`add_rpathdirs` api到target和option,支持动态库的自动加载运行
### 改进
* [#61](https://github.com/xmake-io/xmake/pull/61): 提供更加安全的`xmake install` and `xmake uninstall`任务,更友好的处理root安装问题
* 提供`rpm`, `deb`和`osxpkg`安装包
* [#63](https://github.com/xmake-io/xmake/pull/63): 改进安装脚本,实现更加安全的构建和安装xmake
* [#61](https://github.com/xmake-io/xmake/pull/61): 禁止在root权限下运行xmake命令,增强安全性
* 改进工具链检测,通过延迟延迟检测提升整体检测效率
* 当自动扫面生成`xmake.lua`时,添加更友好的用户提示,避免用户无操作
### Bugs 修复
* 修复版本检测的错误提示信息
* [#60](https://github.com/xmake-io/xmake/issues/60): 修复macosx和windows平台的xmake自举编译
* [#64](https://github.com/xmake-io/xmake/issues/64): 修复构建android `armv8-a`架构失败问题
* [#50](https://github.com/xmake-io/xmake/issues/50): 修复构建android可执行程序,无法运行问题
## v2.1.2
### 新特性
* 添加aur打包脚本,并支持用`yaourt`包管理器进行安装。
* 添加[set_basename](#http://xmake.io/#/zh/manual?id=targetset_basename)接口,便于定制化修改生成后的目标文件名
### 改进
* 支持vs2017编译环境
* 支持编译android版本的rust程序
* 增强vs201x工程生成插件,支持同时多模式、架构编译
### Bugs 修复
* 修复编译android程序,找不到系统头文件问题
* 修复检测选项行为不正确问题
* [#57](https://github.com/xmake-io/xmake/issues/57): 修复代码文件权限到0644
## v2.1.1
### 新特性
* 添加`--links`, `--linkdirs` and `--includedirs` 配置参数
* 添加app2ipa插件
* 为`xmake.lua`工程描述增加dictionay语法风格
* 提供智能扫描编译模式,在无任何`xmake.lua`等工程描述文件的情况下,也能直接快速编译
* 为`xmake.lua`工程描述添加`set_xmakever`接口,更加友好的处理版本兼容性问题
* 为`objc`和`swift`程序添加`add_frameworks`接口
* 更加快速方便的多语言扩展支持,增加`golang`, `dlang`和`rust`程序构建的支持
* 添加`target_end`, `option_end` 和`task_end`等可选api,用于显示结束描述域,进入根域设置,提高可读性
* 添加`golang`, `dlang`和`rust`工程模板
### 改进
* 工程生成插件支持vs2017
* 改进gcc/clang编译器警告和错误提示
* 重构代码架构,改进多语言支持,更加方便灵活的扩展语言支持
* 改进print接口,同时支持原生lua print以及格式化打印
* 如果xmake.lua不存在,自动扫描工程代码文件,并且生成xmake.lua进行编译
* 修改license,使用更加宽松的Apache License 2.0
* 移除一些二进制工具文件
* 移除install.bat脚本,提供windows nsis安装包支持
* 使用[docute](https://github.com/egoist/docute)重写[文档](http://www.xmake.io/#/zh/),提供更加完善的文档支持
* 增强`os.run`, `os.exec`, `os.cp`, `os.mv` 和 `os.rm` 等接口,支持通配符模式匹配和批量文件操作
* 精简和优化构建输出信息,添加`-q|--quiet`选项实现静默构建
* 改进`makefile`生成插件,抽取编译工具和编译选项到全局变量
### Bugs 修复
* [#41](https://github.com/waruqi/xmake/issues/41): 修复在windows下自动检测x64失败问题
* [#43](https://github.com/waruqi/xmake/issues/43): 避免创建不必要的.xmake工程缓存目录
* 针对android版本添加c++ stl搜索目录,解决编译c++失败问题
* 修复在rhel 5.10上编译失败问题
* 修复`os.iorun`返回数据不对问题
## v2.0.5
### 新特性
* 为解释器作用域增加一些内建模块支持
* 针对windows x64平台,支持ml64汇编器
### 改进
* 增强ipairs和pairs接口,支持过滤器模式,简化脚本代码
* 为vs201x工程生成增加文件filter
* 移除`core/tools`目录以及msys工具链,在windows上使用xmake自编译core源码进行安装,优化xmake源码磁盘空间
* 移除`xmake/packages`,默认模板安装不再内置二进制packages,暂时需要手动放置,以后再做成自动包依赖下载编译
### Bugs 修复
* 修复msvc的编译选项不支持问题:`-def:xxx.def`
* 修复ml.exe汇编器脚本
* 修复选项链接顺序问题
## v2.0.4
### 新特性
* 在`xmake.lua`中添加原生shell支持,例如:`add_ldflags("$(shell pkg-config --libs sqlite3)")`
* 编译windows目标程序,默认默认启用pdb符号文件
* 在windows上添加调试器支持(vsjitdebugger, ollydbg, windbg ... )
* 添加`getenv`接口到`xmake.lua`的全局作用域中
* 添加生成vstudio工程插件(支持:vs2002 - vs2015)
* 为option添加`set_default`接口
### 改进
* 增强内建变量的处理
* 支持字符串类型的选项option设置
### Bugs 修复
* 修复在linux下检测ld连接器失败,如果没装g++的话
* 修复`*.cxx`编译失败问题
## v2.0.3
### 新特性
* 增加头文件依赖自动检测和增量编译,提高编译速度
* 在终端中进行颜色高亮提示
* 添加调试器支持,`xmake run -d program ...`
### 改进
* 增强运行shell的系列接口
* 更新luajit到v2.0.4版本
* 改进makefile生成插件,移除对xmake的依赖,并且支持`windows/linux/macosx`等大部分pc平台
* 优化多任务编译速度,在windows下编译提升较为明显
### Bugs 修复
* 修复安装目录错误问题
* 修复`import`根目录错误问题
* 修复在多版本vs同时存在的情况下,检测vs环境失败问题
## v2.0.2
### 改进
* 修改安装和卸载的action处理
* 更新工程模板
* 增强函数检测
### Bugs 修复
* [#7](https://github.com/waruqi/xmake/issues/7): 修复用模板创建工程后,target名不对问题:'[targetname]'
* [#9](https://github.com/waruqi/xmake/issues/9): 修复clang不支持c++11的问题
* 修复api作用域泄露问题
* 修复在windows上的一些路径问题
* 修复检测宏函数失败问题
* 修复检测工具链失败问题
* 修复windows上编译android版本失败
## v2.0.1
### 新特性
* 增加task任务机制,可运行自定义任务脚本
* 实现plugin扩展机制,可以很方便扩展实现自定义插件,目前已实现的一些内置插件
* 增加project文件导出插件(目前已支持makefile的生成,后续会支持:vs, xcode等工程的生成)
* 增加hello xmake插件(插件demo)
* 增加doxygen文档生成插件
* 增加自定义宏脚本插件(支持动态宏记录、宏回放、匿名宏、批量导入、导出等功能)
* 增加更多的类库用于插件化开发
* 实现异常捕获机制,简化上层调用逻辑
* 增加多个option进行宏绑定,实现配置一个参数,就可以同时对多个配置进行生效
* 增加显示全局构建进度
### 改进
* 重构整个xmake.lua描述文件的解释器,更加的灵活可扩展
* 更加严格的语法检测机制
* 更加严格的作用域管理,实现沙盒引擎,对xmake.lua中脚本进行沙盒化处理,使得xmake.lua更加的安全
* 简化模板的开发,简单几行描述就可以扩展一个新的自定义工程模板
* 完全模块化platforms、tools、templates、actions,以及通过自注册机制,只需把自定义的脚本放入对应目录,就可实现快速扩展
* 针对所有可扩展脚本所需api进行大量简化,并实现大量类库,通过import机制进行导入使用
* 移除对gnu make/nmake等make工具的依赖,不再需要makefile,实现自己的make算法,
* 优化构建速度,支持多任务编译(支持vs编译器)(实测:比v1.0.4提升x4倍的构建性能)
* 优化自动检测机制,更加的稳定和准确
* 修改部分工程描述api,增强扩展性,减少一些命名歧义(对低版本向下兼容)
* 优化静态库合并:`add_files("*.a")`,修复一些bug
* 优化交叉编译,通过`--sdk=xxx`参数实现更加方便智能的进行交叉编译配置,简化mingw平台的编译配置
* 简化命令行配置开关, 支持`xmake config --xxx=[y|n|yes|no|true|false]`等开关值
* 合并iphoneos和iphonesimulator平台,以及watchos和watchsimulator平台,通过arch来区分,使得打包更加方便,能够支持一次性打包iphoneos的所有arch到一个包中
### Bugs 修复
* [#3](https://github.com/waruqi/xmake/issues/3): 修复ArchLinux 编译失败问题
* [#4](https://github.com/waruqi/xmake/issues/4): 修复windows上安装失败问题
* 修复windows上环境变量设置问题
## v1.0.4
### 新特性
* 增加对windows汇编器的支持
* 为xmake create增加一些新的工程模板,支持tbox版本
* 支持swift代码
* 针对-v参数,增加错误输出信息
* 增加apple编译平台:watchos, watchsimulator的编译支持
* 增加对windows: x64, amd64, x86_amd64架构的编译支持
* 实现动态库和静态库的快速切换
* 添加-j/--jobs参数,手动指定是否多任务编译,默认改为单任务编译
### 改进
* 增强`add_files`接口,支持直接添加`*.o/obj/a/lib`文件,并且支持静态库的合并
* 裁剪xmake的安装过程,移除一些预编译的二进制程序
### Bugs 修复
* [#1](https://github.com/waruqi/xmake/issues/4): 修复win7上安装失败问题
* 修复和增强工具链检测
* 修复一些安装脚本的bug, 改成外置sudo进行安装
* 修复linux x86_64下安装失败问题
## v1.0.3
### 新特性
* 添加set_runscript接口,支持自定义运行脚本扩展
* 添加import接口,使得在xmake.lua中可以导入一些扩展模块,例如:os,path,utils等等,使得脚本更灵活
* 添加android平台arm64-v8a支持
### Bugs 修复
* 修复set_installscript接口的一些bug
* 修复在windows x86_64下,安装失败的问题
* 修复相对路径的一些bug
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [waruqi@gmail.com]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
# Contributor Covenant行为准则
# 参与者公约
## 我们的保证
为了促进一个开放透明且友好的环境,我们作为贡献者和维护者保证:无论年龄、种族、民族、性别认同和表达(方式)、体型、身体健全与否、经验水平、国籍、个人表现、宗教或性别取向,参与者在我们项目和社区中都免于骚扰。
## 我们的标准
有助于创造正面环境的行为包括但不限于:
* 使用友好和包容性语言
* 尊重不同的观点和经历
* 耐心地接受建设性批评
* 关注对社区最有利的事情
* 友善对待其他社区成员
身为参与者不能接受的行为包括但不限于:
* 使用与性有关的言语或是图像,以及不受欢迎的性骚扰
* 捣乱/煽动/造谣的行为或进行侮辱/贬损的评论,人身攻击及政治攻击
* 公开或私下的骚扰
* 未经许可地发布他人的个人资料,例如住址或是电子地址
* 其他可以被合理地认定为不恰当或者违反职业操守的行为
## 我们的责任
项目维护者有责任为「可接受的行为」标准做出诠释,以及对已发生的不被接受的行为采取恰当且公平的纠正措施。
项目维护者有权利及责任去删除、编辑、拒绝与本行为标准有所违背的评论 (comments)、提交 (commits)、代码、wiki 编辑、问题 (issues) 和其他贡献,以及项目维护者可暂时或永久性的禁止任何他们认为有不适当、威胁、冒犯、有害行为的贡献者。
## 使用范围
当一个人代表该项目或是其社区时,本行为标准适用于其项目平台和公共平台。
代表项目或是社区的情况,举例来说包括使用官方项目的电子邮件地址、通过官方的社区媒体账号发布或线上或线下事件中担任指定代表。
该项目的呈现方式可由其项目维护者进行进一步的定义及解释。
## 强制执行
可以通过[waruqi@gmail.com],来联系项目团队来举报滥用、骚扰或其他不被接受的行为。
任何维护团队认为有必要且适合的所有投诉都将进行审查及调查,并做出相对应的回应。项目小组有对事件回报者有保密的义务。具体执行的方针近一步细节可能会单独公布。
没有切实地遵守或是执行本行为标准的项目维护人员,可能会因项目领导人或是其他成员的决定,暂时或是永久地取消其参与资格。
## 来源
本行为标准改编自[贡献者公约][主页],版本 1.4
可在此观看https://www.contributor-covenant.org/zh-cn/version/1/4/code-of-conduct.html
[主页]: https://www.contributor-covenant.org
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
If you discover issues, have ideas for improvements or new features, or
want to contribute a new module, please report them to the
[issue tracker][1] of the repository or submit a pull request. Please,
try to follow these guidelines when you do so.
## Issue reporting
* Check that the issue has not already been reported.
* Check that the issue has not already been fixed in the latest code
(a.k.a. `master`).
* Be clear, concise and precise in your description of the problem.
* Open an issue with a descriptive title and a summary in grammatically correct,
complete sentences.
* Include any relevant code to the issue summary.
## Pull requests
* Please update your local branch to the latest before submitting a pull request to ensure no merge conflicts.
* Use a topic branch to easily amend a pull request later, if necessary.
* Write good commit messages.
* Please use English for commit messages to standardize the log format.
* Use the same coding conventions as the rest of the project.
* Ensure your edited codes with four spaces instead of TAB.
* Please commit code to `dev` branch and we will merge into `master` branch in future.
* If it involves public API changes, please create a corresponding feature request in issues first, then describe the design of the new API in detail. It needs to be approved before you can start creating a PR to add and implement them, rather than directly opening a PR to add or modify new APIs at will.
## Development Guide
### Compiling Source Code
1. Download source code
```bash
git clone --recursive https://github.com/xmake-io/xmake.git
cd xmake
```
2. Compile
* Linux/macOS
```bash
./configure
make
```
* Windows
```bash
cd core
xmake
```
### Local Debugging
If you want to debug the local xmake source code, you can run the following command to load the local environment.
* Linux/macOS
```bash
source scripts/srcenv.profile
xmake --version
```
* Windows
Run `scripts\srcenv.bat` directly.
After loading the environment, we can directly modify the Lua script in the source code directory, and then run `xmake` to verify the modification effect in real time, without reinstalling.
### Environment Variables for Debugging
* `XMAKE_PROGRAM_DIR`: This environment variable specifies the directory containing Xmake's Lua scripts. By setting this to your local `xmake` source directory (e.g., `path/to/xmake/xmake`), you can force Xmake to use your local scripts. This allows you to test changes to Lua scripts immediately without re-compiling or re-installing.
* `XMAKE_PROGRAM_FILE`: This environment variable specifies the path to the `xmake` executable. It ensures that the correct binary is used, which is useful when you have multiple Xmake versions or want to test a locally compiled binary.
The `source scripts/srcenv.profile` (or `srcenv.bat`) command automatically sets these variables for you.
### Run Tests
Run the tests using the following command (Please ensure the local environment is loaded):
```bash
xmake l tests/run.lua [testname]
```
### Source Code Structure
The xmake source code is mainly divided into two parts: the C core and the Lua scripts.
* `core/`: The C core implementation, including the Lua runtime, cross-platform abstraction layer, and native API implementation.
* `xmake/`: The Lua script implementation, containing the core logic, modules, actions, and platforms.
#### Architecture Design
Xmake adopts a separation of concern design, where the performance-critical parts are implemented in C, and the build logic is implemented in Lua.
* **Sandbox**: User's `xmake.lua` and plugin scripts run in a sandbox environment to ensure safety and isolation. The sandbox API is defined in `xmake/core/sandbox`.
* **Core Modules**: The core Lua modules are located in `xmake/core`.
* **Actions**: Built-in actions (like `build`, `run`, `install`) are in `xmake/actions`.
* **Modules**: Extension modules are in `xmake/modules`.
* **Base API**: Utility scripts run in a base lua environment. Base API is in `xmake/core/base`.
* **Native API**: The Lua API and Xmake extension API, written in C, are located in `core/src/xmake`.
For example, when you call `os.cp()` in `xmake.lua`:
`sandbox_os.cp()` (Sandbox) -> `os.cp()` (Base) -> `xm_os_cpdir()` (Native C) -> `tb_directory_copy()` (Tbox)
## Financial contributions
If you want to contribute to Xmake but are unable to contribute code due to technical or time constraints, you can also support the further development of the community through [financial contributions](https://xmake.io/about/sponsor).
# 贡献代码
如果你发现一些问题,或者想新增或者改进某些新特性,或者想贡献一个新的模块
那么你可以在[issues][1]上提交反馈,或者发起一个提交代码的请求(pull request).
## 问题反馈
* 确认这个问题没有被反馈过
* 确认这个问题最近还没有被修复,请先检查下 `master` 的最新提交
* 请清晰详细地描述你的问题
* 请使用语法正确、完整的句子,开启一个带有描述性标题和摘要的 issue
* 如果发现某些代码存在问题,请在issue上引用相关代码
## 提交代码
* 请先更新你的本地分支到最新,再进行提交代码请求,确保没有合并冲突
* 如果需要,使用 topic 分支以便稍后轻松修改 pull request
* 编写友好可读的提交信息
* 请使用与工程代码相同的代码规范
* 确保提交的代码缩进是四个空格,而不是tab
* 请提交代码到`dev`分支,如果通过,我们会在特定时间合并到`master`分支上
* 为了规范化提交日志的格式,commit消息,不要用中文,请用英文描述
* 如果涉及公开的 API 改动,请先在 issues 中创建对应的 feature request ,然后详细描述下 新 API 的设计,并且需要经过赞同后,才能开始创建 pr 去添加和实现它们,而不是直接打开 pr 去随意添加修改新的 API
## 开发指南
### 源码编译
1. 下载源码
```bash
git clone --recursive https://github.com/xmake-io/xmake.git
cd xmake
```
2. 编译
* Linux/macOS
```bash
./configure
make
```
* Windows
```bash
cd core
xmake
```
### 本地调试
如果想要调试本地 xmake 源码,可以运行以下命令加载本地环境。
* Linux/macOS
```bash
source scripts/srcenv.profile
xmake --version
```
* Windows
直接运行 `scripts\srcenv.bat`。
加载环境后,我们就可以直接修改源码目录下的 Lua 脚本,然后运行 `xmake` 即可实时验证修改效果,无需重新安装。
### 调试环境变量
* `XMAKE_PROGRAM_DIR`: 指定 Xmake 的 Lua 脚本目录。将其设置为本地源码中的 `xmake` 目录(例如 `path/to/xmake/xmake`),可以让 Xmake 直接加载本地脚本。这样修改 Lua 脚本后无需重新编译安装即可生效,非常适合调试脚本逻辑。
* `XMAKE_PROGRAM_FILE`: 指定 `xmake` 可执行文件的路径。确保使用指定的二进制文件运行,适用于多版本共存或测试本地编译生成的二进制文件。
`source scripts/srcenv.profile` (或 `srcenv.bat`) 脚本会自动为你设置这些环境变量。
### 运行测试
使用以下命令运行测试(请确保本地环境已经加载):
```bash
xmake l tests/run.lua [testname]
```
### 源码结构
Xmake 的源码主要分为两部分:C 核心和 Lua 脚本。
* `core/`: C 核心实现,包括 Lua 运行时、跨平台抽象层和原生 API 实现。
* `xmake/`: Lua 脚本实现,包含核心逻辑、模块、操作和平台支持。
#### 架构设计
Xmake 采用关注点分离的设计,性能敏感的部分由 C 实现,而构建逻辑由 Lua 实现。
* **沙盒 (Sandbox)**: 用户的 `xmake.lua` 和插件脚本运行在沙盒环境中,以确保安全性和隔离性。沙盒 API 定义在 `xmake/core/sandbox` 中。
* **核心模块 (Core Modules)**: 核心 Lua 模块位于 `xmake/core`。
* **操作 (Actions)**: 内置操作(如 `build`, `run`, `install`)位于 `xmake/actions`。
* **模块 (Modules)**: 扩展模块位于 `xmake/modules`。
* **基础 API (Base API)**: 工具脚本运行在基础 Lua 环境中。基础 API 位于 `xmake/core/base`。
* **原生 API (Native API)**: 包含 Lua API 和 Xmake 扩展 API,用 C 编写,位于 `core/src/xmake`。
例如,当你在 `xmake.lua` 中调用 `os.cp()` 时:
`sandbox_os.cp()` (Sandbox) -> `os.cp()` (Base) -> `xm_os_cpdir()` (Native C) -> `tb_directory_copy()` (Tbox)
## 资金赞助
如果您想要为 Xmake 做贡献,但受限于技术能力或时间无法参与代码开发,也可以通过[资金赞助](https://xmake.io/about/sponsor)来支持社区的进一步发展。
[1]: https://github.com/xmake-io/xmake/issues
================================================
FILE: LICENSE.md
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2015-present Xmake Open Source Community
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: NOTICE.md
================================================
A cross-platform build utility based on Lua
Copyright 2015-present, The Xmake Open Source Community
This product includes software developed by The Xmake Open Source Community (https://xmake.io/).
-------------------------------------------------------------------------------
This product depends on 'lua-cjson', The Lua CJSON module provides JSON support for Lua,
which can be obtained at:
* LICENSE:
* core/src/lua-cjson/lua-cjson/LICENSE (MIT License)
* HOMEPAGE:
* https://www.kyne.com.au/~mark/software/lua-cjson.php
This product depends on 'pdcurses', an implementation of X/Open curses for multiple platforms,
which can be obtained at:
* LICENSE:
* Public Domain License
* HOMEPAGE:
* http://pdcurses.org/
This product depends on 'libsv', Public domain semantic versioning in c,
which can be obtained at:
* LICENSE:
* core/src/sv/sv/UNLICENSE (Public Domain License)
* HOMEPAGE:
* https://github.com/uael/sv
This product depends on 'LuaJIT', a Just-In-Time Compiler for Lua,
which can be obtained at:
* LICENSE:
* core/src/luajit/luajit/COPYRIGHT (MIT License)
* HOMEPAGE:
* http://luajit.org/
This product depends on 'Lua', The Lua Programming Language,
which can be obtained at:
* LICENSE:
* https://www.lua.org/license.html (MIT License)
* HOMEPAGE:
* http://lua.org/
This product depends on 'lz4', Extremely Fast Compression algorithm,
which can be obtained at:
* LICENSE:
* https://github.com/lz4/lz4/blob/dev/LICENSE
* HOMEPAGE:
* https://www.lz4.org/
This product depends on 'xxHash', Extremely fast non-cryptographic hash algorithm,
which can be obtained at:
* LICENSE:
* https://github.com/Cyan4973/xxHash/blob/dev/LICENSE
* HOMEPAGE:
* https://www.xxhash.com/
This product depends on 'tbox', The Treasure Box Library,
which can be obtained at:
* LICENSE:
* core/src/tbox/tbox/LICENSE.md (Apache License 2.0)
* HOMEPAGE:
* https://tboox.org/
================================================
FILE: README.md
================================================
xmake
A cross-platform build utility based on Lua Modern C/C++ build tool: Simple, Fast, Powerful dependency package integration
## Support this project
Support this project by [becoming a sponsor](https://xmake.io/about/sponsor.html). Your logo will show up here with a link to your website. 🙏
## Introduction ([中文](/README_zh.md))
What is Xmake?
1. Xmake is a cross-platform build utility based on the Lua scripting language.
2. Xmake is very lightweight and has no dependencies outside of the standard library.
3. Uses the `xmake.lua` file to maintain project builds with a simple and readable syntax.
Xmake can be used to directly build source code (like with Make or Ninja), or it can generate project source files like CMake or Meson. It also has a *built-in* package management system to help users integrate C/C++ dependencies.
```
Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache
```
Although less precise, one can still understand Xmake in the following way:
```
Xmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache
```
If you want to know more, please refer to the [Documentation](https://xmake.io/guide/quick-start), [GitHub](https://github.com/xmake-io/xmake) or [Gitee](https://gitee.com/tboox/xmake). You are also welcome to join our [community](https://xmake.io/about/contact).
The official Xmake repository can be found at [xmake-io/xmake-repo](https://github.com/xmake-io/xmake-repo).

## Installation
### With cURL
```bash
curl -fsSL https://xmake.io/shget.text | bash
```
### With Wget
```bash
wget https://xmake.io/shget.text -O - | bash
```
### With PowerShell
```sh
irm https://xmake.io/psget.text | iex
```
### Other installation methods
If you don't want to use the above scripts to install Xmake, visit the [Installation Guide](https://xmake.io/guide/quick-start.html#installation) for other installation methods (building from source, package managers, etc.).
## Simple Project Description
```lua
target("console")
set_kind("binary")
add_files("src/*.c")
```
Creates a new target `console` of kind `binary`, and adds all the files ending in `.c` in the `src` directory.
## Package dependencies
```lua
add_requires("tbox 1.6.*", "zlib", "libpng ~1.6")
```
Adds a requirement of tbox v1.6, zlib (any version), and libpng v1.6.
The official xmake package repository exists at: [xmake-repo](https://github.com/xmake-io/xmake-repo)
## Command line interface reference
The below assumes you are currently in the project's root directory.
### Build a project
```bash
$ xmake
```
### Run target
```bash
$ xmake run console
```
### Debug target
```bash
$ xmake run -d console
```
### Run test
```bash
$ xmake test
```
### Configure platform
```bash
$ xmake f -p [windows|linux|macosx|android|iphoneos ..] -a [x86|arm64 ..] -m [debug|release]
$ xmake
```
### Menu configuration
```bash
$ xmake f --menu
```
## Supported platforms
* Windows (x86, x64, arm, arm64, arm64ec)
* macOS (i386, x86_64, arm64)
* Linux (i386, x86_64, arm, arm64, riscv, mips, 390x, sh4 ...)
* FreeBSD (i386, x86_64)
* NetBSD (i386, x86_64)
* OpenBSD (i386, x86_64)
* DragonflyBSD (i386, x86_64)
* Solaris (i386, x86_64)
* Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a)
* iOS (armv7, armv7s, arm64, i386, x86_64)
* WatchOS (armv7k, i386)
* AppleTVOS (armv7, arm64, i386, x86_64)
* AppleXROS (arm64, x86_64)
* MSYS (i386, x86_64)
* MinGW (i386, x86_64, arm, arm64)
* Cygwin (i386, x86_64)
* Wasm (wasm32, wasm64)
* Haiku (i386, x86_64)
* Harmony (x86_64, armeabi-v7a, arm64-v8a)
* Cross (cross-toolchains ..)
## Supported toolchains
```bash
$ xmake show -l toolchains
xcode Xcode IDE
msvc Microsoft Visual C/C++ Compiler
clang-cl LLVM Clang C/C++ Compiler compatible with msvc
yasm The Yasm Modular Assembler
clang A C language family frontend for LLVM
go Go Programming Language Compiler
dlang D Programming Language Compiler (Auto)
dmd D Programming Language Compiler
ldc The LLVM-based D Compiler
gdc The GNU D Compiler (GDC)
gfortran GNU Fortran Programming Language Compiler
flang LLVM Fortran Compiler
zig Zig Programming Language Compiler
zigcc Use zig cc/c++ as C/C++ Compiler
sdcc Small Device C Compiler
cuda CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)
ndk Android NDK
rust Rust Programming Language Compiler
swift Swift Programming Language Compiler
llvm A collection of modular and reusable compiler and toolchain technologies
cross Common cross compilation toolchain
nasm NASM Assembler
gcc GNU Compiler Collection
mingw Minimalist GNU for Windows
gnu-rm GNU Arm Embedded Toolchain
envs Environment variables toolchain
fasm Flat Assembler
tinycc Tiny C Compiler
emcc A toolchain for compiling to asm.js and WebAssembly
icc Intel C/C++ Compiler
ifort Intel Fortran Compiler
ifx Intel LLVM Fortran Compiler
muslcc The musl-based cross-compilation toolchain
fpc Free Pascal Programming Language Compiler
wasi WASI-enabled WebAssembly C/C++ toolchain
nim Nim Programming Language Compiler
dotnet .NET SDK Toolchain
circle A new C++20 compiler
armcc ARM Compiler Version 5 of Keil MDK
armclang ARM Compiler Version 6 of Keil MDK
c51 Keil development tools for the 8051 Microcontroller Architecture
icx Intel LLVM C/C++ Compiler
dpcpp Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL
masm32 The MASM32 SDK
iverilog Icarus Verilog
verilator Verilator open-source SystemVerilog simulator and lint system
cosmocc build-once run-anywhere
hdk Harmony SDK
ti-c2000 TI-CGT C2000 compiler
ti-c6000 TI-CGT C6000 compiler
iararm IAR ARM C/C++ Compiler
kotlin-native Kotlin Native Programming Language Compiler
```
## Supported languages
* C and C++
* Objective-C and Objective-C++
* Swift
* Assembly
* Golang
* Rust
* Dlang
* Fortran
* Cuda
* Zig
* Vala
* Pascal
* Nim
* Verilog
* FASM
* NASM
* YASM
* MASM32
* Cppfront
* Kotlin
* C#
## Features
Xmake exhibits:
* Simple yet flexible configuration grammar.
* Quick, dependency-free installation.
* Easy compilation for most all supported platforms.
* Supports cross-compilation with intelligent analysis of cross toolchain information.
* Extremely fast parallel compilation support.
* Supports C++ modules (new in C++20).
* Supports cross-platform C/C++ dependencies with built-in package manager.
* Multi-language compilation support including mixed-language projects.
* Rich plug-in support with various project generators (ex. Visual Studio/Makefiles/CMake/`compile_commands.json`)
* REPL interactive execution support
* Incremental compilation support with automatic analysis of header files
* Built-in toolchain management
* A large number of expansion modules
* Remote compilation support
* Distributed compilation support
* Local and remote build cache support
## Supported Project Types
Xmake supports the below types of projects:
* Static libraries
* Shared libraries
* Console/CLI applications
* CUDA programs
* Qt applications
* WDK drivers (umdf/kmdf/wdm)
* WinSDK applications
* MFC applications
* Darwin applications (with metal support)
* Frameworks and bundles (in Darwin)
* SWIG modules (Lua, Python, ...)
* LuaRocks modules
* Protobuf programs
* Lex/Yacc programs
* Linux kernel modules
## Package management
### Download and build
Xmake can automatically fetch and install dependencies!
### Supported package repositories
* Official package repository [xmake-repo](https://github.com/xmake-io/xmake-repo) (tbox >1.6.1)
* Official package manager [Xrepo](https://github.com/xmake-io/xrepo)
* [User-built repositories](https://xmake.io/guide/package-management/using-official-packages.html#using-self-built-private-package-repository)
* Conan (conan::openssl/1.1.1g)
* Conda (conda::libpng 1.3.67)
* Vcpkg (vcpkg:ffmpeg)
* Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)
* Pacman on archlinux/msys2 (pacman::libcurl)
* Apt on ubuntu/debian (apt::zlib1g-dev)
* Clib (clib::clibs/bytes@0.0.4)
* Dub (dub::log 0.4.3)
* Portage on Gentoo/Linux (portage::libhandy)
* Nimble for nimlang (nimble::zip >1.3)
* Cargo for rust (cargo::base64 0.13.0)
* Zypper on openSUSE (zypper::libsfml2 2.5)
### Package management features
* The official repository provides nearly 500+ packages with simple compilation on all supported platforms
* Full platform package support, support for cross-compiled dependent packages
* Support package virtual environment using `xrepo env shell`
* Precompiled package acceleration for Windows (NT)
* Support self-built package repositories and private repository deployment
* Third-party package repository support for repositories such as: vcpkg, conan, conda, etc.
* Supports automatic pulling of remote toolchains
* Supports dependency version locking
## Processing architecture
Below is a diagram showing roughly the architecture of Xmake, and thus how it functions.
## Distributed Compilation
- [X] Cross-platform support.
- [X] Support for MSVC, Clang, GCC and other cross-compilation toolchains.
- [X] Support for building for Android, Linux, Windows NT, and Darwin hosts.
- [X] No dependencies other than the compilation toolchain.
- [X] Support for build server load balancing scheduling.
- [X] Support for real time compressed transfer of large files (lz4).
- [X] Almost zero configuration cost, no shared filesystem required, for convenience and security.
For more details see: [Distributed Compilation](https://xmake.io/guide/extras/distributed-compilation.html)
## Remote Compilation
For more details see: [Remote Compilation](https://xmake.io/guide/extras/remote-compilation.html)
## Local/Remote Build Cache
For more details see: [Build Cache Acceleration](https://xmake.io/guide/extras/build-cache.html)
## Benchmark
Xmake's speed on is par with Ninja! The test project: [xmake-core](https://github.com/xmake-io/xmake/tree/master/core)
### Multi-task parallel compilation
| buildsystem | Termux (8core/-j12) | buildsystem | MacOS (8core/-j12) |
| ------------------ | --------------------- | ------------------ | -------------------- |
| xmake | 24.890s | xmake | 12.264s |
| ninja | 25.682s | ninja | 11.327s |
| cmake(gen+make) | 5.416s+28.473s | cmake(gen+make) | 1.203s+14.030s |
| cmake(gen+ninja) | 4.458s+24.842s | cmake(gen+ninja) | 0.988s+11.644s |
## Single task compilation
| buildsystem | Termux (-j1) | buildsystem | MacOS (-j1) |
| ------------------ | ------------------ | ------------------ | ---------------- |
| xmake | 1m57.707s | xmake | 39.937s |
| ninja | 1m52.845s | ninja | 38.995s |
| cmake(gen+make) | 5.416s+2m10.539s | cmake(gen+make) | 1.203s+41.737s |
| cmake(gen+ninja) | 4.458s+1m54.868s | cmake(gen+ninja) | 0.988s+38.022s |
## More Examples
### Debug and release profiles
```lua
add_rules("mode.debug", "mode.release")
target("console")
set_kind("binary")
add_files("src/*.c")
if is_mode("debug") then
add_defines("DEBUG")
end
```
### Custom scripts
```lua
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target)
print("hello: %s", target:name())
os.exec("echo %s", target:targetfile())
end)
```
### Automatic integration of dependent packages
Download and use packages in [xmake-repo](https://github.com/xmake-io/xmake-repo) or third-party repositories:
```lua
add_requires("tbox >1.6.1", "libuv master", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8")
add_requires("conan::openssl/1.1.1g", {alias = "openssl", optional = true, debug = true})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("tbox", "libuv", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8", "openssl")
```
In addition, we can also use the [xrepo](https://github.com/xmake-io/xrepo) command to quickly install dependencies.
### Qt QuickApp Program
```lua
target("test")
add_rules("qt.quickapp")
add_files("src/*.cpp")
add_files("src/qml.qrc")
```
### Cuda Program
```lua
target("test")
set_kind("binary")
add_files("src/*.cu")
add_cugencodes("native")
add_cugencodes("compute_75")
```
### WDK/UMDF Driver Program
```lua
target("echo")
add_rules("wdk.driver", "wdk.env.umdf")
add_files("driver/*.c")
add_files("driver/*.inx")
add_includedirs("exe")
target("app")
add_rules("wdk.binary", "wdk.env.umdf")
add_files("exe/*.cpp")
```
For more WDK driver examples (UMDF/KMDF/WDM), please visit [WDK Program Examples](https://xmake.io/examples/cpp/wdk.html)
### Darwin Applications
```lua
target("test")
add_rules("xcode.application")
add_files("src/*.m", "src/**.storyboard", "src/*.xcassets")
add_files("src/Info.plist")
```
### Framework and Bundle Program (Darwin)
```lua
target("test")
add_rules("xcode.framework") -- or xcode.bundle
add_files("src/*.m")
add_files("src/Info.plist")
```
### OpenMP Program
```lua
add_requires("libomp", {optional = true})
target("loop")
set_kind("binary")
add_files("src/*.cpp")
add_rules("c++.openmp")
add_packages("libomp")
```
### Zig Program
```lua
target("test")
set_kind("binary")
add_files("src/main.zig")
```
### Automatically fetch remote toolchain
#### fetch a special version of LLVM
Require the Clang version packaged with LLM-10 to compile a project.
```lua
add_requires("llvm 10.x", {alias = "llvm-10"})
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("llvm@llvm-10")
```
#### Fetch a cross-compilation toolchain
We can also pull a specified cross-compilation toolchain in to compile the project.
```lua
add_requires("muslcc")
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("@muslcc")
```
#### Fetch toolchain and packages
We can also use the specified `muslcc` cross-compilation toolchain to compile and integrate all dependent packages.
```lua
add_requires("muslcc")
add_requires("zlib", "libogg", {system = false})
set_toolchains("@muslcc")
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("zlib", "libogg")
```
## Plugins
#### Generate IDE project file plugin(makefile, vs2002 - vs2026 .. )
```bash
$ xmake project -k vsxmake -m "debug,release" # New vsproj generator (Recommended)
$ xmake project -k vs -m "debug,release"
$ xmake project -k cmake
$ xmake project -k ninja
$ xmake project -k compile_commands
```
#### Run a custom lua script plugin
```bash
$ xmake l ./test.lua
$ xmake l -c "print('hello xmake!')"
$ xmake l lib.detect.find_tool gcc
$ xmake l
> print("hello xmake!")
> {1, 2, 3}
< {
1,
2,
3
}
```
To see a list of builtin plugins, please visit [Builtin plugins](https://xmake.io/guide/extensions/builtin-plugins.html).
Please download and install other plugins from the plugins repository [xmake-plugins](https://github.com/xmake-io/xmake-plugins).
## IDE/Editor Integration
* [xmake-vscode](https://github.com/xmake-io/xmake-vscode)
* [xmake-sublime](https://github.com/xmake-io/xmake-sublime)
* [xmake-idea](https://github.com/xmake-io/xmake-idea)
* [xmake-zed](https://github.com/xmake-io/xmake-zed) (thanks [@jeleferai](https://github.com/jeleferai))
* [xmake.vim](https://github.com/luzhlon/xmake.vim) (third-party, thanks [@luzhlon](https://github.com/luzhlon))
* [xmake-visualstudio](https://github.com/HelloWorld886/xmake-visualstudio) (third-party, thanks [@HelloWorld886](https://github.com/HelloWorld886))
* [xmake-qtcreator](https://github.com/Arthapz/xmake-project-manager) (third-party, thanks [@Arthapz](https://github.com/Arthapz))
### Xmake Gradle Plugin (JNI)
We can use the [xmake-gradle](https://github.com/xmake-io/xmake-gradle) plugin to compile JNI libraries via gradle.
```
plugins {
id 'org.tboox.gradle-xmake-plugin' version '1.1.5'
}
android {
externalNativeBuild {
xmake {
path "jni/xmake.lua"
}
}
}
```
The `xmakeBuild` task will be injected into the `assemble` task automatically if the `gradle-xmake-plugin` has been applied.
```console
$ ./gradlew app:assembleDebug
> Task :nativelib:xmakeConfigureForArm64
> Task :nativelib:xmakeBuildForArm64
>> xmake build
[ 50%]: cache compiling.debug nativelib.cc
[ 75%]: linking.debug libnativelib.so
[100%]: build ok!
>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/arm64-v8a
> Task :nativelib:xmakeConfigureForArmv7
> Task :nativelib:xmakeBuildForArmv7
>> xmake build
[ 50%]: cache compiling.debug nativelib.cc
[ 75%]: linking.debug libnativelib.so
[100%]: build ok!
>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/armeabi-v7a
> Task :nativelib:preBuild
> Task :nativelib:assemble
> Task :app:assembleDebug
```
## CI Integration
### GitHub Action
The [github-action-setup-xmake](https://github.com/xmake-io/github-action-setup-xmake) plugin for GitHub Actions can allow you to use Xmake with minimal efforts if you use GitHub Actions for your CI pipeline.
```yaml
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
```
## Who is using Xmake?
The list of people and projects who are using Xmake is available [here](https://xmake.io/about/who_is_using_xmake.html).
If you are using Xmake, you are welcome to submit your information to the above list through a PR, so that other users and the developers can gauge interest. This also lets users use xmake more confidently and gives us motivation to continue to maintain it.
This will help the Xmake project and it's community grow stronger and expand!
## Contacts
* Email:[waruqi@gmail.com](mailto:waruqi@gmail.com)
* Homepage:[xmake.io](https://xmake.io)
* Community
- [Chat on Reddit](https://www.reddit.com/r/xmake/)
- [Chat on Telegram](https://t.me/tbooxorg)
- [Chat on Discord](https://discord.gg/xmake)
- Chat on QQ Group: 343118190, 662147501
* Source Code:[GitHub](https://github.com/xmake-io/xmake), [Gitee](https://gitee.com/tboox/xmake)
* WeChat Public: tboox-os
## Thanks
This project exists thanks to all the people who have [contributed](CONTRIBUTING.md):
* [TitanSnow](https://github.com/TitanSnow): Provide the xmake [logo](https://github.com/TitanSnow/ts-xmake-logo) and install scripts
* [uael](https://github.com/uael): Provide the semantic versioning library [sv](https://github.com/uael/sv)
* [OpportunityLiu](https://github.com/OpportunityLiu): Improve cuda, tests and ci
* [xq144](https://github.com/xq114): Improve `xrepo env shell`, and contribute a lot of packages to the [xmake-repo](https://github.com/xmake-io/xmake-repo) repository.
* [star-hengxing](https://github.com/star-hengxing): Contribute a lot of packages to the [xmake-repo](https://github.com/xmake-io/xmake-repo) repository.
* [Arthapz](https://github.com/Arthapz): Contribute new C++ Modules implementation.
* [SirLynix](https://github.com/SirLynix): Contributed many packages and let more people know about xmake.
* `enderger`: Helped smooth out the edges on the English translation of the README
### Powered by
[](https://jb.gg/OpenSource)
================================================
FILE: README_zh.md
================================================
xmake
A cross-platform build utility based on Lua Modern C/C++ build tools, Simple, Fast, Powerful dependency package integration
## 项目支持
通过[成为赞助者](https://xmake.io/zh/about/sponsor.html)来支持该项目。您的logo将显示在此处,并带有指向您网站的链接。🙏
## 简介
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
```
如果你想要了解更多,请参考:[在线文档](https://xmake.io/zh/guide/quick-start.html), [Github](https://github.com/xmake-io/xmake)以及[Gitee](https://gitee.com/tboox/xmake) 和 [GitCode](https://gitcode.com/xmake-io/xmake),同时也欢迎加入我们的 [社区](https://xmake.io/zh/about/contact)。

## 课程
xmake 官方也推出了一些入门课程,带你一步步快速上手 xmake,课程列表如下:
* [Xmake 带你轻松构建 C/C++ 项目](https://xmake.io/zh/about/course)
## 安装
#### 使用curl
```bash
curl -fsSL https://xmake.io/shget.text | bash
```
#### 使用wget
```bash
wget https://xmake.io/shget.text -O - | bash
```
#### 使用powershell
```powershell
irm https://xmake.io/psget.text | iex
```
#### 其他安装方式
如果不想使用脚本安装,也可以点击查看 [安装文档](https://xmake.io/zh/guide/quick-start.html#installation),了解其他安装方法。
## 简单的工程描述
```lua
target("hello")
set_kind("binary")
add_files("src/*.cpp")
```
## 包依赖描述
```lua
add_requires("tbox 1.6.*", "zlib", "libpng ~1.6")
```
官方的xmake包管理仓库: [xmake-repo](https://github.com/xmake-io/xmake-repo)
## 命令行使用
### 创建工程
```bash
$ xmake create hello
$ cd hello
```
### 构建工程
```bash
$ xmake
```
### 运行目标
```bash
$ xmake run console
```
### 调试程序
```bash
$ xmake run -d console
```
### 运行测试
```bash
$ xmake test
```
### 配置平台
```bash
$ xmake f -p [windows|linux|macosx|android|iphoneos ..] -a [x86|arm64 ..] -m [debug|release]
$ xmake
```
### 图形化菜单配置
```bash
$ xmake f --menu
```
## 跟ninja一样快的构建速度
测试工程: [xmake-core](https://github.com/xmake-io/xmake/tree/master/core)
### 多任务并行编译测试
| 构建系统 | Termux (8core/-j12) | 构建系统 | MacOS (8core/-j12) |
|----- | ---- | --- | --- |
|xmake | 24.890s | xmake | 12.264s |
|ninja | 25.682s | ninja | 11.327s |
|cmake(gen+make) | 5.416s+28.473s | cmake(gen+make) | 1.203s+14.030s |
|cmake(gen+ninja) | 4.458s+24.842s | cmake(gen+ninja) | 0.988s+11.644s |
### 单任务编译测试
| 构建系统 | Termux (-j1) | 构建系统 | MacOS (-j1) |
|----- | ---- | --- | --- |
|xmake | 1m57.707s | xmake | 39.937s |
|ninja | 1m52.845s | ninja | 38.995s |
|cmake(gen+make) | 5.416s+2m10.539s | cmake(gen+make) | 1.203s+41.737s |
|cmake(gen+ninja) | 4.458s+1m54.868s | cmake(gen+ninja) | 0.988s+38.022s |
## 包依赖管理
### 架构和流程
### 支持的包管理仓库
* 官方自建仓库 [xmake-repo](https://github.com/xmake-io/xmake-repo) (tbox >1.6.1)
* 官方包管理器 [Xrepo](https://github.com/xmake-io/xrepo)
* [用户自建仓库](https://xmake.io/package/remote_package?id=using-self-built-private-package-repository)
* Conan (conan::openssl/1.1.1g)
* Conda (conda::libpng 1.3.67)
* Vcpkg (vcpkg::ffmpeg)
* Homebrew/Linuxbrew (brew::pcre2/libpcre2-8)
* Pacman on archlinux/msys2 (pacman::libcurl)
* Apt on ubuntu/debian (apt::zlib1g-dev)
* Clib (clib::clibs/bytes@0.0.4)
* Dub (dub::log 0.4.3)
* Portage on Gentoo/Linux (portage::libhandy)
* Nimble for nimlang (nimble::zip >1.3)
* Cargo for rust (cargo::base64 0.13.0)
### 包管理特性
* 官方仓库提供近 800+ 常用包,真正做到全平台一键下载集成编译
* 全平台包支持,支持交叉编译的依赖包集成
* 支持包虚拟环境管理和加载,`xrepo env shell`
* Windows 云端预编译包加速
* 支持自建包仓库,私有仓库部署
* 第三方包仓库支持,提供更加丰富的包源,例如:vcpkg, conan, conda 等等
* 支持自动拉取使用云端工具链
* 支持包依赖锁定
## 支持平台
* Windows (x86, x64, arm, arm64, arm64ec)
* macOS (i386, x86_64, arm64)
* Linux (i386, x86_64, arm, arm64, riscv, mips, 390x, sh4 ...)
* FreeBSD (i386, x86_64)
* NetBSD (i386, x86_64)
* OpenBSD (i386, x86_64)
* DragonflyBSD (i386, x86_64)
* Solaris (i386, x86_64)
* Android (x86, x86_64, armeabi, armeabi-v7a, arm64-v8a)
* iOS (armv7, armv7s, arm64, i386, x86_64)
* WatchOS (armv7k, i386)
* AppleTVOS (armv7, arm64, i386, x86_64)
* AppleXROS (arm64, x86_64)
* MSYS (i386, x86_64)
* MinGW (i386, x86_64, arm, arm64)
* Cygwin (i386, x86_64)
* Wasm (wasm32, wasm64)
* Haiku (i386, x86_64)
* Harmony (x86_64, armeabi-v7a, arm64-v8a)
* Cross (cross-toolchains ..)
## 支持工具链
```bash
$ xmake show -l toolchains
xcode Xcode IDE
msvc Microsoft Visual C/C++ Compiler
clang-cl LLVM Clang C/C++ Compiler compatible with msvc
yasm The Yasm Modular Assembler
clang A C language family frontend for LLVM
go Go Programming Language Compiler
dlang D Programming Language Compiler (Auto)
dmd D Programming Language Compiler
ldc The LLVM-based D Compiler
gdc The GNU D Compiler (GDC)
gfortran GNU Fortran Programming Language Compiler
flang LLVM Fortran Compiler
zig Zig Programming Language Compiler
zigcc Use zig cc/c++ as C/C++ Compiler
sdcc Small Device C Compiler
cuda CUDA Toolkit (nvcc, nvc, nvc++, nvfortran)
ndk Android NDK
rust Rust Programming Language Compiler
swift Swift Programming Language Compiler
llvm A collection of modular and reusable compiler and toolchain technologies
cross Common cross compilation toolchain
nasm NASM Assembler
gcc GNU Compiler Collection
mingw Minimalist GNU for Windows
gnu-rm GNU Arm Embedded Toolchain
envs Environment variables toolchain
fasm Flat Assembler
tinycc Tiny C Compiler
emcc A toolchain for compiling to asm.js and WebAssembly
icc Intel C/C++ Compiler
ifort Intel Fortran Compiler
ifx Intel LLVM Fortran Compiler
muslcc The musl-based cross-compilation toolchain
fpc Free Pascal Programming Language Compiler
wasi WASI-enabled WebAssembly C/C++ toolchain
nim Nim Programming Language Compiler
dotnet .NET SDK Toolchain
circle A new C++20 compiler
armcc ARM Compiler Version 5 of Keil MDK
armclang ARM Compiler Version 6 of Keil MDK
c51 Keil development tools for the 8051 Microcontroller Architecture
icx Intel LLVM C/C++ Compiler
dpcpp Intel LLVM C++ Compiler for data parallel programming model based on Khronos SYCL
masm32 The MASM32 SDK
iverilog Icarus Verilog
verilator Verilator open-source SystemVerilog simulator and lint system
cosmocc build-once run-anywhere
hdk Harmony SDK
ti-c2000 TI-CGT C2000 compiler
ti-c6000 TI-CGT C6000 compiler
iararm IAR ARM C/C++ Compiler
kotlin-native Kotlin Native Programming Language Compiler
```
## 支持语言
* C/C++
* Objc/Objc++
* Swift
* Assembly
* Golang
* Rust
* Dlang
* Fortran
* Cuda
* Zig
* Vala
* Pascal
* Nim
* Verilog
* FASM
* NASM
* YASM
* MASM32
* Cppfront
* Kotlin
* C#
## 支持特性
* 语法简单易上手
* 快速安装,无任何依赖
* 全平台一键编译
* 支持交叉编译,智能分析交叉工具链信息
* 极速,多任务并行编译支持
* C++20 Module 支持
* 支持跨平台的 C/C++ 依赖包快速集成,内置包管理器
* 多语言混合编译支持
* 丰富的插件支持,提供各种工程生成器,例如:vs/makefile/cmakelists/compile_commands 生成插件
* REPL 交互式执行支持
* 增量编译支持,头文件依赖自动分析
* 工具链的快速切换、定制化支持
* 丰富的扩展模块支持
* 远程编译支持
* 分布式编译支持
* 内置的本地和远程编译缓存支持
## 工程类型
* 静态库程序
* 动态库类型
* 控制台程序
* Cuda 程序
* Qt 应用程序
* WDK Windows 驱动程序
* WinSDK 应用程序
* MFC 应用程序
* iOS/MacOS 应用程序(支持.metal)
* Framework和Bundle程序(iOS/MacOS)
* SWIG/Pybind11 模块 (Lua, python, ...)
* Luarocks 模块
* Protobuf 程序
* Lex/yacc 程序
* C++20 模块
* Linux 内核驱动模块
* Keil MDK/C51 嵌入式程序
* Verilog 仿真程序
## 分布式编译和缓存
- [x] 跨平台支持
- [x] 支持 msvc, clang, gcc 和交叉编译工具链
- [x] 支持构建 android, ios, linux, win, macOS 程序
- [x] 除了编译工具链,无任何其他依赖
- [x] 支持编译服务器负载均衡调度
- [x] 支持大文件实时压缩传输 (lz4)
- [x] 几乎零配置成本,无需共享文件系统,更加方便和安全
关于分布式编译和缓存,可以见下面的文档。
- [分布式编译](https://xmake.io/zh/guide/extras/distributed-compilation.html)
- [编译缓存](https://xmake.io/zh/guide/extras/build-cache.html)
## 远程编译
更多详情见:[远程编译](https://xmake.io/zh/guide/extras/remote-compilation.html)
## 更多例子
#### Debug 和 Release 模式
```lua
add_rules("mode.debug", "mode.release")
target("console")
set_kind("binary")
add_files("src/*.c")
if is_mode("debug") then
add_defines("DEBUG")
end
```
#### 自定义脚本
```lua
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target)
print("hello: %s", target:name())
os.exec("echo %s", target:targetfile())
end)
```
#### 依赖包自动集成
下载和使用在 [xmake-repo](https://github.com/xmake-io/xmake-repo) 和第三方包仓库的依赖包:
```lua
add_requires("tbox >1.6.1", "libuv master", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8")
add_requires("conan::openssl/1.1.1g", {alias = "openssl", optional = true, debug = true})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("tbox", "libuv", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8", "openssl")
```
另外,我们也可以使用 [xrepo](https://github.com/xmake-io/xrepo) 命令来快速安装依赖包。
#### Qt QuickApp 应用程序
```lua
target("test")
add_rules("qt.quickapp")
add_files("src/*.cpp")
add_files("src/qml.qrc")
```
#### Cuda 程序
```lua
target("test")
set_kind("binary")
add_files("src/*.cu")
add_cugencodes("native")
add_cugencodes("compute_75")
```
#### WDK/UMDF 驱动程序
```lua
target("echo")
add_rules("wdk.driver", "wdk.env.umdf")
add_files("driver/*.c")
add_files("driver/*.inx")
add_includedirs("exe")
target("app")
add_rules("wdk.binary", "wdk.env.umdf")
add_files("exe/*.cpp")
```
更多WDK驱动程序例子(umdf/kmdf/wdm),见:[WDK工程例子](https://xmake.io/zh/examples/cpp/wdk.html)
#### iOS/MacOS 应用程序
```lua
target("test")
add_rules("xcode.application")
add_files("src/*.m", "src/**.storyboard", "src/*.xcassets")
add_files("src/Info.plist")
```
#### Framework 和 Bundle 程序(iOS/MacOS)
```lua
target("test")
add_rules("xcode.framework") -- 或者 xcode.bundle
add_files("src/*.m")
add_files("src/Info.plist")
```
#### OpenMP 程序
```lua
add_requires("libomp", {optional = true})
target("loop")
set_kind("binary")
add_files("src/*.cpp")
add_rules("c++.openmp")
add_packages("libomp")
```
#### Zig 程序
```lua
target("test")
set_kind("binary")
add_files("src/main.zig")
```
### 自动拉取远程工具链
#### 拉取指定版本的 llvm 工具链
我们使用 llvm-10 中的 clang 来编译项目。
```lua
add_requires("llvm 10.x", {alias = "llvm-10"})
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("llvm@llvm-10")
```
#### 拉取交叉编译工具链
我们也可以拉取指定的交叉编译工具链来编译项目。
```lua
add_requires("muslcc")
target("test")
set_kind("binary")
add_files("src/*.c")
set_toolchains("@muslcc")
```
#### 拉取工具链并且集成对应工具链编译的依赖包
我们也可以使用指定的muslcc交叉编译工具链去编译和集成所有的依赖包。
```lua
add_requires("muslcc")
add_requires("zlib", "libogg", {system = false})
set_toolchains("@muslcc")
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("zlib", "libogg")
```
## 插件
#### 生成IDE工程文件插件(makefile, vs2002 - vs2026, ...)
```bash
$ xmake project -k vsxmake -m "debug,release" # 新版vs工程生成插件(推荐)
$ xmake project -k vs -m "debug,release"
$ xmake project -k cmake
$ xmake project -k ninja
$ xmake project -k compile_commands
```
#### 加载自定义lua脚本插件
```bash
$ xmake l ./test.lua
$ xmake l -c "print('hello xmake!')"
$ xmake l lib.detect.find_tool gcc
$ xmake l
> print("hello xmake!")
> {1, 2, 3}
< {
1,
2,
3
}
```
更多内置插件见相关文档:[内置插件文档](https://xmake.io/zh/guide/extensions/builtin-plugins.html)
其他扩展插件,请到插件仓库进行下载安装: [xmake-plugins](https://github.com/xmake-io/xmake-plugins).
## IDE和编辑器插件
* [xmake-vscode](https://github.com/xmake-io/xmake-vscode)
* [xmake-sublime](https://github.com/xmake-io/xmake-sublime)
* [xmake-idea](https://github.com/xmake-io/xmake-idea)
* [xmake-zed](https://github.com/xmake-io/xmake-zed) (thanks [@jeleferai](https://github.com/jeleferai))
* [xmake.vim](https://github.com/luzhlon/xmake.vim) (third-party, thanks [@luzhlon](https://github.com/luzhlon))
* [xmake-visualstudio](https://github.com/HelloWorld886/xmake-visualstudio) (third-party, thanks [@HelloWorld886](https://github.com/HelloWorld886))
* [xmake-qtcreator](https://github.com/Arthapz/xmake-project-manager) (third-party, thanks [@Arthapz](https://github.com/Arthapz))
### XMake Gradle插件 (JNI)
我们也可以在Gradle中使用[xmake-gradle](https://github.com/xmake-io/xmake-gradle)插件来集成编译JNI库
```
plugins {
id 'org.tboox.gradle-xmake-plugin' version '1.1.5'
}
android {
externalNativeBuild {
xmake {
path "jni/xmake.lua"
}
}
}
```
当`gradle-xmake-plugin`插件被应用生效后,`xmakeBuild`任务会自动注入到现有的`assemble`任务中去,自动执行jni库编译和集成。
```console
$ ./gradlew app:assembleDebug
> Task :nativelib:xmakeConfigureForArm64
> Task :nativelib:xmakeBuildForArm64
>> xmake build
[ 50%]: ccache compiling.debug nativelib.cc
[ 75%]: linking.debug libnativelib.so
[100%]: build ok!
>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/arm64-v8a
> Task :nativelib:xmakeConfigureForArmv7
> Task :nativelib:xmakeBuildForArmv7
>> xmake build
[ 50%]: ccache compiling.debug nativelib.cc
[ 75%]: linking.debug libnativelib.so
[100%]: build ok!
>> install artifacts to /Users/ruki/projects/personal/xmake-gradle/nativelib/libs/armeabi-v7a
> Task :nativelib:preBuild
> Task :nativelib:assemble
> Task :app:assembleDebug
```
## CI 集成
### GitHub Action
我们可以使用 [github-action-setup-xmake](https://github.com/xmake-io/github-action-setup-xmake) 在 Github Action 上实现跨平台安装集成 Xmake。
```
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
```
## 谁在使用 Xmake?
请点击 [用户列表](https://xmake.io/zh/about/who_is_using_xmake) 查看完整用户使用列表。
如果您在使用 xmake,也欢迎通过 PR 将信息提交至上面的列表,让更多的用户了解有多少用户在使用 xmake,也能让用户更加安心使用 xmake。
我们也会有更多的动力去持续投入,让 xmake 项目和社区更加繁荣。
## 联系方式
* 邮箱:[waruqi@gmail.com](mailto:waruqi@gmail.com)
* 主页:[xmake.io](https://xmake.io/zh/)
* 社区
- [Reddit论坛](https://www.reddit.com/r/xmake/)
- [Telegram群组](https://t.me/tbooxorg)
- [Discord聊天室](https://discord.gg/xmake)
- QQ群:343118190, 662147501
* 源码:[Github](https://github.com/xmake-io/xmake), [Gitee](https://gitee.com/tboox/xmake)
* 微信公众号:tboox-os
## 感谢
感谢所有对xmake有所[贡献](CONTRIBUTING.md)的人:
* [TitanSnow](https://github.com/TitanSnow): 提供xmake [logo](https://github.com/TitanSnow/ts-xmake-logo) 和安装脚本。
* [uael](https://github.com/uael): 提供语义版本跨平台c库 [sv](https://github.com/uael/sv)。
* [OpportunityLiu](https://github.com/OpportunityLiu): 改进cuda构建, tests框架和ci。
* [xq144](https://github.com/xq114): 改进 `xrepo env shell`,并贡献大量包到 [xmake-repo](https://github.com/xmake-io/xmake-repo) 仓库。
* [star-hengxing](https://github.com/star-hengxing): 贡献大量包到 [xmake-repo](https://github.com/xmake-io/xmake-repo) 仓库。
* [SirLynix](https://github.com/SirLynix): 贡献了许多的包,并且让更多的人知道和了解 xmake。
* [Arthapz](https://github.com/Arthapz): 贡献新的 C++ Modules 实现。
================================================
FILE: configure
================================================
#!/bin/sh
# A script-only build utility like autotools
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http:##www.apache.org#licenses#LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copyright (C) 2022-present, Xmake Open Source Community.
#
# @author ruki
# @homepage https://github.com/xmake-io/xmake.sh
#
#-----------------------------------------------------------------------------
# some constants
#
xmake_sh_projectdir=$(X= cd -- "$(dirname -- "$0")" && pwd -P)
xmake_sh_builddir="build"
xmake_sh_version="1.0.5"
xmake_sh_verbose=false
xmake_sh_diagnosis=false
xmake_sh_copyright="Copyright (C) 2022-present Ruki Wang, https://xmake.io."
xmake_sh_makefile="${xmake_sh_projectdir}/Makefile"
xmake_sh_ninjafile="${xmake_sh_projectdir}/build.ninja"
#-----------------------------------------------------------------------------
# some helper functions
#
raise() {
echo "$@" 1>&2 ; exit 1
}
vprint() {
if "${xmake_sh_verbose}"; then
echo "$@"
fi
}
dprint() {
if "${xmake_sh_diagnosis}"; then
echo "$@"
fi
}
# show and escape string instead of `echo -e`, because sh does not support it
print() {
printf "${@}\n"
}
wprint() {
if "${xmake_sh_verbose}"; then
printf "warning: ${@}\n"
fi
}
# test empty string
test_z() {
if test "x${1}" = "x"; then
return 0
fi
return 1
}
# test non-empty string
test_nz() {
if test "x${1}" != "x"; then
return 0
fi
return 1
}
# test string is equal
test_eq() {
if test "x${1}" = "x${2}"; then
return 0
fi
return 1
}
# test string is not equal
test_nq() {
if test "x${1}" != "x${2}"; then
return 0
fi
return 1
}
string_toupper() {
_ret=$(echo "$1" | tr '[a-z]' '[A-Z]')
}
string_tolower() {
_ret=$(echo "$1" | tr '[A-Z]' '[a-z]')
}
string_replace() {
local src="${1}"
local search="${2}"
local replace="${3}"
if test_z "${search}"; then
_ret="${src}"
return
fi
local rest="${src}"
local result=""
local prefix=""
while :; do
case "${rest}" in
*"${search}"*)
prefix="${rest%%"${search}"*}"
result="${result}${prefix}${replace}"
rest="${rest#*"${search}"}"
;;
*)
result="${result}${rest}"
break
;;
esac
done
_ret="${result}"
}
# escape value for writing into ninja files
_ninja_escape() {
local rest="${1}"
case "${rest}" in
*\$*)
local result=""
while :; do
case "${rest}" in
*\$*)
result="${result}${rest%%\$*}\$\$"
rest="${rest#*\$}"
;;
*)
result="${result}${rest}"
break
;;
esac
done
_ret="${result}"
;;
*)
_ret="${rest}"
;;
esac
}
_shell_escape_single_quotes() {
local value="${1}"
case "${value}" in
*"'"*)
local escaped=""
while :; do
case "${value}" in
*"'"*)
escaped="${escaped}${value%%\'*}'\"'\"'"
value="${value#*\'}"
;;
*)
escaped="${escaped}${value}"
break
;;
esac
done
_ret="'${escaped}'"
;;
*)
_ret="'${value}'"
;;
esac
}
# we avoid use `cut` command, because it's slow
string_split() {
local str="${1}"
local sep="${2}"
local idx="${3}"
local oldifs="${IFS}"
IFS="${sep}"
set -- ${str}
if test_nz "${idx}"; then
case "${idx}" in
1) _ret="$1";;
2) _ret="$2";;
3) _ret="$3";;
4) _ret="$4";;
5) _ret="$5";;
6) _ret="$6";;
esac
else
_ret="$1"
_ret2="$2"
_ret3="$3"
_ret4="$4"
_ret5="$5"
_ret6="$6"
fi
IFS="${oldifs}"
}
# does contain sub-string?
# e.g.
# str="src/*.cpp"
# string_contains "$str" "src"
string_contains() {
case "${1}" in
*${2}*) return 0;;
*) return 1;;
esac
return 1
}
# does contain "*"?
string_contains_star() {
case "${1}" in
*\**) return 0;; # bash
*'*'*) return 0;; # csh
*) return 1;;
esac
return 1
}
# does contain "**"?
string_contains_star2() {
case "${1}" in
*\*\**) return 0;; # bash
*'**'*) return 0;; # csh
*) return 1;;
esac
return 1
}
# does startswith sub-string?
# e.g.
# str="src/*.cpp"
# string_startswith "$str" "src"
string_startswith() {
case "${1}" in
${2}*) return 0;;
*) return 1;;
esac
return 1
}
# duplicate characters
# e.g. string_dupch 10 "." => ...........
string_dupch() {
local count=${1}
local ch=${2}
local result=""
while [ "${count:-0}" -gt 0 ]; do
result="${result}${ch}"
count=$((count - 1))
done
printf '%s' "${result}"
}
# replace file content
_io_replace_file() {
local infile="${1}"
local outfile="${2}"
local patterns="${3}"
sed "/./ {${patterns}}" "${infile}" > "${outfile}"
}
# try remove file or directory
_os_tryrm() {
if test -f "${1}"; then
rm "${1}"
elif test -d "${1}"; then
rm -r "${1}"
fi
}
# get temporary file
# https://github.com/xmake-io/xmake/issues/5464
_os_tmpfile() {
_ret=$(mktemp "${TMPDIR-/tmp}/tmp.XXXXXXXX")
}
# try run program
_os_runv() {
if ${xmake_sh_diagnosis}; then
${@}
else
${@} >/dev/null 2>&1
fi
local ok=$?
if test "${ok}" -ne "0"; then
return 1
fi
return 0
}
# try run program and get output
_os_iorunv() {
_os_tmpfile
local tmpfile="${_ret}"
${@} >"${tmpfile}" 2>&1
local ok=$?
if test "${ok}" -ne "0"; then
_ret=""
else
local result=$(cat "${tmpfile}")
_ret="${result}"
fi
_os_tryrm "${tmpfile}"
}
# find file in the given directory
# e.g. _os_find . xmake.sh [depth]
_os_find() {
local dir="${1}"
local name="${2}"
local depth="${3}"
if test_nz "${depth}"; then
# Solaris doesn't support -maxdepth, use shell to filter depth
if is_host "solaris"; then
_ret=""
local file=""
for file in $(find "${dir}" -type f -name "${name}" | LC_ALL=C sort); do
local relpath="${file#${dir}/}"
local slash_count=$(echo "${relpath}" | tr -cd '/' | wc -c | tr -d ' ')
if test "${slash_count}" = "$((${depth} - 1))"; then
if test -z "${_ret}"; then
_ret="${file}"
else
_ret="${_ret}
${file}"
fi
fi
done
else
_ret=$(find "${dir}" -maxdepth "${depth}" -mindepth "${depth}" -type f -name "${name}" | LC_ALL=C sort)
fi
else
_ret=$(find "${dir}" -type f -name "${name}" | LC_ALL=C sort)
fi
}
# get date, "%Y%m%d%H%M" -> 202212072222
# Use deterministic timestamp from SOURCE_DATE_EPOCH if available
# https://reproducible-builds.org/docs/source-date-epoch/
_os_date() {
if test_z "${SOURCE_DATE_EPOCH}"; then
_ret=$(date +"${1}")
else
# Use GNU date options first, then fallback to BSD's, and finally fallback to current time.
_ret=$(date -u -d "@$SOURCE_DATE_EPOCH" +"${1}" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" +"${1}" 2>/dev/null || date +"${1}")
fi
}
# we avoid use `basename`, because it's slow
path_filename() {
local path="${1}"
if test_eq "${path}" "/"; then
_ret="/"
else
_ret="${path##*/}"
fi
}
path_extension() {
path_filename "${1}"; local filename="${_ret}"
_ret=".${filename##*.}"
}
path_basename() {
path_filename "${1}"; local filename="${_ret}"
_ret="${filename%.*}"
}
# we avoid use `dirname -- ${1}`, because it's too slow
path_directory() {
local path="${1}"
if test_z "${path}"; then
raise "invalid empty path in path_directory()."
fi
path="${path%/}"
local dir="${path%/*}"
if string_startswith "${path}" "/"; then
if test_z "${dir}"; then
dir="/"
fi
else
dir="${dir#/}"
if test_z "${dir}"; then
dir="."
fi
fi
_ret="${dir}"
}
# e.g. path_filename_fromdir "/tmp/file" "/tmp" -> "file"
path_filename_fromdir() {
_ret="${1#${2}/}"
}
path_is_absolute() {
if string_startswith "${1}" "/"; then
return 0
fi
return 1
}
# get relative path, e.g $(path_relative ${rootdir} ${absolute_path}`
path_relative() {
local source="${1}"
local target="${2}"
if test_z "${source}" || test_z "${target}"; then
raise "invalid empty path in path_relative()"
fi
# patch missing "./"
source=${source#./}
source=${source#.}
target=${target#./}
target=${target#.}
if test_z "${source}"; then
_ret="${target}"
return
fi
# find common path
local result=""
local common_part=$source
while test_eq "${target#$common_part}" "${target}"; do
# no match, means that candidate common part is not correct
# go up one level (reduce common part)
path_directory "${common_part}"; common_part="${_ret}"
# and record that we went back, with correct / handling
if test_z "${result}"; then
result=".."
else
result="../${result}"
fi
done
if test_eq "${common_part}" "/"; then
# special case for root (no common path)
result="${result}/"
fi
# since we now have identified the common part,
# compute the non-common part
local forward_part="${target#$common_part}"
# and now stick all parts together
if test_nz "${result}" && test_nz "${forward_part}"; then
result="${result}${forward_part}"
elif test_nz "${forward_part}"; then
result="${forward_part#*/}"
fi
# same directory?
if test_z "${result}" && test_eq "${source}" "${target}"; then
result="."
fi
_ret="${result}"
}
path_sourcekind() {
local sourcekind=""
case "${1}" in
*.cpp) sourcekind="cxx";;
*.cc) sourcekind="cxx";;
*.c) sourcekind="cc";;
*.ixx) sourcekind="cxx";;
*.mm) sourcekind="mxx";;
*.m) sourcekind="mm";;
*.S) sourcekind="as";;
*.s) sourcekind="as";;
*.asm) sourcekind="as";;
*) raise "unknown sourcekind for ${1}" ;;
esac
_ret="${sourcekind}"
}
path_toolname() {
local toolname=""
case "${1}" in
*-gcc) toolname="gcc";;
*/gcc) toolname="gcc";;
gcc) toolname="gcc";;
gcc-*) toolname="gcc";;
*/gcc-*) toolname="gcc";;
*-g++) toolname="gxx";;
*/g++) toolname="gxx";;
g++) toolname="gxx";;
g++-*) toolname="gxx";;
*/g++-*) toolname="gxx";;
xcrun*clang++) toolname="clangxx";;
xcrun*clang) toolname="clang";;
*-clang++) toolname="clangxx";;
*/clang++) toolname="clangxx";;
clang++) toolname="clangxx";;
clang++-*) toolname="clangxx";;
*/clang++-*) toolname="clangxx";;
*-clang) toolname="clang";;
*/clang) toolname="clang";;
clang) toolname="clang";;
clang-*) toolname="clang";;
*/clang-*) toolname="clang";;
*/emcc) toolname="emcc";;
emcc) toolname="emcc";;
*/em++) toolname="emxx";;
em++) toolname="emxx";;
*/cosmocc) toolname="cosmocc";;
cosmocc) toolname="cosmocc";;
*/cosmoc++) toolname="cosmocxx";;
cosmoc++) toolname="cosmocxx";;
*-ar) toolname="ar";;
*/ar) toolname="ar";;
ar) toolname="ar";;
*/emar) toolname="emar";;
emar) toolname="emar";;
*/cosmoar) toolname="cosmoar";;
cosmoar) toolname="cosmoar";;
cc) toolname="gcc";;
*/cc) toolname="gcc";;
c++) toolname="gxx";;
*/c++) toolname="gxx";;
tcc) toolname="tcc";;
*/tcc) toolname="tcc";;
*) raise "unknown tool ${1}";;
esac
_ret="${toolname}"
}
# get flag name from toolkind, e.g. cc => cflags, cxx => cxxflags
_get_flagname() {
local toolkind="${1}"
local flagname=""
case "${toolkind}" in
cc) flagname="cflags";;
cxx) flagname="cxxflags";;
as) flagname="asflags";;
mm) flagname="mflags";;
mxx) flagname="mxxflags";;
ar) flagname="arflags";;
sh) flagname="shflags";;
ld) flagname="ldflags";;
*) raise "unknown toolkind(${toolkind})!" ;;
esac
_ret="${flagname}"
}
# is enabled? true, yes, y
_is_enabled() {
local value=${1}
if test_eq "${value}" "true"; then
return 0
elif test_eq "${value}" "yes"; then
return 0
elif test_eq "${value}" "y"; then
return 0
fi
return 1
}
# deduplicate string list
# .e.g "hello world hello how are you world" -> hello world how are you
_dedup() {
_ret=$(echo "${1}" | awk '{for (i = 1; i <= NF; ++i) if (!seen[$i]++) printf $i " "}')
}
# deduplicate string list from the reverse order
# .e.g "hello world hello how are you world" -> hello how are you world
_dedup_reverse() {
local result=""
local list=""
local item=""
list=$(echo "${1}" | awk '{for (i = NF; i > 0; --i) if (!seen[$i]++) printf $i " "}')
for item in ${list}; do
result="${item} ${result}"
done
_ret="${result}"
}
#-----------------------------------------------------------------------------
# map functions
#
# define map, @note we can not use bash/declare to define map, because sh does not support it.
#
# _map "options"
# _map_set "options" "key1" "value1"
# _map_set "options" "key2" "value2"
# _map_set "options" "key2" "value3"
# _map_set "options" "key3" "value3"
# _map_set "options" "key4" "__empty__"
# _map_set "options" "key4" "__empty__"
# _map_count "options"; _count="${_ret}"
# _map_keys "options"; _keys="${_ret}"
# echo ${_count}
# for key in ${_keys}; do
# _map_get "options" ${key}; value="{_ret}"
# echo ${key} "->" ${value}
# done
#
# echo "------"
# _map_remove "options" "key3"
# _map_count "options"; _count="${_ret}"
# _map_keys "options"; _keys="${_ret}"
# echo ${_count}
# for key in ${_keys}; do
# _map_get "options" ${key}; value="{_ret}"
# echo ${key} "->" ${value}
# done
#
_map() {
local name=${1}
# eval _map_${name}_count=0
# eval _map_${name}_keys=""
}
# because the shell is slow, we have to temporarily
# disable some of the map features for performance.
#
#_map_count() {
# local name=${1}
# local count=$(eval echo \$_map_${name}_count)
# _ret="${count}"
#}
_map_get() {
local name="${1}"
local key="${2}"
_ret=$(eval echo \$_map_${name}_value_${key})
if test_eq "${_ret}" "__empty__"; then
_ret=""
fi
}
_map_has() {
local name="${1}"
local key="${2}"
local value=""
value=$(eval echo \$_map_${name}_value_${key})
if test_nz "${value}"; then
return 0
fi
return 1
}
_map_set() {
local name="${1}"
local key="${2}"
local value="${3}"
# if ! _map_has ${name} ${key}; then
# _map_count "options"; local count="${_ret}"
# eval _map_${name}_count=$((${count} + 1))
# local keys=$(eval echo \$_map_${name}_keys)
# keys="${keys} ${key}"
# eval _map_${name}_keys=\${keys}
# fi
eval _map_${name}_value_${key}=\${value}
}
#_map_remove() {
# local name="${1}"
# local key="${2}"
# if _map_has ${name} ${key}; then
# _map_count "options"; local count="${_ret}"
# eval _map_${name}_count=$((${count} - 1))
# eval _map_${name}_value_${key}=""
# local keys=$(eval echo \$_map_${name}_keys)
# local keys_new=""
# local k=""
# for k in ${keys}; do
# if test_nq "${k}" "${key}"; then
# keys_new="${keys_new} ${k}"
# fi
# done
# eval _map_${name}_keys=\${keys_new}
# fi
#}
#_map_keys() {
# local name="${1}"
# local keys=$(eval echo \$_map_${name}_keys)
# _ret="${keys}"
#}
#-----------------------------------------------------------------------------
# detect default environments
#
# detect hosts
os_host=`uname`
string_tolower ${os_host}; os_host="${_ret}"
case "${os_host}" in
*cygwin*) os_host="cygwin" ;;
*mingw*|*msys*) os_host="msys" ;;
*darwin*) os_host="macosx" ;;
*linux*) os_host="linux" ;;
*freebsd*) os_host="freebsd" ;;
*netbsd*) os_host="netbsd" ;;
*openbsd*) os_host="openbsd" ;;
*dragonfly*) os_host="dragonflybsd" ;;
*bsd*) os_host="bsd" ;;
*sunos*) os_host="solaris" ;;
*haiku*) os_host="haiku" ;;
esac
# determining host
# e.g.
# if is_host "linux" "macosx"; then
# ...
# fi
is_host() {
local host=""
for host in $@; do
if test_eq "${os_host}" "${host}"; then
return 0
fi
done
return 1
}
# detect host architecture
os_arch=`uname -m | tr '[A-Z]' '[a-z]'`
if test_eq "${os_arch}" "i686" || test_eq "${os_arch}" "i86pc"; then
os_arch="i386"
elif test_eq "${os_arch}" "amd64"; then
os_arch="x86_64"
elif test_eq "${os_arch}" "aarch64" || test_eq "${os_arch}" "arm64"; then
os_arch="arm64"
elif string_contains "${os_arch}" "armv7"; then
os_arch="armv7"
elif string_contains "${os_arch}" "arm"; then
os_arch="arm"
elif string_contains "${os_arch}" "power macintosh"; then
os_arch="ppc"
fi
# set the default target platform
_target_plat_default=${os_host}
if is_host "msys"; then
_target_plat_default="mingw"
elif is_host "freebsd" "openbsd" "dragonflybsd" "netbsd"; then
_target_plat_default="bsd"
elif test_nz "${EMSDK}"; then
_target_plat_default="wasm"
fi
# set the default target architecture
_target_arch_default=${os_arch}
if is_host "msys" && test_nz "${MSYSTEM_CARCH}"; then
_target_arch_default="${MSYSTEM_CARCH}"
elif test_nz "${TERMUX_ARCH}"; then
_target_arch_default="${TERMUX_ARCH}"
elif test_nz "${EMSDK}"; then
_target_arch_default="wasm32"
fi
if test_eq "${_target_arch_default}" "i686"; then
_target_arch_default="i386"
elif test_eq "${_target_arch_default}" "aarch64" || test_eq "${_target_arch_default}" "arm64"; then
_target_arch_default="arm64"
elif string_contains "${_target_arch_default}" "armv7"; then
_target_arch_default="armv7"
elif string_contains "${_target_arch_default}" "arm"; then
_target_arch_default="arm"
fi
# set the default target mode
_target_mode_default="release"
# set the default target kind
_target_kind_default="static"
# set the default project generator and build program
if is_host "freebsd" "netbsd" "openbsd" "dragonflybsd" "bsd" "solaris"; then
project_generator="gmake"
_make_program_default="gmake"
_ninja_program_default="ninja"
elif is_host "msys" "cygwin"; then
project_generator="gmake"
_make_program_default="make.exe"
_ninja_program_default="ninja.exe"
else
project_generator="gmake"
_make_program_default="make"
_ninja_program_default="ninja"
fi
# set the default directories
if test -d "/usr/local"; then
_install_prefix_default="/usr/local"
elif test -d "/usr"; then
_install_prefix_default="/usr"
fi
_install_bindir_default="\${prefix}/bin"
_install_libdir_default="\${prefix}/lib"
_install_includedir_default="\${prefix}/include"
# determining target platform
# e.g.
# if is_plat "linux" "macosx"; then
# ...
# fi
is_plat() {
local plat=""
for plat in $@; do
if test_eq "${_target_plat}" "${plat}"; then
return 0
fi
done
return 1
}
# determining target architecture
# e.g.
# if is_arch "x86_64" "i386"; then
# ...
# fi
is_arch() {
local arch=""
for arch in $@; do
if test_eq "${_target_arch}" "${arch}"; then
return 0
fi
done
return 1
}
# determining target mode
# e.g.
# if is_mode "release"; then
# ...
# fi
is_mode() {
local mode=""
for mode in $@; do
if test_eq "${_target_mode}" "${mode}"; then
return 0
fi
done
return 1
}
# determining target kind
# e.g.
# if is_kind "release"; then
# ...
# fi
is_kind() {
local kind=""
for kind in $@; do
if test_eq "${_target_kind}" "${kind}"; then
return 0
fi
done
return 1
}
# determining target toolchain
# e.g.
# if is_toolchain "clang"; then
# ...
# fi
is_toolchain() {
local toolchain=""
for toolchain in $@; do
if test_eq "${_target_toolchain}" "${toolchain}"; then
return 0
fi
done
return 1
}
#-----------------------------------------------------------------------------
# project configuration apis
#
# set project name
set_project() {
_xmake_sh_project_name="${1}"
}
# include the given xmake.sh file or directory
# e.g. includes "src" "tests"
includes() {
local path=""
for path in $@; do
if test -f "${path}"; then
path_directory "${path}"; xmake_sh_scriptdir="${_ret}"
. "${path}"
else
local xmake_sh_scriptdir_cur=${xmake_sh_scriptdir}
if test "x${xmake_sh_scriptdir}" != "x"; then
xmake_sh_scriptdir="${xmake_sh_scriptdir_cur}/${path}"
. "${xmake_sh_scriptdir}/xmake.sh"
else
. "${xmake_sh_projectdir}/${path}/xmake.sh"
fi
xmake_sh_scriptdir=${xmake_sh_scriptdir_cur}
fi
done
}
#-----------------------------------------------------------------------------
# some helper functions
#
# split flags
_split_flags() {
string_replace "${1}" ":" " "
}
# get abstract flag for gcc/clang
_get_abstract_flag_for_gcc_clang() {
local toolkind="${1}"
local toolname="${2}"
local itemname="${3}"
local value="${4}"
local flag=""
case "${itemname}" in
defines)
string_replace "${value}" '"' '\"'; value="${_ret}"
flag="-D${value}"
;;
undefines) flag="-U${value}";;
includedirs) flag="-I${value}";;
linkdirs) flag="-L${value}";;
links) flag="-l${value}";;
syslinks) flag="-l${value}";;
frameworks) flag="-framework ${value}";;
frameworkdirs) flag="-F${value}";;
rpathdirs)
if is_plat "macosx"; then
string_replace "${value}" "\$ORIGIN" "@loader_path"; value="${_ret}"
flag="-Xlinker -rpath -Xlinker ${value}"
else
# escape $ORIGIN in makefile, TODO we need also handle it for ninja
string_replace "${value}" "@loader_path" '$$ORIGIN'; value="${_ret}"
if is_plat "bsd"; then
flag="-Wl,-zorigin -Wl,-rpath='${value}'"
else
flag="-Wl,-rpath='${value}'"
fi
fi
;;
symbols)
if test_eq "${value}" "debug"; then
flag="-g"
elif test_eq "${value}" "hidden"; then
flag="-fvisibility=hidden"
fi
;;
strip)
if test_eq "${value}" "debug"; then
flag="-Wl,-S"
elif test_eq "${value}" "all"; then
if is_plat "macosx"; then
flag="-Wl,-x -Wl,-dead_strip"
else
flag="-s"
fi
fi
;;
warnings)
if test_eq "${value}" "all" || test_eq "${value}" "more" || test_eq "${value}" "less"; then
flag="-Wall"
elif test_eq "${value}" "allextra"; then
flag="-Wall -Wextra"
elif test_eq "${value}" "error"; then
flag="-Werror"
elif test_eq "${value}" "everything"; then
flag="-Wall -Wextra"
elif test_eq "${value}" "none"; then
flag="-w"
fi
;;
optimizes)
if test_eq "${value}" "fast"; then
flag="-O1"
elif test_eq "${value}" "faster"; then
flag="-O2"
elif test_eq "${value}" "fastest"; then
flag="-O3"
elif test_eq "${value}" "smallest"; then
if test_eq "${toolname}" "clang" || test_eq "${toolname}" "clangxx"; then
flag="-Oz"
else
flag="-Os"
fi
elif test_eq "${value}" "aggressive"; then
flag="-Ofast"
elif test_eq "${value}" "none"; then
flag="-O0"
fi
;;
languages)
if test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "mm"; then
case "${value}" in
ansi) flag="-ansi";;
c89) flag="-std=c89";;
gnu89) flag="-std=gnu89";;
c99) flag="-std=c99";;
gnu99) flag="-std=gnu99";;
c11) flag="-std=c11";;
gnu11) flag="-std=gnu11";;
c17) flag="-std=c17";;
gnu17) flag="-std=gnu17";;
esac
elif test_eq "${toolkind}" "cxx" || test_eq "${toolkind}" "mxx"; then
case "${value}" in
cxx98) flag="-std=c++98";;
c++98) flag="-std=c++98";;
gnuxx98) flag="-std=gnu++98";;
gnu++98) flag="-std=gnu++98";;
cxx11) flag="-std=c++11";;
c++11) flag="-std=c++11";;
gnuxx11) flag="-std=gnu++11";;
gnu++11) flag="-std=gnu++11";;
cxx14) flag="-std=c++14";;
c++14) flag="-std=c++14";;
gnuxx14) flag="-std=gnu++14";;
gnu++14) flag="-std=gnu++14";;
cxx17) flag="-std=c++17";;
c++17) flag="-std=c++17";;
gnuxx17) flag="-std=gnu++17";;
gnu++17) flag="-std=gnu++17";;
cxx1z) flag="-std=c++1z";;
c++1z) flag="-std=c++1z";;
gnuxx1z) flag="-std=gnu++1z";;
gnu++1z) flag="-std=gnu++1z";;
cxx2a) flag="-std=c++2a";;
c++2a) flag="-std=c++2a";;
gnuxx2a) flag="-std=gnu++2a";;
gnu++2a) flag="-std=gnu++2a";;
cxx20) flag="-std=c++20";;
c++20) flag="-std=c++20";;
gnuxx20) flag="-std=gnu++20";;
gnu++20) flag="-std=gnu++20";;
cxx*) raise "unknown language value(${value})!" ;;
c++*) raise "unknown language value(${value})!" ;;
esac
fi
;;
*) raise "unknown itemname(${itemname})!" ;;
esac
_ret="${flag}"
}
# get abstract flags
_get_abstract_flags() {
local toolkind="${1}"
local toolname="${2}"
local itemname="${3}"
local values="${4}"
local flags=""
local value=""
for value in ${values}; do
local flag=""
case "${toolname}" in
gcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
gxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
clang) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
clangxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
emcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
emxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
cosmocc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
cosmocxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
tcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
if test_nz "${flag}"; then
flags="${flags} ${flag}"
fi
done
_ret="${flags}"
}
#-----------------------------------------------------------------------------
# option configuration apis
#
# define option
option() {
local name="${1}"
local description="${2}"
local default=${3}
_xmake_sh_option_current="${name}"
if ! ${_loading_options}; then
if test_nz "${description}"; then
_xmake_sh_option_current=""
fi
return
fi
if ! _map_has "options" "${name}_name"; then
_xmake_sh_options="${_xmake_sh_options} ${name}"
fi
_map_set "options" "${name}_name" "${name}"
_map_set "options" "${name}_description" "${description}"
_map_set "options" "${name}_default" "${default}"
# we end option if it's just one line
if test_nz "${description}"; then
_xmake_sh_option_current=""
fi
return 0
}
option_end() {
_xmake_sh_option_current=""
}
_map "options"
# has the given option?
_has_option() {
local name=${1}
if _map_has "options" "${name}_name"; then
return 0
fi
return 1
}
# get the given option item
_get_option_item() {
local name=${1}
local key=${2}
_map_get "options" "${name}_${key}"
}
# set the given option item
_set_option_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_set "options" "${name}_${key}" "${@}"
else
raise "please call set_${key}(${@}) in the option scope!"
fi
}
# add values to the given option item
_add_option_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_get "options" "${name}_${key}"; local values="${_ret}"
values="${values} ${@}"
_map_set "options" "${name}_${key}" "${values}"
else
raise "please call add_${key}(${@}) in the option scope!"
fi
}
# get the give option value
_get_option_value() {
local name=${1}
_get_option_item "${name}" "value"
if test "x${_ret}" = "x"; then
_get_option_item "${name}" "default"
fi
}
# set the give option value
_set_option_value() {
local name=${1}
local value=${2}
_set_option_item "${name}" "value" "${value}"
}
# this option need checking?
_option_need_checking() {
local name="${1}"
_get_option_item "${name}" "default"; local default="${_ret}"
if test_nz "${default}"; then
return 1
fi
_get_option_item "${name}" "cfuncs"; local cfuncs="${_ret}"
_get_option_item "${name}" "cxxfuncs"; local cxxfuncs="${_ret}"
_get_option_item "${name}" "cincludes"; local cincludes="${_ret}"
_get_option_item "${name}" "cxxincludes"; local cxxincludes="${_ret}"
_get_option_item "${name}" "ctypes"; local ctypes="${_ret}"
_get_option_item "${name}" "cxxtypes"; local cxxtypes="${_ret}"
_get_option_item "${name}" "csnippets"; local csnippets="${_ret}"
_get_option_item "${name}" "cxxsnippets"; local cxxsnippets="${_ret}"
_get_option_item "${name}" "links"; local links="${_ret}"
_get_option_item "${name}" "syslinks"; local syslinks="${_ret}"
if test_nz "${cfuncs}" || test_nz "${cxxfuncs}" ||
test_nz "${cincludes}" || test_nz "${cxxincludes}" ||
test_nz "${ctypes}" || test_nz "${cxxtypes}" ||
test_nz "${csnippets}" || test_nz "${cxxsnippets}" ||
test_nz "${links}" || test_nz "${syslinks}"; then
return 0
fi
return 1
}
# get options for the help menu
_get_options_for_menu() {
local options=""
local name=""
for name in ${_xmake_sh_options}; do
_get_option_item "${name}" "showmenu"; local showmenu="${_ret}"
if _is_enabled "${showmenu}"; then
options="${options} ${name}"
elif test_z "${showmenu}" && ! _option_need_checking "${name}"; then
options="${options} ${name}"
fi
done
_ret="${options}"
}
# get options for checking
_get_options_for_checking() {
local options=""
local name=""
for name in ${_xmake_sh_options}; do
_get_option_item "${name}" "showmenu"; local showmenu="${_ret}"
if test_z "${showmenu}" && _option_need_checking "${name}"; then
options="${options} ${name}"
fi
done
_ret="${options}"
}
# get abstract flags in option
_get_option_abstract_flags() {
local name="${1}"
local toolkind="${2}"
local toolname="${3}"
local itemname="${4}"
local values="${5}"
if test_z "${values}"; then
_get_option_item "${name}" "${itemname}"; values="${_ret}"
fi
_get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}"
}
# is config for option
is_config() {
if ! ${_loading_targets}; then
return 1
fi
local name=${1}
local value=${2}
_get_option_value "${name}"; local value_cur="${_ret}"
if test_eq "${value_cur}" "${value}"; then
return 0
fi
return 1
}
# has config for option
has_config() {
if ! ${_loading_targets}; then
return 1
fi
local name=${1}
_get_option_value "${name}"; local value_cur="${_ret}"
if _is_enabled ${value_cur}; then
return 0
fi
return 1
}
# set config for option, we can use it to modify option status when loading targets
set_config() {
local name=${1}
local value=${2}
_set_option_value "${name}" "${value}"
}
# set showmenu in option
set_showmenu() {
if ! ${_loading_options}; then
return
fi
local show="${1}"
_set_option_item "${_xmake_sh_option_current}" "showmenu" "${show}"
}
# set description in option
set_description() {
if ! ${_loading_options}; then
return
fi
local description="${1}"
_set_option_item "${_xmake_sh_option_current}" "description" "${description}"
}
# add cfuncs in option
add_cfuncs() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cfuncs" "${@}"
}
# add cxxfuncs in option
add_cxxfuncs() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cxxfuncs" "${@}"
}
# add cincludes in option
add_cincludes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cincludes" "${@}"
}
# add cxxincludes in option
add_cxxincludes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cxxincludes" "${@}"
}
# add ctypes in option
add_ctypes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "ctypes" "${@}"
}
# add cxxtypes in option
add_cxxtypes() {
if ! ${_loading_options}; then
return
fi
_add_option_item "${_xmake_sh_option_current}" "cxxtypes" "${@}"
}
# add csnippets in option
add_csnippets() {
if ! ${_loading_options}; then
return
fi
local csnippets="${1}"
_add_option_item "${_xmake_sh_option_current}" "csnippets" "${csnippets}"
}
# add cxxsnippets in option
add_cxxsnippets() {
if ! ${_loading_options}; then
return
fi
local cxxsnippets="${1}"
_add_option_item "${_xmake_sh_option_current}" "cxxsnippets" "${cxxsnippets}"
}
# before_check in option
before_check() {
if ! ${_loading_options}; then
return
fi
local funcname="${1}"
_add_option_item "${_xmake_sh_option_current}" "before_check" "${funcname}"
}
#-----------------------------------------------------------------------------
# target configuration apis
#
# define target
target() {
local name="${1}"
_xmake_sh_target_current="${name}"
if ! ${_loading_targets}; then
return
fi
if ! _map_has "targets" "${name}_name"; then
_xmake_sh_targets="${_xmake_sh_targets} ${name}"
fi
_map_set "targets" "${name}_name" "${name}"
return 0
}
target_end() {
_xmake_sh_target_current=""
}
_map "targets"
# has the given target?
_has_target() {
local name=${1}
if _map_has "targets" "${name}_name"; then
return 0
fi
return 1
}
# has the given target item
_has_target_item() {
local name=${1}
local key=${2}
if _map_has "targets" "${name}_${key}"; then
return 0
elif _map_has "targets" "__root_${key}"; then
return 0
fi
return 1
}
# get the given target item
_get_target_item() {
local name=${1}
local key=${2}
_map_get "targets" "${name}_${key}"
local values="${_ret}"
if _map_has "targets" "__root_${key}"; then
_map_get "targets" "__root_${key}"; local root_values="${_ret}"
if test_nz "${values}"; then
values="${root_values} ${values}"
else
values="${root_values}"
fi
fi
_ret="${values}"
}
# set the given target item
_set_target_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_set "targets" "${name}_${key}" "${@}"
else
_map_set "targets" "__root_${key}" "${@}"
fi
}
# add values to the given target item
_add_target_item() {
local name=${1}
local key=${2}
shift
shift
if test_nz "${name}"; then
_map_get "targets" "${name}_${key}"; local values="${_ret}"
values="${values} ${@}"
_map_set "targets" "${name}_${key}" "${values}"
else
_map_get "targets" "__root_${key}"; local values="${_ret}"
values="${values} ${@}"
_map_set "targets" "__root_${key}" "${values}"
fi
}
# is default?
_is_target_default() {
local name="${1}"
if _has_target_item "${name}" "default"; then
_get_target_item "${target}" "default"; local default="${_ret}"
if _is_enabled ${default}; then
return 0
fi
return 1
fi
return 0
}
# get target basename
_get_target_basename() {
local name="${1}"
_get_target_item "${name}" "basename"; local basename="${_ret}"
if test_z "${basename}"; then
basename="${name}"
fi
_ret="${basename}"
}
# get target extension
_get_target_extension() {
local name="${1}"
local extension=""
if _has_target_item "${name}" "extension"; then
_get_target_item "${name}" "extension"; extension="${_ret}"
elif is_plat "mingw"; then
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xbinary"; then
extension=".exe"
elif test "x${kind}" = "xstatic"; then
extension=".a"
elif test "x${kind}" = "xshared"; then
extension=".dll"
fi
else
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xstatic"; then
extension=".a"
elif test "x${kind}" = "xshared"; then
if is_plat "macosx"; then
extension=".dylib"
else
extension=".so"
fi
fi
fi
_ret="${extension}"
}
# get target prefixname
_get_target_prefixname() {
local name="${1}"
local prefixname=""
if _has_target_item "${name}" "prefixname"; then
_get_target_item "${name}" "prefixname"; prefixname="${_ret}"
elif is_plat "mingw"; then
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xstatic"; then
prefixname="lib"
elif test "x${kind}" = "xshared"; then
prefixname="lib"
fi
else
_get_target_item "${name}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xstatic"; then
prefixname="lib"
elif test "x${kind}" = "xshared"; then
prefixname="lib"
fi
fi
_ret="${prefixname}"
}
# get target filename
_get_target_filename() {
local name="${1}"
_get_target_item "${name}" "filename"; local filename="${_ret}"
if test_z "${filename}"; then
_get_target_basename "${name}"; local basename="${_ret}"
_get_target_extension "${name}"; local extension="${_ret}"
_get_target_prefixname "${name}"; local prefixname="${_ret}"
filename="${prefixname}${basename}${extension}"
fi
_ret="${filename}"
}
# get target soname
# @see https://github.com/tboox/tbox/issues/214
#
# set_version "1.0.1" "" "1" -> libfoo.so.1, libfoo.1.dylib
# set_version "1.0.1" "" "A" -> libfoo.so.A, libfoo.A.dylib
_get_target_soname() {
local soname=""
local name="${1}"
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared" && is_plat "macosx" "linux" "bsd"; then
_get_target_item "${name}" "version"; local version="${_ret}"
_get_target_item "${name}" "version_soname"; local version_soname="${_ret}"
if test_nz "${version}" && test_nz "${version_soname}"; then
_get_target_filename "${name}"; soname="${_ret}"
_get_target_extension "${name}"; local extension="${_ret}"
if test_eq "${extension}" ".dylib"; then
path_basename "${soname}"; local basename="${_ret}"
soname="${basename}.${version_soname}${extension}"
else
soname="${soname}.${version_soname}"
fi
fi
fi
_ret="${soname}"
}
# get target directory
_get_targetdir() {
local name="${1}"
_get_target_item "${name}" "targetdir"; local targetdir="${_ret}"
if test_z "${targetdir}"; then
targetdir="${xmake_sh_builddir}/${_target_plat}/${_target_arch}/${_target_mode}"
fi
_ret="${targetdir}"
}
# get target object directory
_get_target_objectdir() {
local name="${1}"
_get_target_item "${name}" "objectdir"; local objectdir="${_ret}"
if test_z "${objectdir}"; then
objectdir="${xmake_sh_builddir}/.objs/${name}/${_target_plat}/${_target_arch}/${_target_mode}"
fi
_ret="${objectdir}"
}
# get target file path
_get_target_file() {
local name="${1}"
_get_target_filename "${name}"; local filename="${_ret}"
_get_targetdir "${name}"; local targetdir="${_ret}"
local targetfile="${targetdir}/${filename}"
_ret="${targetfile}"
}
# get target librarydeps
_get_target_librarydeps_impl() {
local name="${1}"
local librarydeps=""
local dep=""
_get_target_item "${name}" "deps"; local deps="${_ret}"
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
librarydeps="${librarydeps} ${dep}"
_get_target_librarydeps_impl "${dep}"; local dep_librarydeps="${_ret}"
if test_nz "${dep_librarydeps}"; then
librarydeps="${librarydeps} ${dep_librarydeps}"
fi
fi
done
_ret="${librarydeps}"
}
_get_target_librarydeps() {
local name="${1}"
_get_target_item "${name}" "librarydeps"; local librarydeps="${_ret}"
if test_z "${librarydeps}" && test_nq "${librarydeps}" "__none__"; then
_get_target_librarydeps_impl "${name}"; librarydeps="${_ret}"
if test_nz "${librarydeps}"; then
_dedup_reverse "${librarydeps}"; librarydeps="${_ret}"
_set_target_item "${name}" "librarydeps" "${librarydeps}"
else
_set_target_item "${name}" "librarydeps" "__none__"
fi
fi
if test_eq "${librarydeps}" "__none__"; then
librarydeps=""
fi
_ret="${librarydeps}"
}
# get sourcefiles in target
_get_target_sourcefiles() {
local name="${1}"
_get_target_item "${name}" "files"
}
# get objectfile in target
_get_target_objectfile() {
local name="${1}"
local sourcefile="${2}"
local extension=".o"
if is_plat "mingw"; then
extension=".obj"
fi
_get_target_objectdir "${name}"; local objectdir="${_ret}"
local objectfile="${objectdir}/${sourcefile}${extension}"
_ret="${objectfile}"
}
# get objectfiles in target
_get_target_objectfiles() {
local name="${1}"
_get_target_sourcefiles "${name}"; local sourcefiles="${_ret}"
local objectfiles=""
local sourcefile=""
for sourcefile in ${sourcefiles}; do
_get_target_objectfile "${name}" "${sourcefile}"; local objectfile="${_ret}"
objectfiles="${objectfiles} ${objectfile}"
done
_ret="${objectfiles}"
}
# get abstract flags in target
_get_target_abstract_flags() {
local name="${1}"
local toolkind="${2}"
local toolname="${3}"
local itemname="${4}"
local values="${5}"
if test_z "${values}"; then
# get values from target
_get_target_item "${name}" "${itemname}"; values="${_ret}"
# get values from target deps
_get_target_librarydeps "${name}"; local deps="${_ret}"
local dep=""
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_target_item "${dep}" "${itemname}_public"; local depvalues="${_ret}"
if test_nz "${depvalues}"; then
values="${values} ${depvalues}"
fi
fi
done
fi
if test_nz "${values}"; then
_get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}"
else
_ret=""
fi
}
# get toolchain flags for ar in target
_get_target_toolchain_flags_for_ar() {
_ret="-cr"
}
# get toolchain flags for gcc in target
_get_target_toolchain_flags_for_gcc() {
local name="${1}"
local toolkind="${2}"
local flags=""
if is_arch "i386"; then
flags="${flags} -m32"
fi
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
if test_eq "${toolkind}" "sh"; then
flags="${flags} -shared -fPIC"
elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then
flags="${flags} -fPIC"
fi
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${toolkind}" "sh"; then
_get_target_soname "${name}"; local soname="${_ret}"
if test_nz "${soname}"; then
if is_plat "macosx"; then
flags="${flags} -Wl,-install_name,${soname}"
else
flags="${flags} -Wl,-soname,${soname}"
fi
fi
fi
fi
_ret="${flags}"
}
# get macOS sysroot and target flags for clang
# usage: _get_macosx_sysroot_flags [quoted]
# if quoted is "quoted", the sysroot path will be wrapped in escaped quotes (for eval)
_get_macosx_sysroot_flags() {
local flags=""
if is_plat "macosx"; then
_os_iorunv "xcrun" "-sdk" "macosx" "--show-sdk-path"; local sdkdir="${_ret}"
if test_nz "${sdkdir}"; then
if test_eq "${1}" "quoted"; then
flags="${flags} -isysroot \"${sdkdir}\""
else
flags="${flags} -isysroot ${sdkdir}"
fi
path_basename "${sdkdir}"; local basename="${_ret}"
if test_nz "${basename}" && string_startswith "${basename}" "MacOSX"; then
string_replace "${basename}" "MacOSX" ""; local target_minver="${_ret}"
if test_nz "${target_minver}"; then
flags="${flags} -target ${_target_arch}-apple-macos${target_minver}"
fi
fi
fi
fi
_ret="${flags}"
}
# get toolchain flags for clang in target
_get_target_toolchain_flags_for_clang() {
local name="${1}"
local toolkind="${2}"
local flags="-Qunused-arguments"
if is_arch "i386"; then
flags="${flags} -m32"
fi
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
if test_eq "${toolkind}" "sh"; then
flags="${flags} -shared -fPIC"
elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then
flags="${flags} -fPIC"
fi
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${toolkind}" "sh"; then
_get_target_soname "${name}"; local soname="${_ret}"
if test_nz "${soname}"; then
if is_plat "macosx"; then
flags="${flags} -Wl,-install_name,${soname}"
else
flags="${flags} -Wl,-soname,${soname}"
fi
fi
fi
fi
# set target and sysroot
_get_macosx_sysroot_flags "quoted"; flags="${flags}${_ret}"
_ret="${flags}"
}
# get toolchain flags for tcc in target
_get_target_toolchain_flags_for_tcc() {
local name="${1}"
local toolkind="${2}"
local flags=""
if is_arch "i386"; then
flags="${flags} -m32"
fi
_get_target_item "${name}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
if test_eq "${toolkind}" "sh"; then
flags="${flags} -shared -fPIC"
elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then
flags="${flags} -fPIC"
fi
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${toolkind}" "sh"; then
_get_target_soname "${name}"; local soname="${_ret}"
if test_nz "${soname}"; then
if is_plat "macosx"; then
flags="${flags} -Wl,-install_name,${soname}"
else
flags="${flags} -Wl,-soname,${soname}"
fi
fi
fi
fi
# set target and sysroot
_get_macosx_sysroot_flags "quoted"; flags="${flags}${_ret}"
_ret="${flags}"
}
# get toolchain flags in target
_get_target_toolchain_flags() {
local name="${1}"
local toolkind="${2}"
local toolname="${3}"
local flags=""
case "${toolname}" in
gcc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
gxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
clang) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
clangxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
emcc) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
emxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";;
cosmocc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
cosmocxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";;
tcc) _get_target_toolchain_flags_for_tcc "${name}" "${toolkind}"; flags="${_ret}";;
ar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";;
emar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";;
cosmoar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
_ret="${flags}"
}
# get compiler flags in target
_get_target_compiler_flags() {
local name="${1}"
local toolkind="${2}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local result=""
# get toolchain flags
_get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}"
if test_nz "${toolchain_flags}"; then
result="${result} ${toolchain_flags}"
fi
# get abstract flags
local itemnames="symbols optimizes warnings languages defines undefines includedirs frameworkdirs frameworks"
local itemname=""
for itemname in ${itemnames}; do
_get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
done
# get raw flags, e.g. add_cflags, add_cxxflags
_get_flagname "${toolkind}"; local flagname="${_ret}"
_get_target_item "${name}" "${flagname}"; local flags="${_ret}"
# get flags from target deps
_get_target_librarydeps "${name}"; local deps="${_ret}"
local dep=""
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}"
if test_nz "${depflags}"; then
flags="${flags} ${depflags}"
fi
fi
done
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
if test_eq "${flagname}" "cflags" || test_eq "${flagname}" "cxxflags"; then
_get_target_item "${name}" "cxflags"; flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
elif test_eq "${flagname}" "mflags" || test_eq "${flagname}" "mxxflags"; then
_get_target_item "${name}" "mxflags"; flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
fi
# get flags from environments, e.g. $CFLAGS, $CXXFLAGS
if test_nz "${CPPFLAGS}"; then
result="${result} ${CPPFLAGS}"
fi
if test_eq "${flagname}" "cflags" && test_nz "${CFLAGS}"; then
result="${result} ${CFLAGS}"
fi
if test_eq "${flagname}" "cxxflags" && test_nz "${CXXFLAGS}"; then
result="${result} ${CXXFLAGS}"
fi
if test_eq "${flagname}" "mflags" && test_nz "${MFLAGS}"; then
result="${result} ${MFLAGS}"
fi
if test_eq "${flagname}" "mxxflags" && test_nz "${MXXFLAGS}"; then
result="${result} ${MXXFLAGS}"
fi
_ret="${result}"
}
# get linker flags in target
_get_target_linker_flags() {
local name="${1}"
local toolkind="${2}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local result=""
# get toolchain flags
_get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}"
if test_nz "${toolchain_flags}"; then
result="${result} ${toolchain_flags}"
fi
# get flags from target deps
_get_target_librarydeps "${name}"; local deps="${_ret}"
local dep=""
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_targetdir "${dep}"; local dep_targetdir="${_ret}"
_get_target_basename "${dep}"; local dep_basename="${_ret}"
_get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "linkdirs" "${dep_targetdir}"; local linkdirs_flags="${_ret}"
_get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "links" "${dep_basename}"; local links_flags="${_ret}"
if test_eq "${dep_kind}" "shared"; then
local rpathdir="@loader_path"
_get_targetdir "${name}"; local targetdir="${_ret}"
path_relative "${targetdir}" "${dep_targetdir}"; local subdir="${_ret}"
if test_nz "${subdir}"; then
rpathdir="${rpathdir}/${subdir}"
fi
_get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "rpathdirs" "${rpathdir}"; local rpathdirs_flags="${_ret}"
result="${result} ${rpathdirs_flags}"
fi
result="${result} ${linkdirs_flags} ${links_flags}"
fi
done
# get abstract flags
local itemnames="strip frameworkdirs linkdirs links rpathdirs frameworks syslinks"
local itemname=""
for itemname in ${itemnames}; do
_get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
done
# get raw flags, e.g. add_ldflags, add_shflags
_get_flagname "${toolkind}"; local flagname="${_ret}"
_get_target_item "${name}" "${flagname}"; local flags="${_ret}"
# get flags from target deps
for dep in ${deps}; do
_get_target_item "${dep}" "kind"; local dep_kind="${_ret}"
if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then
_get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}"
if test_nz "${depflags}"; then
flags="${flags} ${depflags}"
fi
fi
done
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
# get flags from environments, e.g. $LDFLAGS
if test_eq "${flagname}" "ldflags" && test_nz "${LDFLAGS}"; then
result="${result} ${LDFLAGS}"
fi
if test_eq "${flagname}" "shflags" && test_nz "${LDFLAGS}"; then
result="${result} ${LDFLAGS}"
fi
_ret="${result}"
}
# get archiver flags in target
_get_target_archiver_flags() {
local name="${1}"
local toolkind="${2}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local result=""
# get toolchain flags
_get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}"
if test_nz "${toolchain_flags}"; then
result="${result} ${toolchain_flags}"
fi
# get raw flags, e.g. add_arflags
_get_flagname "${toolkind}"; local flagname="${_ret}"
_get_target_item "${name}" "${flagname}"; local flags="${_ret}"
if test_nz "${flags}"; then
result="${result} ${flags}"
fi
_ret="${result}"
}
# get target flags
_get_target_flags() {
local name="${1}"
local toolkind="${2}"
local flags=""
if test_eq "${toolkind}" "sh"; then
_get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}"
elif test_eq "${toolkind}" "ld"; then
_get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}"
elif test_eq "${toolkind}" "ar"; then
_get_target_archiver_flags "${name}" "${toolkind}"; flags="${_ret}"
else
_get_target_compiler_flags "${name}" "${toolkind}"; flags="${_ret}"
fi
_ret="${flags}"
}
# add file paths in target
_add_target_filepaths() {
local key="$1"
shift
# we need avoid escape `*` automatically in for-loop
local file=""
string_replace "${@}" "\*" "?"; local list="${_ret}"
if test_eq "${key}" "files"; then
for file in ${list}; do
path_sourcekind "${file}"; local sourcekind="${_ret}"
_targets_toolkinds="${_targets_toolkinds} ${sourcekind}"
done
fi
for file in ${list}; do
string_replace "${file}" "?" "*"; file="${_ret}"
if ! path_is_absolute "${file}"; then
file="${xmake_sh_scriptdir}/${file}"
fi
local files=""
if string_contains_star2 "${file}"; then
path_directory "${file}"; local dir="${_ret}"
path_filename_fromdir "${file}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}"; files="${_ret}"
elif string_contains_star "${file}"; then
path_directory "${file}"; local dir="${_ret}"
path_filename_fromdir "${file}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}" 1; files="${_ret}"
else
files="${file}"
fi
for file in ${files}; do
path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}"
_add_target_item "${_xmake_sh_target_current}" "${key}" "${file}"
done
done
}
# add install paths in target
_add_target_installpaths() {
local key="$1"
local filepattern="${2}"
local prefixdir="${3}"
local filename=${4}
# get root directory, e.g. "src/foo/(*.h)" -> "src/foo"
local rootdir=""
if string_contains "${filepattern}" "("; then
string_split "${filepattern}" "(" 1; rootdir="${_ret}"
rootdir=${rootdir%/}
if ! path_is_absolute "${rootdir}"; then
rootdir="${xmake_sh_scriptdir}/${rootdir}"
fi
path_relative "${xmake_sh_projectdir}" "${rootdir}"; rootdir="${_ret}"
rootdir=${rootdir%/}
fi
# remove (), e.g. "src/(*.h)" -> "src/*.h"
string_replace ${filepattern} "(" ""; filepattern="${_ret}"
string_replace ${filepattern} ")" ""; filepattern="${_ret}"
# get real path
if ! path_is_absolute "${filepattern}"; then
filepattern="${xmake_sh_scriptdir}/${filepattern}"
fi
local files=""
if string_contains_star2 "${filepattern}"; then
path_directory "${filepattern}"; local dir="${_ret}"
path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}"; files="${_ret}"
elif string_contains_star "${filepattern}"; then
path_directory "${filepattern}"; local dir="${_ret}"
path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}"
_os_find "${dir}" "${name}" 1; files="${_ret}"
else
files="${filepattern}"
fi
for file in ${files}; do
path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}"
_add_target_item "${_xmake_sh_target_current}" "${key}" "${file}:${rootdir}:${prefixdir}:${filename}"
done
}
# set target file path
_set_target_filepath() {
local key="${1}"
local path="${2}"
if ! path_is_absolute "${path}"; then
path="${xmake_sh_scriptdir}/${path}"
fi
path_relative ${xmake_sh_projectdir} "${path}"; path="${_ret}"
_set_target_item "${_xmake_sh_target_current}" "${key}" "${path}"
}
# set kind in target
set_kind() {
if ! ${_loading_targets}; then
return
fi
local kind=${1}
_set_target_item "${_xmake_sh_target_current}" "kind" "${kind}"
case "${kind}" in
binary) _targets_toolkinds="${_targets_toolkinds} ld";;
static) _targets_toolkinds="${_targets_toolkinds} ar";;
shared) _targets_toolkinds="${_targets_toolkinds} sh";;
*) raise "unknown target kind ${kind}";;
esac
}
# set version in target
set_version() {
if ! ${_loading_targets}; then
return
fi
local version="${1}"
local version_build="${2}"
local version_soname="${3}"
_set_target_item "${_xmake_sh_target_current}" "version" "${version}"
_set_target_item "${_xmake_sh_target_current}" "version_build" "${version_build}"
_set_target_item "${_xmake_sh_target_current}" "version_soname" "${version_soname}"
}
# set default in target
set_default() {
local default=${1}
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "default" "${default}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "default" "${default}"
fi
}
# set configvar in target
set_configvar() {
if ! ${_loading_targets}; then
return
fi
local name="${1}"
local value="${2}"
_set_target_item "${_xmake_sh_target_current}" "configvar_${name}" "${value}"
_add_target_item "${_xmake_sh_target_current}" "configvars" "${name}"
}
# set filename in target
set_filename() {
if ! ${_loading_targets}; then
return
fi
local filename="${1}"
_set_target_item "${_xmake_sh_target_current}" "filename" "${filename}"
}
# set basename in target
set_basename() {
if ! ${_loading_targets}; then
return
fi
local basename="${1}"
_set_target_item "${_xmake_sh_target_current}" "basename" "${basename}"
}
# set extension in target
set_extension() {
if ! ${_loading_targets}; then
return
fi
local extension=${1}
_set_target_item "${_xmake_sh_target_current}" "extension" "${extension}"
}
# set prefixname in target
set_prefixname() {
if ! ${_loading_targets}; then
return
fi
local prefixname=${1}
_set_target_item "${_xmake_sh_target_current}" "prefixname" "${prefixname}"
}
# set target directory
set_targetdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "targetdir" "${1}"
}
# set target object directory
set_objectdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "objectdir" "${1}"
}
# set target config directory
set_configdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "configdir" "${1}"
}
# set target install directory
set_installdir() {
if ! ${_loading_targets}; then
return
fi
_set_target_filepath "installdir" "${1}"
}
# add deps in target
add_deps() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "deps" "${@}"
}
# add files in target
add_files() {
if ! ${_loading_targets}; then
return
fi
_add_target_filepaths "files" "$@"
}
# add install files in target
add_installfiles() {
if ! ${_loading_targets}; then
return
fi
_add_target_installpaths "installfiles" "$@"
}
# add header files in target
add_headerfiles() {
if ! ${_loading_targets}; then
return
fi
_add_target_installpaths "headerfiles" "$@"
}
# add config files in target
add_configfiles() {
if ! ${_loading_targets}; then
return
fi
_add_target_filepaths "configfiles" "$@"
}
# add defines in target
add_defines() {
local define=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for define in $@; do
if test_nq "${define}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "defines" "${define}"
else
public=true
fi
done
if ${public}; then
for define in $@; do
if test_nq "${define}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "defines_public" "${define}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "defines" "${@}"
fi
}
# add undefines in target
add_undefines() {
local undefine=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for undefine in $@; do
if test_nq "${undefine}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "undefines" "${undefine}"
else
public=true
fi
done
if ${public}; then
for undefine in $@; do
if test_nq "${undefine}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "undefines_public" "${undefine}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "undefines" "${@}"
fi
}
# add includedirs in target
add_includedirs() {
local public=false
local dir=""
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "includedirs" "${dir}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "includedirs" "${dir}"
fi
else
public=true
fi
done
if ${public}; then
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "includedirs_public" "${dir}"
fi
fi
done
fi
}
# add links in target
add_links() {
local link=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for link in $@; do
if test_nq "${link}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "links" "${link}"
else
public=true
fi
done
if ${public}; then
for link in $@; do
if test_nq "${link}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "links_public" "${link}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "links" "${@}"
fi
}
# add syslinks in target
add_syslinks() {
local syslink=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for syslink in $@; do
if test_nq "${syslink}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "syslinks" "${syslink}"
else
public=true
fi
done
if ${public}; then
for syslink in $@; do
if test_nq "${syslink}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "syslinks_public" "${syslink}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "syslinks" "${@}"
fi
}
# add linkdirs in target
add_linkdirs() {
local dir=""
local public=false
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "linkdirs" "${dir}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "linkdirs" "${dir}"
fi
else
public=true
fi
done
if ${public}; then
for dir in $@; do
if test_nq "${dir}" "{public}"; then
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
if string_startswith "${dir}" "${xmake_sh_projectdir}"; then
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
fi
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "linkdirs_public" "${dir}"
fi
fi
done
fi
}
# add rpathdirs in target
add_rpathdirs() {
if ! ${_loading_targets}; then
return
fi
local dir=""
for dir in $@; do
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
_add_target_item "${_xmake_sh_target_current}" "rpathdirs" "${dir}"
done
}
# add frameworks in target
add_frameworks() {
local framework=""
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
local public=false
for framework in $@; do
if test_nq "${framework}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "frameworks" "${framework}"
else
public=true
fi
done
if ${public}; then
for framework in $@; do
if test_nq "${framework}" "{public}"; then
_add_target_item "${_xmake_sh_target_current}" "frameworks_public" "${framework}"
fi
done
fi
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "frameworks" "${@}"
fi
}
# add frameworkdirs in target
add_frameworkdirs() {
local dir=""
for dir in $@; do
if ! path_is_absolute "${dir}"; then
dir="${xmake_sh_scriptdir}/${dir}"
fi
path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}"
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "frameworkdirs" "${dir}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "frameworkdirs" "${dir}"
fi
done
}
# set strip in target
set_strip() {
if ! ${_loading_targets}; then
return
fi
local strip=${1}
_set_target_item "${_xmake_sh_target_current}" "strip" "${strip}"
}
# set symbols in target
set_symbols() {
if ! ${_loading_targets}; then
return
fi
local symbols="${1}"
_set_target_item "${_xmake_sh_target_current}" "symbols" "${symbols}"
}
# set languages in target
set_languages() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "languages" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "languages" "${@}"
fi
}
# set warnings in target
set_warnings() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "warnings" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "warnings" "${@}"
fi
}
# set optimizes in target
set_optimizes() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_set_target_item "${_xmake_sh_target_current}" "optimizes" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_set_option_item "${_xmake_sh_option_current}" "optimizes" "${@}"
fi
}
# add cflags in target
add_cflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "cflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "cflags" "${@}"
fi
}
# add cxflags in target
add_cxflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "cxflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "cxflags" "${@}"
fi
}
# add cxxflags in target
add_cxxflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "cxxflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "cxxflags" "${@}"
fi
}
# add asflags in target
add_asflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "asflags" "${@}"
}
# add mflags in target
add_mflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "mflags" "${@}"
}
# add mxflags in target
add_mxflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "mxflags" "${@}"
}
# add mxxflags in target
add_mxxflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "mxxflags" "${@}"
}
# add ldflags in target
add_ldflags() {
if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then
_add_target_item "${_xmake_sh_target_current}" "ldflags" "${@}"
elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then
_add_option_item "${_xmake_sh_option_current}" "ldflags" "${@}"
fi
}
# add shflags in target
add_shflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "shflags" "${@}"
}
# add arflags in target
add_arflags() {
if ! ${_loading_targets}; then
return
fi
_add_target_item "${_xmake_sh_target_current}" "arflags" "${@}"
}
# add options in target
add_options() {
if ! ${_loading_targets}; then
return
fi
local name=""
local public=false
for name in $@; do
if test_nq "${name}" "{public}"; then
public=true
break
fi
done
for name in $@; do
if has_config "${name}"; then
local itemname=""
local itemnames="includedirs linkdirs links defines cflags cxflags cxxflags ldflags"
for itemname in ${itemnames}; do
_get_option_item "${name}" "${itemname}"; local values="${_ret}"
if test_nz "${values}"; then
_add_target_item "${_xmake_sh_target_current}" "${itemname}" "${values}"
if $public; then
_add_target_item "${_xmake_sh_target_current}" "${itemname}_public" "${values}"
fi
fi
done
fi
done
}
# before_install in target
before_install() {
if ! ${_loading_targets}; then
return
fi
local funcname="${1}"
_add_target_item "${_xmake_sh_target_current}" "before_install" "${funcname}"
}
# after_install in target
after_install() {
if ! ${_loading_targets}; then
return
fi
local funcname="${1}"
_add_target_item "${_xmake_sh_target_current}" "after_install" "${funcname}"
}
#-----------------------------------------------------------------------------
# toolchain configuration apis
#
# define toolchain
toolchain() {
local name="${1}"
_xmake_sh_toolchain_current="${name}"
if ! ${_loading_toolchains}; then
return
fi
_xmake_sh_toolchains="${_xmake_sh_toolchains} ${name}"
_map_set "toolchains" "${name}_name" "${name}"
return 0
}
toolchain_end() {
_xmake_sh_toolchain_current=""
}
_map "toolchains"
# has the given toolchain?
_has_toolchain() {
local name=${1}
if _map_has "toolchains" "${name}_name"; then
return 0
fi
return 1
}
# get the given toolchain item
_get_toolchain_item() {
local name=${1}
local key=${2}
_map_get "toolchains" "${name}_${key}"
}
# set the given toolchain item
_set_toolchain_item() {
local name=${1}
local key=${2}
local value="${3}"
if test_nz "${name}"; then
_map_set "toolchains" "${name}_${key}" "${value}"
else
raise "please set toolchain in the toolchain scope!"
fi
}
# get the give toolchain toolset
_get_toolchain_toolset() {
local name=${1}
local kind=${2}
_get_toolchain_item "${name}" "toolset_${kind}"
}
# set the give toolchain toolset
_set_toolchain_toolset() {
local name=${1}
local kind=${2}
local programs="${3}"
_set_toolchain_item "${name}" "toolset_${kind}" "${programs}"
}
# add the give toolchain toolset
_add_toolchain_toolset() {
local name=${1}
local kind=${2}
local program="${3}"
_get_toolchain_item "${name}" "toolset_${kind}"; local programs="${_ret}"
if test_nz "${programs}"; then
programs="${programs}:${program}"
else
programs="${program}"
fi
_set_toolchain_item "${name}" "toolset_${kind}" "${programs}"
}
# set toolset in toolchain
set_toolset() {
if ! ${_loading_toolchains}; then
return
fi
local kind=${1}
shift
local idx=0
while test $# != 0; do
local program="${1}"
local key="${kind}"
if test_nq "${idx}" "0"; then
key="${key}_${idx}"
fi
_set_toolchain_toolset "${_xmake_sh_toolchain_current}" "${key}" "${program}"
idx=$((idx+1))
shift
done
}
#-----------------------------------------------------------------------------
# load options
#
# load options and toolchains
_load_options_and_toolchains() {
_loading_options=true
_loading_toolchains=true
_loading_targets=false
local file=${xmake_sh_projectdir}/xmake.sh
if test -f "${file}"; then
includes "${file}"
else
# include all xmake.sh files in next sub-directories
_os_find "${xmake_sh_projectdir}" "xmake.sh" "2"
local files="${_ret}"
for file in ${files}; do
includes "${file}"
done
fi
}
_load_options_and_toolchains
# show option usage
_show_options_usage() {
_get_options_for_menu; local options="${_ret}"
for name in ${options}; do
_get_option_item "${name}" "description"; local description="${_ret}"
_get_option_item "${name}" "default"; local default="${_ret}"
string_toupper ${name}; local head="--${name}="${_ret}""
local headsize=${#head}
local tail="${description}"
if test "x${default}" != "x"; then
local defval=${default}
if test "x${defval}" = "xtrue"; then
defval="yes"
elif test "x${defval}" = "xfalse"; then
defval="no"
fi
tail="${tail} (default: ${defval})"
fi
local width=24
local padding_width=$((${width} - ${headsize}))
local padding=$(string_dupch ${padding_width} " ")
echo " ${head}${padding}${tail}"
done
}
# show configure usage
_show_usage() {
echo '
Usage: '"$0"' [...]
Options: [defaults in brackets after descriptions]
Common options:
--help Print this message.
--version Only print version information.
--verbose Display more information.
--diagnosis Display lots of diagnosis information.
--generator=GENERATOR Set the project generator. (default: '"${project_generator}"')
- gmake
- ninja
--make=MAKE Set the make program. (default: '"${_make_program_default}"')
--ninja=NINJA Set the Ninja program. (default: '"${_ninja_program_default}"')
--plat=PLAT Compile for the given platform. (default: '"${_target_plat_default}"')
- msys
- cross
- bsd
- mingw
- macosx
- linux
- wasm
--arch=ARCH Compile for the given architecture. (default: '"${_target_arch_default}"')
- msys: i386 x86_64
- cross: i386 x86_64 arm arm64 mips mips64 riscv riscv64 loong64 s390x ppc ppc64 sh4
- bsd: i386 x86_64
- mingw: i386 x86_64 arm arm64
- macosx: x86_64 arm64
- linux: i386 x86_64 armv7 armv7s arm64-v8a mips mips64 mipsel mips64el
--mode=MODE Set the given compilation mode. (default: '"${_target_mode_default}"')
- release
- debug
--kind=KIND Set the given target kind. (default: '"${_target_kind_default}"')
- static
- shared
- binary
--toolchain=TOOLCHAIN Set toolchain name.
- clang
- gcc
- emcc
- tinycc
- cosmocc
--builddir=DIR Set build directory. (default: '"${xmake_sh_builddir}"')
Autoconf options:
--build=BUILD Configure for building on BUILD [guessed]
--host=HOST Cross-compile to build programs to run on HOST [BUILD]
--prefix=PREFIX Set install files directory in tree rooted at PREFIX. (default: '"${_install_prefix_default}"')
--bindir=DIR Set install binaries directory in PREFIX/DIR. (default: '"${_install_bindir_default}"')
--libdir=DIR Set install libraries directory in PREFIX/DIR. (default: '"${_install_libdir_default}"')
--includedir=DIR Set install includes directory in PREFIX/DIR. (default: '"${_install_includedir_default}"')
Project options:
'"$(_show_options_usage)"'
'
exit 1
}
# show xmake.sh version
_show_version() {
echo "xmake.sh v${xmake_sh_version}, A script-only build utility like autotools"
echo "${xmake_sh_copyright}"
echo ' _ _ '
echo " __ ___ __ __ __ _| | ______ ___| |__ "
echo " \ \/ / | \/ |/ _ | |/ / __ \ / __| '_ \ "
echo " > < | \__/ | /_| | < ___/_\__ \ | | | "
echo " /_/\_\_|_| |_|\__ \|_|\_\____(_)___/_| |_| "
echo ' by ruki, xmake.io'
echo ' '
echo ' 👉 Manual: https://xmake.io/guide/quick-start '
echo ' 🙏 Donate: https://xmake.io/about/sponsor '
echo ' '
exit 2
}
# --foo=yes => foo
_parse_argument_name() {
local arg="${1#--}"
case "${arg}" in
*=*) arg="${arg%%=*}" ;;
esac
string_replace "${arg}" "-" "_"
}
# --foo=yes => yes
_parse_argument_value() {
case "${1}" in
*=*) _ret="${1#*=}" ;;
*) _ret="" ;;
esac
}
# parse input arguments
_handle_option() {
_parse_argument_name ${1}; local name="${_ret}"
_parse_argument_value ${1}; local value="${_ret}"
if test_eq "${name}" "help"; then
_show_usage
return 0
elif test_eq "${name}" "version"; then
_show_version
return 0
elif test_eq "${name}" "verbose"; then
xmake_sh_verbose=true
return 0
elif test_eq "${name}" "diagnosis"; then
xmake_sh_diagnosis=true
return 0
elif test_eq "${name}" "plat"; then
_target_plat=${value}
return 0
elif test_eq "${name}" "arch"; then
_target_arch=${value}
return 0
elif test_eq "${name}" "mode"; then
_target_mode=${value}
return 0
elif test_eq "${name}" "kind"; then
_target_kind=${value}
return 0
elif test_eq "${name}" "toolchain"; then
_target_toolchain=${value}
return 0
elif test_eq "${name}" "generator"; then
project_generator=${value}
return 0
elif test_eq "${name}" "make"; then
_make_program=${value}
return 0
elif test_eq "${name}" "ninja"; then
_ninja_program=${value}
return 0
elif test_eq "${name}" "prefix"; then
_install_prefix_default="${value}"
return 0
elif test_eq "${name}" "bindir"; then
_install_bindir_default="${value}"
return 0
elif test_eq "${name}" "libdir"; then
_install_libdir_default="${value}"
return 0
elif test_eq "${name}" "includedir"; then
_install_includedir_default="${value}"
return 0
elif test_eq "${name}" "builddir" || test_eq "${name}" "buildir"; then
xmake_sh_builddir="${value}"
return 0
elif test_eq "${name}" "build"; then
_autoconf_build_type="${value}"
return 0
elif test_eq "${name}" "host"; then
_autoconf_host_type="${value}"
return 0
elif _has_option "${name}"; then
_set_option_value "${name}" "${value}"
return 0
fi
return 1
}
while test $# != 0; do
if ! _handle_option ${1}; then
wprint "unknown option: $1"
fi
shift
done
#-----------------------------------------------------------------------------
# handle some autoconf configurations
#
# parse triplet
# https://github.com/xmake-io/xmake/issues/3869
# e.g. i686-linux-gnu, aarch64-apple-darwin, x86_64-w64-mingw32, i686-redhat-linux-gnu
_parse_triplet() {
local triplet="${1}"
string_split "${triplet}" "-"
}
_get_arch_from_cpu() {
local cpu="${1}"
case "${cpu}" in
i686) _ret="i386";;
i386) _ret="i386";;
x86_64) _ret="x86_64";;
aarch64) _ret="arm64";;
arm64) _ret="arm64";;
arm*) _ret="arm";;
*) _ret="${cpu}";;
esac
}
_get_plat_from_vendor_os() {
local vendor="${1}"
local os="${2}"
case "${vendor}" in
linux)
if string_contains "${os}" "android"; then
_ret="android"
else
_ret="linux"
fi
;;
apple)
if test_eq "${os}" "darwin"; then
_ret="macosx"
fi
;;
w64) _ret="mingw";;
*) _ret="${os}";;
esac
}
_handle_autoconf_configs() {
if test_z "${_autoconf_host_type}"; then
_autoconf_host_type="${_autoconf_build_type}"
fi
if test_nz "${_autoconf_build_type}"; then
_parse_triplet "${_autoconf_build_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}"
_get_arch_from_cpu "${cpu}"
if test_nz "${_ret}"; then
os_arch="${_ret}"
else
wprint "unknown cpu: ${cpu} in --build=${value}"
fi
_get_plat_from_vendor_os "${vendor}" "${os}"
if test_nz "${_ret}"; then
os_host="${_ret}"
else
wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}"
fi
fi
if test_nz "${_autoconf_host_type}"; then
_parse_triplet "${_autoconf_host_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}"
_get_arch_from_cpu "${cpu}"
if test_nz "${_ret}"; then
_target_arch_default="${_ret}"
else
wprint "unknown cpu: ${cpu} in --host=${value}"
fi
_get_plat_from_vendor_os "${vendor}" "${os}"
if test_nz "${_ret}"; then
_target_plat_default="${_ret}"
else
wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}"
fi
fi
}
_handle_autoconf_configs
#-----------------------------------------------------------------------------
# detect platform and toolchains
#
# envs toolchain
toolchain "envs"
set_toolset "as" "$CC" "$CXX" "$AS"
set_toolset "cc" "$CC"
set_toolset "cxx" "$CC" "$CXX"
set_toolset "mm" "$CC" "$CXX"
set_toolset "mxx" "$CC" "$CXX"
set_toolset "ld" "$CXX" "$CC" "$LD"
set_toolset "sh" "$CXX" "$CC" "$LD"
set_toolset "ar" "$AR" "ar"
toolchain_end
# clang toolchain
toolchain "clang"
set_toolset "as" "clang"
set_toolset "cc" "clang"
set_toolset "cxx" "clang" "clang++"
set_toolset "mm" "clang"
set_toolset "mxx" "clang" "clang++"
set_toolset "ld" "clang++" "clang"
set_toolset "sh" "clang++" "clang"
set_toolset "ar" "ar"
toolchain_end
# gcc toolchain
toolchain "gcc"
set_toolset "as" "gcc"
set_toolset "cc" "gcc"
set_toolset "cxx" "gcc" "g++"
set_toolset "mm" "gcc"
set_toolset "mxx" "gcc" "g++"
set_toolset "ld" "g++" "gcc"
set_toolset "sh" "g++" "gcc"
set_toolset "ar" "ar"
toolchain_end
# mingw toolchain (x86_64)
toolchain "x86_64_w64_mingw32"
set_toolset "as" "x86_64-w64-mingw32-gcc"
set_toolset "cc" "x86_64-w64-mingw32-gcc"
set_toolset "cxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++"
set_toolset "mm" "x86_64-w64-mingw32-gcc"
set_toolset "mxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++"
set_toolset "ld" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc"
set_toolset "sh" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc"
set_toolset "ar" "x86_64-w64-mingw32-ar" "ar"
toolchain_end
# mingw toolchain (i686)
toolchain "i686_w64_mingw32"
set_toolset "as" "i686-w64-mingw32-gcc"
set_toolset "cc" "i686-w64-mingw32-gcc"
set_toolset "cxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++"
set_toolset "mm" "i686-w64-mingw32-gcc"
set_toolset "mxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++"
set_toolset "ld" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc"
set_toolset "sh" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc"
set_toolset "ar" "i686-w64-mingw32-ar" "ar"
toolchain_end
# aarch64 toolchain (aarch64)
toolchain "aarch64_linux_gnu"
set_toolset "as" "aarch64-linux-gnu-gcc"
set_toolset "cc" "aarch64-linux-gnu-gcc"
set_toolset "cxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++"
set_toolset "mm" "aarch64-linux-gnu-gcc"
set_toolset "mxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++"
set_toolset "ld" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc"
set_toolset "sh" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc"
set_toolset "ar" "aarch64-linux-gnu-ar" "ar"
toolchain_end
# emcc toolchain (wasm32)
toolchain "emcc"
set_toolset "as" "emcc"
set_toolset "cc" "emcc"
set_toolset "cxx" "emcc" "em++"
set_toolset "mm" "emcc"
set_toolset "mxx" "emcc" "em++"
set_toolset "ld" "em++" "emcc"
set_toolset "sh" "em++" "emcc"
set_toolset "ar" "emar" "ar"
toolchain_end
# cosmocc toolchain, e.g. ./configure --plat=linux --toolchain=cosmocc
toolchain "cosmocc"
set_toolset "as" "cosmocc"
set_toolset "cc" "cosmocc"
set_toolset "cxx" "cosmocc" "cosmoc++"
set_toolset "mm" "cosmocc"
set_toolset "mxx" "cosmocc" "cosmoc++"
set_toolset "ld" "cosmoc++" "cosmocc"
set_toolset "sh" "cosmoc++" "cosmocc"
set_toolset "ar" "cosmoar"
toolchain_end
# tinycc toolchain
toolchain "tinycc"
set_toolset "as" "tcc" "gcc" "clang"
set_toolset "cc" "tcc"
set_toolset "cxx" "gcc" "g++" "clang" "clang++"
set_toolset "mm" "gcc" "clang"
set_toolset "mxx" "gcc" "g++" "clang" "clang++"
set_toolset "ld" "tcc"
set_toolset "sh" "tcc"
set_toolset "ar" "tcc -ar" "ar"
toolchain_end
# check platform
_check_platform() {
if test "x${_target_plat}" = "x"; then
_target_plat=${_target_plat_default}
fi
if test "x${_target_arch}" = "x"; then
_target_arch=${_target_arch_default}
fi
if test "x${_target_mode}" = "x"; then
_target_mode=${_target_mode_default}
fi
if test "x${_target_kind}" = "x"; then
_target_kind=${_target_kind_default}
fi
echo "checking for platform ... ${_target_plat}"
echo "checking for architecture ... ${_target_arch}"
}
# get toolchain compile command for gcc/clang
_toolchain_compcmd_for_gcc_clang() {
local program="${1}"
local objectfile="${2}"
local sourcefile="${3}"
local flags="${4}"
_ret="${program} -c ${flags} -o ${objectfile} ${sourcefile}"
}
# get toolchain link command for gcc/clang
_toolchain_linkcmd_for_gcc_clang() {
local toolkind="${1}"
local program="${2}"
local binaryfile="${3}"
local objectfiles="${4}"
local flags="${5}"
if test_eq "${toolkind}" "sh"; then
flags="-shared -fPIC ${flags}"
fi
_ret="${program} -o ${binaryfile} ${objectfiles} ${flags}"
}
# get toolchain link command for ar
_toolchain_linkcmd_for_ar() {
local toolkind="${1}"
local program="${2}"
local binaryfile="${3}"
local objectfiles="${4}"
local flags="${5}"
_ret="${program} ${flags} ${binaryfile} ${objectfiles}"
}
# get toolchain compile command
_toolchain_compcmd() {
local sourcekind="${1}"
local objectfile="${2}"
local sourcefile="${3}"
local flags="${4}"
_get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local compcmd=""
case "${toolname}" in
gcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
gxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
clang) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
clangxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
emcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
emxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
cosmocc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
cosmocxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
tcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
_ret="${compcmd}"
}
# get toolchain link command
_toolchain_linkcmd() {
local toolkind="${1}"
local binaryfile="${2}"
local objectfiles="${3}"
local flags="${4}"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
case "${toolname}" in
gcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
gxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
clang) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
clangxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
emcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
emxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
cosmocc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
cosmocxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
tcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
ar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
emar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
cosmoar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
_ret="${linkcmd}"
}
# try make
_toolchain_try_make() {
local program="${1}"
if _os_runv "${program}" "--version"; then
return 0
fi
return 1
}
# try ninja
_toolchain_try_ninja() {
local program="${1}"
if _os_runv "${program}" "--version"; then
return 0
fi
return 1
}
# try gcc
_toolchain_try_gcc() {
if test "x${_toolchain_try_gcc_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_gcc_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_gcc_result="ok"
return 0
fi
_toolchain_try_gcc_result="no"
return 1
}
# try g++
_toolchain_try_gxx() {
if test "x${_toolchain_try_gxx_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_gxx_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_gxx_result="ok"
return 0
fi
_toolchain_try_gxx_result="no"
return 1
}
# try clang
_toolchain_try_clang() {
if test "x${_toolchain_try_clang_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_clang_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_clang_result="ok"
return 0
fi
_toolchain_try_clang_result="no"
return 1
}
# try clang++
_toolchain_try_clangxx() {
if test "x${_toolchain_try_clangxx_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_clangxx_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_clangxx_result="ok"
return 0
fi
_toolchain_try_clangxx_result="no"
return 1
}
# try tcc
_toolchain_try_tcc() {
if test "x${_toolchain_try_tcc_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_tcc_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "-v"; then
_toolchain_try_tcc_result="ok"
return 0
fi
_toolchain_try_tcc_result="no"
return 1
}
# try ar
_toolchain_try_ar() {
local kind="${1}"
local program="${2}"
# generate the source file
_os_tmpfile
local tmpfile="${_ret}"
local objectfile="${tmpfile}.o"
local libraryfile="${tmpfile}.a"
echo "" > "${objectfile}"
# try linking it
local ok=false
if _os_runv "${program}" "-cr" "${libraryfile}" "${objectfile}"; then
ok=true
fi
# remove files
_os_tryrm "${objectfile}"
_os_tryrm "${libraryfile}"
if ${ok}; then
return 0
fi
return 1
}
# try cosmoar
_toolchain_try_cosmoar() {
if test "x${_toolchain_try_cosmoar_result}" = "xok"; then
return 0
elif test "x${_toolchain_try_cosmoar_result}" = "xno"; then
return 1
fi
local kind="${1}"
local program="${2}"
if _os_runv "${program}" "--version"; then
_toolchain_try_cosmoar_result="ok"
return 0
fi
_toolchain_try_cosmoar_result="no"
return 1
}
# try program
_toolchain_try_program() {
local toolchain="${1}"
local kind="${2}"
local program="${3}"
local ok=false
path_toolname "${program}"; local toolname="${_ret}"
case "${toolname}" in
gcc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;;
gxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;;
clang) _toolchain_try_clang "${kind}" "${program}" && ok=true;;
clangxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;;
emcc) _toolchain_try_clang "${kind}" "${program}" && ok=true;;
emxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;;
cosmocc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;;
cosmocxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;;
tcc) _toolchain_try_tcc "${kind}" "${program}" && ok=true;;
ar) _toolchain_try_ar "${kind}" "${program}" && ok=true;;
emar) _toolchain_try_ar "${kind}" "${program}" && ok=true;;
cosmoar) _toolchain_try_cosmoar "${kind}" "${program}" && ok=true;;
*) raise "unknown toolname(${toolname})!" ;;
esac
if ${ok}; then
vprint "checking for ${program} ... ok"
return 0
fi
vprint "checking for ${program} ... no"
return 1
}
# try toolset
_toolchain_try_toolset() {
local toolchain=${1}
local kind=${2}
local description=${3}
local indices="0 1 2 3 4 5"
for idx in ${indices}; do
local key="${kind}"
if test_nq "${idx}" "0"; then
key="${key}_${idx}"
fi
_get_toolchain_toolset "${toolchain}" "${key}"; local program="${_ret}"
if test_nz "${program}"; then
if _toolchain_try_program "${toolchain}" "${kind}" "${program}"; then
_set_toolchain_toolset "${toolchain}" "${kind}" "${program}"
echo "checking for the ${description} (${kind}) ... ${program}"
return 0
fi
fi
done
return 1
}
# try toolchain
_toolchain_try() {
local toolchain=${1}
vprint "checking for $toolchain toolchain ..."
if _toolchain_try_toolset "${toolchain}" "cc" "c compiler" &&
_toolchain_try_toolset "${toolchain}" "cxx" "c++ compiler" &&
_toolchain_try_toolset "${toolchain}" "as" "assembler" &&
_toolchain_try_toolset "${toolchain}" "mm" "objc compiler" &&
_toolchain_try_toolset "${toolchain}" "mxx" "objc++ compiler" &&
_toolchain_try_toolset "${toolchain}" "ld" "linker" &&
_toolchain_try_toolset "${toolchain}" "ar" "static library archiver" &&
_toolchain_try_toolset "${toolchain}" "sh" "shared library linker"; then
return 0
fi
return 1
}
# detect make
_toolchain_detect_make() {
if test "x${_make_program}" = "x"; then
_make_program=${_make_program_default}
fi
if _toolchain_try_make "${_make_program}"; then
echo "checking for make ... ok"
else
echo "checking for make ... no"
raise "make not found!"
fi
}
# detect ninja
_toolchain_detect_ninja() {
if test "x${_ninja_program}" = "x"; then
_ninja_program=${_ninja_program_default}
fi
if _toolchain_try_ninja "${_ninja_program}"; then
echo "checking for ninja ... ok"
else
echo "checking for ninja ... no"
raise "ninja not found!"
fi
}
# detect build backend
_toolchain_detect_backend() {
if test "x${project_generator}" = "xgmake"; then
_toolchain_detect_make
elif test "x${project_generator}" = "xninja"; then
_toolchain_detect_ninja
fi
}
# detect toolchain
_toolchain_detect() {
# detect build backend
_toolchain_detect_backend
# detect toolchains
local toolchains="${1}"
if test "x${toolchains}" = "x"; then
if is_plat "macosx"; then
toolchains="envs clang gcc"
elif is_plat "mingw"; then
if is_arch "i386"; then
toolchains="i686_w64_mingw32"
else
toolchains="x86_64_w64_mingw32"
fi
elif is_plat "wasm"; then
toolchains="emcc"
elif is_plat "linux" && ! is_arch "${os_arch}"; then
toolchains="envs"
if is_arch "arm64"; then
toolchains="${toolchains} aarch64_linux_gnu"
fi
else
toolchains="envs gcc clang"
fi
fi
for toolchain in ${toolchains}; do
if _toolchain_try "$toolchain"; then
_target_toolchain=${toolchain}
break
fi
done
}
# check toolchain
_check_toolchain() {
local toolchain=${_target_toolchain}
_target_toolchain=""
_toolchain_detect ${toolchain}
if test "x${_target_toolchain}" != "x"; then
echo "checking for toolchain ... ${_target_toolchain}"
else
echo "checking for toolchain ... no"
raise "toolchain not found!"
fi
}
# get function code
#
# sigsetjmp
# sigsetjmp((void*)0, 0)
#
_get_funccode() {
local func="${1}"
local code=""
if string_contains "${func}" "("; then
code="${func}"
else
code="typedef void (*func_t)(); volatile func_t p${func} = (func_t)${func}; while (p${func}) {break;};"
fi
_ret="${code}"
}
# generate cxsnippets source code
_generate_cxsnippets_sourcecode() {
local funcs="${1}"
local includes="${2}"
local types="${3}"
local snippets="${4}"
local snippet_includes=""
for include in $includes; do
snippet_includes="${snippet_includes}#include \"${include}\"\n"
done
local snippet_types=""
for type in $types; do
string_replace "${type}" '[^a-zA-Z]' "_"; local typevar="${_ret}"
snippet_types="${snippet_types}typedef ${type} __type_${typevar};\n"
done
local snippet_funcs=""
for func in $funcs; do
_get_funccode "${func}"; func="${_ret}"
snippet_funcs="${snippet_funcs}${func}\n "
done
local snippets_code=""
if test_nz "${snippet_includes}"; then
snippets_code="${snippets_code}${snippet_includes}\n"
fi
if test_nz "${snippet_types}"; then
snippets_code="${snippets_code}${snippet_types}\n"
fi
if test_nz "${snippets}"; then
snippets_code="${snippets_code}${snippets}\n"
fi
_ret='
'"${snippets_code}"'int main(int argc, char** argv) {
'"${snippet_funcs}"'
return 0;
}'
}
# check cxsnippets
_check_cxsnippets() {
local name="${1}"
local kind="${2}"
_get_option_item "${name}" "${kind}funcs"; local funcs="${_ret}"
_get_option_item "${name}" "${kind}includes"; local includes="${_ret}"
_get_option_item "${name}" "${kind}types"; local types="${_ret}"
_get_option_item "${name}" "${kind}snippets"; local snippets="${_ret}"
if test_z "${funcs}" && test_z "${includes}" &&
test_z "${types}" && test_z "${snippets}"; then
return 0
fi
# get c/c++ extension
local extension=".c"
local sourcekind="cc"
if test_eq "${kind}" "cxx"; then
extension=".cpp"
sourcekind="cxx"
fi
# generate source code
_generate_cxsnippets_sourcecode "${funcs}" "${includes}" "${types}" "${snippets}"; local sourcecode="${_ret}"
dprint "${sourcecode}"
# generate the source file
_os_tmpfile
local tmpfile="${_ret}"
local sourcefile="${tmpfile}${extension}"
local objectfile="${tmpfile}.o"
local binaryfile="${tmpfile}.bin"
print "${sourcecode}" > "${sourcefile}"
# try compiling it
local ok=false
if ! ${ok}; then
local compflags=""
_get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local itemnames="languages warnings optimizes defines undefines includedirs"
for itemname in ${itemnames}; do
_get_option_abstract_flags "${name}" "${sourcekind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
_split_flags "${flags}"; flags="${_ret}"
compflags="${compflags} ${flags}"
fi
done
local flagnames="cxflags"
if test_eq "${sourcekind}" "cxx"; then
flagnames="${flagnames} cxxflags"
else
flagnames="${flagnames} cflags"
fi
for flagname in $flagnames; do
_get_option_item "${name}" "${flagname}"; local flags="${_ret}"
if test_nz "${flags}"; then
compflags="${compflags} ${flags}"
fi
done
if test_eq "${sourcekind}" "cxx"; then
if test_nz "${CXXFLAGS}"; then
compflags="${compflags} ${CXXFLAGS}"
fi
else
if test_nz "${CFLAGS}"; then
compflags="${compflags} ${CFLAGS}"
fi
fi
if test_nz "${CPPFLAGS}"; then
compflags="${compflags} ${CPPFLAGS}"
fi
# add -isysroot and -target on macOS to ensure system SDK headers are used for option checking
_get_macosx_sysroot_flags; compflags="${_ret} ${compflags}"
_toolchain_compcmd "${sourcekind}" "${objectfile}" "${sourcefile}" "${compflags}"; local compcmd="${_ret}"
if ${xmake_sh_diagnosis}; then
print "> ${compcmd}"
fi
if _os_runv ${compcmd}; then
ok=true
fi
fi
# try linking it
_get_option_item "${name}" "links"; local links="${_ret}"
_get_option_item "${name}" "syslinks"; local syslinks="${_ret}"
_get_option_item "${name}" "ldflags"; local ldflags="${_ret}"
if test_nz "${syslinks}"; then
links="${links} ${syslinks}"
fi
if ${ok} && (test_nz "${links}" || test_nz "${ldflags}"); then
local toolkind="ld"
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
local itemnames="linkdirs links syslinks"
local linkflags=""
for itemname in ${itemnames}; do
_get_option_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}"
if test_nz "${flags}"; then
_split_flags "${flags}"; flags="${_ret}"
linkflags="${linkflags} ${flags}"
fi
done
_get_option_item "${name}" "ldflags"; local flags="${_ret}"
if test_nz "${flags}"; then
linkflags="${linkflags} ${flags}"
fi
if test_nz "${LDFLAGS}"; then
linkflags="${linkflags} ${LDFLAGS}"
fi
_toolchain_linkcmd "${toolkind}" "${binaryfile}" "${objectfile}" "${linkflags}"; local linkcmd="${_ret}"
if ${xmake_sh_diagnosis}; then
print "> ${linkcmd}"
fi
if _os_runv ${linkcmd}; then
ok=true
else
ok=false
fi
fi
# trace
if ${xmake_sh_verbose} || ${xmake_sh_diagnosis}; then
if test_nz "${includes}"; then
print "> checking for ${kind} includes(${includes})"
fi
if test_nz "${types}"; then
print "> checking for ${kind} types(${types})"
fi
if test_nz "${funcs}"; then
print "> checking for ${kind} funcs(${funcs})"
fi
if test_nz "${links}"; then
print "> checking for ${kind} links(${links})"
fi
fi
# remove files
_os_tryrm "${sourcefile}"
_os_tryrm "${objectfile}"
_os_tryrm "${binaryfile}"
if ${ok}; then
return 0
fi
return 1
}
# check csnippets
_check_csnippets() {
local name="${1}"
if _check_cxsnippets "${name}" "c"; then
return 0
fi
return 1
}
# check cxxsnippets
_check_cxxsnippets() {
local name="${1}"
if _check_cxsnippets "${name}" "cxx"; then
return 0
fi
return 1
}
# check option
_check_option() {
local name="${1}"
_get_option_value "${name}"; local value="${_ret}"
_get_option_item "${name}" "default"; local default="${_ret}"
if test_nz "${value}"; then
if _is_enabled "${value}"; then
return 0
else
return 1
fi
elif test_nz "${default}"; then
if _is_enabled "${default}"; then
return 0
else
return 1
fi
else
_get_option_item "${name}" "before_check"; local before_check="${_ret}"
if test_nz "${before_check}"; then
eval ${before_check}
fi
if _check_csnippets "${name}" && _check_cxxsnippets "${name}"; then
return 0
fi
fi
return 1
}
# check options
_check_options() {
_get_options_for_checking; local options="${_ret}"
for name in $options; do
if _check_option "$name"; then
echo "checking for ${name} .. ok"
_set_option_value "${name}" true
else
echo "checking for ${name} .. no"
_set_option_value "${name}" false
fi
done
}
# check all
_check_all() {
_check_platform
_check_toolchain
_check_options
}
_check_all
#-----------------------------------------------------------------------------
# init builtin variables, e.g. add_headerfiles "${builddir}/config.h"
#
projectdir="${xmake_sh_projectdir}"
if path_is_absolute "${xmake_sh_builddir}"; then
builddir="${xmake_sh_builddir}"
else
builddir="${xmake_sh_projectdir}/${xmake_sh_builddir}"
fi
buildir=${builddir} # deprecated
plat="${_target_plat}"
arch="${_target_arch}"
mode="${_target_mode}"
kind="${_target_kind}"
#-----------------------------------------------------------------------------
# load project targets
#
# load targets
_load_targets() {
echo "analyzing project configuration .."
_loading_options=false
_loading_toolchains=false
_loading_targets=true
_xmake_sh_option_current=""
_xmake_sh_target_current=""
_xmake_sh_toolchain_current=""
local file=${xmake_sh_projectdir}/xmake.sh
if test -f "${file}"; then
includes "${file}"
else
# include all xmake.sh files in next sub-directories
_os_find "${xmake_sh_projectdir}" "xmake.sh" 2; local files="${_ret}"
for file in ${files}; do
includes "${file}"
done
fi
}
_load_targets
# get toolset kinds for all targets
# e.g. cc cxx as mm mxx ld sh ar
_get_targets_toolkinds() {
if test_z "${_targets_toolkinds_dedup}"; then
_dedup "${_targets_toolkinds}"; _targets_toolkinds_dedup="${_ret}"
fi
_ret="${_targets_toolkinds_dedup}"
}
#-----------------------------------------------------------------------------
# generate configfiles
#
# vprint config variable in `${name}`
_vprint_configvar_value() {
local name="${1}"
local value="${2}"
vprint " > replace ${name} -> ${value}"
}
# vprint config variable in `${define name}`
_vprint_configvar_define() {
local name="${1}"
local value="${2}"
if test_z "${value}"; then
vprint " > replace ${name} -> /* #undef ${name} */"
elif test_eq "${value}" "1" || test_eq "${value}" "true"; then
vprint " > replace ${name} -> #define ${name} 1"
elif test_eq "${value}" "0" || test_eq "${value}" "false"; then
vprint " > replace ${name} -> /*#define ${name} 0*/"
else
vprint " > replace ${name} -> #define ${name} ${value}"
fi
}
# replace config variable in `${define name}`
_replace_configvar_define() {
local name="${1}"
local value="${2}"
if test_z "${value}"; then
_ret="s/\${define ${name}}/\/*#undef ${name}*\//g"
elif test_eq "${value}" "1" || test_eq "${value}" "true"; then
_ret="s/\${define ${name}}/#define ${name} 1/g"
elif test_eq "${value}" "0" || test_eq "${value}" "false"; then
_ret="s/\${define ${name}}/\/*#define ${name} 0*\//g"
else
_ret="s/\${define ${name}}/#define ${name} ${value}/g"
fi
}
# replace config variable in `${name}`
_replace_configvar_value() {
local name="${1}"
local value="${2}"
_ret="s@\${${name}}@${value}@g"
}
# generate configfile for the given target
_generate_configfile() {
local target="${1}"
local configfile_in="${2}"
_get_target_item "${target}" "configdir"; local configdir="${_ret}"
if test_z "${configdir}"; then
path_directory configfile_in; configdir="${_ret}"
fi
if ! test -d "${configdir}"; then
mkdir -p "${configdir}"
fi
path_basename "${configfile_in}"; local filename="${_ret}"
local configfile="${configdir}/${filename}"
echo "generating ${configfile} .."
# replace builtin variables
local patterns=""
local target_os=""
if is_plat "mingw"; then
target_os="windows"
else
target_os="${_target_plat}"
fi
string_toupper ${target_os}; target_os="${_ret}"
_vprint_configvar_value "OS" "${target_os}"
_replace_configvar_value "OS" "${target_os}"; patterns="${_ret};${patterns}"
# replace version
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_item "${target}" "version_build"; local version_build="${_ret}"
string_split "${version}" "."
local version_major="${_ret}"
local version_minor="${_ret2}"
local version_alter="${_ret3}"
if test_nz "${version}"; then
_vprint_configvar_value "VERSION" "${version}"
_replace_configvar_value "VERSION" "${version}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_major}"; then
_vprint_configvar_value "VERSION_MAJOR" "${version_major}"
_replace_configvar_value "VERSION_MAJOR" "${version_major}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_minor}"; then
_vprint_configvar_value "VERSION_MINOR" "${version_minor}"
_replace_configvar_value "VERSION_MINOR" "${version_minor}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_alter}"; then
_vprint_configvar_value "VERSION_ALTER" "${version_alter}"
_replace_configvar_value "VERSION_ALTER" "${version_alter}"; patterns="${_ret};${patterns}"
fi
if test_nz "${version_build}"; then
_os_date "${version_build}"; version_build="${_ret}"
_vprint_configvar_value "VERSION_BUILD" "${version_build}"
_replace_configvar_value "VERSION_BUILD" "${version_build}"; patterns="${_ret};${patterns}"
fi
# replace git variables
local content=""
content=$(cat "${configfile_in}")
if string_contains "${content}" "GIT_"; then
_os_iorunv "git" "describe" "--tags"; local git_tag="${_ret}"
_vprint_configvar_value "GIT_TAG" "${git_tag}"
_replace_configvar_value "GIT_TAG" "${git_tag}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "describe" "--tags" "--long"; local git_tag_long="${_ret}"
_vprint_configvar_value "GIT_TAG_LONG" "${git_tag_long}"
_replace_configvar_value "GIT_TAG_LONG" "${git_tag_long}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "rev-parse" "--abbrev-ref" "HEAD"; local git_branch="${_ret}"
_vprint_configvar_value "GIT_BRANCH" "${git_branch}"
_replace_configvar_value "GIT_BRANCH" "${git_branch}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "rev-parse" "--short" "HEAD"; local git_commit="${_ret}"
_vprint_configvar_value "GIT_COMMIT" "${git_commit}"
_replace_configvar_value "GIT_COMMIT" "${git_commit}"; patterns="${_ret};${patterns}"
_os_iorunv "git" "rev-parse" "HEAD"; local git_commit_long="${_ret}"
_vprint_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}"
_replace_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}"; patterns="${_ret};${patterns}"
_os_iorunv "log" "-1" "--date=format:%Y%m%d%H%M%S" "--format=%ad"; local git_commit_date="${_ret}"
_vprint_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}"
_replace_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}"; patterns="${_ret};${patterns}"
fi
# replace configvars in target
local count=0
local configfile_dst="${configfile}"
_os_tmpfile; local tmpfile="${_ret}"
cp "${configfile_in}" "${tmpfile}"
_get_target_item "${target}" "configvars"; local configvars="${_ret}"
for name in ${configvars}; do
_get_target_item "${target}" "configvar_${name}"; local value="${_ret}"
_vprint_configvar_define "${name}" "${value}"
_vprint_configvar_value "${name}" "${value}"
_replace_configvar_define "${name}" "${value}"; patterns="${_ret};${patterns}"
_replace_configvar_value "${name}" "${value}"; patterns="${_ret};${patterns}"
count=$((count + 1))
# do replace
if test_eq "$count" "10"; then
_io_replace_file "${tmpfile}" "${configfile}" "${patterns}"
local swapfile="${tmpfile}"
tmpfile="${configfile}"
configfile="${swapfile}"
patterns=""
count=0
fi
done
# do replace (left)
if test_nz "${patterns}"; then
_io_replace_file "${tmpfile}" "${configfile}" "${patterns}"
local swapfile="${tmpfile}"
tmpfile="${configfile}"
configfile="${swapfile}"
patterns=""
count=0
fi
# replace fallback
patterns='s/${define \(.*\)}/\/*#undef \1*\//g;'
_io_replace_file "${tmpfile}" "${configfile}" "${patterns}"
if test_nq "${configfile}" "${configfile_dst}"; then
cp "${configfile}" "${configfile_dst}"
fi
echo "${configfile_dst} is generated!"
}
# generate configfiles
_generate_configfiles() {
for target in ${_xmake_sh_targets}; do
_get_target_item "${target}" "configfiles"; local configfiles="${_ret}"
for configfile in ${configfiles}; do
_generate_configfile "${target}" "${configfile}"
done
done
}
_generate_configfiles
#-----------------------------------------------------------------------------
# generate gmake file
#
_gmake_begin() {
echo "generating makefile .."
}
_gmake_add_header() {
echo "# this is the build file for this project
# it is autogenerated by the xmake.sh build system.
# do not edit by hand.
" > "${xmake_sh_makefile}"
}
_gmake_add_switches() {
echo "ifneq (\$(VERBOSE),1)" >> "${xmake_sh_makefile}"
echo "VV=@" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
echo "ifeq (\$(PREFIX),)" >> "${xmake_sh_makefile}"
echo "PREFIX=${_install_prefix_default}" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
echo "INSTALLDIR:=\$(DESTDIR)" >> "${xmake_sh_makefile}"
echo "ifneq (\$(PREFIX),)" >> "${xmake_sh_makefile}"
echo "ifneq (\$(INSTALLDIR),)" >> "${xmake_sh_makefile}"
echo "PREFIX_:=\$(patsubst /%,%,\$(PREFIX))" >> "${xmake_sh_makefile}"
echo "INSTALLDIR:=\$(INSTALLDIR)/\$(PREFIX_)" >> "${xmake_sh_makefile}"
echo "else" >> "${xmake_sh_makefile}"
echo "INSTALLDIR:=\$(PREFIX)" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "endif" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_flags() {
_get_targets_toolkinds; local kinds="${_ret}"
for target in ${_xmake_sh_targets}; do
for kind in ${kinds}; do
_get_target_flags "${target}" "${kind}"; local flags="${_ret}"
_get_flagname "${kind}"; local flagname="${_ret}"
local key="${target}_${flagname}"
echo "${key}=${flags}" >> "${xmake_sh_makefile}"
done
echo "" >> "${xmake_sh_makefile}"
done
}
_gmake_add_toolchains() {
_get_targets_toolkinds; local kinds="${_ret}"
for kind in ${kinds}; do
_get_toolchain_toolset "${_target_toolchain}" "${kind}"; local program="${_ret}"
local key="${kind}"
echo "${key}=${program}" >> "${xmake_sh_makefile}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_build_object_for_gcc_clang() {
local kind="${1}"
local sourcefile="${2}"
local objectfile="${3}"
local flagname="${4}"
path_directory "${objectfile}"; local objectdir="${_ret}"
print "\t@mkdir -p ${objectdir}" >> "${xmake_sh_makefile}"
print "\t\$(VV)\$(${kind}) -c \$(${flagname}) -o ${objectfile} ${sourcefile}" >> "${xmake_sh_makefile}"
}
_gmake_add_build_object() {
local target=${1}
local sourcefile="${2}"
local objectfile="${3}"
path_sourcekind "${sourcefile}"; local sourcekind="${_ret}"
_get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
_get_flagname "${sourcekind}"; local flagname="${_ret}"
flagname="${target}_${flagname}"
echo "${objectfile}: ${sourcefile}" >> "${xmake_sh_makefile}"
print "\t@echo compiling.${_target_mode} ${sourcefile}" >> "${xmake_sh_makefile}"
case "${toolname}" in
gcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
gxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
clang) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
clangxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
emcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
emxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
cosmocc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
cosmocxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
tcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_build_objects() {
local target=${1}
_get_target_sourcefiles "${target}"; local sourcefiles="${_ret}"
for sourcefile in ${sourcefiles}; do
_get_target_objectfile "${target}" "${sourcefile}"; local objectfile="${_ret}"
_gmake_add_build_object "${target}" "${sourcefile}" "${objectfile}"
done
}
_gmake_add_build_target_for_gcc_clang() {
local kind="${1}"
local targetfile="${2}"
local objectfiles="${3}"
local flagname="${4}"
path_directory "${targetfile}"; local targetdir="${_ret}"
print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}"
print "\t\$(VV)\$(${kind}) -o ${targetfile} ${objectfiles} \$(${flagname})" >> "${xmake_sh_makefile}"
}
_gmake_add_build_target_for_ar() {
local kind="${1}"
local targetfile="${2}"
local objectfiles="${3}"
local flagname="${4}"
path_directory "${targetfile}"; local targetdir="${_ret}"
print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}"
print "\t\$(VV)\$(${kind}) \$(${flagname}) ${flags} ${targetfile} ${objectfiles}" >> "${xmake_sh_makefile}"
}
_gmake_add_build_target() {
local target=${1}
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_file "${target}"; local targetfile="${_ret}"
_get_target_item "${target}" "deps"; local deps="${_ret}"
_get_target_objectfiles "${target}"; local objectfiles="${_ret}"
# get linker
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
local toolkind=""
case "${targetkind}" in
binary) toolkind="ld";;
static) toolkind="ar";;
shared) toolkind="sh";;
*) raise "unknown targetkind(${targetkind})!" ;;
esac
_get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}"
path_toolname "${program}"; local toolname="${_ret}"
# get linker flags
_get_flagname "${toolkind}"; local flagname="${_ret}"
flagname="${target}_${flagname}"
# get depfiles
local dep=""
local depfiles=""
for dep in ${deps}; do
_get_target_file "${dep}"; local depfile="${_ret}"
if test_nz "${depfiles}"; then
depfiles="${depfiles} ${depfile}"
else
depfiles="${depfile}"
fi
done
# link target
echo "${target}: ${targetfile}" >> "${xmake_sh_makefile}"
echo "${targetfile}: ${depfiles}${objectfiles}" >> "${xmake_sh_makefile}"
if test_eq "${targetkind}" "static"; then
print "\t@echo archiving.${_target_mode} ${targetfile}" >> "${xmake_sh_makefile}"
else
print "\t@echo linking.${_target_mode} ${targetfile}" >> "${xmake_sh_makefile}"
fi
case "${toolname}" in
gcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
gxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
clang) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
clangxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
emcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
emxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
cosmocc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
cosmocxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
tcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
ar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
emar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
cosmoar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";;
*) raise "unknown toolname(${toolname})!" ;;
esac
# @see https://github.com/tboox/tbox/issues/214
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_filename "${target}"; local filename="${_ret}"
_get_target_extension "${target}"; local extension="${_ret}"
local targetfile_with_version="${targetdir}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${targetdir}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${targetdir}/${soname}"
path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}"
if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then
print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}"
print "\t@cd ${targetdir} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}"
fi
fi
fi
# end
echo "" >> "${xmake_sh_makefile}"
# build objects
_gmake_add_build_objects "${target}"
}
_gmake_add_build_targets() {
local target=""
local defaults=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
defaults="${defaults} ${target}"
fi
done
echo "default:${defaults}" >> "${xmake_sh_makefile}"
echo "all:${_xmake_sh_targets}" >> "${xmake_sh_makefile}"
echo ".PHONY: default all" >> "${xmake_sh_makefile}"
echo "" >> "${xmake_sh_makefile}"
for target in ${_xmake_sh_targets}; do
_gmake_add_build_target "${target}"
done
}
_gmake_add_build() {
_gmake_add_build_targets
}
_gmake_add_run_target() {
local target=${1}
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_file "${target}"; local targetfile="${_ret}"
if is_plat "macosx"; then
print "\t@DYLD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}"
elif is_plat "linux" "bsd"; then
print "\t@LD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}"
else
print "\t@${targetfile}" >> "${xmake_sh_makefile}"
fi
}
_gmake_add_run_targets() {
local target=""
local targets=""
for target in ${_xmake_sh_targets}; do
_get_target_item "${target}" "kind"; local kind="${_ret}"
if test "x${kind}" = "xbinary"; then
if _is_target_default "${target}"; then
targets="${targets} ${target}"
fi
fi
done
echo "run:${targets}" >> "${xmake_sh_makefile}"
for target in ${targets}; do
_gmake_add_run_target "${target}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_run() {
_gmake_add_run_targets
}
_gmake_add_clean_target() {
local target=${1}
local objectfile=""
_get_target_file "${target}"; local targetfile="${_ret}"
_get_target_objectfiles "${target}"; local objectfiles="${_ret}"
print "\t@rm ${targetfile}" >> "${xmake_sh_makefile}"
for objectfile in ${objectfiles}; do
print "\t@rm ${objectfile}" >> "${xmake_sh_makefile}"
done
# @see https://github.com/tboox/tbox/issues/214
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_filename "${target}"; local filename="${_ret}"
_get_target_extension "${target}"; local extension="${_ret}"
local targetfile_with_version="${targetdir}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${targetdir}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${targetdir}/${soname}"
print "\t@if test -f ${targetfile_with_soname}; then rm ${targetfile_with_soname}; fi" >> "${xmake_sh_makefile}"
print "\t@if test -f ${targetfile_with_version}; then rm ${targetfile_with_version}; fi" >> "${xmake_sh_makefile}"
fi
fi
}
_gmake_add_clean_targets() {
local target=""
local targets=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
targets="${targets} ${target}"
fi
done
echo "clean:${targets}" >> "${xmake_sh_makefile}"
for target in ${targets}; do
_gmake_add_clean_target "${target}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_clean() {
_gmake_add_clean_targets
}
_gmake_add_install_target() {
local target=${1}
_get_target_file "${target}"; local targetfile="${_ret}"
path_filename "${targetfile}"; local filename="${_ret}"
_get_target_item "${target}" "installdir"; local installdir="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
if test_z "${installdir}"; then
installdir="\$(INSTALLDIR)"
fi
# before install
_get_target_item "${target}" "before_install"; local before_install="${_ret}"
if test_nz "${before_install}"; then
eval ${before_install} "\${target}" "\${installdir}"
fi
# @see https://github.com/tboox/tbox/issues/214
install_for_soname=false
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_extension "${target}"; local extension="${_ret}"
string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}"
local targetfile_with_version="${_install_libdir_default}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${_install_libdir_default}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${_install_libdir_default}/${soname}"
path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}"
if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then
install_for_soname=true
fi
fi
fi
# install target file
if test_eq "${targetkind}" "binary"; then
string_replace "${_install_bindir_default}" "\${prefix}" "${installdir}"; _install_bindir_default="${_ret}"
print "\t@echo installing ${targetfile} to ${_install_bindir_default}" >> "${xmake_sh_makefile}"
print "\t@mkdir -p ${_install_bindir_default}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${targetfile} ${_install_bindir_default}/${filename}" >> "${xmake_sh_makefile}"
elif ${install_for_soname}; then
string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}"
print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}"
print "\t@cd ${_install_libdir_default} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}"
elif test_eq "${targetkind}" "static" || test_eq "${targetkind}" "shared"; then
string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}"
print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${targetfile} ${_install_libdir_default}/${filename}" >> "${xmake_sh_makefile}"
fi
# install header files
_get_target_item "${target}" "headerfiles"; local headerfiles="${_ret}"
if test_nz "${headerfiles}"; then
string_replace "${_install_includedir_default}" "\${prefix}" "${installdir}"; _install_includedir_default="${_ret}"
local srcheaderfile=""
local includedir="${_install_includedir_default}"
for srcheaderfile in ${headerfiles}; do
string_split "${srcheaderfile}" ":"
local srcheaderfile="${_ret}"
local rootdir="${_ret2}"
local prefixdir="${_ret3}"
local filename="${_ret4}"
if test_z "${filename}"; then
path_filename "${srcheaderfile}"; filename="${_ret}"
fi
local dstheaderdir="${includedir}"
if test_nz "${prefixdir}"; then
dstheaderdir="${dstheaderdir}/${prefixdir}"
fi
local dstheaderfile="${dstheaderdir}/${filename}"
if test_nz "${rootdir}"; then
path_relative "${rootdir}" "${srcheaderfile}"; local subfile="${_ret}"
dstheaderfile="${dstheaderdir}/${subfile}"
fi
path_directory "${dstheaderfile}"; dstheaderdir="${_ret}"
print "\t@mkdir -p ${dstheaderdir}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${srcheaderfile} ${dstheaderfile}" >> "${xmake_sh_makefile}"
done
fi
# install user files
_get_target_item "${target}" "installfiles"; local installfiles="${_ret}"
if test_nz "${installfiles}"; then
local srcinstallfile=""
for srcinstallfile in ${installfiles}; do
string_split "${srcinstallfile}" ":"
local srcinstallfile="${_ret}"
local rootdir="${_ret2}"
local prefixdir="${_ret3}"
local filename="${_ret4}"
if test_z "${filename}"; then
path_filename "${srcinstallfile}"; filename="${_ret}"
fi
local dstinstalldir="${installdir}"
if test_nz "${prefixdir}"; then
dstinstalldir="${dstinstalldir}/${prefixdir}"
fi
local dstinstallfile="${dstinstalldir}/${filename}"
if test_nz "${rootdir}"; then
path_relative "${rootdir}" "${srcinstallfile}"; local subfile="${_ret}"
dstinstallfile="${dstinstalldir}/${subfile}"
fi
path_directory "${dstinstallfile}"; dstinstalldir="${_ret}"
print "\t@mkdir -p ${dstinstalldir}" >> "${xmake_sh_makefile}"
print "\t@cp -p ${srcinstallfile} ${dstinstallfile}" >> "${xmake_sh_makefile}"
done
fi
# after install
_get_target_item "${target}" "after_install"; local after_install="${_ret}"
if test_nz "${after_install}"; then
eval ${after_install} "\${target}" "\${installdir}"
fi
}
_gmake_add_install_targets() {
local target=""
local targets=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
targets="${targets} ${target}"
fi
done
echo "install:${targets}" >> "${xmake_sh_makefile}"
for target in ${targets}; do
_gmake_add_install_target "${target}"
done
echo "" >> "${xmake_sh_makefile}"
}
_gmake_add_install() {
_gmake_add_install_targets
}
_gmake_done() {
echo "makefile is generated!"
if "${xmake_sh_diagnosis}"; then
cat "${xmake_sh_makefile}"
fi
}
# generate build file for gmake
_generate_for_gmake() {
_gmake_begin
_gmake_add_header
_gmake_add_switches
_gmake_add_toolchains
_gmake_add_flags
_gmake_add_build
_gmake_add_clean
_gmake_add_install
_gmake_add_run
_gmake_done
}
#-----------------------------------------------------------------------------
# generate ninja file
#
_ninja_begin() {
echo "generating ninja build file .."
}
_ninja_add_header() {
echo "# this is the build file for this project
# it is autogenerated by the xmake.sh build system.
# do not edit by hand.
" > "${xmake_sh_ninjafile}"
echo "ninja_required_version = 1.3" >> "${xmake_sh_ninjafile}"
echo "builddir = ${xmake_sh_builddir}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_switches() {
local value=""
value="${_install_prefix_default}"; _ninja_escape "${value}"; value="${_ret}"
echo "prefix_default = ${value}" >> "${xmake_sh_ninjafile}"
value="${_install_bindir_default}"; _ninja_escape "${value}"; value="${_ret}"
echo "bindir_default = ${value}" >> "${xmake_sh_ninjafile}"
value="${_install_libdir_default}"; _ninja_escape "${value}"; value="${_ret}"
echo "libdir_default = ${value}" >> "${xmake_sh_ninjafile}"
value="${_install_includedir_default}"; _ninja_escape "${value}"; value="${_ret}"
echo "includedir_default = ${value}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_rules() {
echo "rule command" >> "${xmake_sh_ninjafile}"
echo " command = \$command" >> "${xmake_sh_ninjafile}"
echo " description = \$description" >> "${xmake_sh_ninjafile}"
echo " restat = \$restat" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_toolchains() {
_get_targets_toolkinds; local kinds="${_ret}"
if test_nz "${kinds}"; then
echo "# toolchain programs" >> "${xmake_sh_ninjafile}"
for kind in ${kinds}; do
_get_toolchain_toolset "${_target_toolchain}" "${kind}"; local program="${_ret}"
echo "${kind} = ${program}" >> "${xmake_sh_ninjafile}"
done
echo "" >> "${xmake_sh_ninjafile}"
fi
}
_ninja_add_flags() {
_get_targets_toolkinds; local kinds="${_ret}"
for target in ${_xmake_sh_targets}; do
for kind in ${kinds}; do
_get_target_flags "${target}" "${kind}"; local flags="${_ret}"
if test_nz "${flags}"; then
_get_flagname "${kind}"; local flagname="${_ret}"
local key="${target}_${flagname}"
_ninja_escape "${flags}"; flags="${_ret}"
echo "${key} = ${flags}" >> "${xmake_sh_ninjafile}"
fi
done
echo "" >> "${xmake_sh_ninjafile}"
done
}
_ninja_add_build_object() {
local target=${1}
local sourcefile="${2}"
local objectfile="${3}"
path_sourcekind "${sourcefile}"; local sourcekind="${_ret}"
_get_target_flags "${target}" "${sourcekind}"; local flags="${_ret}"
_toolchain_compcmd "${sourcekind}" "${objectfile}" "${sourcefile}" "${flags}"; local compcmd="${_ret}"
path_directory "${objectfile}"; local objectdir="${_ret}"
local use_shell_wrapper=false
local command="mkdir -p \"${objectdir}\" && ${compcmd}"
if is_host "msys" "cygwin" "mingw"; then
use_shell_wrapper=true
fi
if ${use_shell_wrapper}; then
_shell_escape_single_quotes "${command}"; local command_script="${_ret}"
command="sh -lc ${command_script}"
fi
local description="compiling.${_target_mode} ${sourcefile}"
_ninja_escape "${command}"; command="${_ret}"
_ninja_escape "${description}"; description="${_ret}"
echo "build ${objectfile}: command ${sourcefile}" >> "${xmake_sh_ninjafile}"
echo " command = ${command}" >> "${xmake_sh_ninjafile}"
echo " description = ${description}" >> "${xmake_sh_ninjafile}"
echo " restat = 0" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_build_objects() {
local target=${1}
_get_target_sourcefiles "${target}"; local sourcefiles="${_ret}"
for sourcefile in ${sourcefiles}; do
_get_target_objectfile "${target}" "${sourcefile}"; local objectfile="${_ret}"
_ninja_add_build_object "${target}" "${sourcefile}" "${objectfile}"
done
}
_ninja_add_build_target() {
local target=${1}
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_file "${target}"; local targetfile="${_ret}"
_get_target_item "${target}" "deps"; local deps="${_ret}"
_get_target_objectfiles "${target}"; local objectfiles="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
local toolkind=""
case "${targetkind}" in
binary) toolkind="ld";;
static) toolkind="ar";;
shared) toolkind="sh";;
*) raise "unknown targetkind(${targetkind})!" ;;
esac
_get_target_flags "${target}" "${toolkind}"; local linkflags="${_ret}"
_toolchain_linkcmd "${toolkind}" "${targetfile}" "${objectfiles}" "${linkflags}"; local linkcmd="${_ret}"
local use_shell_wrapper=false
local command="mkdir -p \"${targetdir}\" && ${linkcmd}"
if is_host "msys" "cygwin" "mingw"; then
use_shell_wrapper=true
fi
local description="linking.${_target_mode} ${targetfile}"
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_filename "${target}"; local targetfilename="${_ret}"
_get_target_extension "${target}"; local extension="${_ret}"
local targetfile_with_version="${targetdir}/${targetfilename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${targetfilename}"; local basename="${_ret}"
targetfile_with_version="${targetdir}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${targetdir}/${soname}"
path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}"
if test_nq "${soname}" "${targetfilename}" && test_nq "${soname}" "${targetfilename_with_version}"; then
command="${command} && cp -p ${targetfile} ${targetfile_with_version} && cd \"${targetdir}\" && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${targetfilename}"
fi
fi
fi
if ${use_shell_wrapper}; then
_shell_escape_single_quotes "${command}"; local command_script="${_ret}"
command="sh -lc ${command_script}"
fi
_ninja_escape "${command}"; command="${_ret}"
_ninja_escape "${description}"; description="${_ret}"
local orderdeps=""
local dep=""
for dep in ${deps}; do
_get_target_file "${dep}"; local depfile="${_ret}"
if test_nz "${orderdeps}"; then
orderdeps="${orderdeps} ${depfile}"
else
orderdeps="${depfile}"
fi
done
if test_nz "${orderdeps}"; then
echo "build ${targetfile}: command ${objectfiles} | ${orderdeps}" >> "${xmake_sh_ninjafile}"
else
echo "build ${targetfile}: command ${objectfiles}" >> "${xmake_sh_ninjafile}"
fi
echo " command = ${command}" >> "${xmake_sh_ninjafile}"
echo " description = ${description}" >> "${xmake_sh_ninjafile}"
echo " restat = 0" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
echo "build ${target}: phony ${targetfile}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
_ninja_add_build_objects "${target}"
}
_ninja_add_build_targets() {
local target=""
local defaults=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
if test_nz "${defaults}"; then
defaults="${defaults} ${target}"
else
defaults="${target}"
fi
fi
done
if test_nz "${defaults}"; then
echo "build default: phony ${defaults}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
echo "default default" >> "${xmake_sh_ninjafile}"
else
echo "default all" >> "${xmake_sh_ninjafile}"
fi
echo "build all: phony ${_xmake_sh_targets}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
for target in ${_xmake_sh_targets}; do
_ninja_add_build_target "${target}"
done
}
_ninja_add_build() {
_ninja_add_build_targets
}
_ninja_add_run_target() {
local target=${1}
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_file "${target}"; local targetfile="${_ret}"
local command=""
if is_host "msys" "cygwin" "mingw"; then
local projectdir="${xmake_sh_projectdir}"
local targetfile_rel="./${targetfile}"
local targetfile_alt="./build/${targetfile#*/}"
local targetbuilddir="${targetfile%/*}"
local targetbuilddir_rel="./${targetbuilddir}"
local targetbuilddir_alt="./build/${targetbuilddir#*/}"
local run_script="cd \"${projectdir}\" && target=\"${targetfile_rel}\"; alt=\"${targetfile_alt}\"; if [ ! -f \"\$target\" ] && [ -f \"\$alt\" ]; then target=\"\$alt\"; fi; if [ ! -f \"\$target\" ]; then echo \"[ninja run] missing ${targetfile_rel} (and fallback ${targetfile_alt})\"; ls -l \"${targetbuilddir_rel}\" || true; ls -l \"${targetbuilddir_alt}\" || true; exit 1; fi; \"\$target\""
_shell_escape_single_quotes "${run_script}"; local run_script_escaped="${_ret}"
command="sh -lc ${run_script_escaped}"
elif is_plat "macosx"; then
command="DYLD_LIBRARY_PATH=${targetdir} ${targetfile}"
elif is_plat "linux" "bsd"; then
command="LD_LIBRARY_PATH=${targetdir} ${targetfile}"
else
command="${targetfile}"
fi
local description="running.${_target_mode} ${targetfile}"
_ninja_escape "${command}"; command="${_ret}"
_ninja_escape "${description}"; description="${_ret}"
echo "build run.${target}: command | ${targetfile}" >> "${xmake_sh_ninjafile}"
echo " command = ${command}" >> "${xmake_sh_ninjafile}"
echo " description = ${description}" >> "${xmake_sh_ninjafile}"
echo " restat = 0" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_run_targets() {
local target=""
local runtargets=""
for target in ${_xmake_sh_targets}; do
_get_target_item "${target}" "kind"; local kind="${_ret}"
if test_eq "${kind}" "binary"; then
if _is_target_default "${target}"; then
if test_nz "${runtargets}"; then
runtargets="${runtargets} run.${target}"
else
runtargets="run.${target}"
fi
_ninja_add_run_target "${target}"
fi
fi
done
if test_nz "${runtargets}"; then
echo "build run: phony ${runtargets}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
fi
}
_ninja_add_run() {
_ninja_add_run_targets
}
_ninja_add_clean_target() {
local target=${1}
_get_target_file "${target}"; local targetfile="${_ret}"
_get_target_objectfiles "${target}"; local objectfiles="${_ret}"
local removefiles="${targetfile}"
local objectfile=""
for objectfile in ${objectfiles}; do
removefiles="${removefiles} ${objectfile}"
done
_get_targetdir "${target}"; local targetdir="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; local version="${_ret}"
_get_target_soname "${target}"; local soname="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
_get_target_filename "${target}"; local filename="${_ret}"
_get_target_extension "${target}"; local extension="${_ret}"
local targetfile_with_version="${targetdir}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
path_basename "${filename}"; local basename="${_ret}"
targetfile_with_version="${targetdir}/${basename}.${version}${extension}"
fi
local targetfile_with_soname="${targetdir}/${soname}"
removefiles="${removefiles} ${targetfile_with_soname} ${targetfile_with_version}"
fi
fi
local command="rm -f ${removefiles}"
local description="cleaning.${_target_mode} ${target}"
_ninja_escape "${command}"; command="${_ret}"
_ninja_escape "${description}"; description="${_ret}"
echo "build clean.${target}: command" >> "${xmake_sh_ninjafile}"
echo " command = ${command}" >> "${xmake_sh_ninjafile}"
echo " description = ${description}" >> "${xmake_sh_ninjafile}"
echo " restat = 0" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_clean_targets() {
local target=""
local cleantargets=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
if test_nz "${cleantargets}"; then
cleantargets="${cleantargets} clean.${target}"
else
cleantargets="clean.${target}"
fi
_ninja_add_clean_target "${target}"
fi
done
if test_nz "${cleantargets}"; then
echo "build clean: phony ${cleantargets}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
fi
}
_ninja_add_clean() {
_ninja_add_clean_targets
}
_ninja_install_prepare_script() {
local target="${1}"
local ninjadir="${xmake_sh_builddir}/.ninja"
local scriptdir="${xmake_sh_projectdir}/${ninjadir}"
mkdir -p "${scriptdir}"
_ret="${scriptdir}/install_${target}.sh"
_ret2="${ninjadir}/install_${target}.sh"
}
_ninja_install_write_header() {
local scriptfile="${1}"
local escaped_prefix_default="${2}"
local escaped_installdir_template="${3}"
local escaped_projectdir="${4}"
local escaped_bindir_template="${5}"
local escaped_libdir_template="${6}"
local escaped_includedir_template="${7}"
cat > "${scriptfile}" <> "${scriptfile}"
elif ${install_for_soname}; then
local version_template="${_install_libdir_default}/${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
version_template="${_install_libdir_default}/${filename_basename}.${version}${extension}"
fi
_shell_escape_single_quotes "${targetfile}"; local escaped_targetfile="${_ret}"
_shell_escape_single_quotes "${version_template}"; local escaped_version_template="${_ret}"
_shell_escape_single_quotes "${soname}"; local escaped_soname="${_ret}"
_shell_escape_single_quotes "${filename}"; local escaped_filename="${_ret}"
cat >> "${scriptfile}" <> "${scriptfile}"
fi
}
_ninja_install_append_headerfiles() {
local scriptfile="${1}"
local headerfiles="${2}"
if test_nz "${headerfiles}"; then
local srcheaderfile=""
for srcheaderfile in ${headerfiles}; do
string_split "${srcheaderfile}" ":"
local srcheaderpath="${_ret}"
local rootdir="${_ret2}"
local prefixdir="${_ret3}"
local headername="${_ret4}"
if test_z "${headername}"; then
path_filename "${srcheaderpath}"; headername="${_ret}"
fi
local dstheaderdir_template="${_install_includedir_default}"
if test_nz "${prefixdir}"; then
dstheaderdir_template="${dstheaderdir_template}/${prefixdir}"
fi
local dstheaderfile_template=""
if test_nz "${rootdir}"; then
path_relative "${rootdir}" "${srcheaderpath}"; local subfile="${_ret}"
dstheaderfile_template="${dstheaderdir_template}/${subfile}"
else
dstheaderfile_template="${dstheaderdir_template}/${headername}"
fi
_shell_escape_single_quotes "${srcheaderpath}"; local escaped_src="${_ret}"
_shell_escape_single_quotes "${dstheaderfile_template}"; local escaped_dst="${_ret}"
echo "copy_file ${escaped_src} ${escaped_dst}" >> "${scriptfile}"
done
fi
}
_ninja_install_append_installfiles() {
local scriptfile="${1}"
local installdir="${2}"
local installfiles="${3}"
if test_nz "${installfiles}"; then
local srcinstallfile=""
for srcinstallfile in ${installfiles}; do
string_split "${srcinstallfile}" ":"
local srcfilepath="${_ret}"
local rootdir="${_ret2}"
local prefixdir="${_ret3}"
local installname="${_ret4}"
if test_z "${installname}"; then
path_filename "${srcfilepath}"; installname="${_ret}"
fi
local dst_template="${installdir}"
if test_z "${dst_template}"; then
dst_template="\${prefix}"
fi
if test_nz "${prefixdir}"; then
dst_template="${dst_template}/${prefixdir}"
fi
if test_nz "${rootdir}"; then
path_relative "${rootdir}" "${srcfilepath}"; local subfile="${_ret}"
dst_template="${dst_template}/${subfile}"
else
dst_template="${dst_template}/${installname}"
fi
_shell_escape_single_quotes "${srcfilepath}"; local escaped_src="${_ret}"
_shell_escape_single_quotes "${dst_template}"; local escaped_dst="${_ret}"
echo "copy_file ${escaped_src} ${escaped_dst}" >> "${scriptfile}"
done
fi
}
_ninja_add_install_target() {
local target=${1}
_get_target_file "${target}"; local targetfile="${_ret}"
path_filename "${targetfile}"; local filename="${_ret}"
_get_target_item "${target}" "installdir"; local installdir="${_ret}"
_get_target_item "${target}" "kind"; local targetkind="${_ret}"
local install_for_soname=false
local version=""
local soname=""
local extension=""
local filename_basename=""
if test_eq "${targetkind}" "shared"; then
_get_target_item "${target}" "version"; version="${_ret}"
_get_target_soname "${target}"; soname="${_ret}"
_get_target_extension "${target}"; extension="${_ret}"
path_basename "${filename}"; filename_basename="${_ret}"
if test_nz "${soname}" && test_nz "${version}"; then
local targetfilename_with_version_guess="${filename}.${version}"
if test_eq "${extension}" ".dylib"; then
targetfilename_with_version_guess="${filename_basename}.${version}${extension}"
fi
if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version_guess}"; then
install_for_soname=true
fi
fi
fi
_ninja_install_prepare_script "${target}"
local scriptfile="${_ret}"
local scriptfile_rel="${_ret2}"
_shell_escape_single_quotes "${_install_prefix_default}"; local escaped_prefix_default="${_ret}"
_shell_escape_single_quotes "${installdir}"; local escaped_installdir_template="${_ret}"
_shell_escape_single_quotes "${xmake_sh_projectdir}"; local escaped_projectdir="${_ret}"
_shell_escape_single_quotes "${_install_bindir_default}"; local escaped_bindir_template="${_ret}"
_shell_escape_single_quotes "${_install_libdir_default}"; local escaped_libdir_template="${_ret}"
_shell_escape_single_quotes "${_install_includedir_default}"; local escaped_includedir_template="${_ret}"
_ninja_install_write_header "${scriptfile}" \
"${escaped_prefix_default}" \
"${escaped_installdir_template}" \
"${escaped_projectdir}" \
"${escaped_bindir_template}" \
"${escaped_libdir_template}" \
"${escaped_includedir_template}"
_ninja_install_append_target_artifacts "${scriptfile}" "${targetkind}" "${install_for_soname}" \
"${targetfile}" "${filename}" "${version}" "${soname}" "${extension}" "${filename_basename}"
_get_target_item "${target}" "headerfiles"; local headerfiles="${_ret}"
_ninja_install_append_headerfiles "${scriptfile}" "${headerfiles}"
_get_target_item "${target}" "installfiles"; local installfiles="${_ret}"
_ninja_install_append_installfiles "${scriptfile}" "${installdir}" "${installfiles}"
echo "" >> "${scriptfile}"
chmod +x "${scriptfile}"
local command="sh ${scriptfile_rel}"
local description="installing.${_target_mode} ${target}"
_ninja_escape "${command}"; command="${_ret}"
_ninja_escape "${description}"; description="${_ret}"
echo "build install.${target}: command | ${targetfile}" >> "${xmake_sh_ninjafile}"
echo " command = ${command}" >> "${xmake_sh_ninjafile}"
echo " description = ${description}" >> "${xmake_sh_ninjafile}"
echo " restat = 0" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
}
_ninja_add_install_targets() {
local target=""
local installtargets=""
for target in ${_xmake_sh_targets}; do
if _is_target_default "${target}"; then
if test_nz "${installtargets}"; then
installtargets="${installtargets} install.${target}"
else
installtargets="install.${target}"
fi
_ninja_add_install_target "${target}"
fi
done
if test_nz "${installtargets}"; then
echo "build install: phony ${installtargets}" >> "${xmake_sh_ninjafile}"
echo "" >> "${xmake_sh_ninjafile}"
fi
}
_ninja_add_install() {
_ninja_add_install_targets
}
_ninja_done() {
echo "ninja build file is generated!"
if "${xmake_sh_diagnosis}"; then
cat "${xmake_sh_ninjafile}"
fi
}
# generate build file for ninja
_generate_for_ninja() {
_ninja_begin
_ninja_add_header
_ninja_add_switches
_ninja_add_toolchains
_ninja_add_flags
_ninja_add_rules
_ninja_add_build
_ninja_add_clean
_ninja_add_install
_ninja_add_run
_ninja_done
}
#-----------------------------------------------------------------------------
# generate build file
#
_generate_build_file() {
if test_eq "${project_generator}" "gmake"; then
_generate_for_gmake
elif test_eq "${project_generator}" "ninja"; then
_generate_for_ninja
else
raise "unknown generator: ${project_generator}"
fi
}
_generate_build_file
================================================
FILE: core/src/cli/xmake.c
================================================
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "xmake/xmake.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* main
*/
tb_int_t main(tb_int_t argc, tb_char_t** argv) {
return xm_engine_run("xmake", argc, argv, tb_null, tb_null);
}
================================================
FILE: core/src/cli/xmake.lua
================================================
target("cli")
-- disable this target if only build libaries
if has_config("onlylib") then
set_default(false)
end
-- add deps
add_deps("xmake")
-- make as a binary
set_kind("binary")
set_basename("xmake")
set_targetdir("$(builddir)")
-- add definitions
add_defines("__tb_prefix__=\"xmake\"")
-- add includes directory
add_includedirs("$(projectdir)", "$(projectdir)/src")
-- add common source files
add_files("**.c")
-- add resource files (it will be enabled after publishing new version)
if is_plat("windows") then
add_files("*.rc")
end
-- add links
if is_plat("windows") then
add_syslinks("ws2_32", "advapi32", "shell32", "wintrust", "crypt32")
add_ldflags("/export:malloc", "/export:free", "/export:memmove")
elseif is_plat("android") then
add_syslinks("m", "c")
elseif is_plat("macosx") and is_config("runtime", "luajit") then
add_ldflags("-all_load", "-pagezero_size 10000", "-image_base 100000000")
elseif is_plat("mingw") then
add_ldflags("-static-libgcc", {force = true})
elseif is_plat("haiku") then
add_syslinks("pthread", "network", "m", "c")
else
add_syslinks("pthread", "dl", "m", "c")
end
-- enable xp compatibility mode
if is_plat("windows") then
if is_arch("x86") then
add_ldflags("/subsystem:console,5.01")
else
add_ldflags("/subsystem:console,5.02")
end
end
-- add install files
if is_plat("windows") then
add_installfiles("$(projectdir)/../LICENSE.md")
add_installfiles("$(projectdir)/../NOTICE.md")
add_installfiles("$(projectdir)/../xmake/(**.lua)")
add_installfiles("$(projectdir)/../xmake/(scripts/**)")
add_installfiles("$(projectdir)/../xmake/(repository/templates/**)")
add_installfiles("$(projectdir)/../scripts/xrepo.bat")
add_installfiles("$(projectdir)/../scripts/xrepo.ps1")
set_prefixdir("/", {bindir = "/"})
after_install(function (target)
os.cp(path.join(os.programdir(), "winenv"), target:installdir())
end)
else
add_installfiles("$(projectdir)/../(xmake/**.lua)", {prefixdir = "share"})
add_installfiles("$(projectdir)/../(xmake/scripts/**)", {prefixdir = "share"})
add_installfiles("$(projectdir)/../(xmake/repository/templates/**)", {prefixdir = "share"})
add_installfiles("$(projectdir)/../scripts/xrepo.sh", {prefixdir = "bin", filename = "xrepo"})
end
before_installcmd(function (target, batchcmds, opt)
-- we need to avoid some old files interfering with xmake's module import.
local package = opt.package
if target:is_plat("windows") then
batchcmds:rmdir(package:installdir("actions"))
batchcmds:rmdir(package:installdir("core"))
batchcmds:rmdir(package:installdir("includes"))
batchcmds:rmdir(package:installdir("languages"))
batchcmds:rmdir(package:installdir("modules"))
batchcmds:rmdir(package:installdir("platforms"))
batchcmds:rmdir(package:installdir("plugins"))
batchcmds:rmdir(package:installdir("repository"))
batchcmds:rmdir(package:installdir("rules"))
batchcmds:rmdir(package:installdir("templates"))
batchcmds:rmdir(package:installdir("scripts"))
batchcmds:rmdir(package:installdir("themes"))
batchcmds:rmdir(package:installdir("toolchains"))
end
end)
================================================
FILE: core/src/cli/xmake.rc
================================================
#include "xmake.config.h"
#include "winres.h"
#define _STR(x) #x
#define STR(x) _STR(x)
VS_VERSION_INFO VERSIONINFO
FILEVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0
PRODUCTVERSION XM_CONFIG_VERSION_MAJOR, XM_CONFIG_VERSION_MINOR, XM_CONFIG_VERSION_ALTER, 0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000004B0"
BEGIN
VALUE "Comments", "A cross-platform build utility based on Lua\nwebsite: https://xmake.io"
VALUE "CompanyName", "The Xmake Open Source Community"
VALUE "FileDescription", "XMake build utility"
VALUE "FileVersion", XM_CONFIG_VERSION "+" STR(XM_CONFIG_VERSION_BUILD)
VALUE "InternalName", "xmake"
VALUE "LegalCopyright", "Copyright (C) 2015-present Ruki Wang, https://xmake.io"
VALUE "LegalTrademarks", ""
VALUE "OriginalFilename", "xmake.exe"
VALUE "ProductName", "XMake"
VALUE "ProductVersion", XM_CONFIG_VERSION "+" STR(XM_CONFIG_VERSION_BUILD)
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0, 1200
END
END
IDI_APP ICON DISCARDABLE "xmake.ico"
================================================
FILE: core/src/cli/xmake.sh
================================================
#!/bin/sh
target "cli"
add_deps "xmake"
set_kind "binary"
set_basename "xmake"
set_targetdir "${builddir}"
# add definitions
add_defines "__tb_prefix__=\"xmake\""
# add includes directory
add_includedirs "${projectdir}/core" "${projectdir}/core/src"
# add the common source files
add_files "**.c"
# add links
if is_plat "macosx" && is_config "runtime" "luajit"; then
add_ldflags "-all_load" "-pagezero_size 10000" "-image_base 100000000"
elif is_plat "mingw"; then
add_ldflags "-static-libgcc" "-lwintrust" "-lcrypt32"
fi
# add install files
add_installfiles "${projectdir}/(xmake/**.lua)" "share"
add_installfiles "${projectdir}/(xmake/scripts/*)" "share"
add_installfiles "${projectdir}/(xmake/scripts/cmake_importfiles/**)" "share"
add_installfiles "${projectdir}/(xmake/scripts/completions/**)" "share"
add_installfiles "${projectdir}/(xmake/scripts/xpack/**)" "share"
add_installfiles "${projectdir}/(xmake/scripts/xrepo/**)" "share"
add_installfiles "${projectdir}/(xmake/scripts/virtualenvs/**)" "share"
add_installfiles "${projectdir}/(xmake/scripts/conan/**)" "share"
add_installfiles "${projectdir}/(xmake/scripts/module/**)" "share"
add_installfiles "${projectdir}/(xmake/repository/templates/**)" "share"
add_installfiles "${projectdir}/scripts/xrepo.sh" "bin" "xrepo"
# fix os.exec() call incorrect program from /mingw64/bin. e.g. python, ..
#
# because xmake is installed to /mingw64/bin/xmake,
# os.exec/CreateProcess always gives the highest priority to finding the process from /mingw64/bin (if it exists),
# rather than from the $PATH environment variable.
#
# we install the xmake executable into a separate directory to ensure
# that os.exec() does not look for additional executables.
#
# @see https://github.com/xmake-io/xmake/issues/3628
if is_host "msys"; then
after_install "xmake_after_install"
fi
# add syslinks
add_options "atomic"
if is_plat "mingw" "msys" "cygwin"; then
add_syslinks "ws2_32" "pthread" "m"
elif is_plat "bsd" "solaris"; then
add_syslinks "pthread" "m"
elif is_plat "haiku"; then
add_syslinks "pthread" "network" "m"
elif test_nz "${TERMUX_ARCH}"; then
add_syslinks "m" "dl"
else
add_syslinks "pthread" "dl" "m" "c"
fi
xmake_after_install() {
local target=${1}
local installdir=${2}
if test_eq "${project_generator}" "gmake"; then
print "\t@if test -f ${installdir}/bin/xmake.exe; then rm ${installdir}/bin/xmake.exe; fi" >> "${xmake_sh_makefile}"
print "\t@cp ${projectdir}/scripts/msys/xmake.sh ${installdir}/bin/xmake" >> "${xmake_sh_makefile}"
print "\t@cp ${projectdir}/scripts/msys/xmake.cmd ${installdir}/bin/xmake.cmd" >> "${xmake_sh_makefile}"
print "\t@cp ${projectdir}/scripts/msys/xmake.ps1 ${installdir}/bin/xmake.ps1" >> "${xmake_sh_makefile}"
print "\t@cp ${builddir}/xmake.exe ${installdir}/share/xmake" >> "${xmake_sh_makefile}"
fi
}
================================================
FILE: core/src/lua/xmake.lua
================================================
target("lua")
set_kind("static")
set_warnings("all")
-- disable c99(/TP) for windows
if is_plat("windows") then
set_languages("c89")
end
-- add header files
add_headerfiles("lua/(*.h)", {prefixdir = "lua"})
-- add include directories
add_includedirs("lua", {public = true})
-- add the common source files
add_files("lua/*.c|lua.c|onelua.c|loslib.c")
if not is_plat("iphoneos") then
add_files("lua/loslib.c")
end
-- add definitions
add_defines("LUA_COMPAT_5_1", "LUA_COMPAT_5_2", "LUA_COMPAT_5_3", {public = true})
if is_plat("windows", "mingw") then
-- it has been defined in luaconf.h
--add_defines("LUA_USE_WINDOWS")
elseif is_plat("macosx", "iphoneos") then
add_defines("LUA_USE_MACOSX")
else
add_defines("LUA_USE_LINUX")
end
-- we just disable os.execute for ios, because os.execv do not use it
-- @see https://github.com/xmake-io/xmake/issues/2187
on_load("iphoneos", function (target)
local loslib_file = target:autogenfile("loslib.c")
os.cp(path.join(os.scriptdir(), "lua", "loslib.c"), loslib_file)
io.replace(loslib_file, "system(cmd)", "0", {plain = true})
target:add("files", loslib_file)
end)
================================================
FILE: core/src/lua/xmake.sh
================================================
#!/bin/sh
target "lua"
set_kind "static"
set_default false
set_warnings "all"
# add include directories
add_includedirs "lua" "{public}"
# add the common source files
add_files "lua/lapi.c"
add_files "lua/lauxlib.c"
add_files "lua/lbaselib.c"
add_files "lua/lcode.c"
add_files "lua/lcorolib.c"
add_files "lua/lctype.c"
add_files "lua/ldblib.c"
add_files "lua/ldebug.c"
add_files "lua/ldo.c"
add_files "lua/ldump.c"
add_files "lua/lfunc.c"
add_files "lua/lgc.c"
add_files "lua/linit.c"
add_files "lua/liolib.c"
add_files "lua/llex.c"
add_files "lua/lmathlib.c"
add_files "lua/lmem.c"
add_files "lua/loadlib.c"
add_files "lua/lobject.c"
add_files "lua/lopcodes.c"
add_files "lua/loslib.c"
add_files "lua/lparser.c"
add_files "lua/lstate.c"
add_files "lua/lstring.c"
add_files "lua/lstrlib.c"
add_files "lua/ltable.c"
add_files "lua/ltablib.c"
add_files "lua/ltm.c"
add_files "lua/lundump.c"
add_files "lua/lutf8lib.c"
add_files "lua/lvm.c"
add_files "lua/lzio.c"
# add definitions
add_defines "LUA_COMPAT_5_1" "LUA_COMPAT_5_2" "LUA_COMPAT_5_3" "{public}"
if is_plat "mingw"; then true
# it has been defined in luaconf.h
#add_defines "LUA_USE_WINDOWS"
elif is_plat "macosx"; then
add_defines "LUA_USE_MACOSX"
else
add_defines "LUA_USE_LINUX"
fi
================================================
FILE: core/src/lua-cjson/xmake.lua
================================================
target("lua-cjson")
set_kind("static")
set_warnings("all")
if is_config("runtime", "luajit") then
add_deps("luajit")
else
add_deps("lua")
end
if is_plat("windows") then
set_languages("c89")
end
add_files("lua-cjson/*.c|fpconv.c")
-- Use internal strtod() / g_fmt() code for performance and disable multi-thread
add_defines("NDEBUG", "USE_INTERNAL_FPCONV")
add_defines("XM_CONFIG_API_HAVE_LUA_CJSON", {public = true})
if is_plat("windows") then
add_defines("inline=__inline")
end
================================================
FILE: core/src/lua-cjson/xmake.sh
================================================
#!/bin/sh
target "lua_cjson"
set_kind "static"
set_default false
set_warnings "all"
if has_config "external"; then
if is_config "runtime" "luajit"; then
if has_config "luajit"; then
add_options "luajit" "{public}"
fi
else
if has_config "lua"; then
add_options "lua" "{public}"
fi
fi
else
if is_config "runtime" "luajit"; then
add_deps "luajit"
else
add_deps "lua"
fi
fi
add_files "lua-cjson/dtoa.c"
add_files "lua-cjson/lua_cjson.c"
add_files "lua-cjson/strbuf.c"
add_files "lua-cjson/g_fmt.c"
# Use internal strtod() / g_fmt() code for performance and disable multi-thread
add_defines "NDEBUG" "USE_INTERNAL_FPCONV"
add_defines "XM_CONFIG_API_HAVE_LUA_CJSON" "{public}"
================================================
FILE: core/src/luajit/xmake.lua
================================================
-- disable jit compiler for redhat and centos
local jit = true
local plat = "$(plat)"
local arch = "$(arch)"
if is_plat("msys", "mingw", "cygwin") then
plat = "windows"
arch = is_arch("x86_64") and "x64" or "x86"
elseif is_plat("android") then
plat = "linux"
end
if is_arch("arm64", "arm64-v8a") then
arch = "arm64"
elseif is_arch("arm.*") then
arch = "arm"
elseif is_arch("mips64.*") then
arch = "mips64"
jit = false
end
if os.isfile("/etc/redhat-release") then
jit = false
end
local autogendir = path.join("luajit", "autogen", plat, jit and "jit" or "nojit", arch)
-- add target
target("luajit")
-- make as a static library
set_kind("static")
-- set warning all and disable error
set_warnings("all")
-- disable c99(/TP) for windows
if is_plat("windows") then
set_languages("c89")
end
-- add header files
add_headerfiles("luajit/src/(*.h)", {prefixdir = "luajit"})
-- add include directories
add_includedirs(autogendir)
add_includedirs("luajit/src", {public = true})
-- add the common source files
add_files("luajit/src/*.c|ljamalg.c|luajit.c")
if is_plat("windows") then
add_files(autogendir .. "/lj_vm.obj")
elseif is_plat("msys", "cygwin", "mingw") then
add_files(autogendir .. "/lj_vm.o")
else
add_files(autogendir .. "/*.S")
end
add_defines("USE_LUAJIT", {interface = true})
-- disable jit compiler?
if not jit then
add_defines("LUAJIT_DISABLE_JIT")
end
-- using internal memory management under armv7, gc will cause a crash when free strings in lua_close()
if arch == "arm" then
add_defines("LUAJIT_USE_SYSMALLOC")
end
-- fix call math.sin/log crash for fedora/i386/lj_vm.S with `LDFLAGS = -specs=/usr/lib/rpm/redhat/redhat-hardened-ld` in xmake.spec/%set_build_flags
if is_plat("linux") and is_arch("i386") then
add_asflags("-fPIE")
add_ldflags("-fPIE")
end
-- enable lua5.2 compat, @see http://luajit.org/extensions.html
--[[
add_defines("LUAJIT_ENABLE_LUA52COMPAT")
if not is_plat("windows") then
add_cflags("-Wno-error=unused-function")
end]]
================================================
FILE: core/src/luajit/xmake.sh
================================================
#!/bin/sh
# disable jit compiler for redhat and centos
jit=true
jit_plat="${plat}"
jit_arch="${arch}"
if is_plat "mingw"; then
jit_plat="windows"
if is_arch "x86_64"; then
jit_arch="x64"
else
jit_arch="x86"
fi
fi
if is_arch "arm64" "arm64-v8a"; then
jit_arch="arm64"
elif is_arch "arm" "armv7"; then
jit_arch="arm"
elif is_arch "mips64"; then
jit_arch="mips64"
jit=false
fi
if test -f "/etc/redhat-release"; then
jit=false
fi
if $jit; then
jit_dir="jit"
else
jit_dir="nojit"
fi
jit_autogendir="luajit/autogen/${jit_plat}/${jit_dir}/${jit_arch}"
target "luajit"
set_kind "static"
set_default false
set_warnings "all"
# add include directories
add_includedirs "${jit_autogendir}"
add_includedirs "luajit/src" "{public}"
# add the common source files
add_files "luajit/src/lj_*.c"
add_files "luajit/src/lib_*.c"
if is_plat "mingw"; then
add_files "${jit_autogendir}/lj_vm.o"
else
add_files "${jit_autogendir}/*.S"
fi
add_defines "USE_LUAJIT" "{public}"
# disable jit compiler?
if ! $jit; then
add_defines "LUAJIT_DISABLE_JIT"
fi
# using internal memory management under armv7 gc will cause a crash when free strings in lua_close
if test_eq "${jit_arch}" "arm"; then
add_defines "LUAJIT_USE_SYSMALLOC"
fi
# fix call math.sin/log crash for fedora/i386/lj_vm.S with `LDFLAGS = -specs=/usr/lib/rpm/redhat/redhat-hardened-ld` in xmake.spec/%set_build_flags
if is_plat "linux" && is_arch "i386"; then
add_asflags "-fPIE"
add_ldflags "-fPIE"
fi
================================================
FILE: core/src/lz4/xmake.lua
================================================
target("lz4")
set_kind("static")
set_warnings("all")
-- disable c99(/TP) for windows
if is_plat("windows") then
set_languages("c89")
end
-- add header files
add_headerfiles("lz4/lib/(*.h)")
-- add include directories
add_includedirs("lz4/lib", {public = true})
-- add the common source files
add_files("lz4/lib/*.c|lz4file.c")
-- add definitions
add_defines("XXH_NAMESPACE=LZ4_")
================================================
FILE: core/src/lz4/xmake.sh
================================================
#!/bin/sh
target "lz4"
set_kind "static"
set_default false
set_warnings "all"
add_includedirs "lz4/lib" "{public}"
add_files "lz4/lib/lz4.c"
add_files "lz4/lib/lz4frame.c"
add_files "lz4/lib/lz4hc.c"
add_files "lz4/lib/xxhash.c"
add_defines "XXH_NAMESPACE=LZ4_"
================================================
FILE: core/src/pdcurses/xmake.lua
================================================
-- add target
target("pdcurses")
-- enable this target
if not has_config("pdcurses") then
set_default(false)
end
-- make as a static library
set_kind("static")
-- add includes directory
add_includedirs("pdcurses", {public = true})
-- add the common source files
add_files("pdcurses/pdcurses/*.c", "pdcurses/wincon/*.c")
-- add definitions
add_defines("PDC_WIDE")
-- set languages
set_languages("c89")
-- unset warnings
set_warnings("none")
================================================
FILE: core/src/sv/.gitignore
================================================
# Created by .ignore support plugin (hsz.mobi)
### Autotools template
# http://www.gnu.org/software/automake
Makefile.in
/ar-lib
/mdate-sh
/py-compile
/test-driver
/ylwrap
# http://www.gnu.org/software/autoconf
/autom4te.cache
/autoscan.log
/autoscan-*.log
/aclocal.m4
/compile
/config.guess
/config.h.in
/config.sub
/configure
/configure.scan
/depcomp
/install-sh
/missing
/stamp-h1
# https://www.gnu.org/software/libtool/
/ltmain.sh
# http://www.gnu.org/software/texinfo
/texinfo.tex
### CMake template
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
### C template
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
modules.order
Module.symvers
Mkfile.old
dkms.conf
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Clion
.idea/
cmake-build-debug/
# xmake
.xmake/
build/
================================================
FILE: core/src/sv/.travis.yml
================================================
sudo: false
language: c
before_install:
- bash <(curl -s https://raw.githubusercontent.com/xmake-io/xmake/master/scripts/get.sh)
install:
- xmake
- cd build
- cmake ..
- make all
script:
- ctest --verbose
- cd .. && xmake check
matrix:
include:
- os: linux
- os: linux
compiler: gcc-4.9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.9
- os: linux
compiler: gcc-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-5
- os: linux
compiler: gcc-6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- os: linux
compiler: clang-3.5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.5
packages:
- clang-3.5
- os: linux
compiler: clang-3.6
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
packages:
- clang-3.6
- os: linux
compiler: clang-3.7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
packages:
- clang-3.7
- os: linux
compiler: clang-3.8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
packages:
- clang-3.8
- os: linux
compiler: clang-3.9
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.9
packages:
- clang-3.9
- os: linux
dist: trusty
compiler: clang-4.0
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
packages:
- clang-4.0
- os: osx
osx_image: xcode6.4
compiler: clang
- os: osx
osx_image: xcode7.3
compiler: clang
- os: osx
osx_image: xcode8.3
compiler: clang
================================================
FILE: core/src/sv/xmake.lua
================================================
includes("sv")
================================================
FILE: core/src/sv/xmake.sh
================================================
#!/bin/sh
target "sv"
set_kind "static"
set_default false
set_languages "c99"
add_includedirs "sv/include" "{public}"
add_files "sv/src/*.c"
================================================
FILE: core/src/tbox/inc/bsd/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_BSD 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/* #undef TB_CONFIG_API_HAVE_DEPRECATED */
/* #undef TB_CONFIG_EXCEPTION_ENABLE */
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
#define TB_CONFIG_LIBC_HAVE_MEMMEM 1
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSNLEN */
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1
#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
#define TB_CONFIG_LIBC_HAVE_SRANDOM 1
#define TB_CONFIG_LIBC_HAVE_RANDOM 1
// libm functions
#define TB_CONFIG_LIBM_HAVE_SINCOS 1
#define TB_CONFIG_LIBM_HAVE_SINCOSF 1
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_SELECT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
#define TB_CONFIG_POSIX_HAVE_SOCKET 1
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
#define TB_CONFIG_POSIX_HAVE_DLOPEN 1
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1
#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1
#define TB_CONFIG_POSIX_HAVE_SYSCONF 1
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */
#define TB_CONFIG_POSIX_HAVE_REGCOMP 1
#define TB_CONFIG_POSIX_HAVE_REGEXEC 1
#define TB_CONFIG_POSIX_HAVE_READV 1
#define TB_CONFIG_POSIX_HAVE_WRITEV 1
#define TB_CONFIG_POSIX_HAVE_PREADV 1
#define TB_CONFIG_POSIX_HAVE_PWRITEV 1
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
#define TB_CONFIG_POSIX_HAVE_FDATASYNC 1
/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */
/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1
#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1
#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1
#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
#define TB_CONFIG_POSIX_HAVE_PIPE 1
#define TB_CONFIG_POSIX_HAVE_PIPE2 1
#define TB_CONFIG_POSIX_HAVE_MKFIFO 1
#define TB_CONFIG_POSIX_HAVE_MMAP 1
#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1
#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1
// windows functions
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
#endif
================================================
FILE: core/src/tbox/inc/cygwin/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_WINDOWS 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/* #undef TB_CONFIG_API_HAVE_DEPRECATED */
/* #undef TB_CONFIG_EXCEPTION_ENABLE */
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
/* #undef TB_CONFIG_LIBC_HAVE_STRUPR */
/* #undef TB_CONFIG_LIBC_HAVE_STRLWR */
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
/* #undef TB_CONFIG_LIBC_HAVE_SETJMP */
/* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */
/* #undef TB_CONFIG_LIBC_HAVE_KILL */
/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
/* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */
/* #undef TB_CONFIG_LIBC_HAVE_RANDOM */
// libm functions
#define TB_CONFIG_LIBM_HAVE_SINCOS 1
#define TB_CONFIG_LIBM_HAVE_SINCOSF 1
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
/* #undef TB_CONFIG_POSIX_HAVE_POLL */
/* #undef TB_CONFIG_POSIX_HAVE_SELECT */
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
/* #undef TB_CONFIG_POSIX_HAVE_SOCKET */
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
/* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */
/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
/* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */
/* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */
/* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */
/* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */
/* #undef TB_CONFIG_POSIX_HAVE_READV */
/* #undef TB_CONFIG_POSIX_HAVE_WRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREADV */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */
/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */
/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
#define TB_CONFIG_POSIX_HAVE_EXECVPE 1
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */
/* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */
/* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */
/* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
/* #undef TB_CONFIG_POSIX_HAVE_PIPE */
/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */
/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */
/* #undef TB_CONFIG_POSIX_HAVE_MMAP */
/* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */
/* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */
// windows functions
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
#endif
================================================
FILE: core/src/tbox/inc/haiku/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230201
// defines
#define TB_CONFIG_OS_HAIKU 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/*#undef TB_CONFIG_MICRO_ENABLE*/
/*#undef TB_CONFIG_TYPE_HAVE_WCHAR*/
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/*#undef TB_CONFIG_API_HAVE_DEPRECATED*/
/*#undef TB_CONFIG_EXCEPTION_ENABLE*/
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/*#undef TB_CONFIG_PACKAGE_HAVE_ZLIB*/
/*#undef TB_CONFIG_PACKAGE_HAVE_MYSQL*/
/*#undef TB_CONFIG_PACKAGE_HAVE_SQLITE3*/
/*#undef TB_CONFIG_PACKAGE_HAVE_OPENSSL*/
/*#undef TB_CONFIG_PACKAGE_HAVE_POLARSSL*/
/*#undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS*/
/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE2*/
/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE*/
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
#define TB_CONFIG_LIBC_HAVE_MEMMEM 1
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
/*#undef TB_CONFIG_LIBC_HAVE_STRUPR*/
/*#undef TB_CONFIG_LIBC_HAVE_STRLWR*/
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSCASESTR*/
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSUPR*/
/*#undef TB_CONFIG_LIBC_HAVE_WCSLWR*/
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1
/*#undef TB_CONFIG_LIBC_HAVE_BACKTRACE*/
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
#define TB_CONFIG_LIBC_HAVE_SRANDOM 1
#define TB_CONFIG_LIBC_HAVE_RANDOM 1
// libm functions
#define TB_CONFIG_LIBM_HAVE_SINCOS 1
#define TB_CONFIG_LIBM_HAVE_SINCOSF 1
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_SELECT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/*#undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP*/
#define TB_CONFIG_POSIX_HAVE_SOCKET 1
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
#define TB_CONFIG_POSIX_HAVE_DLOPEN 1
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/*#undef TB_CONFIG_POSIX_HAVE_STAT64*/
/*#undef TB_CONFIG_POSIX_HAVE_LSTAT64*/
#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1
#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1
#define TB_CONFIG_POSIX_HAVE_SYSCONF 1
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/*#undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY*/
#define TB_CONFIG_POSIX_HAVE_REGCOMP 1
#define TB_CONFIG_POSIX_HAVE_REGEXEC 1
#define TB_CONFIG_POSIX_HAVE_READV 1
#define TB_CONFIG_POSIX_HAVE_WRITEV 1
/*#undef TB_CONFIG_POSIX_HAVE_PREADV*/
/*#undef TB_CONFIG_POSIX_HAVE_PWRITEV*/
/*#undef TB_CONFIG_POSIX_HAVE_PREAD64*/
/*#undef TB_CONFIG_POSIX_HAVE_PWRITE64*/
/*#undef TB_CONFIG_POSIX_HAVE_FDATASYNC*/
/*#undef TB_CONFIG_POSIX_HAVE_COPYFILE*/
/*#undef TB_CONFIG_POSIX_HAVE_SENDFILE*/
/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE*/
/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT*/
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1
#if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400)
# undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15
#endif
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
#define TB_CONFIG_POSIX_HAVE_EXECVPE 1
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1
#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1
#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1
#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
#define TB_CONFIG_POSIX_HAVE_PIPE 1
/*#undef TB_CONFIG_POSIX_HAVE_PIPE2*/
#define TB_CONFIG_POSIX_HAVE_MKFIFO 1
#define TB_CONFIG_POSIX_HAVE_MMAP 1
#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1
#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1
// windows functions
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL*/
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1
/*#undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP*/
// linux functions
/*#undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT*/
// valgrind functions
/*#undef TB_CONFIG_VALGRIND_HAVE_VALGRIND_STACK_REGISTER*/
#endif
================================================
FILE: core/src/tbox/inc/iphoneos/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_IOS 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/* #undef TB_CONFIG_API_HAVE_DEPRECATED */
/* #undef TB_CONFIG_EXCEPTION_ENABLE */
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
#define TB_CONFIG_LIBC_HAVE_MEMMEM 1
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1
#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
#define TB_CONFIG_LIBC_HAVE_SRANDOM 1
#define TB_CONFIG_LIBC_HAVE_RANDOM 1
// libm functions
/* #undef TB_CONFIG_LIBM_HAVE_SINCOS */
/* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_SELECT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
#define TB_CONFIG_POSIX_HAVE_SOCKET 1
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
#define TB_CONFIG_POSIX_HAVE_DLOPEN 1
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1
#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1
/* #undef TB_CONFIG_POSIX_HAVE_SEM_INIT */
#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1
#define TB_CONFIG_POSIX_HAVE_SYSCONF 1
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */
#define TB_CONFIG_POSIX_HAVE_REGCOMP 1
#define TB_CONFIG_POSIX_HAVE_REGEXEC 1
#define TB_CONFIG_POSIX_HAVE_READV 1
#define TB_CONFIG_POSIX_HAVE_WRITEV 1
/* #undef TB_CONFIG_POSIX_HAVE_PREADV */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */
#define TB_CONFIG_POSIX_HAVE_COPYFILE 1
/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
/* #undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP */
#if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400)
# undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15
#endif
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1
#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1
#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1
#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
#define TB_CONFIG_POSIX_HAVE_PIPE 1
/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */
#define TB_CONFIG_POSIX_HAVE_MKFIFO 1
#define TB_CONFIG_POSIX_HAVE_MMAP 1
#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1
#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1
// windows functions
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
#endif
================================================
FILE: core/src/tbox/inc/linux/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_LINUX 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
#define TB_CONFIG_LIBC_HAVE_MEMMEM 1
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1
/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
#define TB_CONFIG_LIBC_HAVE_SRANDOM 1
#define TB_CONFIG_LIBC_HAVE_RANDOM 1
// libm functions
#define TB_CONFIG_LIBM_HAVE_SINCOS 1
#define TB_CONFIG_LIBM_HAVE_SINCOSF 1
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_SELECT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
#if defined(__ANDROID__)
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
#else
# define TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP 1
#endif
#define TB_CONFIG_POSIX_HAVE_SOCKET 1
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
#define TB_CONFIG_POSIX_HAVE_DLOPEN 1
#define TB_CONFIG_POSIX_HAVE_OPEN 1
// alpine does not support
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
/* #undef TB_CONFIG_POSIX_HAVE_LSTAT64 */
#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1
// alpine does not support
/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */
/* #undef TB_CONFIG_LINUX_HAVE_IFADDRS */
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1
#define TB_CONFIG_POSIX_HAVE_SYSCONF 1
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
#define TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY 1
#define TB_CONFIG_POSIX_HAVE_REGCOMP 1
#define TB_CONFIG_POSIX_HAVE_REGEXEC 1
#define TB_CONFIG_POSIX_HAVE_READV 1
#define TB_CONFIG_POSIX_HAVE_WRITEV 1
#define TB_CONFIG_POSIX_HAVE_PREADV 1
#define TB_CONFIG_POSIX_HAVE_PWRITEV 1
// alpine does not support
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
#define TB_CONFIG_POSIX_HAVE_FDATASYNC 1
/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */
#define TB_CONFIG_POSIX_HAVE_SENDFILE 1
#ifdef __COSMOPOLITAN__
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#else
# define TB_CONFIG_POSIX_HAVE_EPOLL_CREATE 1
# define TB_CONFIG_POSIX_HAVE_EPOLL_WAIT 1
#endif
#if defined(__ANDROID__)
/* #undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP */
#else
# define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#endif
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
#define TB_CONFIG_POSIX_HAVE_EXECVPE 1
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
#if defined(__ANDROID__)
/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */
#else
# define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1
#endif
#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1
#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1
#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
#define TB_CONFIG_POSIX_HAVE_PIPE 1
/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */
#ifdef __COSMOPOLITAN__
/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */
#else
# define TB_CONFIG_POSIX_HAVE_MKFIFO 1
#endif
#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1
#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1
#define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
// linux functions
#ifdef __COSMOPOLITAN__
/* #undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT */
#else
# define TB_CONFIG_LINUX_HAVE_INOTIFY_INIT 1
#endif
#endif
================================================
FILE: core/src/tbox/inc/macosx/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_MACOSX 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
#define TB_CONFIG_LIBC_HAVE_MEMMEM 1
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLCPY 1
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRCASESTR 1
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
#define TB_CONFIG_LIBC_HAVE_WCSNCASECMP 1
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1
#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
#define TB_CONFIG_LIBC_HAVE_SRANDOM 1
#define TB_CONFIG_LIBC_HAVE_RANDOM 1
// libm functions
/* #undef TB_CONFIG_LIBM_HAVE_SINCOS */
/* #undef TB_CONFIG_LIBM_HAVE_SINCOSF */
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_SELECT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
#define TB_CONFIG_POSIX_HAVE_SOCKET 1
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
#define TB_CONFIG_POSIX_HAVE_DLOPEN 1
#define TB_CONFIG_POSIX_HAVE_OPEN 1
#if !defined(__arm64__) && !defined(__aarch64__)
# define TB_CONFIG_POSIX_HAVE_STAT64 1
# define TB_CONFIG_POSIX_HAVE_LSTAT64 1
#else
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
#endif
#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1
#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1
#define TB_CONFIG_POSIX_HAVE_SYSCONF 1
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */
#define TB_CONFIG_POSIX_HAVE_REGCOMP 1
#define TB_CONFIG_POSIX_HAVE_REGEXEC 1
#define TB_CONFIG_POSIX_HAVE_READV 1
#define TB_CONFIG_POSIX_HAVE_WRITEV 1
/* #undef TB_CONFIG_POSIX_HAVE_PREADV */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */
#define TB_CONFIG_POSIX_HAVE_COPYFILE 1
/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
/* #undef TB_CONFIG_POSIX_HAVE_EXECVPE */
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1
#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1
#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1
#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
#define TB_CONFIG_POSIX_HAVE_PIPE 1
/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */
#define TB_CONFIG_POSIX_HAVE_MKFIFO 1
#define TB_CONFIG_POSIX_HAVE_FUTIMENS 1
#define TB_CONFIG_POSIX_HAVE_UTIMENSAT 1
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
#endif
================================================
FILE: core/src/tbox/inc/mingw/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_WINDOWS 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/* #undef TB_CONFIG_API_HAVE_DEPRECATED */
/* #undef TB_CONFIG_EXCEPTION_ENABLE */
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
/* #undef TB_CONFIG_LIBC_HAVE_STRUPR */
/* #undef TB_CONFIG_LIBC_HAVE_STRLWR */
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
/* #undef TB_CONFIG_LIBC_HAVE_SETJMP */
/* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */
/* #undef TB_CONFIG_LIBC_HAVE_KILL */
/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
/* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */
/* #undef TB_CONFIG_LIBC_HAVE_RANDOM */
// libm functions
#define TB_CONFIG_LIBM_HAVE_SINCOS 1
#define TB_CONFIG_LIBM_HAVE_SINCOSF 1
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
/* #undef TB_CONFIG_POSIX_HAVE_POLL */
/* #undef TB_CONFIG_POSIX_HAVE_SELECT */
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
/* #undef TB_CONFIG_POSIX_HAVE_SOCKET */
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
/* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */
/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
/* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */
/* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */
/* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */
/* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */
/* #undef TB_CONFIG_POSIX_HAVE_READV */
/* #undef TB_CONFIG_POSIX_HAVE_WRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREADV */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */
/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */
/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
#define TB_CONFIG_POSIX_HAVE_EXECVPE 1
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */
/* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */
/* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */
/* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
/* #undef TB_CONFIG_POSIX_HAVE_PIPE */
/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */
/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */
/* #undef TB_CONFIG_POSIX_HAVE_MMAP */
/* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */
/* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */
// windows functions
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
#endif
================================================
FILE: core/src/tbox/inc/msys/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.3"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 3
#define TB_CONFIG_VERSION_BUILD 20230119
// defines
#define TB_CONFIG_OS_WINDOWS 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/* #undef TB_CONFIG_MICRO_ENABLE */
/* #undef TB_CONFIG_TYPE_HAVE_WCHAR */
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/* #undef TB_CONFIG_API_HAVE_DEPRECATED */
/* #undef TB_CONFIG_EXCEPTION_ENABLE */
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/* #undef TB_CONFIG_PACKAGE_HAVE_ZLIB */
/* #undef TB_CONFIG_PACKAGE_HAVE_MYSQL */
/* #undef TB_CONFIG_PACKAGE_HAVE_SQLITE3 */
/* #undef TB_CONFIG_PACKAGE_HAVE_OPENSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_POLARSSL */
/* #undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE2 */
/* #undef TB_CONFIG_PACKAGE_HAVE_PCRE */
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_MEMMEM */
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_STRLCPY */
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
#define TB_CONFIG_LIBC_HAVE_STRNLEN 1
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_STRCASESTR */
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
#define TB_CONFIG_LIBC_HAVE_STRCASECMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
#define TB_CONFIG_LIBC_HAVE_STRNCASECMP 1
/* #undef TB_CONFIG_LIBC_HAVE_STRUPR */
/* #undef TB_CONFIG_LIBC_HAVE_STRLWR */
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSLCPY */
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSNLEN 1
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASESTR */
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSCASECMP */
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP */
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/* #undef TB_CONFIG_LIBC_HAVE_WCSUPR */
/* #undef TB_CONFIG_LIBC_HAVE_WCSLWR */
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
/* #undef TB_CONFIG_LIBC_HAVE_SETJMP */
/* #undef TB_CONFIG_LIBC_HAVE_SIGSETJMP */
/* #undef TB_CONFIG_LIBC_HAVE_KILL */
/* #undef TB_CONFIG_LIBC_HAVE_BACKTRACE */
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
/* #undef TB_CONFIG_LIBC_HAVE_SRANDOM */
/* #undef TB_CONFIG_LIBC_HAVE_RANDOM */
// libm functions
#define TB_CONFIG_LIBM_HAVE_SINCOS 1
#define TB_CONFIG_LIBM_HAVE_SINCOSF 1
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
/* #undef TB_CONFIG_POSIX_HAVE_POLL */
/* #undef TB_CONFIG_POSIX_HAVE_SELECT */
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/* #undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP */
/* #undef TB_CONFIG_POSIX_HAVE_SOCKET */
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
/* #undef TB_CONFIG_POSIX_HAVE_DLOPEN */
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/* #undef TB_CONFIG_POSIX_HAVE_STAT64 */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTNAME */
/* #undef TB_CONFIG_POSIX_HAVE_GETIFADDRS */
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
/* #undef TB_CONFIG_POSIX_HAVE_GETPAGESIZE */
/* #undef TB_CONFIG_POSIX_HAVE_SYSCONF */
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/* #undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY */
/* #undef TB_CONFIG_POSIX_HAVE_REGCOMP */
/* #undef TB_CONFIG_POSIX_HAVE_REGEXEC */
/* #undef TB_CONFIG_POSIX_HAVE_READV */
/* #undef TB_CONFIG_POSIX_HAVE_WRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREADV */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITEV */
/* #undef TB_CONFIG_POSIX_HAVE_PREAD64 */
/* #undef TB_CONFIG_POSIX_HAVE_PWRITE64 */
/* #undef TB_CONFIG_POSIX_HAVE_FDATASYNC */
/* #undef TB_CONFIG_POSIX_HAVE_COPYFILE */
/* #undef TB_CONFIG_POSIX_HAVE_SENDFILE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE */
/* #undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT */
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
#define TB_CONFIG_POSIX_HAVE_EXECVPE 1
#define TB_CONFIG_POSIX_HAVE_FORK 1
#define TB_CONFIG_POSIX_HAVE_VFORK 1
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
/* #undef TB_CONFIG_POSIX_HAVE_GETDTABLESIZE */
/* #undef TB_CONFIG_POSIX_HAVE_GETRLIMIT */
/* #undef TB_CONFIG_POSIX_HAVE_GETADDRINFO */
/* #undef TB_CONFIG_POSIX_HAVE_GETNAMEINFO */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME */
/* #undef TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR */
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
/* #undef TB_CONFIG_POSIX_HAVE_PIPE */
/* #undef TB_CONFIG_POSIX_HAVE_PIPE2 */
/* #undef TB_CONFIG_POSIX_HAVE_MKFIFO */
/* #undef TB_CONFIG_POSIX_HAVE_MMAP */
/* #undef TB_CONFIG_POSIX_HAVE_FUTIMENS */
/* #undef TB_CONFIG_POSIX_HAVE_UTIMENSAT */
// windows functions
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64 */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ */
/* #undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL */
// bsd functions
#define TB_CONFIG_BSD_HAVE_FLOCK 1
// systemv functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMGET */
/* #undef TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP */
// valgrind functions
/* #undef TB_CONFIG_SYSTEMV_HAVE_VALGRIND_STACK_REGISTER */
#endif
================================================
FILE: core/src/tbox/inc/solaris/tbox.config.h
================================================
#ifndef TB_CONFIG_H
#define TB_CONFIG_H
// version
#define TB_CONFIG_VERSION "1.7.7"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 7
#define TB_CONFIG_VERSION_ALTER 7
#define TB_CONFIG_VERSION_BUILD 20251123
// defines
#define TB_CONFIG_OS_SOLARIS 1
#define _GNU_SOURCE 1
#define _REENTRANT 1
#define TB_CONFIG_SMALL 1
/*#undef TB_CONFIG_MICRO_ENABLE*/
/*#undef TB_CONFIG_TYPE_HAVE_WCHAR*/
#define TB_CONFIG_TYPE_HAVE_FLOAT 1
#define TB_CONFIG_FORCE_UTF8 1
/*#undef TB_CONFIG_API_HAVE_DEPRECATED*/
/*#undef TB_CONFIG_EXCEPTION_ENABLE*/
// keywords
#define TB_CONFIG_KEYWORD_HAVE__thread 1
#define TB_CONFIG_KEYWORD_HAVE_Thread_local 1
// features
#define TB_CONFIG_FEATURE_HAVE_ANONYMOUS_UNION 1
// modules
/* #undef TB_CONFIG_MODULE_HAVE_XML */
/* #undef TB_CONFIG_MODULE_HAVE_ZIP */
#define TB_CONFIG_MODULE_HAVE_HASH 1
/* #undef TB_CONFIG_MODULE_HAVE_REGEX */
/* #undef TB_CONFIG_MODULE_HAVE_OBJECT */
#define TB_CONFIG_MODULE_HAVE_CHARSET 1
/* #undef TB_CONFIG_MODULE_HAVE_DATABASE */
/* #undef TB_CONFIG_MODULE_HAVE_COROUTINE */
// packages
/*#undef TB_CONFIG_PACKAGE_HAVE_ZLIB*/
/*#undef TB_CONFIG_PACKAGE_HAVE_MYSQL*/
/*#undef TB_CONFIG_PACKAGE_HAVE_SQLITE3*/
/*#undef TB_CONFIG_PACKAGE_HAVE_OPENSSL*/
/*#undef TB_CONFIG_PACKAGE_HAVE_POLARSSL*/
/*#undef TB_CONFIG_PACKAGE_HAVE_MBEDTLS*/
/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE2*/
/*#undef TB_CONFIG_PACKAGE_HAVE_PCRE*/
// libc functions
#define TB_CONFIG_LIBC_HAVE_MEMCPY 1
#define TB_CONFIG_LIBC_HAVE_MEMSET 1
#define TB_CONFIG_LIBC_HAVE_MEMMOVE 1
#define TB_CONFIG_LIBC_HAVE_MEMCMP 1
/*#undef TB_CONFIG_LIBC_HAVE_MEMMEM*/
#define TB_CONFIG_LIBC_HAVE_STRCAT 1
#define TB_CONFIG_LIBC_HAVE_STRNCAT 1
#define TB_CONFIG_LIBC_HAVE_STRCPY 1
#define TB_CONFIG_LIBC_HAVE_STRNCPY 1
/*#undef TB_CONFIG_LIBC_HAVE_STRLCPY*/
#define TB_CONFIG_LIBC_HAVE_STRLEN 1
/*#undef TB_CONFIG_LIBC_HAVE_STRNLEN*/
#define TB_CONFIG_LIBC_HAVE_STRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRRCHR 1
#define TB_CONFIG_LIBC_HAVE_STRSTR 1
/*#undef TB_CONFIG_LIBC_HAVE_STRCASESTR*/
#define TB_CONFIG_LIBC_HAVE_STRCMP 1
/*#undef TB_CONFIG_LIBC_HAVE_STRCASECMP*/
#define TB_CONFIG_LIBC_HAVE_STRNCMP 1
/*#undef TB_CONFIG_LIBC_HAVE_STRNCASECMP*/
#define TB_CONFIG_LIBC_HAVE_WCSCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSNCAT 1
#define TB_CONFIG_LIBC_HAVE_WCSCPY 1
#define TB_CONFIG_LIBC_HAVE_WCSNCPY 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSLCPY*/
#define TB_CONFIG_LIBC_HAVE_WCSLEN 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSNLEN*/
#define TB_CONFIG_LIBC_HAVE_WCSSTR 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSCASESTR*/
#define TB_CONFIG_LIBC_HAVE_WCSCMP 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSCASECMP*/
#define TB_CONFIG_LIBC_HAVE_WCSNCMP 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSNCASECMP*/
#define TB_CONFIG_LIBC_HAVE_WCSTOMBS 1
#define TB_CONFIG_LIBC_HAVE_MBSTOWCS 1
#define TB_CONFIG_LIBC_HAVE_TOWLOWER 1
#define TB_CONFIG_LIBC_HAVE_TOWUPPER 1
/*#undef TB_CONFIG_LIBC_HAVE_WCSUPR*/
/*#undef TB_CONFIG_LIBC_HAVE_WCSLWR*/
#define TB_CONFIG_LIBC_HAVE_GMTIME 1
#define TB_CONFIG_LIBC_HAVE_MKTIME 1
#define TB_CONFIG_LIBC_HAVE_LOCALTIME 1
#define TB_CONFIG_LIBC_HAVE_GETTIMEOFDAY 1
#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
/*#undef TB_CONFIG_LIBC_HAVE_SIGSETJMP*/
/*#undef TB_CONFIG_LIBC_HAVE_KILL*/
#define TB_CONFIG_LIBC_HAVE_BACKTRACE 1
#define TB_CONFIG_LIBC_HAVE_SETLOCALE 1
#define TB_CONFIG_LIBC_HAVE_FPUTC 1
#define TB_CONFIG_LIBC_HAVE_FGETC 1
#define TB_CONFIG_LIBC_HAVE_UNGETC 1
#define TB_CONFIG_LIBC_HAVE_FPUTS 1
#define TB_CONFIG_LIBC_HAVE_FGETS 1
#define TB_CONFIG_LIBC_HAVE_FREAD 1
#define TB_CONFIG_LIBC_HAVE_FWRITE 1
/*#undef TB_CONFIG_LIBC_HAVE_SRANDOM*/
/*#undef TB_CONFIG_LIBC_HAVE_RANDOM*/
// libm functions
/*#undef TB_CONFIG_LIBM_HAVE_SINCOS*/
/*#undef TB_CONFIG_LIBM_HAVE_SINCOSF*/
#define TB_CONFIG_LIBM_HAVE_LOG2 1
#define TB_CONFIG_LIBM_HAVE_LOG2F 1
#define TB_CONFIG_LIBM_HAVE_SQRT 1
#define TB_CONFIG_LIBM_HAVE_SQRTF 1
#define TB_CONFIG_LIBM_HAVE_ACOS 1
#define TB_CONFIG_LIBM_HAVE_ACOSF 1
#define TB_CONFIG_LIBM_HAVE_ASIN 1
#define TB_CONFIG_LIBM_HAVE_ASINF 1
#define TB_CONFIG_LIBM_HAVE_POW 1
#define TB_CONFIG_LIBM_HAVE_POWF 1
#define TB_CONFIG_LIBM_HAVE_FMOD 1
#define TB_CONFIG_LIBM_HAVE_FMODF 1
#define TB_CONFIG_LIBM_HAVE_TAN 1
#define TB_CONFIG_LIBM_HAVE_TANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN 1
#define TB_CONFIG_LIBM_HAVE_ATANF 1
#define TB_CONFIG_LIBM_HAVE_ATAN2 1
#define TB_CONFIG_LIBM_HAVE_ATAN2F 1
#define TB_CONFIG_LIBM_HAVE_COS 1
#define TB_CONFIG_LIBM_HAVE_COSF 1
#define TB_CONFIG_LIBM_HAVE_SIN 1
#define TB_CONFIG_LIBM_HAVE_SINF 1
#define TB_CONFIG_LIBM_HAVE_EXP 1
#define TB_CONFIG_LIBM_HAVE_EXPF 1
// posix functions
#define TB_CONFIG_POSIX_HAVE_POLL 1
#define TB_CONFIG_POSIX_HAVE_SELECT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1
/*#undef TB_CONFIG_POSIX_HAVE_PTHREAD_SETAFFINITY_NP*/
#define TB_CONFIG_POSIX_HAVE_SOCKET 1
#define TB_CONFIG_POSIX_HAVE_OPENDIR 1
#define TB_CONFIG_POSIX_HAVE_DLOPEN 1
#define TB_CONFIG_POSIX_HAVE_OPEN 1
/*#undef TB_CONFIG_POSIX_HAVE_STAT64*/
/*#undef TB_CONFIG_POSIX_HAVE_LSTAT64*/
#define TB_CONFIG_POSIX_HAVE_GETHOSTNAME 1
#define TB_CONFIG_POSIX_HAVE_GETIFADDRS 1
#define TB_CONFIG_POSIX_HAVE_SEM_INIT 1
#define TB_CONFIG_POSIX_HAVE_GETPAGESIZE 1
#define TB_CONFIG_POSIX_HAVE_SYSCONF 1
#define TB_CONFIG_POSIX_HAVE_SCHED_YIELD 1
/*#undef TB_CONFIG_POSIX_HAVE_SCHED_SETAFFINITY*/
#define TB_CONFIG_POSIX_HAVE_REGCOMP 1
#define TB_CONFIG_POSIX_HAVE_REGEXEC 1
#define TB_CONFIG_POSIX_HAVE_READV 1
#define TB_CONFIG_POSIX_HAVE_WRITEV 1
#define TB_CONFIG_POSIX_HAVE_PREADV 1
#define TB_CONFIG_POSIX_HAVE_PWRITEV 1
/*#undef TB_CONFIG_POSIX_HAVE_PREAD64*/
/*#undef TB_CONFIG_POSIX_HAVE_PWRITE64*/
#define TB_CONFIG_POSIX_HAVE_FDATASYNC 1
/*#undef TB_CONFIG_POSIX_HAVE_COPYFILE*/
#define TB_CONFIG_POSIX_HAVE_SENDFILE 1
/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_CREATE*/
/*#undef TB_CONFIG_POSIX_HAVE_EPOLL_WAIT*/
#define TB_CONFIG_POSIX_HAVE_POSIX_SPAWNP 1
/*#undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP*/
#if (defined(__MACH__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 101400)
# undef TB_CONFIG_POSIX_HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP // only for macOS >=10.15
#endif
#define TB_CONFIG_POSIX_HAVE_EXECVP 1
#define TB_CONFIG_POSIX_HAVE_EXECVPE 1
#define TB_CONFIG_POSIX_HAVE_FORK 1
/*#undef TB_CONFIG_POSIX_HAVE_VFORK*/
#define TB_CONFIG_POSIX_HAVE_WAITPID 1
#define TB_CONFIG_POSIX_HAVE_GETDTABLESIZE 1
#define TB_CONFIG_POSIX_HAVE_GETRLIMIT 1
#define TB_CONFIG_POSIX_HAVE_GETADDRINFO 1
#define TB_CONFIG_POSIX_HAVE_GETNAMEINFO 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYNAME 1
#define TB_CONFIG_POSIX_HAVE_GETHOSTBYADDR 1
#define TB_CONFIG_POSIX_HAVE_FCNTL 1
#define TB_CONFIG_POSIX_HAVE_PIPE 1
#define TB_CONFIG_POSIX_HAVE_PIPE2 1
#define TB_CONFIG_POSIX_HAVE_MKFIFO 1
#define TB_CONFIG_POSIX_HAVE_MMAP 1
/*#undef TB_CONFIG_POSIX_HAVE_FUTIMENS*/
/*#undef TB_CONFIG_POSIX_HAVE_UTIMENSAT*/
// windows functions
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGE8_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDOR8_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDEXCHANGEADD64_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE_REL*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_NF*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_ACQ*/
/*#undef TB_CONFIG_WINDOWS_HAVE__INTERLOCKEDCOMPAREEXCHANGE64_REL*/
// bsd functions
/*#undef TB_CONFIG_BSD_HAVE_FLOCK*/
// systemv functions
#define TB_CONFIG_SYSTEMV_HAVE_SEMGET 1
#define TB_CONFIG_SYSTEMV_HAVE_SEMTIMEDOP 1
// linux functions
/*#undef TB_CONFIG_LINUX_HAVE_INOTIFY_INIT*/
/*#undef TB_CONFIG_LINUX_HAVE_IFADDRS*/
// valgrind functions
/*#undef TB_CONFIG_VALGRIND_HAVE_VALGRIND_STACK_REGISTER*/
#endif
================================================
FILE: core/src/tbox/xmake.lua
================================================
includes("tbox")
-- enable hash, charset, utf8 modules
for _, name in ipairs({ "hash", "charset", "force-utf8" }) do
option(name)
set_default(true)
after_check(function (option)
option:enable(true)
end)
option_end()
end
-- disable demo
option("demo")
set_default(false)
option_end()
================================================
FILE: core/src/tbox/xmake.sh
================================================
#!/bin/sh
set_config "hash" true
set_config "charset" true
set_config "force_utf8" true
set_config "float" true
set_config "demo" false
check_interfaces_enabled=false
includes "tbox/src"
hide_options() {
local name=""
local options="demo small micro float info exception deprecated force_utf8 xml zip hash regex object charset database coroutine"
for name in $options; do
option "${name}"
set_showmenu false
option_end
done
}
hide_options
target "tbox"
set_default false
set_configvar "TB_CONFIG_MODULE_HAVE_HASH" 1
set_configvar "TB_CONFIG_MODULE_HAVE_CHARSET" 1
set_configvar "TB_CONFIG_FORCE_UTF8" 1
set_configvar "TB_CONFIG_TYPE_HAVE_FLOAT" 1
add_includedirs "inc/${plat}" "{public}"
if is_mode "debug"; then
add_defines "__tb_debug__"
fi
================================================
FILE: core/src/xmake/base64/decode.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file base64.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "base64"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_base64_decode(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the string
size_t size = 0;
tb_char_t const *cstr = luaL_checklstring(lua, 1, &size);
tb_check_return_val(cstr && size, 0);
// decode it
tb_byte_t buff[8192];
if (size < sizeof(buff)) {
tb_size_t real = tb_base64_decode(cstr, size, buff, sizeof(buff));
if (real > 0) {
lua_pushlstring(lua, (tb_char_t const *)buff, (tb_int_t)real);
return 1;
}
}
lua_pushnil(lua);
lua_pushstring(lua, "buffer is too small");
return 2;
}
================================================
FILE: core/src/xmake/base64/encode.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file base64.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "base64"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_base64_encode(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 1)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);
}
if (xm_lua_isinteger(lua, 2)) {
size = (tb_size_t)lua_tointeger(lua, 2);
}
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// encode it
tb_char_t buff[8192];
if (size * 3 / 2 < sizeof(buff)) {
tb_size_t real = tb_base64_encode(data, size, buff, sizeof(buff));
if (real > 0) {
lua_pushlstring(lua, buff, (tb_int_t)real);
return 1;
}
}
lua_pushnil(lua);
lua_pushstring(lua, "buffer is too small");
return 2;
}
================================================
FILE: core/src/xmake/base64/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BASE64_PREFIX_H
#define XM_BASE64_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/binutils/ar/extractlib.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file extractlib.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "extractlib"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* generate unique filename to handle name conflicts
*
* @param base_name the base filename
* @param id the unique ID
* @param output output buffer
* @param output_size size of output buffer
* @param output_len output: actual output length
* @return tb_true on success
*/
static tb_bool_t xm_binutils_ar_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) {
tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false);
// find the last dot for extension
tb_char_t const *ext = tb_strrchr(base_name, '.');
tb_long_t n = -1;
if (ext) {
tb_size_t base_len = (tb_size_t)(ext - base_name);
tb_size_t ext_len = tb_strlen(ext);
if (base_len + ext_len + 16 < output_size) {
n = tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext);
}
} else {
// no extension
if (tb_strlen(base_name) + 16 < output_size) {
n = tb_snprintf(output, output_size, "%s_%u", base_name, id);
}
}
if (n >= 0) {
*output_len = (tb_size_t)n;
return tb_true;
}
return tb_false;
}
/* extract AR archive to directory
*
* @param istream the input stream
* @param outputdir the output directory
* @return tb_true on success, tb_false on failure
*/
tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir) {
tb_assert_and_check_return_val(istream && outputdir, tb_false);
// get output directory length
tb_size_t outputdir_len = tb_strlen(outputdir);
// check AR magic (!\n)
if (!xm_binutils_ar_check_magic(istream, 0)) {
return tb_false;
}
// ensure output directory exists
// check if directory already exists
if (!tb_file_info(outputdir, tb_null)) {
// directory doesn't exist, create it
if (!tb_directory_create(outputdir)) {
return tb_false;
}
}
tb_bool_t ok = tb_true;
// iterate through AR members
while (ok) {
// read AR header
// AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2]
xm_ar_header_t header;
if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
// end of file
break;
}
// parse member size
tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10);
if (member_size < 0) {
ok = tb_false;
break;
}
// get member name
tb_char_t member_name[256] = {0};
tb_size_t name_len = 0;
tb_hize_t name_bytes_read = 0;
// get member name (handles both regular and extended name formats)
tb_bool_t skip = tb_false;
if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) {
skip = tb_true;
} else if (xm_binutils_ar_is_symbol_table(member_name)) {
// skip symbol tables
skip = tb_true;
} else if (!xm_binutils_ar_is_object_file(member_name)) {
// only extract object files
skip = tb_true;
}
if (skip) {
// skip remaining data + padding using sequential read
tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read;
if (member_size % 2) {
skip_size++; // add padding
}
if (!tb_stream_skip(istream, skip_size)) {
ok = tb_false;
break;
}
continue;
}
// handle name conflicts by checking if file exists and renaming with ID
tb_char_t output_name[512] = {0};
tb_char_t output_path_check[1024] = {0};
if (outputdir_len + 1 + name_len >= sizeof(output_path_check)) {
ok = tb_false;
break;
}
tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, member_name);
// check if file already exists
tb_uint32_t conflict_id = 1;
tb_size_t output_name_len = name_len;
if (tb_file_info(output_path_check, tb_null)) {
// name conflict, try different IDs until we find an available name
while (conflict_id < 10000) { // reasonable limit
if (!xm_binutils_ar_generate_unique_name(member_name, conflict_id, output_name, sizeof(output_name), &output_name_len)) {
ok = tb_false;
break;
}
if (outputdir_len + 1 + output_name_len >= sizeof(output_path_check)) {
ok = tb_false;
break;
}
tb_snprintf(output_path_check, sizeof(output_path_check), "%s/%s", outputdir, output_name);
if (!tb_file_info(output_path_check, tb_null)) {
// found available name
break;
}
conflict_id++;
}
if (conflict_id >= 10000) {
ok = tb_false;
break;
}
} else {
// first occurrence, use original name
tb_strlcpy(output_name, member_name, sizeof(output_name));
}
// build output path
tb_char_t output_path[1024] = {0};
if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {
ok = tb_false;
break;
}
tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name);
// create output file
tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
if (!ostream) {
ok = tb_false;
break;
}
if (!tb_stream_open(ostream)) {
tb_stream_exit(ostream);
ok = tb_false;
break;
}
// copy member data to output file
// member_size includes the name if extended format was used, so subtract name_bytes_read
tb_hize_t remaining = (tb_hize_t)member_size - name_bytes_read;
if (!xm_binutils_stream_copy(istream, ostream, remaining)) {
ok = tb_false;
}
tb_stream_clos(ostream);
tb_stream_exit(ostream);
tb_check_break(ok);
// align to 2-byte boundary (AR format requirement)
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
}
return ok;
}
================================================
FILE: core/src/xmake/binutils/ar/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_AR_PREFIX_H
#define XM_BINUTILS_AR_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#include "../coff/prefix.h"
#include "../elf/prefix.h"
#include "../macho/prefix.h"
#include "../wasm/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* forward declarations
*/
extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
#include "tbox/prefix/packed.h"
typedef struct __xm_ar_header_t {
tb_char_t name[16]; // file name (null-padded)
tb_char_t date[12]; // modification time (decimal)
tb_char_t uid[6]; // user ID (decimal)
tb_char_t gid[6]; // group ID (decimal)
tb_char_t mode[8]; // file mode (octal)
tb_char_t size[10]; // file size (decimal)
tb_char_t fmag[2]; // magic: "`\n"
} __tb_packed__ xm_ar_header_t;
#include "tbox/prefix/packed.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
/* parse decimal number from string
*
* @param str the string
* @param len the length
* @return the parsed number, or -1 on error
*/
static __tb_inline__ tb_int64_t xm_binutils_ar_parse_decimal(tb_char_t const *str, tb_size_t len) {
tb_assert_and_check_return_val(str && len > 0, -1);
tb_int64_t result = 0;
for (tb_size_t i = 0; i < len; i++) {
if (str[i] == ' ' || str[i] == '\0') {
break;
}
if (str[i] < '0' || str[i] > '9') {
return -1;
}
result = result * 10 + (str[i] - '0');
}
return result;
}
/* get member name from AR header, handling extended names (#N/L format)
*
* @param istream the input stream
* @param header the AR header
* @param name output buffer for the name
* @param name_size size of the name buffer
* @param name_len output: actual name length
* @param bytes_read output: total bytes read from stream (including newline, for extended names)
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_ar_get_member_name(tb_stream_ref_t istream, xm_ar_header_t const* header, tb_char_t* name, tb_size_t name_size, tb_size_t* name_len, tb_hize_t* bytes_read) {
tb_assert_and_check_return_val(istream && header && name && name_size > 0 && name_len && bytes_read, tb_false);
*bytes_read = 0;
/* check for extended name format (#N/L or #1/N)
* In BSD AR format:
* - #1/N means name is directly after header, N is total length (including name)
* - #N/L means name length is N, total length is L
* - #1/N can also mean name is in long name table at offset 1
* We'll try to read the name directly from stream first
*/
if (header->name[0] == '#') {
// find the '/' separator
tb_size_t slash_pos = 0;
for (tb_size_t i = 1; i < 16; i++) {
if (header->name[i] == '/') {
slash_pos = i;
break;
}
}
if (slash_pos > 0 && slash_pos < 16) {
// parse the number before '/' (could be name length or offset)
tb_int64_t first_num = xm_binutils_ar_parse_decimal(header->name + 1, slash_pos - 1);
// parse the number after '/' (total length)
tb_int64_t total_length = xm_binutils_ar_parse_decimal(header->name + slash_pos + 1, 16 - slash_pos - 1);
if (first_num <= 0 || total_length <= 0) {
return tb_false;
}
/* In BSD AR format, extended name is directly after header
* The name data starts immediately after the header, no newline
* Read exactly total_length bytes for the name section
*/
tb_byte_t c;
tb_size_t name_bytes = 0;
tb_hize_t bytes_read_so_far = 0;
// Read name characters until we hit null terminator or reach total_length
while (bytes_read_so_far < (tb_hize_t)total_length && name_bytes < name_size - 1) {
if (!tb_stream_bread(istream, &c, 1)) {
return tb_false;
}
bytes_read_so_far++;
if (c == '\0') {
// Stop reading name at null terminator, but continue reading to reach total_length
break;
}
// Include all characters in the name, including newlines if present
name[name_bytes++] = (tb_char_t)c;
}
name[name_bytes] = '\0';
*name_len = name_bytes;
// Skip remaining bytes to reach total_length (there may be padding or null terminators)
if (bytes_read_so_far < (tb_hize_t)total_length) {
tb_hize_t remaining_to_read = (tb_hize_t)total_length - bytes_read_so_far;
if (!tb_stream_skip(istream, remaining_to_read)) {
return tb_false;
}
}
// Total bytes read = name + padding = total_length
*bytes_read = (tb_hize_t)total_length;
return tb_true;
}
}
if (header->name[0] == '/') {
if (header->name[1] == '/') {
tb_strlcpy(name, "//", name_size);
*name_len = 2;
} else {
tb_strlcpy(name, "/", name_size);
*name_len = 1;
}
*bytes_read = 0;
return tb_true;
}
// regular name (null-terminated or space-padded)
tb_size_t i = 0;
for (i = 0; i < 16 && i < name_size - 1; i++) {
if (header->name[i] == ' ' || header->name[i] == '\0' || header->name[i] == '/') {
break;
}
name[i] = header->name[i];
}
name[i] = '\0';
*name_len = i;
*bytes_read = 0; // Regular names are in header, not read from stream
return tb_true;
}
/* check AR magic (!\n)
*
* @param istream the input stream
* @param base_offset the base offset
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_ar_check_magic(tb_stream_ref_t istream, tb_hize_t base_offset) {
tb_uint8_t magic[8];
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, magic, 8)) {
return tb_false;
}
if (magic[0] != '!' || magic[1] != '<' || magic[2] != 'a' || magic[3] != 'r' ||
magic[4] != 'c' || magic[5] != 'h' || (magic[6] != '>' && magic[6] != '\n') ||
(magic[7] != '\n' && magic[7] != '\r')) {
return tb_false;
}
return tb_true;
}
/* check if member is a symbol table (should be skipped)
*
* @param name the member name
* @return tb_true if it's a symbol table, tb_false otherwise
*/
static __tb_inline__ tb_bool_t xm_binutils_ar_is_symbol_table(tb_char_t const *name) {
tb_assert_and_check_return_val(name, tb_false);
return (tb_strcmp(name, "__.SYMDEF") == 0 || tb_strcmp(name, "__.SYMDEF SORTED") == 0 ||
tb_strcmp(name, "/") == 0 || tb_strcmp(name, "//") == 0 ||
tb_strncmp(name, "__.SYMDEF", 9) == 0);
}
/* check if member is an object file (based on extension)
*
* @param name the member name
* @return tb_true if it's likely an object file, tb_false otherwise
*/
static __tb_inline__ tb_bool_t xm_binutils_ar_is_object_file(tb_char_t const *name) {
tb_assert_and_check_return_val(name, tb_false);
tb_size_t len = tb_strlen(name);
if (len == 0) {
return tb_false;
}
// check common object file extensions
if (len >= 2 && name[len - 2] == '.' && name[len - 1] == 'o') {
return tb_true;
}
if (len >= 4 && tb_strcmp(name + len - 4, ".obj") == 0) {
return tb_true;
}
// check if it's a COFF/ELF/Mach-O file by detecting format
// For now, we'll extract all non-symbol-table members
return tb_true;
}
#endif
================================================
FILE: core/src/xmake/binutils/ar/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
#define TB_TRACE_MODULE_NAME "readsyms_ar"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
static tb_int_t xm_binutils_ar_detect_member_format(tb_stream_ref_t istream, tb_hize_t base_offset) {
tb_uint8_t magic[8] = {0};
if (!tb_stream_seek(istream, base_offset)) {
return -1;
}
if (!tb_stream_bread(istream, magic, 8)) {
tb_stream_seek(istream, base_offset);
return -1;
}
tb_stream_seek(istream, base_offset);
if (magic[0] == XM_WASM_MAGIC0 && magic[1] == XM_WASM_MAGIC1 && magic[2] == XM_WASM_MAGIC2 && magic[3] == XM_WASM_MAGIC3) {
return XM_BINUTILS_FORMAT_WASM;
}
if (magic[0] == XM_ELF_MAGIC0 && magic[1] == XM_ELF_MAGIC1 && magic[2] == XM_ELF_MAGIC2 && magic[3] == XM_ELF_MAGIC3) {
return XM_BINUTILS_FORMAT_ELF;
}
tb_uint32_t macho_magic = tb_bits_get_u32_be(magic);
if (macho_magic == XM_MACHO_MAGIC_32 || macho_magic == XM_MACHO_MAGIC_64 ||
macho_magic == XM_MACHO_MAGIC_32_BE || macho_magic == XM_MACHO_MAGIC_64_BE) {
return XM_BINUTILS_FORMAT_MACHO;
}
return XM_BINUTILS_FORMAT_UNKNOWN;
}
/* parse BSD symbol table (__.SYMDEF or __.SYMDEF SORTED)
*
* Header:
* - ranlib_size (uint32_t)
* - ranlibs (struct ranlib[ranlib_size/8])
* - strtab_size (uint32_t)
* - strtab (char[strtab_size])
*
* struct ranlib {
* uint32_t ran_strx; // offset into string table
* uint32_t ran_off; // offset into archive
* };
*/
static tb_bool_t xm_binutils_ar_parse_bsd_symdef(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) {
tb_hize_t start_pos = tb_stream_offset(istream);
// read size of ranlib array
tb_uint32_t ranlib_size = 0;
if (!tb_stream_bread_u32_le(istream, &ranlib_size)) {
return tb_false;
}
// sanity check
if (ranlib_size == 0 || ranlib_size >= member_size) {
tb_stream_seek(istream, start_pos);
return tb_false;
}
// read ranlib array
tb_size_t num_ranlibs = ranlib_size / 8;
// allocate buffers
tb_uint32_t* ran_strx = tb_nalloc_type(num_ranlibs, tb_uint32_t);
tb_uint32_t* ran_off = tb_nalloc_type(num_ranlibs, tb_uint32_t);
if (!ran_strx || !ran_off) {
if (ran_strx) {
tb_free(ran_strx);
}
if (ran_off) {
tb_free(ran_off);
}
tb_stream_seek(istream, start_pos);
return tb_false;
}
tb_size_t i;
for (i = 0; i < num_ranlibs; i++) {
if (!tb_stream_bread_u32_le(istream, &ran_strx[i]) ||
!tb_stream_bread_u32_le(istream, &ran_off[i])) {
tb_free(ran_strx);
tb_free(ran_off);
tb_stream_seek(istream, start_pos);
return tb_false;
}
}
// read string table size
tb_uint32_t strtab_size = 0;
if (!tb_stream_bread_u32_le(istream, &strtab_size)) {
tb_free(ran_strx);
tb_free(ran_off);
tb_stream_seek(istream, start_pos);
return tb_false;
}
// read string table
tb_char_t* strtab = (tb_char_t*)tb_malloc_bytes(strtab_size);
if (!strtab) {
tb_free(ran_strx);
tb_free(ran_off);
tb_stream_seek(istream, start_pos);
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)strtab, strtab_size)) {
tb_free(strtab);
tb_free(ran_strx);
tb_free(ran_off);
tb_stream_seek(istream, start_pos);
return tb_false;
}
// populate map
for (i = 0; i < num_ranlibs; i++) {
tb_uint32_t off = ran_off[i];
tb_uint32_t strx = ran_strx[i];
if (strx < strtab_size) {
tb_char_t* name = strtab + strx;
// add to map: map[off] = { {name=name, type="T"}, ... }
lua_pushinteger(lua, off);
lua_rawget(lua, map_idx);
if (lua_isnil(lua, -1)) {
lua_pop(lua, 1);
lua_newtable(lua);
lua_pushinteger(lua, off);
lua_pushvalue(lua, -2);
lua_rawset(lua, map_idx);
}
int count = (int)lua_objlen(lua, -1);
lua_newtable(lua);
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
lua_pushstring(lua, "type");
lua_pushstring(lua, "T");
lua_settable(lua, -3);
lua_rawseti(lua, -2, count + 1);
lua_pop(lua, 1); // pop list
}
}
tb_free(strtab);
tb_free(ran_strx);
tb_free(ran_off);
return tb_true;
}
/* parse SysV symbol table (/)
*
* Header:
* - num_symbols (uint32_t BE)
* - offsets (uint32_t[num_symbols] BE)
* - string table (null-terminated strings)
*/
static tb_bool_t xm_binutils_ar_parse_sysv_symdef(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) {
tb_hize_t start_pos = tb_stream_offset(istream);
// read number of symbols
tb_uint32_t num_symbols = 0;
if (!tb_stream_bread_u32_be(istream, &num_symbols)) {
return tb_false;
}
// sanity check
if (num_symbols == 0 || num_symbols * 4 >= member_size) {
tb_stream_seek(istream, start_pos);
return tb_false;
}
// read offsets
tb_uint32_t* offsets = tb_nalloc_type(num_symbols, tb_uint32_t);
if (!offsets) {
tb_stream_seek(istream, start_pos);
return tb_false;
}
tb_size_t i;
for (i = 0; i < num_symbols; i++) {
if (!tb_stream_bread_u32_be(istream, &offsets[i])) {
tb_free(offsets);
tb_stream_seek(istream, start_pos);
return tb_false;
}
}
// read string table
tb_hize_t current = tb_stream_offset(istream);
tb_hize_t strtab_size = member_size - (current - start_pos);
tb_char_t* strtab = (tb_char_t*)tb_malloc_bytes((tb_size_t)strtab_size);
if (!strtab) {
tb_free(offsets);
tb_stream_seek(istream, start_pos);
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)strtab, (tb_size_t)strtab_size)) {
tb_free(strtab);
tb_free(offsets);
tb_stream_seek(istream, start_pos);
return tb_false;
}
// populate map
tb_char_t* p = strtab;
tb_char_t* end = strtab + strtab_size;
for (i = 0; i < num_symbols; i++) {
if (p >= end) {
break;
}
tb_char_t* name = p;
tb_size_t len = tb_strlen(name);
p += len + 1;
tb_uint32_t off = offsets[i];
// add to map
lua_pushinteger(lua, off);
lua_rawget(lua, map_idx);
if (lua_isnil(lua, -1)) {
lua_pop(lua, 1);
lua_newtable(lua);
lua_pushinteger(lua, off);
lua_pushvalue(lua, -2);
lua_rawset(lua, map_idx);
}
int count = (int)lua_objlen(lua, -1);
lua_newtable(lua);
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
lua_pushstring(lua, "type");
lua_pushstring(lua, "T");
lua_settable(lua, -3);
lua_rawseti(lua, -2, count + 1);
lua_pop(lua, 1); // pop list
}
tb_free(strtab);
tb_free(offsets);
return tb_true;
}
/* read symbols from AR archive
*
* @param istream the input stream
* @param base_offset the base offset
* @param lua the lua state
* @return tb_true on success, tb_false on failure
*/
tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State* lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// check AR magic (!\n)
if (!xm_binutils_ar_check_magic(istream, base_offset)) {
return tb_false;
}
// get result list index
int list_idx = lua_gettop(lua);
// init map table for symbol table
lua_newtable(lua);
int map_idx = lua_gettop(lua);
tb_bool_t ok = tb_true;
tb_size_t object_count = 0;
// iterate through AR members
while (ok) {
// save member header position
tb_hize_t member_header_pos = tb_stream_offset(istream);
/* read AR header
* AR header is exactly 60 bytes: name[16] + date[12] + uid[6] + gid[6] + mode[8] + size[10] + fmag[2]
*/
xm_ar_header_t header;
if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
// end of file
break;
}
// parse member size
tb_int64_t member_size = xm_binutils_ar_parse_decimal(header.size, 10);
if (member_size < 0) {
ok = tb_false;
break;
}
// get member name
tb_char_t member_name[256] = {0};
tb_size_t name_len = 0;
tb_hize_t name_bytes_read = 0;
// get member name (handles both regular and extended name formats)
tb_bool_t skip = tb_false;
if (!xm_binutils_ar_get_member_name(istream, &header, member_name, sizeof(member_name), &name_len, &name_bytes_read)) {
skip = tb_true;
} else {
if (xm_binutils_ar_is_symbol_table(member_name)) {
/* parse symbol table
*
* The symbol table in the archive only contains symbol names and their offsets,
* but lacks detailed symbol type information (e.g., distinguishing between code and data).
* However, for object files that cannot be parsed (e.g., LTO bitcode) or unknown formats,
* parsing the symbol table serves as a robust fallback to ensure symbols are extracted.
*/
tb_hize_t current = tb_stream_offset(istream);
if (tb_strcmp(member_name, "/") == 0) {
xm_binutils_ar_parse_sysv_symdef(istream, member_size, lua, map_idx);
} else if (tb_strcmp(member_name, "//") != 0) {
xm_binutils_ar_parse_bsd_symdef(istream, member_size, lua, map_idx);
}
tb_stream_seek(istream, current); // restore position for skip
skip = tb_true;
} else if (!xm_binutils_ar_is_object_file(member_name)) {
// only extract object files
skip = tb_true;
}
}
if (skip) {
// skip remaining data + padding using sequential read
tb_hize_t skip_size = (tb_hize_t)member_size - name_bytes_read;
if (member_size % 2) {
skip_size++; // add padding
}
if (!tb_stream_skip(istream, skip_size)) {
ok = tb_false;
break;
}
continue;
}
// save current position
tb_hize_t current_pos = tb_stream_offset(istream);
// detect format
tb_int_t format = xm_binutils_ar_detect_member_format(istream, current_pos);
if (format != XM_BINUTILS_FORMAT_AR) {
// create entry table
lua_newtable(lua);
// object name
lua_pushstring(lua, "objectfile");
lua_pushstring(lua, member_name);
lua_settable(lua, -3);
// symbols
lua_pushstring(lua, "symbols");
tb_bool_t read_ok = tb_false;
if (format == XM_BINUTILS_FORMAT_COFF) {
read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua);
} else if (format == XM_BINUTILS_FORMAT_ELF) {
read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua);
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua);
} else if (format == XM_BINUTILS_FORMAT_WASM) {
read_ok = xm_binutils_wasm_read_symbols(istream, current_pos, lua);
}
if (!read_ok) {
/* try get from map
*
* If parsing the object file fails (e.g. for LTO bitcode or unsupported formats),
* we fall back to using the symbols parsed from the archive symbol table.
* Although the type information is less accurate (defaulting to "T"),
* it guarantees that symbols are not lost.
*
* cast to lua_Integer to avoid warning C4244 on 32-bit MSVC
* member_header_pos is tb_hize_t (64-bit), but AR offsets are usually 32-bit
*/
lua_pushinteger(lua, (lua_Integer)member_header_pos);
lua_rawget(lua, map_idx);
if (!lua_isnil(lua, -1)) {
read_ok = tb_true;
} else {
lua_pop(lua, 1);
}
}
if (read_ok) {
lua_settable(lua, -3);
lua_rawseti(lua, list_idx, (int)(++object_count));
} else {
lua_pop(lua, 2); // pop symbols key and entry table
}
}
// skip to next member
tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos;
tb_hize_t remaining_size = (tb_hize_t)member_size - name_bytes_read - member_data_read;
if (member_size % 2) {
remaining_size++; // add padding
}
if (remaining_size > 0) {
if (!tb_stream_skip(istream, remaining_size)) {
ok = tb_false;
break;
}
} else if (remaining_size < 0) {
/* should not happen if readsyms functions respect boundaries, but just in case
* seek back to correct position
*/
if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size - name_bytes_read + (member_size % 2))) {
ok = tb_false;
break;
}
}
}
lua_remove(lua, map_idx);
return ok;
}
================================================
FILE: core/src/xmake/binutils/bin2c.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bin2c.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bin2c"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_BIN2C_DATA_SIZE (8 * 1024)
#define XM_BIN2C_LINE_SIZE (4 * 1024)
#define XM_BIN2C_LINEWIDTH_MAX ((XM_BIN2C_LINE_SIZE - 2) / 6)
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
// optimized hex conversion table
static tb_char_t const *xm_binutils_bin2c_digits = "0123456789ABCDEF";
// inline hex conversion for better performance
static __tb_inline__ tb_void_t xm_binutils_bin2c_write_hex(tb_char_t *str, tb_byte_t value) {
str[0] = ' ';
str[1] = '0';
str[2] = 'x';
str[3] = xm_binutils_bin2c_digits[(value >> 4) & 15];
str[4] = xm_binutils_bin2c_digits[value & 15];
}
static tb_bool_t xm_binutils_bin2c_dump(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_int_t linewidth,
tb_bool_t nozeroend) {
tb_bool_t first = tb_true;
tb_bool_t zero_pending = tb_false;
tb_byte_t data[XM_BIN2C_DATA_SIZE];
tb_char_t line[XM_BIN2C_LINE_SIZE];
tb_size_t linesize = 0;
tb_size_t bytes_in_line = 0;
tb_size_t data_pos = 0;
tb_size_t data_size = 0;
tb_assert_and_check_return_val(linewidth > 0 && linewidth <= XM_BIN2C_LINEWIDTH_MAX, tb_false);
while (!tb_stream_beof(istream) || data_pos < data_size || zero_pending) {
// read a large chunk of data if buffer is empty
if (data_pos >= data_size) {
// handle pending zero terminator
if (zero_pending) {
data[0] = '\0';
data_size = 1;
data_pos = 0;
zero_pending = tb_false;
} else {
tb_hong_t left = tb_stream_left(istream);
tb_size_t to_read = (tb_size_t)tb_min(left, (tb_hong_t)XM_BIN2C_DATA_SIZE);
tb_check_break(to_read);
if (!tb_stream_bread(istream, data, to_read)) {
break;
}
data_size = to_read;
data_pos = 0;
// check if we need to add zero terminator at the end
if (!nozeroend && tb_stream_beof(istream)) {
if (data_size < XM_BIN2C_DATA_SIZE) {
// can add directly to current buffer
data[data_size++] = '\0';
} else {
// buffer is full, need to add zero in next iteration
zero_pending = tb_true;
}
}
}
}
// process bytes from buffer
while (data_pos < data_size) {
// check if we need a new line
if (bytes_in_line >= (tb_size_t)linewidth) {
// write line (tb_stream_bwrit_line will add newline automatically)
if (tb_stream_bwrit_line(ostream, line, linesize) < 0) {
return tb_false;
}
linesize = 0;
bytes_in_line = 0;
first = tb_false;
}
// ensure we have enough space in line buffer (6 chars per byte: ", 0xXX")
if (linesize + 6 > sizeof(line)) {
// flush partial line if buffer is full
if (linesize > 0) {
if (!tb_stream_bwrit(ostream, (tb_byte_t *)line, linesize)) {
return tb_false;
}
linesize = 0;
}
}
// add separator
if (bytes_in_line == 0 && first) {
line[linesize++] = ' ';
first = tb_false;
} else {
line[linesize++] = ',';
}
// write hex value (inline for performance)
xm_binutils_bin2c_write_hex(line + linesize, data[data_pos]);
linesize += 5;
bytes_in_line++;
data_pos++;
}
}
// flush remaining line
if (linesize > 0) {
// write line (tb_stream_bwrit_line will add newline automatically)
if (tb_stream_bwrit_line(ostream, line, linesize) < 0) {
return tb_false;
}
}
return tb_stream_beof(istream);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* generate c/c++ code from the binary file
*
* local ok, errors = binutils.bin2c(binaryfile, outputfile, linewidth, nozeroend)
*/
tb_int_t xm_binutils_bin2c(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binaryfile
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// get the outputfile
tb_char_t const *outputfile = luaL_checkstring(lua, 2);
tb_check_return_val(outputfile, 0);
// get line width
tb_int_t linewidth = (tb_int_t)lua_tointeger(lua, 3);
// no zero end?
tb_bool_t nozeroend = (tb_bool_t)lua_toboolean(lua, 4);
// do dump
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2c: open %s failed", binaryfile);
break;
}
if (!tb_stream_open(ostream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2c: open %s failed", outputfile);
break;
}
if (!xm_binutils_bin2c_dump(istream, ostream, linewidth, nozeroend)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2c: dump data failed");
break;
}
ok = tb_true;
lua_pushboolean(lua, ok);
} while (0);
if (istream) {
tb_stream_clos(istream);
}
istream = tb_null;
if (ostream) {
tb_stream_clos(ostream);
}
ostream = tb_null;
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/coff/bin2coff.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bin2coff.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bin2coff"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_binutils_bin2coff_dump(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_char_t const *symbol_prefix,
tb_char_t const *arch,
tb_char_t const *basename,
tb_bool_t zeroend) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
// get file size
tb_hong_t filesize = tb_stream_size(istream);
if (filesize < 0 || filesize > 0xffffffffU) {
return tb_false;
}
tb_uint32_t datasize = (tb_uint32_t)filesize;
// add null terminator if zeroend is true
if (zeroend) {
if (datasize >= 0xffffffffU) {
return tb_false; // would overflow
}
datasize++;
}
// determine architecture for symbol prefix adjustment
tb_uint16_t machine = xm_binutils_coff_get_machine(arch);
tb_bool_t is_i386 = (machine == XM_COFF_MACHINE_I386);
// generate symbol names from filename
tb_char_t symbol_name[256] = {0};
tb_char_t symbol_start[256] = {0};
tb_char_t symbol_end[256] = {0};
// use basename or default to "data"
if (!basename || !basename[0]) {
basename = "data";
}
// build symbol name
// note: on i386 Windows, C compiler automatically adds an underscore prefix to external symbols
// so if we use "_binary_", the actual symbol becomes "__binary_" after compilation
// to match, we need to ensure the prefix has two underscores for i386
if (symbol_prefix) {
if (is_i386 && symbol_prefix[0] == '_' && symbol_prefix[1] != '_') {
// i386: if prefix starts with single underscore, add another one
tb_snprintf(symbol_name, sizeof(symbol_name), "_%s%s", symbol_prefix, basename);
} else {
tb_snprintf(symbol_name, sizeof(symbol_name), "%s%s", symbol_prefix, basename);
}
} else {
if (is_i386) {
tb_snprintf(symbol_name, sizeof(symbol_name), "__binary_%s", basename);
} else {
tb_snprintf(symbol_name, sizeof(symbol_name), "_binary_%s", basename);
}
}
// replace non-alphanumeric with underscore
xm_binutils_sanitize_symbol_name(symbol_name);
tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name);
tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name);
// calculate offsets
tb_uint32_t header_size = sizeof(xm_coff_header_t);
tb_uint32_t section_header_size = sizeof(xm_coff_section_t);
tb_uint32_t section_data_ofs = header_size + section_header_size;
tb_uint32_t section_data_size = datasize;
tb_uint32_t section_data_padding = (4 - (section_data_size & 3)) & 3;
tb_uint32_t symbol_table_ofs = section_data_ofs + section_data_size + section_data_padding;
// calculate string table size (content only, excluding the 4-byte size field)
tb_uint32_t string_table_content_size = 0;
tb_size_t start_len = tb_strlen(symbol_start);
tb_size_t end_len = tb_strlen(symbol_end);
if (start_len > 8) {
string_table_content_size += (tb_uint32_t)(start_len + 1);
}
if (end_len > 8) {
string_table_content_size += (tb_uint32_t)(end_len + 1);
}
// string table size field should include the size field itself
tb_uint32_t string_table_size = 4 + string_table_content_size;
// write COFF header
xm_coff_header_t header;
tb_memset(&header, 0, sizeof(header));
header.machine = machine;
header.nsects = 1;
header.time = 0;
header.symtabofs = symbol_table_ofs;
// note: COFF spec says nsyms is the number of symbol table entries (including aux entries)
// section symbol (1) + aux entry (1) + start symbol (1) + end symbol (1) = 4 entries
// total size: 4 * 18 = 72 bytes
// i386 linker calculates string table as symtabofs + nsyms * 18 = symtabofs + 72 (correct)
// when reading symbols, linker follows naux fields to skip aux entries correctly
// from mingw i386 analysis: section symbols MUST have aux entry (naux=1)
header.nsyms = 4; // 3 symbols + 1 aux entry
header.opthdr = 0;
header.flags = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {
return tb_false;
}
// write section header (.rdata)
xm_coff_section_t section;
tb_memset(§ion, 0, sizeof(section));
tb_strncpy(section.name, ".rdata", 8);
section.vsize = datasize;
section.vaddr = 0;
section.size = datasize;
section.ofs = section_data_ofs;
section.relocofs = 0;
section.linenoofs = 0;
section.nreloc = 0;
section.nlineno = 0;
section.flags = XM_COFF_SECTION_RDATA;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion, sizeof(section))) {
return tb_false;
}
// write section data
if (!xm_binutils_stream_copy(istream, ostream, filesize)) {
return tb_false;
}
// append null terminator if zeroend is true
if (zeroend) {
tb_byte_t zero = 0;
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
// align to 4 bytes
if (section_data_padding > 0) {
xm_binutils_coff_write_padding(ostream, section_data_padding);
}
// write symbol table
// symbol 0: .rdata section symbol
xm_coff_symbol_t sym_section;
tb_memset(&sym_section, 0, sizeof(sym_section));
tb_strncpy(sym_section.n.shortname.name, ".rdata", 8);
sym_section.value = 0;
sym_section.sect = 1; // section index (1-based)
sym_section.type = 0; // IMAGE_SYM_TYPE_NULL
sym_section.scl = 3; // IMAGE_SYM_CLASS_STATIC
// section symbol MUST have auxiliary entry for i386 compatibility (as seen in mingw-generated files)
sym_section.naux = 1; // auxiliary entry (required for i386)
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_section, sizeof(sym_section))) {
return tb_false;
}
// auxiliary entry for section (18 bytes total)
xm_coff_aux_section_t aux_section;
tb_memset(&aux_section, 0, sizeof(aux_section));
aux_section.length = datasize;
aux_section.nreloc = 0;
aux_section.nlineno = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&aux_section, sizeof(aux_section))) {
return tb_false;
}
// symbol 1: _binary_xxx_start (or __binary_xxx_start for i386)
tb_uint32_t strtab_offset = 4; // start after size field
xm_binutils_coff_write_symbol_name(ostream, symbol_start, &strtab_offset);
xm_coff_symbol_tail_t sym_start_tail;
tb_memset(&sym_start_tail, 0, sizeof(sym_start_tail));
sym_start_tail.value = 0;
sym_start_tail.sect = 1;
sym_start_tail.type = 0; // IMAGE_SYM_TYPE_NULL
sym_start_tail.scl = 2; // IMAGE_SYM_CLASS_EXTERNAL
sym_start_tail.naux = 0; // no auxiliary entry
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start_tail, sizeof(sym_start_tail))) {
return tb_false;
}
// symbol 2: _binary_xxx_end (or __binary_xxx_end for i386)
xm_binutils_coff_write_symbol_name(ostream, symbol_end, &strtab_offset);
xm_coff_symbol_tail_t sym_end_tail;
tb_memset(&sym_end_tail, 0, sizeof(sym_end_tail));
sym_end_tail.value = datasize;
sym_end_tail.sect = 1;
sym_end_tail.type = 0; // IMAGE_SYM_TYPE_NULL
sym_end_tail.scl = 2; // IMAGE_SYM_CLASS_EXTERNAL
sym_end_tail.naux = 0; // no auxiliary entry
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end_tail, sizeof(sym_end_tail))) {
return tb_false;
}
// write string table
// symbol table size: section symbol (18) + aux entry (18) + start symbol (18) + end symbol (18) = 72 bytes
// string table starts at symtabofs + 72, which matches nsyms * 18 = 4 * 18 = 72
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&string_table_size, 4)) {
return tb_false;
}
if (start_len > 8) {
xm_binutils_coff_write_string(ostream, symbol_start, start_len);
tb_byte_t null = 0;
tb_stream_bwrit(ostream, &null, 1);
}
if (end_len > 8) {
xm_binutils_coff_write_string(ostream, symbol_end, end_len);
tb_byte_t null = 0;
tb_stream_bwrit(ostream, &null, 1);
}
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* generate COFF object file from binary file
*
* @param lua the lua state
* @return 1 on success, 2 on failure (with error message on stack)
*/
tb_int_t xm_binutils_bin2coff(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binaryfile
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// get the outputfile
tb_char_t const *outputfile = luaL_checkstring(lua, 2);
tb_check_return_val(outputfile, 0);
// get symbol prefix (optional)
tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null;
// get arch (optional)
tb_char_t const *arch = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null;
// get basename (optional)
tb_char_t const *basename = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null;
// get zeroend (optional, default: false)
tb_bool_t zeroend = lua_toboolean(lua, 6);
// do dump
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2coff: open %s failed", binaryfile);
break;
}
if (!tb_stream_open(ostream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2coff: open %s failed", outputfile);
break;
}
if (!xm_binutils_bin2coff_dump(istream, ostream, symbol_prefix, arch, basename, zeroend)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2coff: dump data failed");
break;
}
ok = tb_true;
lua_pushboolean(lua, ok);
} while (0);
if (istream) {
tb_stream_clos(istream);
}
istream = tb_null;
if (ostream) {
tb_stream_clos(ostream);
}
ostream = tb_null;
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/coff/deplibs.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file deplibs.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "deplibs_coff"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_uint32_t xm_binutils_coff_get_import_rva(tb_stream_ref_t istream, tb_uint16_t opthdr_size) {
// save current offset
tb_hize_t opt_offset = tb_stream_offset(istream);
tb_uint32_t import_rva = 0;
// read magic
tb_uint16_t magic = 0;
if (tb_stream_bread(istream, (tb_byte_t*)&magic, sizeof(magic))) {
// seek back
if (tb_stream_seek(istream, opt_offset)) {
if (magic == XM_PE32_MAGIC) {
xm_pe32_opt_header_t opt_header = {0};
if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), opthdr_size))) {
if (opt_header.number_of_rva_and_sizes > 1) {
import_rva = opt_header.data_directory[1].vaddr;
}
}
} else if (magic == XM_PE32P_MAGIC) {
xm_pe32p_opt_header_t opt_header = {0};
if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), opthdr_size))) {
if (opt_header.number_of_rva_and_sizes > 1) {
import_rva = opt_header.data_directory[1].vaddr;
}
}
}
}
}
return import_rva;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
tb_bool_t ok = tb_false;
xm_coff_section_t* sections = tb_null;
do {
// read COFF header
xm_coff_header_t header;
if (!tb_stream_seek(istream, base_offset)) break;
if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) break;
// read optional header and import rva
tb_uint32_t import_rva = 0;
if (header.opthdr > 0) {
import_rva = xm_binutils_coff_get_import_rva(istream, header.opthdr);
}
// read section headers
if (header.nsects > 0) {
sections = tb_nalloc_type(header.nsects, xm_coff_section_t);
if (!sections) break;
tb_hize_t section_offset = base_offset + sizeof(xm_coff_header_t) + header.opthdr;
if (!tb_stream_seek(istream, section_offset)) break;
if (!tb_stream_bread(istream, (tb_byte_t*)sections, header.nsects * sizeof(xm_coff_section_t))) break;
}
if (!sections) {
if (header.nsects > 0) break;
ok = tb_true;
break;
}
tb_size_t result_count = 0;
tb_bool_t failed = tb_false;
for (tb_uint16_t i = 0; i < header.nsects; i++) {
xm_coff_section_t* section = §ions[i];
// check if it is .idata section (import directory table)
tb_bool_t found_idt = tb_false;
tb_uint32_t idt_offset = 0;
if (import_rva != 0) {
// check if import rva is in this section
if (import_rva >= section->vaddr && import_rva < section->vaddr + section->vsize) {
idt_offset = section->ofs + (import_rva - section->vaddr);
found_idt = tb_true;
}
} else {
// fallback to check section name
if (tb_strncmp(section->name, ".idata", 6) == 0) {
idt_offset = section->ofs;
found_idt = tb_true;
}
}
if (found_idt) {
/* read import directory table
* The .idata section contains the Import Directory Table.
* Each entry is 20 bytes (IMAGE_IMPORT_DESCRIPTOR).
* The table ends with a null entry.
*/
/* We need to iterate over IMAGE_IMPORT_DESCRIPTOR entries.
* struct IMAGE_IMPORT_DESCRIPTOR {
* DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
* DWORD TimeDateStamp; // 0 if not bound,
* DWORD ForwarderChain; // -1 if no forwarders
* DWORD Name; // RVA to DLL name
* DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
* };
*/
if (!tb_stream_seek(istream, idt_offset)) {
failed = tb_true;
break;
}
while (1) {
xm_coff_import_directory_table_t entry;
if (!tb_stream_bread(istream, (tb_byte_t*)&entry, sizeof(entry))) {
break;
}
// check for null entry (end of table)
if (entry.original_first_thunk == 0 && entry.name_rva == 0) {
break;
}
tb_uint32_t name_rva = tb_bits_le_to_ne_u32(entry.name_rva);
if (name_rva != 0) {
/* map RVA to file offset to read the name
* We need to find the section that contains this RVA.
*/
tb_hize_t saved_pos_inner = tb_stream_offset(istream);
tb_uint32_t name_file_offset = 0;
// Find the section containing name_rva
for (tb_uint16_t k = 0; k < header.nsects; k++) {
xm_coff_section_t* s = §ions[k];
if (name_rva >= s->vaddr && name_rva < s->vaddr + s->vsize) {
name_file_offset = s->ofs + (name_rva - s->vaddr);
break;
}
}
if (name_file_offset != 0) {
tb_char_t dll_name[256];
if (xm_binutils_read_string(istream, name_file_offset, dll_name, sizeof(dll_name)) && dll_name[0]) {
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, dll_name);
lua_settable(lua, -3);
result_count++;
}
}
tb_stream_seek(istream, saved_pos_inner);
}
}
break;
}
}
tb_check_break(!failed);
ok = tb_true;
} while (0);
if (sections) tb_free(sections);
return ok;
}
================================================
FILE: core/src/xmake/binutils/coff/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_COFF_PREFIX_H
#define XM_BINUTILS_COFF_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_COFF_MACHINE_I386 0x014c
#define XM_COFF_MACHINE_AMD64 0x8664
#define XM_COFF_MACHINE_ARM 0x01c0
#define XM_COFF_MACHINE_ARM64 0xaa64
// PE Optional Header Magic
#define XM_PE32_MAGIC 0x10b
#define XM_PE32P_MAGIC 0x20b
// COFF section flags
#define XM_COFF_SCN_CNT_CODE 0x20 // IMAGE_SCN_CNT_CODE
#define XM_COFF_SCN_CNT_INITIALIZED_DATA 0x40 // IMAGE_SCN_CNT_INITIALIZED_DATA
#define XM_COFF_SCN_CNT_UNINITIALIZED_DATA 0x80 // IMAGE_SCN_CNT_UNINITIALIZED_DATA
#define XM_COFF_SECTION_RDATA 0x40000040 // IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
#include "tbox/prefix/packed.h"
typedef struct __xm_coff_header_t {
tb_uint16_t machine;
tb_uint16_t nsects;
tb_uint32_t time;
tb_uint32_t symtabofs;
tb_uint32_t nsyms;
tb_uint16_t opthdr;
tb_uint16_t flags;
} __tb_packed__ xm_coff_header_t;
typedef struct __xm_pe32_data_directory_t {
tb_uint32_t vaddr;
tb_uint32_t size;
} __tb_packed__ xm_pe32_data_directory_t;
typedef struct __xm_pe32_opt_header_t {
tb_uint16_t magic;
tb_uint8_t major_linker_version;
tb_uint8_t minor_linker_version;
tb_uint32_t size_of_code;
tb_uint32_t size_of_initialized_data;
tb_uint32_t size_of_uninitialized_data;
tb_uint32_t address_of_entry_point;
tb_uint32_t base_of_code;
tb_uint32_t base_of_data;
tb_uint32_t image_base;
tb_uint32_t section_alignment;
tb_uint32_t file_alignment;
tb_uint16_t major_operating_system_version;
tb_uint16_t minor_operating_system_version;
tb_uint16_t major_image_version;
tb_uint16_t minor_image_version;
tb_uint16_t major_subsystem_version;
tb_uint16_t minor_subsystem_version;
tb_uint32_t win32_version_value;
tb_uint32_t size_of_image;
tb_uint32_t size_of_headers;
tb_uint32_t checksum;
tb_uint16_t subsystem;
tb_uint16_t dll_characteristics;
tb_uint32_t size_of_stack_reserve;
tb_uint32_t size_of_stack_commit;
tb_uint32_t size_of_heap_reserve;
tb_uint32_t size_of_heap_commit;
tb_uint32_t loader_flags;
tb_uint32_t number_of_rva_and_sizes;
xm_pe32_data_directory_t data_directory[16];
} __tb_packed__ xm_pe32_opt_header_t;
typedef struct __xm_pe32p_opt_header_t {
tb_uint16_t magic;
tb_uint8_t major_linker_version;
tb_uint8_t minor_linker_version;
tb_uint32_t size_of_code;
tb_uint32_t size_of_initialized_data;
tb_uint32_t size_of_uninitialized_data;
tb_uint32_t address_of_entry_point;
tb_uint32_t base_of_code;
tb_uint64_t image_base;
tb_uint32_t section_alignment;
tb_uint32_t file_alignment;
tb_uint16_t major_operating_system_version;
tb_uint16_t minor_operating_system_version;
tb_uint16_t major_image_version;
tb_uint16_t minor_image_version;
tb_uint16_t major_subsystem_version;
tb_uint16_t minor_subsystem_version;
tb_uint32_t win32_version_value;
tb_uint32_t size_of_image;
tb_uint32_t size_of_headers;
tb_uint32_t checksum;
tb_uint16_t subsystem;
tb_uint16_t dll_characteristics;
tb_uint64_t size_of_stack_reserve;
tb_uint64_t size_of_stack_commit;
tb_uint64_t size_of_heap_reserve;
tb_uint64_t size_of_heap_commit;
tb_uint32_t loader_flags;
tb_uint32_t number_of_rva_and_sizes;
xm_pe32_data_directory_t data_directory[16];
} __tb_packed__ xm_pe32p_opt_header_t;
typedef struct __xm_coff_import_directory_table_t {
tb_uint32_t original_first_thunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
tb_uint32_t time_date_stamp; // 0 if not bound, -1 if bound, and real date\time stamp in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) O.W. date/time stamp of DLL bound to (Old BIND)
tb_uint32_t forwarder_chain; // -1 if no forwarders
tb_uint32_t name_rva; // RVA to name
tb_uint32_t first_thunk; // RVA to IAT (if bound this IAT has actual addresses)
} __tb_packed__ xm_coff_import_directory_table_t;
typedef struct __xm_coff_import_header_t {
tb_uint16_t sig1; // 0
tb_uint16_t sig2; // 0xffff
tb_uint16_t version;
tb_uint16_t machine;
tb_uint32_t time;
tb_uint32_t size; // size of data
tb_uint16_t ordinal; // ordinal or hint
tb_uint16_t type; // type
} __tb_packed__ xm_coff_import_header_t;
typedef struct __xm_coff_anon_header_t {
tb_uint16_t sig1; // 0
tb_uint16_t sig2; // 0xffff
tb_uint16_t version;
tb_uint16_t machine;
tb_uint32_t time;
tb_uint8_t clsid[16];
tb_uint32_t size; // size of data
} __tb_packed__ xm_coff_anon_header_t;
typedef struct __xm_coff_section_t {
tb_char_t name[8];
tb_uint32_t vsize;
tb_uint32_t vaddr;
tb_uint32_t size;
tb_uint32_t ofs;
tb_uint32_t relocofs;
tb_uint32_t linenoofs;
tb_uint16_t nreloc;
tb_uint16_t nlineno;
tb_uint32_t flags;
} __tb_packed__ xm_coff_section_t;
typedef struct __xm_coff_symbol_t {
union {
struct {
tb_char_t name[8];
} shortname;
struct {
tb_uint32_t zeros;
tb_uint32_t offset;
} longname;
} n;
tb_uint32_t value;
tb_int16_t sect;
tb_uint16_t type;
tb_uint8_t scl;
tb_uint8_t naux;
} __tb_packed__ xm_coff_symbol_t;
typedef struct __xm_coff_aux_section_t {
tb_uint32_t length;
tb_uint16_t nreloc;
tb_uint16_t nlineno;
tb_uint8_t reserved[10];
} __tb_packed__ xm_coff_aux_section_t;
typedef struct __xm_coff_symbol_tail_t {
tb_uint32_t value;
tb_int16_t sect;
tb_uint16_t type;
tb_uint8_t scl;
tb_uint8_t naux;
} __tb_packed__ xm_coff_symbol_tail_t;
#include "tbox/prefix/packed.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
/* get machine type from architecture string
*
* @param arch the architecture string (e.g., "x86_64", "i386", "arm64")
* @return the machine type
*/
static __tb_inline__ tb_uint16_t xm_binutils_coff_get_machine(tb_char_t const *arch) {
if (!arch) {
return XM_COFF_MACHINE_I386;
}
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return XM_COFF_MACHINE_AMD64;
} else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) {
return XM_COFF_MACHINE_ARM64;
} else if (tb_strcmp(arch, "arm") == 0) {
return XM_COFF_MACHINE_ARM;
} else if (tb_strcmp(arch, "i386") == 0 || tb_strcmp(arch, "x86") == 0) {
return XM_COFF_MACHINE_I386;
}
return XM_COFF_MACHINE_I386;
}
/* write string to stream
*
* @param ostream the output stream
* @param str the string to write
* @param len the length (0 for auto-detect)
*/
static __tb_inline__ tb_void_t xm_binutils_coff_write_string(tb_stream_ref_t ostream, tb_char_t const *str, tb_size_t len) {
tb_assert_and_check_return(ostream && str);
if (len == 0) {
len = tb_strlen(str);
}
tb_stream_bwrit(ostream, (tb_byte_t const *)str, len);
}
/* write padding bytes to stream
*
* @param ostream the output stream
* @param count the number of padding bytes
*/
static __tb_inline__ tb_void_t xm_binutils_coff_write_padding(tb_stream_ref_t ostream, tb_size_t count) {
tb_assert_and_check_return(ostream);
tb_byte_t zero = 0;
while (count-- > 0) {
tb_stream_bwrit(ostream, &zero, 1);
}
}
/* write symbol name to stream (handles short and long names)
*
* @param ostream the output stream
* @param name the symbol name
* @param strtab_offset the string table offset (updated if long name)
*/
static __tb_inline__ tb_void_t xm_binutils_coff_write_symbol_name(tb_stream_ref_t ostream, tb_char_t const *name, tb_uint32_t *strtab_offset) {
tb_assert_and_check_return(ostream && name && strtab_offset);
tb_size_t len = tb_strlen(name);
if (len <= 8) {
// short name: store directly in symbol name field
xm_binutils_coff_write_string(ostream, name, len);
if (len < 8) {
xm_binutils_coff_write_padding(ostream, 8 - len);
}
} else {
// long name: store offset in string table
tb_uint32_t zeros = 0;
tb_stream_bwrit(ostream, (tb_byte_t const *)&zeros, 4);
tb_stream_bwrit(ostream, (tb_byte_t const *)strtab_offset, 4);
*strtab_offset += (tb_uint32_t)(len + 1); // +1 for null terminator
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* readsyms inline implementation
*/
/* read string from COFF string table
*
* @param istream the input stream
* @param strtab_offset the string table offset (including 4-byte size field)
* @param offset the string offset (from start of string table content, after size field)
* @return the string (static buffer, valid until next call)
*/
static __tb_inline__ tb_bool_t xm_binutils_coff_read_string(tb_stream_ref_t istream, tb_hize_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) {
tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);
// In COFF format, the offset in symbol table is from the start of string table
// (including the 4-byte size field). So offset=4 points to the first string after
// the size field, offset=74 points to a string at position 74 from the start.
// read string table size first to validate offset
tb_uint32_t strtab_size = 0;
tb_hize_t saved_pos = tb_stream_offset(istream);
if (!tb_stream_seek(istream, strtab_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&strtab_size, 4)) {
tb_stream_seek(istream, saved_pos);
return tb_false;
}
// check offset (must be >= 4 to skip the size field, and < strtab_size)
if (offset < 4 || offset >= strtab_size) {
tb_stream_seek(istream, saved_pos);
return tb_false;
}
// restore position and use common implementation
tb_stream_seek(istream, saved_pos);
return xm_binutils_read_string(istream, strtab_offset + offset, name, name_size);
}
/* get symbol name from COFF symbol entry
*
* @param istream the input stream
* @param sym the symbol entry
* @param strtab_offset the string table offset
* @param name the buffer to store the symbol name
* @param name_size the size of the buffer
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_coff_get_symbol_name(tb_stream_ref_t istream, xm_coff_symbol_t const *sym, tb_hize_t strtab_offset, tb_char_t *name, tb_size_t name_size) {
tb_assert_and_check_return_val(istream && sym && name && name_size > 0, tb_false);
// check if it's a long name (first 4 bytes are zeros)
if (sym->n.longname.zeros == 0) {
// long name: read from string table
return xm_binutils_coff_read_string(istream, strtab_offset, sym->n.longname.offset, name, name_size);
} else {
// short name: use directly
tb_size_t len = tb_min(8, name_size - 1);
tb_strncpy(name, sym->n.shortname.name, len);
name[len] = '\0';
// trim trailing nulls
while (len > 0 && name[len - 1] == '\0') {
len--;
}
name[len] = '\0';
return tb_true;
}
}
/* get symbol type character (nm-style) from COFF symbol
*
* @param scl the storage class
* @param sect the section number (0 = undefined, 1-based)
* @param sections the section headers array
* @param nsects the number of sections
* @return the type character (T/t/D/d/B/b/U)
*/
static __tb_inline__ tb_char_t xm_binutils_coff_get_symbol_type_char(tb_uint8_t scl, tb_int16_t sect, xm_coff_section_t const *sections, tb_uint16_t nsects) {
// undefined symbol
if (sect == 0) {
return 'U';
}
// check if external
tb_bool_t is_external = (scl == 2); // IMAGE_SYM_CLASS_EXTERNAL
// check section flags to determine type
if (sections && sect > 0 && sect <= nsects) {
tb_uint32_t flags = sections[sect - 1].flags; // section numbers are 1-based
// IMAGE_SCN_CNT_CODE (0x20) - code section
if (flags & XM_COFF_SCN_CNT_CODE) {
return is_external ? 'T' : 't'; // text section
}
// IMAGE_SCN_CNT_UNINITIALIZED_DATA (0x80) - bss section
if (flags & XM_COFF_SCN_CNT_UNINITIALIZED_DATA) {
return is_external ? 'B' : 'b'; // bss section
}
// IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) - data section
if (flags & XM_COFF_SCN_CNT_INITIALIZED_DATA) {
return is_external ? 'D' : 'd'; // data section
}
}
// fallback: use section number heuristic
if (sect == 1) {
return is_external ? 'T' : 't'; // text section
} else if (sect == 2) {
return is_external ? 'D' : 'd'; // data section
} else if (sect == 3) {
return is_external ? 'B' : 'b'; // bss section
}
return is_external ? 'S' : 's'; // other section
}
#endif
================================================
FILE: core/src/xmake/binutils/coff/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "readsyms_coff"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_binutils_coff_read_import_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_coff_header_t const* header) {
// create result table
lua_newtable(lua);
/* check version
* version is the low 16 bits of the time field (offset 4)
* xm_coff_header_t: machine(2), nsects(2), time(4)
* xm_coff_import_header_t: sig1(2), sig2(2), version(2), machine(2)
*/
tb_uint16_t version = header->time & 0xffff;
if (version == 1) {
// anonymous object header (used for CLSID)
/*
* @note we can not read symbols from the anonymous object (LTO/GL/LTCG),
* because it does not contain the symbol table.
*/
xm_coff_anon_header_t anon_header;
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&anon_header, sizeof(anon_header))) {
return tb_false;
}
} else {
// import header
xm_coff_import_header_t import_header;
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&import_header, sizeof(import_header))) {
return tb_false;
}
// read symbol name (it follows the header)
tb_char_t name[256] = {0};
tb_size_t pos = 0;
tb_byte_t c;
while (pos < sizeof(name) - 1) {
if (!tb_stream_bread(istream, &c, 1)) {
break;
}
if (c == 0) {
break;
}
name[pos++] = (tb_char_t)c;
}
name[pos] = '\0';
if (name[0]) {
lua_pushinteger(lua, 1);
lua_newtable(lua);
// name
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
// type
lua_pushstring(lua, "type");
lua_pushstring(lua, "I");
lua_settable(lua, -3);
lua_settable(lua, -3);
}
}
return tb_true;
}
tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// read COFF header
xm_coff_header_t header;
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
return tb_false;
}
// check if it is an import object
if (header.machine == 0 && header.nsects == 0xffff) {
return xm_binutils_coff_read_import_symbols(istream, base_offset, lua, &header);
}
// check if there are symbols
if (header.nsyms == 0 || header.symtabofs == 0) {
lua_newtable(lua);
return tb_true;
}
// create result table
lua_newtable(lua);
// read string table offset (after symbol table)
tb_uint32_t strtab_offset = header.symtabofs + header.nsyms * 18; // each symbol is 18 bytes
// read section headers to determine section types
xm_coff_section_t *sections = tb_null;
if (header.nsects > 0) {
sections = (xm_coff_section_t*)tb_malloc(header.nsects * sizeof(xm_coff_section_t));
if (sections) {
tb_hize_t saved_pos = tb_stream_offset(istream);
// section headers are after COFF header and optional header
tb_uint32_t section_offset = sizeof(xm_coff_header_t) + (header.opthdr > 0 ? header.opthdr : 0);
if (tb_stream_seek(istream, base_offset + section_offset)) {
for (tb_uint16_t i = 0; i < header.nsects; i++) {
if (!tb_stream_bread(istream, (tb_byte_t*)§ions[i], sizeof(xm_coff_section_t))) {
break;
}
}
}
tb_stream_seek(istream, saved_pos);
}
}
// read symbols
if (!tb_stream_seek(istream, base_offset + header.symtabofs)) {
if (sections) {
tb_free(sections);
}
return tb_false;
}
tb_uint32_t sym_index = 0;
tb_uint32_t sym_count = 0;
while (sym_index < header.nsyms) {
// read symbol
xm_coff_symbol_t sym;
if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {
if (sections) {
tb_free(sections);
}
return tb_false;
}
tb_bool_t skip = tb_false;
tb_char_t name[256] = {0};
if (!xm_binutils_coff_get_symbol_name(istream, &sym, base_offset + strtab_offset, name, sizeof(name)) || !name[0]) {
skip = tb_true;
} else if (name[0] == '.') {
skip = tb_true;
} else if (tb_strchr(name, '$') != tb_null ||
tb_strstr(name, ".constprop") != tb_null ||
tb_strstr(name, ".startup") != tb_null ||
tb_strstr(name, "ta$") != tb_null) {
skip = tb_true;
}
if (!skip) {
// create symbol table entry
lua_pushinteger(lua, sym_count + 1);
lua_newtable(lua);
// name
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
// type (nm-style: T/t/D/d/B/b/U)
tb_char_t type_char = xm_binutils_coff_get_symbol_type_char(sym.scl, sym.sect, sections, header.nsects);
tb_char_t type_str[2] = {type_char, '\0'};
lua_pushstring(lua, "type");
lua_pushstring(lua, type_str);
lua_settable(lua, -3);
lua_settable(lua, -3);
sym_count++;
}
// skip to the next symbol, including auxiliary entries
sym_index++;
if (sym.naux > 0) {
sym_index += sym.naux;
if (!tb_stream_seek(istream, tb_stream_offset(istream) + sym.naux * 18)) {
if (sections) {
tb_free(sections);
}
return tb_false;
}
}
}
if (sections) {
tb_free(sections);
}
return tb_true;
}
================================================
FILE: core/src/xmake/binutils/deplibs.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file deplibs.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "deplibs"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "coff/prefix.h"
#include "elf/prefix.h"
#include "macho/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* forward declarations
*/
extern tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_elf_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_macho_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* get dependent libraries from binary file (auto-detect format)
*
* @param lua the lua state
* @return 1 on success (table on stack), 2 on failure (with error message on stack)
*/
tb_int_t xm_binutils_deplibs(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binary file path
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// open file
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "open %s failed", binaryfile);
return 2;
}
tb_bool_t ok = tb_false;
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "open %s failed", binaryfile);
break;
}
// detect format
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "cannot detect file format");
break;
}
// create result list
lua_newtable(lua);
// get dependents based on format
if (format == XM_BINUTILS_FORMAT_COFF) {
if (!xm_binutils_coff_deplibs(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "failed to parse COFF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_PE) {
// seek to e_lfanew
if (!tb_stream_seek(istream, 0x3c)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "failed to seek to e_lfanew");
break;
}
// read e_lfanew
tb_uint32_t e_lfanew = 0;
if (!tb_stream_bread(istream, (tb_byte_t*)&e_lfanew, 4)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "failed to read e_lfanew");
break;
}
// e_lfanew is little endian
e_lfanew = tb_bits_le_to_ne_u32(e_lfanew);
// call coff deplibs with offset = e_lfanew + 4 (skip PE signature)
if (!xm_binutils_coff_deplibs(istream, e_lfanew + 4, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "failed to parse PE/COFF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
if (!xm_binutils_macho_deplibs(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "failed to parse Mach-O");
break;
}
} else if (format == XM_BINUTILS_FORMAT_ELF) {
if (!xm_binutils_elf_deplibs(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "failed to parse ELF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_WASM) {
} else {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "unsupported format %d", format);
break;
}
ok = tb_true;
} while (0);
if (istream) {
tb_stream_exit(istream);
}
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/elf/bin2elf.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bin2elf.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bin2elf"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_binutils_bin2elf_dump_32(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_char_t const *symbol_prefix,
tb_char_t const *arch,
tb_char_t const *basename,
tb_bool_t zeroend) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
// get file size
tb_hong_t filesize = tb_stream_size(istream);
if (filesize < 0 || filesize > 0xffffffffU) {
return tb_false;
}
tb_uint32_t datasize = (tb_uint32_t)filesize;
// add null terminator if zeroend is true
if (zeroend) {
if (datasize >= 0xffffffffU) {
return tb_false; // would overflow
}
datasize++;
}
// generate symbol names from filename
tb_char_t symbol_name[256] = {0};
tb_char_t symbol_start[256] = {0};
tb_char_t symbol_end[256] = {0};
// use basename or default to "data"
if (!basename || !basename[0]) {
basename = "data";
}
// build symbol name
if (symbol_prefix) {
tb_snprintf(symbol_name, sizeof(symbol_name), "%s%s", symbol_prefix, basename);
} else {
tb_snprintf(symbol_name, sizeof(symbol_name), "_binary_%s", basename);
}
// replace non-alphanumeric with underscore
xm_binutils_sanitize_symbol_name(symbol_name);
tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name);
tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name);
// calculate offsets
tb_uint32_t header_size = sizeof(xm_elf32_header_t);
tb_uint32_t section_header_size = sizeof(xm_elf32_section_t);
tb_uint32_t section_count = 6; // NULL, .rodata, .symtab, .strtab, .shstrtab, .note.GNU-stack
tb_uint32_t section_headers_ofs = header_size;
tb_uint32_t rodata_ofs = section_headers_ofs + section_count * section_header_size;
tb_uint32_t rodata_size = datasize;
tb_uint32_t rodata_padding = (4 - (rodata_size & 3)) & 3; // align to 4 bytes for 32-bit
tb_uint32_t symtab_ofs = rodata_ofs + rodata_size + rodata_padding;
tb_uint32_t symtab_size = 3 * sizeof(xm_elf32_symbol_t); // NULL, start, end
tb_uint32_t symtab_padding = (4 - (symtab_size & 3)) & 3; // align to 4 bytes
tb_uint32_t strtab_ofs = symtab_ofs + symtab_size + symtab_padding;
// calculate string table size
tb_size_t start_len = tb_strlen(symbol_start);
tb_size_t end_len = tb_strlen(symbol_end);
tb_uint32_t strtab_size = 1; // initial null byte
strtab_size += (tb_uint32_t)(start_len + 1);
strtab_size += (tb_uint32_t)(end_len + 1);
tb_uint32_t strtab_padding = (4 - (strtab_size & 3)) & 3; // align to 4 bytes
tb_uint32_t shstrtab_ofs = strtab_ofs + strtab_size + strtab_padding;
// calculate section header string table size
tb_uint32_t shstrtab_size = 1; // initial null byte
shstrtab_size += 8; // ".rodata\0" (7 + 1)
shstrtab_size += 8; // ".symtab\0" (7 + 1)
shstrtab_size += 8; // ".strtab\0" (7 + 1)
shstrtab_size += 10; // ".shstrtab\0" (9 + 1)
shstrtab_size += 16; // ".note.GNU-stack\0" (15 + 1)
// write ELF header
xm_elf32_header_t header;
tb_memset(&header, 0, sizeof(header));
header.e_ident[0] = 0x7f;
header.e_ident[1] = 'E';
header.e_ident[2] = 'L';
header.e_ident[3] = 'F';
header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS32;
header.e_ident[5] = 1; // ELFDATA2LSB
header.e_ident[6] = 1; // EV_CURRENT
header.e_ident[7] = 0; // ELFOSABI_SYSV
header.e_type = 1; // ET_REL
header.e_machine = xm_binutils_elf_get_machine(arch);
header.e_version = 1;
header.e_shoff = section_headers_ofs;
header.e_ehsize = header_size;
header.e_shentsize = section_header_size;
header.e_shnum = section_count;
header.e_shstrndx = 4; // .shstrtab section index
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {
return tb_false;
}
// write section headers
xm_elf32_section_t section_null;
tb_memset(§ion_null, 0, sizeof(section_null));
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_null, sizeof(section_null))) {
return tb_false;
}
// write .rodata section header
xm_elf32_section_t section_rodata;
tb_memset(§ion_rodata, 0, sizeof(section_rodata));
section_rodata.sh_name = 1; // ".rodata" in shstrtab
section_rodata.sh_type = XM_ELF_SHT_PROGBITS;
section_rodata.sh_flags = XM_ELF_SHF_ALLOC;
section_rodata.sh_offset = rodata_ofs;
section_rodata.sh_size = rodata_size;
section_rodata.sh_addralign = 4;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_rodata, sizeof(section_rodata))) {
return tb_false;
}
// write .symtab section header
xm_elf32_section_t section_symtab;
tb_memset(§ion_symtab, 0, sizeof(section_symtab));
section_symtab.sh_name = 9; // ".symtab" in shstrtab
section_symtab.sh_type = XM_ELF_SHT_SYMTAB;
section_symtab.sh_offset = symtab_ofs;
section_symtab.sh_size = symtab_size;
section_symtab.sh_link = 3; // .strtab section index
section_symtab.sh_info = 1; // first global symbol index
section_symtab.sh_addralign = 4;
section_symtab.sh_entsize = sizeof(xm_elf32_symbol_t);
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_symtab, sizeof(section_symtab))) {
return tb_false;
}
// write .strtab section header
xm_elf32_section_t section_strtab;
tb_memset(§ion_strtab, 0, sizeof(section_strtab));
section_strtab.sh_name = 17; // ".strtab" in shstrtab
section_strtab.sh_type = XM_ELF_SHT_STRTAB;
section_strtab.sh_offset = strtab_ofs;
section_strtab.sh_size = strtab_size;
section_strtab.sh_addralign = 1;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_strtab, sizeof(section_strtab))) {
return tb_false;
}
// write .shstrtab section header
xm_elf32_section_t section_shstrtab;
tb_memset(§ion_shstrtab, 0, sizeof(section_shstrtab));
section_shstrtab.sh_name = 25; // ".shstrtab" in shstrtab
section_shstrtab.sh_type = XM_ELF_SHT_STRTAB;
section_shstrtab.sh_offset = shstrtab_ofs;
section_shstrtab.sh_size = shstrtab_size;
section_shstrtab.sh_addralign = 1;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_shstrtab, sizeof(section_shstrtab))) {
return tb_false;
}
// write .note.GNU-stack section header (empty section to mark stack as non-executable)
xm_elf32_section_t section_note_gnu_stack;
tb_memset(§ion_note_gnu_stack, 0, sizeof(section_note_gnu_stack));
section_note_gnu_stack.sh_name = 35; // ".note.GNU-stack" in shstrtab (25 + 10)
section_note_gnu_stack.sh_type = XM_ELF_SHT_PROGBITS;
section_note_gnu_stack.sh_flags = 0; // no flags
section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab
section_note_gnu_stack.sh_size = 0; // empty section
section_note_gnu_stack.sh_addralign = 1;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_note_gnu_stack, sizeof(section_note_gnu_stack))) {
return tb_false;
}
// write .rodata section data
if (!xm_binutils_stream_copy(istream, ostream, filesize)) {
return tb_false;
}
// append null terminator if zeroend is true
if (zeroend) {
tb_byte_t zero = 0;
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
// align .rodata to 4 bytes
if (rodata_padding > 0) {
tb_byte_t zero = 0;
while (rodata_padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write symbol table
// symbol 0: NULL symbol
xm_elf32_symbol_t sym_null;
tb_memset(&sym_null, 0, sizeof(sym_null));
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) {
return tb_false;
}
// symbol 1: _binary_xxx_start
xm_elf32_symbol_t sym_start;
tb_memset(&sym_start, 0, sizeof(sym_start));
sym_start.st_name = 1; // offset in .strtab (after initial null)
sym_start.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;
sym_start.st_shndx = 1; // .rodata section index
sym_start.st_value = 0;
sym_start.st_size = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) {
return tb_false;
}
// symbol 2: _binary_xxx_end
xm_elf32_symbol_t sym_end;
tb_memset(&sym_end, 0, sizeof(sym_end));
sym_end.st_name = 1 + (tb_uint32_t)(start_len + 1); // offset in .strtab
sym_end.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;
sym_end.st_shndx = 1; // .rodata section index
sym_end.st_value = rodata_size;
sym_end.st_size = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) {
return tb_false;
}
// align .symtab to 4 bytes
if (symtab_padding > 0) {
tb_byte_t zero = 0;
while (symtab_padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write string table
tb_byte_t null = 0;
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
// align .strtab to 4 bytes
if (strtab_padding > 0) {
tb_byte_t zero = 0;
while (strtab_padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write section header string table
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".rodata", 7)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".symtab", 7)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".strtab", 7)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".shstrtab", 9)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".note.GNU-stack", 15)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
return tb_true;
}
static tb_bool_t xm_binutils_bin2elf_dump_64(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_char_t const *symbol_prefix,
tb_char_t const *arch,
tb_char_t const *basename,
tb_bool_t zeroend) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
// get file size
tb_hong_t filesize = tb_stream_size(istream);
if (filesize < 0 || filesize > 0xffffffffU) {
return tb_false;
}
tb_uint32_t datasize = (tb_uint32_t)filesize;
// add null terminator if zeroend is true
if (zeroend) {
if (datasize >= 0xffffffffU) {
return tb_false; // would overflow
}
datasize++;
}
// generate symbol names from filename
tb_char_t symbol_name[256] = {0};
tb_char_t symbol_start[256] = {0};
tb_char_t symbol_end[256] = {0};
// use basename or default to "data"
if (!basename || !basename[0]) {
basename = "data";
}
// build symbol name
if (symbol_prefix) {
tb_snprintf(symbol_name, sizeof(symbol_name), "%s%s", symbol_prefix, basename);
} else {
tb_snprintf(symbol_name, sizeof(symbol_name), "_binary_%s", basename);
}
// replace non-alphanumeric with underscore
xm_binutils_sanitize_symbol_name(symbol_name);
tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name);
tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name);
// calculate offsets
tb_uint32_t header_size = sizeof(xm_elf64_header_t);
tb_uint32_t section_header_size = sizeof(xm_elf64_section_t);
tb_uint32_t section_count = 6; // NULL, .rodata, .symtab, .strtab, .shstrtab, .note.GNU-stack
tb_uint32_t section_headers_ofs = header_size;
tb_uint32_t rodata_ofs = section_headers_ofs + section_count * section_header_size;
tb_uint32_t rodata_size = datasize;
tb_uint32_t rodata_padding = (8 - (rodata_size & 7)) & 7;
tb_uint32_t symtab_ofs = rodata_ofs + rodata_size + rodata_padding;
tb_uint32_t symtab_size = 3 * sizeof(xm_elf64_symbol_t); // NULL, start, end
tb_uint32_t symtab_padding = (8 - (symtab_size & 7)) & 7;
tb_uint32_t strtab_ofs = symtab_ofs + symtab_size + symtab_padding;
// calculate string table size
tb_size_t start_len = tb_strlen(symbol_start);
tb_size_t end_len = tb_strlen(symbol_end);
tb_uint32_t strtab_size = 1; // initial null byte
strtab_size += (tb_uint32_t)(start_len + 1);
strtab_size += (tb_uint32_t)(end_len + 1);
tb_uint32_t strtab_padding = (8 - (strtab_size & 7)) & 7;
// calculate section header string table size
tb_uint32_t shstrtab_size = 1; // initial null byte
shstrtab_size += 8; // ".rodata\0" (7 + 1)
shstrtab_size += 8; // ".symtab\0" (7 + 1)
shstrtab_size += 8; // ".strtab\0" (7 + 1)
shstrtab_size += 10; // ".shstrtab\0" (9 + 1)
shstrtab_size += 16; // ".note.GNU-stack\0" (15 + 1)
tb_uint32_t shstrtab_ofs = strtab_ofs + strtab_size + strtab_padding;
// write ELF header
xm_elf64_header_t header;
tb_memset(&header, 0, sizeof(header));
header.e_ident[0] = 0x7f;
header.e_ident[1] = 'E';
header.e_ident[2] = 'L';
header.e_ident[3] = 'F';
header.e_ident[XM_ELF_EI_CLASS] = XM_ELF_CLASS64;
header.e_ident[5] = 1; // ELFDATA2LSB
header.e_ident[6] = 1; // EV_CURRENT
header.e_ident[7] = 0; // ELFOSABI_SYSV
header.e_type = 1; // ET_REL
header.e_machine = xm_binutils_elf_get_machine(arch);
header.e_version = 1;
header.e_shoff = section_headers_ofs;
header.e_ehsize = header_size;
header.e_shentsize = section_header_size;
header.e_shnum = section_count;
header.e_shstrndx = 4; // .shstrtab section index
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {
return tb_false;
}
// write section headers
xm_elf64_section_t section_null;
tb_memset(§ion_null, 0, sizeof(section_null));
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_null, sizeof(section_null))) {
return tb_false;
}
// write .rodata section header
xm_elf64_section_t section_rodata;
tb_memset(§ion_rodata, 0, sizeof(section_rodata));
section_rodata.sh_name = 1; // ".rodata" in shstrtab
section_rodata.sh_type = XM_ELF_SHT_PROGBITS;
section_rodata.sh_flags = XM_ELF_SHF_ALLOC;
section_rodata.sh_offset = rodata_ofs;
section_rodata.sh_size = rodata_size;
section_rodata.sh_addralign = 8;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_rodata, sizeof(section_rodata))) {
return tb_false;
}
// write .symtab section header
xm_elf64_section_t section_symtab;
tb_memset(§ion_symtab, 0, sizeof(section_symtab));
section_symtab.sh_name = 9; // ".symtab" in shstrtab
section_symtab.sh_type = XM_ELF_SHT_SYMTAB;
section_symtab.sh_offset = symtab_ofs;
section_symtab.sh_size = symtab_size;
section_symtab.sh_link = 3; // .strtab section index
section_symtab.sh_info = 1; // first global symbol index
section_symtab.sh_addralign = 8;
section_symtab.sh_entsize = sizeof(xm_elf64_symbol_t);
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_symtab, sizeof(section_symtab))) {
return tb_false;
}
// write .strtab section header
xm_elf64_section_t section_strtab;
tb_memset(§ion_strtab, 0, sizeof(section_strtab));
section_strtab.sh_name = 17; // ".strtab" in shstrtab
section_strtab.sh_type = XM_ELF_SHT_STRTAB;
section_strtab.sh_offset = strtab_ofs;
section_strtab.sh_size = strtab_size;
section_strtab.sh_addralign = 1;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_strtab, sizeof(section_strtab))) {
return tb_false;
}
// write .shstrtab section header
xm_elf64_section_t section_shstrtab;
tb_memset(§ion_shstrtab, 0, sizeof(section_shstrtab));
section_shstrtab.sh_name = 25; // ".shstrtab" in shstrtab
section_shstrtab.sh_type = XM_ELF_SHT_STRTAB;
section_shstrtab.sh_offset = shstrtab_ofs; // points to initial null byte
section_shstrtab.sh_size = shstrtab_size; // size includes initial null and all strings
section_shstrtab.sh_addralign = 1;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_shstrtab, sizeof(section_shstrtab))) {
return tb_false;
}
// write .note.GNU-stack section header (empty section to mark stack as non-executable)
xm_elf64_section_t section_note_gnu_stack;
tb_memset(§ion_note_gnu_stack, 0, sizeof(section_note_gnu_stack));
section_note_gnu_stack.sh_name = 35; // ".note.GNU-stack" in shstrtab (25 + 10)
section_note_gnu_stack.sh_type = XM_ELF_SHT_PROGBITS;
section_note_gnu_stack.sh_flags = 0; // no flags
section_note_gnu_stack.sh_offset = shstrtab_ofs + shstrtab_size; // after .shstrtab
section_note_gnu_stack.sh_size = 0; // empty section
section_note_gnu_stack.sh_addralign = 1;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion_note_gnu_stack, sizeof(section_note_gnu_stack))) {
return tb_false;
}
// write .rodata section data
if (!xm_binutils_stream_copy(istream, ostream, filesize)) {
return tb_false;
}
// append null terminator if zeroend is true
if (zeroend) {
tb_byte_t zero = 0;
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
// align .rodata to 8 bytes
if (rodata_padding > 0) {
tb_byte_t zero = 0;
while (rodata_padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write symbol table
// symbol 0: NULL symbol
xm_elf64_symbol_t sym_null;
tb_memset(&sym_null, 0, sizeof(sym_null));
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_null, sizeof(sym_null))) {
return tb_false;
}
// symbol 1: _binary_xxx_start
xm_elf64_symbol_t sym_start;
tb_memset(&sym_start, 0, sizeof(sym_start));
sym_start.st_name = 1; // offset in .strtab (after initial null)
sym_start.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;
sym_start.st_shndx = 1; // .rodata section index
sym_start.st_value = 0;
sym_start.st_size = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_start, sizeof(sym_start))) {
return tb_false;
}
// symbol 2: _binary_xxx_end
xm_elf64_symbol_t sym_end;
tb_memset(&sym_end, 0, sizeof(sym_end));
sym_end.st_name = 1 + (tb_uint32_t)(start_len + 1); // offset in .strtab
sym_end.st_info = (XM_ELF_STB_GLOBAL << 4) | XM_ELF_STT_OBJECT;
sym_end.st_shndx = 1; // .rodata section index
sym_end.st_value = rodata_size;
sym_end.st_size = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&sym_end, sizeof(sym_end))) {
return tb_false;
}
// align .symtab to 8 bytes
if (symtab_padding > 0) {
tb_byte_t zero = 0;
while (symtab_padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write string table
tb_byte_t null = 0;
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
// align .strtab to 8 bytes
if (strtab_padding > 0) {
tb_byte_t zero = 0;
while (strtab_padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write section header string table
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".rodata", 7)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".symtab", 7)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".strtab", 7)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".shstrtab", 9)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)".note.GNU-stack", 15)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, &null, 1)) {
return tb_false;
}
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* generate ELF object file from binary file
*
* local ok, errors = binutils.bin2elf(binaryfile, outputfile, symbol_prefix, arch, basename, zeroend)
*/
tb_int_t xm_binutils_bin2elf(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binaryfile
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// get the outputfile
tb_char_t const *outputfile = luaL_checkstring(lua, 2);
tb_check_return_val(outputfile, 0);
// get symbol prefix (optional)
tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null;
// get arch (optional)
tb_char_t const *arch = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null;
// get basename (optional)
tb_char_t const *basename = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null;
// get zeroend (optional, default: false)
tb_bool_t zeroend = lua_toboolean(lua, 6);
// do dump
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2elf: open %s failed", binaryfile);
break;
}
if (!tb_stream_open(ostream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2elf: open %s failed", outputfile);
break;
}
// choose 32-bit or 64-bit ELF based on architecture
tb_bool_t is_64bit = xm_binutils_elf_is_64bit(arch);
if (is_64bit) {
if (!xm_binutils_bin2elf_dump_64(istream, ostream, symbol_prefix, arch, basename, zeroend)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2elf: dump data failed");
break;
}
} else {
if (!xm_binutils_bin2elf_dump_32(istream, ostream, symbol_prefix, arch, basename, zeroend)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2elf: dump data failed");
break;
}
}
ok = tb_true;
lua_pushboolean(lua, ok);
} while (0);
if (istream)
tb_stream_clos(istream);
istream = tb_null;
if (ostream)
tb_stream_clos(ostream);
ostream = tb_null;
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/elf/deplibs.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file deplibs.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "deplibs_elf"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_binutils_elf_check_path(tb_char_t const* path, tb_char_t const* name, tb_char_t* output, tb_size_t output_size) {
tb_char_t fullpath[TB_PATH_MAXN];
tb_snprintf(fullpath, sizeof(fullpath), "%s/%s", path, name);
if (tb_file_info(fullpath, tb_null)) {
if (output) {
tb_strlcpy(output, fullpath, output_size);
}
return tb_true;
}
return tb_false;
}
static tb_void_t xm_binutils_elf_resolve_path(tb_char_t const* name, tb_char_t const* rpath, tb_char_t const* binary_dir, tb_char_t* output, tb_size_t output_size) {
// absolute path?
if (tb_path_is_absolute(name)) {
tb_strlcpy(output, name, output_size);
return;
}
// try rpath/runpath
if (rpath && binary_dir) {
tb_char_t const* p = rpath;
tb_char_t const* e = tb_null;
while (*p) {
e = tb_strchr(p, ':');
tb_size_t n = e ? (tb_size_t)(e - p) : tb_strlen(p);
if (n > 0) {
tb_char_t path[TB_PATH_MAXN];
tb_char_t expanded_path[TB_PATH_MAXN];
tb_strncpy(path, p, n);
path[n] = '\0';
// replace $ORIGIN
tb_char_t* origin = tb_strstr(path, "$ORIGIN");
if (origin) {
tb_long_t len = tb_snprintf(expanded_path, sizeof(expanded_path), "%.*s%s%s", (tb_int_t)(origin - path), path, binary_dir, origin + 7);
if (len >= 0) {
if (xm_binutils_elf_check_path(expanded_path, name, output, output_size)) {
return;
}
}
} else {
if (xm_binutils_elf_check_path(path, name, output, output_size)) {
return;
}
}
}
if (e) p = e + 1;
else break;
}
}
// try system paths
static tb_char_t const* s_sys_paths[] = {
"/lib",
"/usr/lib",
"/lib64",
"/usr/lib64",
"/usr/local/lib",
"/usr/local/lib64",
"/lib/x86_64-linux-gnu", // Debian/Ubuntu
"/usr/lib/x86_64-linux-gnu",
"/lib/i386-linux-gnu",
"/usr/lib/i386-linux-gnu",
"/lib/aarch64-linux-gnu",
"/usr/lib/aarch64-linux-gnu",
"/lib/arm-linux-gnueabihf",
"/usr/lib/arm-linux-gnueabihf",
tb_null
};
for (tb_char_t const** sys_path = s_sys_paths; *sys_path; sys_path++) {
if (xm_binutils_elf_check_path(*sys_path, name, output, output_size)) {
return;
}
}
// not found, return original name
tb_strlcpy(output, name, output_size);
}
static tb_bool_t xm_binutils_elf_deplibs_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// read ELF header
xm_elf32_header_t header;
if (!xm_binutils_elf_read_header_32(istream, base_offset, &header)) {
return tb_false;
}
// find program interpreter (PT_INTERP) and push
tb_char_t name[256];
tb_size_t result_count = 0;
if (xm_binutils_elf_find_interp_32(istream, base_offset, &header, name, sizeof(name))) {
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, name);
lua_settable(lua, -3);
result_count++;
}
// build dynamic/string table context
xm_elf_context_t ctx;
if (!xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) {
return tb_true;
}
// scan .dynamic entries: collect NEEDED and read RPATH/RUNPATH
tb_uint32_t count = (tb_uint32_t)(ctx.dynamic_size / sizeof(xm_elf32_dynamic_t));
if (!tb_stream_seek(istream, base_offset + ctx.dynamic_offset)) {
return tb_false;
}
tb_char_t rpath[8192] = {0};
tb_char_t runpath[8192] = {0};
tb_vector_ref_t needed_libs = tb_vector_init(0, tb_element_str(tb_true));
if (needed_libs) {
for (tb_uint32_t i = 0; i < count; i++) {
xm_elf32_dynamic_t dyn;
if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) {
break;
}
if (dyn.d_tag == XM_ELF_DT_NULL) {
break;
}
if (dyn.d_tag == XM_ELF_DT_NEEDED || dyn.d_tag == XM_ELF_DT_SONAME || dyn.d_tag == XM_ELF_DT_AUXILIARY || dyn.d_tag == XM_ELF_DT_FILTER) {
tb_char_t name[256];
if (xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, name, sizeof(name)) && name[0]) {
tb_vector_insert_tail(needed_libs, name);
}
} else if (dyn.d_tag == XM_ELF_DT_RPATH) {
xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, rpath, sizeof(rpath));
} else if (dyn.d_tag == XM_ELF_DT_RUNPATH) {
xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + dyn.d_un.d_val, runpath, sizeof(runpath));
}
}
tb_char_t const* binary_path = tb_null;
tb_char_t binary_dir[TB_PATH_MAXN] = {0};
if (tb_stream_ctrl(istream, TB_STREAM_CTRL_GET_PATH, &binary_path) && binary_path) {
tb_path_directory(binary_path, binary_dir, sizeof(binary_dir));
}
// resolve $ORIGIN and rpath/runpath, push full paths
tb_for_all (tb_char_t const*, name, needed_libs) {
tb_char_t fullpath[TB_PATH_MAXN];
xm_binutils_elf_resolve_path(name, runpath[0]? runpath : rpath, binary_dir[0]? binary_dir : tb_null, fullpath, sizeof(fullpath));
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, fullpath);
lua_settable(lua, -3);
result_count++;
}
tb_vector_exit(needed_libs);
}
return tb_true;
}
static tb_bool_t xm_binutils_elf_deplibs_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// read ELF header
xm_elf64_header_t header;
if (!xm_binutils_elf_read_header_64(istream, base_offset, &header)) {
return tb_false;
}
// find program interpreter (PT_INTERP) and push
tb_char_t name[256];
tb_size_t result_count = 0;
if (xm_binutils_elf_find_interp_64(istream, base_offset, &header, name, sizeof(name))) {
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, name);
lua_settable(lua, -3);
result_count++;
}
// build dynamic/string table context
xm_elf_context_t ctx;
if (!xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) {
return tb_true;
}
// read dynamic entries
tb_uint32_t count = (tb_uint32_t)(ctx.dynamic_size / sizeof(xm_elf64_dynamic_t));
if (!tb_stream_seek(istream, base_offset + ctx.dynamic_offset)) {
return tb_false;
}
tb_char_t rpath[8192] = {0};
tb_char_t runpath[8192] = {0};
tb_vector_ref_t needed_libs = tb_vector_init(0, tb_element_str(tb_true));
if (needed_libs) {
for (tb_uint32_t i = 0; i < count; i++) {
xm_elf64_dynamic_t dyn;
if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) {
break;
}
if (dyn.d_tag == XM_ELF_DT_NULL) {
break;
}
if (dyn.d_tag == XM_ELF_DT_NEEDED || dyn.d_tag == XM_ELF_DT_SONAME || dyn.d_tag == XM_ELF_DT_AUXILIARY || dyn.d_tag == XM_ELF_DT_FILTER) {
tb_char_t name[256];
if (xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, name, sizeof(name)) && name[0]) {
tb_vector_insert_tail(needed_libs, name);
}
} else if (dyn.d_tag == XM_ELF_DT_RPATH) {
xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, rpath, sizeof(rpath));
} else if (dyn.d_tag == XM_ELF_DT_RUNPATH) {
xm_binutils_read_string(istream, base_offset + ctx.strtab_offset + (tb_uint32_t)dyn.d_un.d_val, runpath, sizeof(runpath));
}
}
// get binary directory
tb_char_t const* binary_path = tb_null;
tb_char_t binary_dir[TB_PATH_MAXN] = {0};
if (tb_stream_ctrl(istream, TB_STREAM_CTRL_GET_PATH, &binary_path) && binary_path) {
tb_path_directory(binary_path, binary_dir, sizeof(binary_dir));
}
// resolve and push paths
tb_for_all (tb_char_t const*, name, needed_libs) {
tb_char_t fullpath[TB_PATH_MAXN];
xm_binutils_elf_resolve_path(name, runpath[0]? runpath : rpath, binary_dir[0]? binary_dir : tb_null, fullpath, sizeof(fullpath));
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, fullpath);
lua_settable(lua, -3);
result_count++;
}
tb_vector_exit(needed_libs);
}
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_bool_t xm_binutils_elf_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// read and check ELF magic
tb_uint8_t magic[4];
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, magic, 4)) {
return tb_false;
}
if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') {
return tb_false;
}
// check ELF class (32-bit or 64-bit)
tb_uint8_t elf_class;
if (!tb_stream_seek(istream, base_offset + 4)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) {
return tb_false;
}
if (elf_class == 1) {
return xm_binutils_elf_deplibs_32(istream, base_offset, lua);
} else if (elf_class == 2) {
return xm_binutils_elf_deplibs_64(istream, base_offset, lua);
}
return tb_false;
}
================================================
FILE: core/src/xmake/binutils/elf/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_ELF_PREFIX_H
#define XM_BINUTILS_ELF_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_ELF_MAGIC0 0x7f
#define XM_ELF_MAGIC1 'E'
#define XM_ELF_MAGIC2 'L'
#define XM_ELF_MAGIC3 'F'
// ELF class
#define XM_ELF_EI_CLASS 4
#define XM_ELF_CLASS32 1
#define XM_ELF_CLASS64 2
#define XM_ELF_MACHINE_NONE 0x00
#define XM_ELF_MACHINE_SPARC 0x02
#define XM_ELF_MACHINE_I386 0x03
#define XM_ELF_MACHINE_MIPS 0x08
#define XM_ELF_MACHINE_POWERPC 0x14
#define XM_ELF_MACHINE_POWERPC64 0x15
#define XM_ELF_MACHINE_S390 0x16
#define XM_ELF_MACHINE_ARM 0x28
#define XM_ELF_MACHINE_SUPERH 0x2a
#define XM_ELF_MACHINE_SPARC64 0x2b
#define XM_ELF_MACHINE_IA_64 0x32
#define XM_ELF_MACHINE_X86_64 0x3e
#define XM_ELF_MACHINE_RISCV 0xf3
#define XM_ELF_MACHINE_ARM64 0xb7
#define XM_ELF_MACHINE_WASM 0xe7
#define XM_ELF_MACHINE_LOONGARCH 0x102
#define XM_ELF_SHT_PROGBITS 0x1
#define XM_ELF_SHT_SYMTAB 0x2
#define XM_ELF_SHT_STRTAB 0x3
#define XM_ELF_SHT_DYNAMIC 0x6
#define XM_ELF_PT_LOAD 1
#define XM_ELF_PT_DYNAMIC 2
#define XM_ELF_PT_INTERP 3
#define XM_ELF_DT_NULL 0
#define XM_ELF_DT_NEEDED 1
#define XM_ELF_DT_STRTAB 5
#define XM_ELF_DT_STRSZ 10
#define XM_ELF_DT_SONAME 14
#define XM_ELF_DT_RPATH 15
#define XM_ELF_DT_RUNPATH 29
#define XM_ELF_DT_AUXILIARY 0x7ffffffd
#define XM_ELF_DT_FILTER 0x7fffffff
#define XM_ELF_SHF_ALLOC 0x2
#define XM_ELF_SHF_WRITE 0x1
#define XM_ELF_STB_GLOBAL 0x1
#define XM_ELF_STT_OBJECT 0x1
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
#include "tbox/prefix/packed.h"
typedef struct __xm_elf_context_t {
tb_hize_t dynamic_offset; // file offset of .dynamic
tb_hize_t dynamic_size; // size of .dynamic
tb_hize_t strtab_offset; // file offset of .dynstr
tb_hize_t strtab_size; // size of .dynstr
tb_hize_t symtab_offset; // file offset of .symtab
tb_hize_t symtab_size; // size of .symtab
tb_hize_t symstr_offset; // file offset of .strtab (for .symtab)
tb_hize_t symstr_size; // size of .strtab (for .symtab)
tb_bool_t is64;
} xm_elf_context_t;
typedef struct __xm_elf32_header_t {
tb_uint8_t e_ident[16];
tb_uint16_t e_type;
tb_uint16_t e_machine;
tb_uint32_t e_version;
tb_uint32_t e_entry;
tb_uint32_t e_phoff;
tb_uint32_t e_shoff;
tb_uint32_t e_flags;
tb_uint16_t e_ehsize;
tb_uint16_t e_phentsize;
tb_uint16_t e_phnum;
tb_uint16_t e_shentsize;
tb_uint16_t e_shnum;
tb_uint16_t e_shstrndx;
} __tb_packed__ xm_elf32_header_t;
typedef struct __xm_elf32_section_t {
tb_uint32_t sh_name;
tb_uint32_t sh_type;
tb_uint32_t sh_flags;
tb_uint32_t sh_addr;
tb_uint32_t sh_offset;
tb_uint32_t sh_size;
tb_uint32_t sh_link;
tb_uint32_t sh_info;
tb_uint32_t sh_addralign;
tb_uint32_t sh_entsize;
} __tb_packed__ xm_elf32_section_t;
typedef struct __xm_elf32_symbol_t {
tb_uint32_t st_name;
tb_uint32_t st_value;
tb_uint32_t st_size;
tb_uint8_t st_info;
tb_uint8_t st_other;
tb_uint16_t st_shndx;
} __tb_packed__ xm_elf32_symbol_t;
typedef struct __xm_elf32_phdr_t {
tb_uint32_t p_type;
tb_uint32_t p_offset;
tb_uint32_t p_vaddr;
tb_uint32_t p_paddr;
tb_uint32_t p_filesz;
tb_uint32_t p_memsz;
tb_uint32_t p_flags;
tb_uint32_t p_align;
} __tb_packed__ xm_elf32_phdr_t;
typedef struct __xm_elf64_header_t {
tb_uint8_t e_ident[16];
tb_uint16_t e_type;
tb_uint16_t e_machine;
tb_uint32_t e_version;
tb_uint64_t e_entry;
tb_uint64_t e_phoff;
tb_uint64_t e_shoff;
tb_uint32_t e_flags;
tb_uint16_t e_ehsize;
tb_uint16_t e_phentsize;
tb_uint16_t e_phnum;
tb_uint16_t e_shentsize;
tb_uint16_t e_shnum;
tb_uint16_t e_shstrndx;
} __tb_packed__ xm_elf64_header_t;
typedef struct __xm_elf64_section_t {
tb_uint32_t sh_name;
tb_uint32_t sh_type;
tb_uint64_t sh_flags;
tb_uint64_t sh_addr;
tb_uint64_t sh_offset;
tb_uint64_t sh_size;
tb_uint32_t sh_link;
tb_uint32_t sh_info;
tb_uint64_t sh_addralign;
tb_uint64_t sh_entsize;
} __tb_packed__ xm_elf64_section_t;
typedef struct __xm_elf64_symbol_t {
tb_uint32_t st_name;
tb_uint8_t st_info;
tb_uint8_t st_other;
tb_uint16_t st_shndx;
tb_uint64_t st_value;
tb_uint64_t st_size;
} __tb_packed__ xm_elf64_symbol_t;
typedef struct __xm_elf64_phdr_t {
tb_uint32_t p_type;
tb_uint32_t p_flags;
tb_uint64_t p_offset;
tb_uint64_t p_vaddr;
tb_uint64_t p_paddr;
tb_uint64_t p_filesz;
tb_uint64_t p_memsz;
tb_uint64_t p_align;
} __tb_packed__ xm_elf64_phdr_t;
typedef struct __xm_elf32_dynamic_t {
tb_int32_t d_tag;
union {
tb_uint32_t d_val;
tb_uint32_t d_ptr;
} d_un;
} __tb_packed__ xm_elf32_dynamic_t;
typedef struct __xm_elf64_dynamic_t {
tb_int64_t d_tag;
union {
tb_uint64_t d_val;
tb_uint64_t d_ptr;
} d_un;
} __tb_packed__ xm_elf64_dynamic_t;
#include "tbox/prefix/packed.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
/* get machine type from architecture string
*
* @param arch the architecture string (e.g., "x86_64", "i386", "arm64", "riscv")
* @return the machine type
*/
static __tb_inline__ tb_uint16_t xm_binutils_elf_get_machine(tb_char_t const *arch) {
if (!arch) {
return XM_ELF_MACHINE_X86_64;
}
// x86/x86_64
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return XM_ELF_MACHINE_X86_64;
} else if (tb_strcmp(arch, "i386") == 0 || tb_strcmp(arch, "x86") == 0) {
return XM_ELF_MACHINE_I386;
}
// ARM
else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 ||
tb_strcmp(arch, "arm64-v8a") == 0) {
return XM_ELF_MACHINE_ARM64;
} else if (tb_strcmp(arch, "arm") == 0 || tb_strcmp(arch, "armv7") == 0 ||
tb_strcmp(arch, "armeabi-v7a") == 0 || tb_strcmp(arch, "armv6") == 0 ||
tb_strcmp(arch, "armv5") == 0) {
return XM_ELF_MACHINE_ARM;
}
// MIPS (MIPS and MIPS64 use same machine type, distinguished by ELF class)
else if (tb_strncmp(arch, "mips", 4) == 0) {
return XM_ELF_MACHINE_MIPS;
}
// PowerPC
else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) {
return XM_ELF_MACHINE_POWERPC64;
} else if (tb_strncmp(arch, "ppc", 3) == 0 || tb_strncmp(arch, "powerpc", 7) == 0) {
return XM_ELF_MACHINE_POWERPC;
}
// RISC-V (RISC-V and RISC-V64 use different machine types)
else if (tb_strncmp(arch, "riscv64", 7) == 0 ||
(tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) {
return XM_ELF_MACHINE_RISCV; // RISC-V 64-bit uses same machine type, distinguished by ELF class
} else if (tb_strncmp(arch, "riscv", 5) == 0) {
return XM_ELF_MACHINE_RISCV;
}
// SPARC
else if (tb_strncmp(arch, "sparc64", 7) == 0) {
return XM_ELF_MACHINE_SPARC64;
} else if (tb_strncmp(arch, "sparc", 5) == 0) {
return XM_ELF_MACHINE_SPARC;
}
// s390x
else if (tb_strcmp(arch, "s390x") == 0 || tb_strcmp(arch, "s390") == 0) {
return XM_ELF_MACHINE_S390;
}
// LoongArch (LoongArch and LoongArch64 use same machine type, distinguished by ELF class)
else if (tb_strncmp(arch, "loongarch", 9) == 0 || tb_strncmp(arch, "loong64", 7) == 0) {
return XM_ELF_MACHINE_LOONGARCH;
}
// WebAssembly (WASM and WASM64 use same machine type, distinguished by ELF class)
else if (tb_strncmp(arch, "wasm", 4) == 0) {
return XM_ELF_MACHINE_WASM;
}
// SuperH
else if (tb_strncmp(arch, "sh", 2) == 0 || tb_strncmp(arch, "superh", 6) == 0) {
return XM_ELF_MACHINE_SUPERH;
}
// IA-64 (Itanium)
else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) {
return XM_ELF_MACHINE_IA_64;
}
return XM_ELF_MACHINE_X86_64;
}
/* check if architecture is 64-bit
*
* @param arch the architecture string
* @return tb_true if 64-bit, tb_false otherwise
*/
static __tb_inline__ tb_bool_t xm_binutils_elf_is_64bit(tb_char_t const *arch) {
return xm_binutils_arch_is_64bit(arch);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* readsyms inline implementation
*/
/* get symbol type character (nm-style) from ELF symbol
*
* @param st_info the symbol info byte
* @param st_shndx the section index (0 = undefined)
* @return the type character (T/t/D/d/B/b/U)
*/
static __tb_inline__ tb_char_t xm_binutils_elf_get_symbol_type_char(tb_uint8_t st_info, tb_uint16_t st_shndx) {
// undefined symbol
if (st_shndx == 0) {
return 'U';
}
// check bind (global = uppercase, local = lowercase)
tb_uint8_t bind = (st_info >> 4) & 0xf;
tb_bool_t is_global = (bind == 1); // STB_GLOBAL
// check type
tb_uint8_t type = st_info & 0xf;
if (type == 2) { // STT_FUNC
return is_global ? 'T' : 't'; // text (function)
} else if (type == 1) { // STT_OBJECT
// For object symbols, we need section info to determine data/bss
// For simplicity, we'll use 'D' for data, 'B' for bss
// This is a heuristic - in practice, we'd need to check section flags
return is_global ? 'D' : 'd'; // data (assume data section)
}
// other types
return is_global ? 'S' : 's'; // other section
}
/* get symbol bind string from ELF symbol info
*
* @param st_info the symbol info byte
* @return the bind string
*/
static __tb_inline__ tb_char_t const *xm_binutils_elf_get_symbol_bind(tb_uint8_t st_info) {
tb_uint8_t bind = (st_info >> 4) & 0xf;
switch (bind) {
case 0: return "local";
case 1: return "global";
case 2: return "weak";
default: return "unknown";
}
}
// read ELF header (32-bit)
static __tb_inline__ tb_bool_t xm_binutils_elf_read_header_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf32_header_t* header) {
if (!tb_stream_seek(istream, base_offset)) return tb_false;
if (!tb_stream_bread(istream, (tb_byte_t*)header, sizeof(*header))) return tb_false;
return tb_true;
}
// read ELF header (64-bit)
static __tb_inline__ tb_bool_t xm_binutils_elf_read_header_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf64_header_t* header) {
if (!tb_stream_seek(istream, base_offset)) return tb_false;
if (!tb_stream_bread(istream, (tb_byte_t*)header, sizeof(*header))) return tb_false;
return tb_true;
}
static __tb_inline__ tb_bool_t xm_binutils_elf_get_context_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) {
tb_memset(ctx, 0, sizeof(xm_elf_context_t));
ctx->is64 = tb_false;
// read ELF header
xm_elf32_header_t header;
if (!xm_binutils_elf_read_header_32(istream, base_offset, &header)) return tb_false;
// try to find from section headers first
if (header.e_shoff != 0 && header.e_shnum > 0) {
if (tb_stream_seek(istream, base_offset + header.e_shoff)) {
for (tb_uint16_t i = 0; i < header.e_shnum; i++) {
xm_elf32_section_t section;
if (!tb_stream_bread(istream, (tb_byte_t*)§ion, sizeof(section))) break;
if (section.sh_type == XM_ELF_SHT_DYNAMIC) {
ctx->dynamic_offset = section.sh_offset;
ctx->dynamic_size = section.sh_size;
// find string table via sh_link
xm_elf32_section_t strtab_section;
if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf32_section_t)) &&
tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) {
ctx->strtab_offset = strtab_section.sh_offset;
ctx->strtab_size = strtab_section.sh_size;
}
} else if (section.sh_type == XM_ELF_SHT_SYMTAB) {
ctx->symtab_offset = section.sh_offset;
ctx->symtab_size = section.sh_size;
xm_elf32_section_t symstr_section;
if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf32_section_t)) &&
tb_stream_bread(istream, (tb_byte_t*)&symstr_section, sizeof(symstr_section))) {
ctx->symstr_offset = symstr_section.sh_offset;
ctx->symstr_size = symstr_section.sh_size;
}
}
}
}
}
// fallback to program headers
if ((ctx->dynamic_offset == 0 || ctx->strtab_offset == 0) && header.e_phoff != 0 && header.e_phnum > 0) {
if (tb_stream_seek(istream, base_offset + header.e_phoff)) {
for (tb_uint16_t i = 0; i < header.e_phnum; i++) {
xm_elf32_phdr_t phdr;
if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;
if (phdr.p_type == XM_ELF_PT_DYNAMIC) {
ctx->dynamic_offset = phdr.p_offset;
ctx->dynamic_size = phdr.p_memsz;
break;
}
}
}
if (ctx->dynamic_offset > 0 && ctx->dynamic_size > 0) {
// read dynamic entries to find strtab address and size
tb_uint64_t strtab_vaddr = 0;
tb_uint64_t strtab_sz = 0;
tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / sizeof(xm_elf32_dynamic_t));
if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) {
for (tb_uint32_t i = 0; i < count; i++) {
xm_elf32_dynamic_t dyn;
if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;
if (dyn.d_tag == XM_ELF_DT_STRTAB) strtab_vaddr = dyn.d_un.d_val;
else if (dyn.d_tag == XM_ELF_DT_STRSZ) strtab_sz = dyn.d_un.d_val;
}
}
if (strtab_vaddr > 0) {
// map strtab vaddr to file offset using PT_LOAD
if (tb_stream_seek(istream, base_offset + header.e_phoff)) {
for (tb_uint16_t i = 0; i < header.e_phnum; i++) {
xm_elf32_phdr_t phdr;
if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;
if (phdr.p_type == XM_ELF_PT_LOAD && strtab_vaddr >= phdr.p_vaddr && strtab_vaddr < phdr.p_vaddr + phdr.p_memsz) {
ctx->strtab_offset = phdr.p_offset + (strtab_vaddr - phdr.p_vaddr);
ctx->strtab_size = strtab_sz;
break;
}
}
}
}
}
}
return (ctx->dynamic_offset != 0 && ctx->strtab_offset != 0);
}
static __tb_inline__ tb_bool_t xm_binutils_elf_get_context_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) {
tb_memset(ctx, 0, sizeof(xm_elf_context_t));
ctx->is64 = tb_true;
// read ELF header
xm_elf64_header_t header;
if (!xm_binutils_elf_read_header_64(istream, base_offset, &header)) return tb_false;
// try to find from section headers first
if (header.e_shoff != 0 && header.e_shnum > 0) {
if (tb_stream_seek(istream, base_offset + header.e_shoff)) {
for (tb_uint16_t i = 0; i < header.e_shnum; i++) {
xm_elf64_section_t section;
if (!tb_stream_bread(istream, (tb_byte_t*)§ion, sizeof(section))) break;
if (section.sh_type == XM_ELF_SHT_DYNAMIC) {
ctx->dynamic_offset = section.sh_offset;
ctx->dynamic_size = section.sh_size;
// find string table via sh_link
xm_elf64_section_t strtab_section;
if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf64_section_t)) &&
tb_stream_bread(istream, (tb_byte_t*)&strtab_section, sizeof(strtab_section))) {
ctx->strtab_offset = strtab_section.sh_offset;
ctx->strtab_size = strtab_section.sh_size;
}
} else if (section.sh_type == XM_ELF_SHT_SYMTAB) {
ctx->symtab_offset = section.sh_offset;
ctx->symtab_size = section.sh_size;
xm_elf64_section_t symstr_section;
if (tb_stream_seek(istream, base_offset + header.e_shoff + section.sh_link * sizeof(xm_elf64_section_t)) &&
tb_stream_bread(istream, (tb_byte_t*)&symstr_section, sizeof(symstr_section))) {
ctx->symstr_offset = symstr_section.sh_offset;
ctx->symstr_size = symstr_section.sh_size;
}
}
}
}
}
// fallback to program headers
if ((ctx->dynamic_offset == 0 || ctx->strtab_offset == 0) && header.e_phoff != 0 && header.e_phnum > 0) {
if (tb_stream_seek(istream, base_offset + header.e_phoff)) {
for (tb_uint16_t i = 0; i < header.e_phnum; i++) {
xm_elf64_phdr_t phdr;
if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;
if (phdr.p_type == XM_ELF_PT_DYNAMIC) {
ctx->dynamic_offset = phdr.p_offset;
ctx->dynamic_size = phdr.p_memsz;
break;
}
}
}
if (ctx->dynamic_offset > 0 && ctx->dynamic_size > 0) {
// read dynamic entries to find strtab address and size
tb_uint64_t strtab_vaddr = 0;
tb_uint64_t strtab_sz = 0;
tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / sizeof(xm_elf64_dynamic_t));
if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) {
for (tb_uint32_t i = 0; i < count; i++) {
xm_elf64_dynamic_t dyn;
if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;
if (dyn.d_tag == XM_ELF_DT_STRTAB) strtab_vaddr = dyn.d_un.d_val;
else if (dyn.d_tag == XM_ELF_DT_STRSZ) strtab_sz = dyn.d_un.d_val;
}
}
if (strtab_vaddr > 0) {
// map strtab vaddr to file offset using PT_LOAD
if (tb_stream_seek(istream, base_offset + header.e_phoff)) {
for (tb_uint16_t i = 0; i < header.e_phnum; i++) {
xm_elf64_phdr_t phdr;
if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;
if (phdr.p_type == XM_ELF_PT_LOAD && strtab_vaddr >= phdr.p_vaddr && strtab_vaddr < phdr.p_vaddr + phdr.p_memsz) {
ctx->strtab_offset = phdr.p_offset + (strtab_vaddr - phdr.p_vaddr);
ctx->strtab_size = strtab_sz;
break;
}
}
}
}
}
}
return (ctx->dynamic_offset != 0 && ctx->strtab_offset != 0);
}
// find PT_INTERP and read interpreter path (32-bit)
static __tb_inline__ tb_bool_t xm_binutils_elf_find_interp_32(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf32_header_t const* header, tb_char_t* name, tb_size_t size) {
if (header->e_phoff != 0 && header->e_phnum > 0) {
if (tb_stream_seek(istream, base_offset + header->e_phoff)) {
for (tb_uint16_t i = 0; i < header->e_phnum; i++) {
xm_elf32_phdr_t phdr;
if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;
if (phdr.p_type == XM_ELF_PT_INTERP) {
return xm_binutils_read_string(istream, base_offset + phdr.p_offset, name, size) && name[0];
}
}
}
}
return tb_false;
}
// find PT_INTERP and read interpreter path (64-bit)
static __tb_inline__ tb_bool_t xm_binutils_elf_find_interp_64(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf64_header_t const* header, tb_char_t* name, tb_size_t size) {
if (header->e_phoff != 0 && header->e_phnum > 0) {
if (tb_stream_seek(istream, base_offset + header->e_phoff)) {
for (tb_uint16_t i = 0; i < header->e_phnum; i++) {
xm_elf64_phdr_t phdr;
if (!tb_stream_bread(istream, (tb_byte_t*)&phdr, sizeof(phdr))) break;
if (phdr.p_type == XM_ELF_PT_INTERP) {
return xm_binutils_read_string(istream, base_offset + phdr.p_offset, name, size) && name[0];
}
}
}
}
return tb_false;
}
#endif
================================================
FILE: core/src/xmake/binutils/elf/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "readsyms_elf"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
tb_bool_t xm_binutils_elf_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// build context and ensure .symtab/.strtab are available
xm_elf_context_t ctx;
xm_binutils_elf_get_context_32(istream, base_offset, &ctx);
if (!ctx.symtab_offset || !ctx.symstr_offset) {
// no symbol table present: return empty result
lua_newtable(lua);
return tb_true;
}
// create result table
lua_newtable(lua);
// compute symbol count and seek to .symtab
tb_uint32_t sym_count = (tb_uint32_t)(ctx.symtab_size / sizeof(xm_elf32_symbol_t));
if (!tb_stream_seek(istream, base_offset + ctx.symtab_offset)) {
return tb_false;
}
tb_uint32_t result_count = 0;
for (tb_uint32_t i = 0; i < sym_count; i++) {
xm_elf32_symbol_t sym;
if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {
return tb_false;
}
// skip NULL symbol entries
if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) {
continue;
}
// skip section/file symbols
tb_uint8_t type = sym.st_info & 0xf;
if (type == 3 || type == 4) {
continue;
}
// read symbol name from .strtab
tb_char_t name[256];
if (!xm_binutils_read_string(istream, base_offset + ctx.symstr_offset + sym.st_name, name, sizeof(name)) || !name[0]) {
continue;
}
// skip internal ('.', '$') and local-defined symbols
if (name[0] == '.' || name[0] == '$') {
continue;
}
tb_uint8_t bind = (sym.st_info >> 4) & 0xf;
if (bind == 0 && sym.st_shndx != 0) {
continue;
}
// push symbol entry: name + nm-style type
lua_pushinteger(lua, result_count + 1);
lua_newtable(lua);
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx);
tb_char_t type_str[2] = {type_char, '\0'};
lua_pushstring(lua, "type");
lua_pushstring(lua, type_str);
lua_settable(lua, -3);
lua_settable(lua, -3);
result_count++;
}
return tb_true;
}
tb_bool_t xm_binutils_elf_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// build context and ensure .symtab/.strtab are available
xm_elf_context_t ctx;
xm_binutils_elf_get_context_64(istream, base_offset, &ctx);
if (!ctx.symtab_offset || !ctx.symstr_offset) {
// no symbol table present: return empty result
lua_newtable(lua);
return tb_true;
}
// create result table
lua_newtable(lua);
// compute symbol count and seek to .symtab
tb_uint32_t sym_count = (tb_uint32_t)(ctx.symtab_size / sizeof(xm_elf64_symbol_t));
if (!tb_stream_seek(istream, base_offset + ctx.symtab_offset)) {
return tb_false;
}
tb_uint32_t result_count = 0;
for (tb_uint32_t i = 0; i < sym_count; i++) {
xm_elf64_symbol_t sym;
if (!tb_stream_bread(istream, (tb_byte_t*)&sym, sizeof(sym))) {
return tb_false;
}
// skip NULL symbol entries
if (sym.st_name == 0 && sym.st_value == 0 && sym.st_size == 0) {
continue;
}
// skip section/file symbols
tb_uint8_t type = sym.st_info & 0xf;
if (type == 3 || type == 4) {
continue;
}
// read symbol name from .strtab
tb_char_t name[256];
if (!xm_binutils_read_string(istream, base_offset + ctx.symstr_offset + sym.st_name, name, sizeof(name)) || !name[0]) {
continue;
}
// skip internal ('.', '$') and local-defined symbols
if (name[0] == '.' || name[0] == '$') {
continue;
}
tb_uint8_t bind = (sym.st_info >> 4) & 0xf;
if (bind == 0 && sym.st_shndx != 0) {
continue;
}
// push symbol entry: name + nm-style type
lua_pushinteger(lua, result_count + 1);
lua_newtable(lua);
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
tb_char_t type_char = xm_binutils_elf_get_symbol_type_char(sym.st_info, sym.st_shndx);
tb_char_t type_str[2] = {type_char, '\0'};
lua_pushstring(lua, "type");
lua_pushstring(lua, type_str);
lua_settable(lua, -3);
lua_settable(lua, -3);
result_count++;
}
return tb_true;
}
tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// read and check ELF magic
tb_uint8_t magic[4];
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, magic, 4)) {
return tb_false;
}
if (magic[0] != 0x7f || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') {
return tb_false;
}
// check ELF class (32-bit or 64-bit)
tb_uint8_t elf_class;
if (!tb_stream_seek(istream, base_offset + 4)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&elf_class, 1)) {
return tb_false;
}
if (elf_class == 1) {
return xm_binutils_elf_read_symbols_32(istream, base_offset, lua);
} else if (elf_class == 2) {
return xm_binutils_elf_read_symbols_64(istream, base_offset, lua);
}
return tb_false;
}
================================================
FILE: core/src/xmake/binutils/elf/rpath.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rpath.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rpath_elf"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_binutils_elf_add_rpaths(lua_State *lua, tb_char_t const* rpath, tb_size_t* pcount) {
if (!rpath || !*rpath) return;
tb_char_t path[TB_PATH_MAXN];
tb_char_t const* p = rpath;
tb_char_t const* e = tb_null;
while (*p) {
e = tb_strchr(p, ':');
tb_size_t n = e ? (tb_size_t)(e - p) : tb_strlen(p);
if (n > 0) {
if (n > sizeof(path) - 1) n = sizeof(path) - 1;
tb_strncpy(path, p, n);
path[n] = '\0';
lua_pushinteger(lua, *pcount + 1);
lua_pushstring(lua, path);
lua_settable(lua, -3);
(*pcount)++;
}
if (e) p = e + 1;
else break;
}
}
// parse .dynamic section and read DT_RPATH/DT_RUNPATH to build rpath list
static tb_bool_t xm_binutils_elf_rpath_list_impl(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx, lua_State *lua) {
tb_bool_t ok = tb_false;
do {
tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / (ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t)));
if (!tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) break;
tb_char_t rpath[8192] = {0};
tb_char_t runpath[8192] = {0};
// scan dynamic entries
for (tb_uint32_t i = 0; i < count; i++) {
tb_hize_t val = 0;
tb_hize_t tag = 0;
if (ctx->is64) {
xm_elf64_dynamic_t dyn;
if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;
tag = dyn.d_tag;
val = dyn.d_un.d_val;
} else {
xm_elf32_dynamic_t dyn;
if (!tb_stream_bread(istream, (tb_byte_t*)&dyn, sizeof(dyn))) break;
tag = dyn.d_tag;
val = dyn.d_un.d_val;
}
if (tag == XM_ELF_DT_NULL) break;
// read rpath/runpath string from strtab
if (tag == XM_ELF_DT_RPATH) {
xm_binutils_read_string(istream, base_offset + ctx->strtab_offset + val, rpath, sizeof(rpath));
} else if (tag == XM_ELF_DT_RUNPATH) {
xm_binutils_read_string(istream, base_offset + ctx->strtab_offset + val, runpath, sizeof(runpath));
}
}
// split rpath(s) and push into Lua table
tb_size_t result_count = 0;
if (runpath[0]) {
xm_binutils_elf_add_rpaths(lua, runpath, &result_count);
} else if (rpath[0]) {
xm_binutils_elf_add_rpaths(lua, rpath, &result_count);
}
ok = tb_true;
} while (0);
return ok;
}
// remove DT_RPATH/DT_RUNPATH entries from .dynamic and write back
static tb_bool_t xm_binutils_elf_rpath_clean_impl(tb_stream_ref_t istream, tb_hize_t base_offset, xm_elf_context_t* ctx) {
tb_bool_t ok = tb_false;
tb_byte_t* buffer = tb_null;
do {
tb_uint32_t count = (tb_uint32_t)(ctx->dynamic_size / (ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t)));
// allocate buffer for all dynamic entries
tb_size_t dyn_size = (tb_size_t)ctx->dynamic_size;
buffer = (tb_byte_t*)tb_malloc(dyn_size);
if (!buffer) break;
if (!tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) break;
if (!tb_stream_bread(istream, buffer, dyn_size)) break;
// p: read pointer, w: write pointer after filtering
tb_byte_t* p = buffer;
tb_byte_t* w = buffer;
tb_size_t entry_size = ctx->is64 ? sizeof(xm_elf64_dynamic_t) : sizeof(xm_elf32_dynamic_t);
for (tb_uint32_t i = 0; i < count; i++) {
tb_hize_t tag = 0;
if (ctx->is64) {
tag = ((xm_elf64_dynamic_t*)p)->d_tag;
} else {
tag = ((xm_elf32_dynamic_t*)p)->d_tag;
}
if (tag == XM_ELF_DT_NULL) {
// copy NULL entry and stop
tb_memcpy(w, p, entry_size);
w += entry_size;
p += entry_size;
break;
}
// keep entries except rpath/runpath
if (tag != XM_ELF_DT_RPATH && tag != XM_ELF_DT_RUNPATH) {
if (w != p) tb_memcpy(w, p, entry_size);
w += entry_size;
}
p += entry_size;
}
// fill remaining with NULLs
if (w < buffer + dyn_size) {
tb_memset(w, 0, (buffer + dyn_size) - w);
}
// write back
if (tb_stream_seek(istream, base_offset + ctx->dynamic_offset)) {
tb_stream_bwrit(istream, buffer, dyn_size);
}
ok = tb_true;
} while (0);
if (buffer) tb_free(buffer);
return ok;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_bool_t xm_binutils_elf_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
tb_bool_t ok = tb_false;
do {
// read ident
tb_byte_t ident[16];
if (!tb_stream_seek(istream, base_offset)) break;
if (!tb_stream_bread(istream, ident, sizeof(ident))) break;
// build ELF context (dynamic, strtab offsets)
xm_elf_context_t ctx;
if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS32) {
if (xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) {
if (xm_binutils_elf_rpath_list_impl(istream, base_offset, &ctx, lua)) ok = tb_true;
}
} else if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS64) {
if (xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) {
if (xm_binutils_elf_rpath_list_impl(istream, base_offset, &ctx, lua)) ok = tb_true;
}
}
} while (0);
return ok;
}
tb_bool_t xm_binutils_elf_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset) {
tb_assert_and_check_return_val(istream, tb_false);
tb_bool_t ok = tb_false;
do {
// read ident
tb_byte_t ident[16];
if (!tb_stream_seek(istream, base_offset)) break;
if (!tb_stream_bread(istream, ident, sizeof(ident))) break;
// build ELF context and cleanup rpath entries
xm_elf_context_t ctx;
if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS32) {
if (xm_binutils_elf_get_context_32(istream, base_offset, &ctx)) {
if (xm_binutils_elf_rpath_clean_impl(istream, base_offset, &ctx)) ok = tb_true;
}
} else if (ident[XM_ELF_EI_CLASS] == XM_ELF_CLASS64) {
if (xm_binutils_elf_get_context_64(istream, base_offset, &ctx)) {
if (xm_binutils_elf_rpath_clean_impl(istream, base_offset, &ctx)) ok = tb_true;
}
}
} while (0);
return ok;
}
================================================
FILE: core/src/xmake/binutils/extractlib.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file extractlib.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "extractlib"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "ar/prefix.h"
#include "mslib/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* forward declarations
*/
extern tb_bool_t xm_binutils_ar_extract(tb_stream_ref_t istream, tb_char_t const *outputdir);
extern tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* extract static library to directory (Lua interface)
* Supports AR format (.a) and MSVC lib format (.lib)
*
* @param lua the lua state
*
* libraryfile = lua[1]
* outputdir = lua[2]
* plain = lua[3] (optional, default: true)
*
* @return 1 on success, 2 on failure (with error message)
*/
tb_int_t xm_binutils_extractlib(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the library file path
tb_char_t const *libraryfile = luaL_checkstring(lua, 1);
tb_check_return_val(libraryfile, 0);
// get the output directory
tb_char_t const *outputdir = luaL_checkstring(lua, 2);
tb_check_return_val(outputdir, 0);
// get the plain mode (optional)
tb_bool_t plain = tb_true;
if (lua_gettop(lua) >= 3 && !lua_isnil(lua, 3)) {
plain = lua_toboolean(lua, 3);
}
// open library file
tb_stream_ref_t istream = tb_stream_init_from_file(libraryfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "open %s failed", libraryfile);
return 2;
}
tb_bool_t ok = tb_false;
tb_char_t const* error_msg = tb_null;
do {
if (!tb_stream_open(istream)) {
error_msg = "open failed";
break;
}
// detect format
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
error_msg = "cannot detect format";
break;
}
// extract based on format
if (format == XM_BINUTILS_FORMAT_AR) {
// AR archive format (.a or .lib in AR format)
// if the file extension is .lib, we use the msvc lib extractor to support long paths and subdirectories
tb_size_t n = tb_strlen(libraryfile);
if (n > 4 && !tb_strnicmp(libraryfile + n - 4, ".lib", 4)) {
if (!xm_binutils_mslib_extract(istream, outputdir, plain)) {
error_msg = "extract MSVC lib failed";
break;
}
} else {
if (!xm_binutils_ar_extract(istream, outputdir)) {
error_msg = "extract AR archive failed";
break;
}
}
ok = tb_true;
} else if (format == XM_BINUTILS_FORMAT_COFF) {
// MSVC lib format (.lib in COFF format)
// Check if it's actually a library (not just a single object file)
// MSVC lib files can be:
// 1. Import libraries (different format)
// 2. Static libraries (COFF archive format, similar to AR but different)
if (!xm_binutils_mslib_extract(istream, outputdir, plain)) {
error_msg = "extract MSVC lib failed";
break;
}
ok = tb_true;
} else {
error_msg = "unsupported format (only AR and MSVC lib are supported)";
break;
}
} while (0);
if (istream) {
tb_stream_clos(istream);
tb_stream_exit(istream);
}
if (ok) {
lua_pushboolean(lua, tb_true);
return 1;
} else {
lua_pushboolean(lua, tb_false);
if (error_msg) {
lua_pushfstring(lua, "%s %s", error_msg, libraryfile);
} else {
lua_pushfstring(lua, "unknown error for %s", libraryfile);
}
return 2;
}
}
================================================
FILE: core/src/xmake/binutils/format.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file format.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "format"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
/* check PE by validating DOS header (MZ/ZM) and PE signature at e_lfanew
*
* note: unlike ELF/Mach-O/AR, PE needs an additional read/peek to locate the PE signature.
*/
static tb_bool_t xm_binutils_format_is_pe(tb_stream_ref_t istream, tb_byte_t* first8) {
tb_assert_and_check_return_val(istream && first8, tb_false);
tb_bool_t ok = tb_false;
do {
// fast reject: DOS magic
tb_check_break((first8[0] == 'M' && first8[1] == 'Z') || (first8[0] == 'Z' && first8[1] == 'M'));
// ensure we can read enough for DOS stub + PE signature
tb_hong_t size = tb_stream_size(istream);
if (size > 0 && size < XM_BINUTILS_PE_DOS_STUB_MIN_SIZE + 4) {
break;
}
// peek a bounded prefix to locate e_lfanew and PE\\0\\0 signature
tb_size_t max_peek = 4096;
if (size > 0) {
max_peek = (tb_size_t)tb_min((tb_hize_t)max_peek, (tb_hize_t)size);
}
tb_byte_t* p = tb_null;
if (!tb_stream_peek(istream, &p, max_peek)) {
break;
}
// e_lfanew points to PE signature offset
tb_uint32_t e_lfanew = tb_bits_get_u32_le(p + XM_BINUTILS_PE_DOS_ELFANEW_OFFSET);
tb_check_break(e_lfanew >= XM_BINUTILS_PE_DOS_STUB_MIN_SIZE);
tb_check_break((tb_size_t)e_lfanew + 4 <= max_peek);
tb_check_break(size <= 0 || (tb_hize_t)e_lfanew + 4 <= (tb_hize_t)size);
tb_byte_t const* signature = p + (tb_size_t)e_lfanew;
ok = (signature[0] == 'P' && signature[1] == 'E' && signature[2] == 0 && signature[3] == 0);
} while (0);
return ok;
}
// quick header checks from the first 8 bytes
static __tb_inline__ tb_bool_t xm_binutils_format_is_ar(tb_byte_t const* first8) {
return first8[0] == '!' && first8[1] == '<' && first8[2] == 'a' &&
first8[3] == 'r' && first8[4] == 'c' && first8[5] == 'h' &&
(first8[6] == '>' || first8[6] == '\n') &&
(first8[7] == '\n' || first8[7] == '\r');
}
static __tb_inline__ tb_bool_t xm_binutils_format_is_shebang(tb_byte_t const* first2) {
return first2[0] == '#' && first2[1] == '!';
}
static __tb_inline__ tb_bool_t xm_binutils_format_is_ape(tb_byte_t const* first8) {
return first8[0] == 'M' && first8[1] == 'Z' &&
first8[2] == 'q' && first8[3] == 'F' &&
first8[4] == 'p' && first8[5] == 'D';
}
static __tb_inline__ tb_bool_t xm_binutils_format_is_wasm(tb_byte_t const* first8) {
return first8[0] == 0x00 && first8[1] == 0x61 && first8[2] == 0x73 && first8[3] == 0x6d;
}
static __tb_inline__ tb_bool_t xm_binutils_format_is_elf(tb_byte_t const* first8) {
return first8[0] == 0x7f && first8[1] == 'E' && first8[2] == 'L' && first8[3] == 'F';
}
static __tb_inline__ tb_bool_t xm_binutils_format_is_macho(tb_byte_t const* first8) {
return (first8[0] == 0xfe && first8[1] == 0xed && first8[2] == 0xfa && (first8[3] == 0xce || first8[3] == 0xcf)) ||
(first8[0] == 0xce && first8[1] == 0xfa && first8[2] == 0xed && first8[3] == 0xfe) ||
(first8[0] == 0xcf && first8[1] == 0xfa && first8[2] == 0xed && first8[3] == 0xfe);
}
static __tb_inline__ tb_bool_t xm_binutils_format_is_coff(tb_byte_t const* first8) {
tb_uint16_t machine = tb_bits_get_u16_le(first8);
if (machine == 0x0000) {
tb_uint16_t machine2 = tb_bits_get_u16_le(first8 + 2);
if (machine2 == 0xffff) {
return tb_true;
}
}
return machine == XM_BINUTILS_COFF_MACHINE_I386 ||
machine == XM_BINUTILS_COFF_MACHINE_AMD64 ||
machine == XM_BINUTILS_COFF_MACHINE_ARM ||
machine == XM_BINUTILS_COFF_MACHINE_ARM64;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* detect object file format from stream
*
* @param istream the input stream
* @return XM_BINUTILS_FORMAT_COFF, XM_BINUTILS_FORMAT_ELF, XM_BINUTILS_FORMAT_MACHO,
* XM_BINUTILS_FORMAT_AR, XM_BINUTILS_FORMAT_PE, XM_BINUTILS_FORMAT_UNKNOWN, or -1 on error
*/
tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream) {
tb_assert_and_check_return_val(istream, -1);
tb_assert_and_check_return_val(tb_stream_offset(istream) == 0, -1);
tb_int_t format = -1;
do {
tb_byte_t* p2 = tb_null;
if (!tb_stream_peek(istream, &p2, 2)) {
tb_hong_t size = tb_stream_size(istream);
if (size > 0 && size < 2) {
format = XM_BINUTILS_FORMAT_UNKNOWN;
}
break;
}
if (xm_binutils_format_is_shebang(p2)) {
format = XM_BINUTILS_FORMAT_SHEBANG;
break;
}
tb_byte_t* p = tb_null;
if (!tb_stream_peek(istream, &p, 8)) {
tb_hong_t size = tb_stream_size(istream);
if (size > 0 && size < 8) {
format = XM_BINUTILS_FORMAT_UNKNOWN;
}
break;
}
if (xm_binutils_format_is_ar(p)) {
format = XM_BINUTILS_FORMAT_AR;
break;
}
if (xm_binutils_format_is_ape(p)) {
format = XM_BINUTILS_FORMAT_APE;
break;
}
if (xm_binutils_format_is_wasm(p)) {
format = XM_BINUTILS_FORMAT_WASM;
break;
}
if (xm_binutils_format_is_elf(p)) {
format = XM_BINUTILS_FORMAT_ELF;
break;
}
if (xm_binutils_format_is_macho(p)) {
format = XM_BINUTILS_FORMAT_MACHO;
break;
}
if (xm_binutils_format_is_pe(istream, p)) {
format = XM_BINUTILS_FORMAT_PE;
break;
}
if (xm_binutils_format_is_coff(p)) {
format = XM_BINUTILS_FORMAT_COFF;
break;
}
format = XM_BINUTILS_FORMAT_UNKNOWN;
} while (0);
return format;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* lua implementation
*/
/* get binary file format (auto-detect format)
*
* local format, errors = binutils.format(filepath)
*/
tb_int_t xm_binutils_format(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binary file path
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// open file
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushnil(lua);
lua_pushfstring(lua, "open %s failed", binaryfile);
return 2;
}
tb_bool_t ok = tb_false;
do {
if (!tb_stream_open(istream)) {
lua_pushnil(lua);
lua_pushfstring(lua, "open %s failed", binaryfile);
break;
}
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushnil(lua);
lua_pushliteral(lua, "cannot detect file format");
break;
}
switch (format) {
case XM_BINUTILS_FORMAT_COFF: lua_pushliteral(lua, "coff"); break;
case XM_BINUTILS_FORMAT_ELF: lua_pushliteral(lua, "elf"); break;
case XM_BINUTILS_FORMAT_MACHO: lua_pushliteral(lua, "macho"); break;
case XM_BINUTILS_FORMAT_AR: lua_pushliteral(lua, "ar"); break;
case XM_BINUTILS_FORMAT_PE: lua_pushliteral(lua, "pe"); break;
case XM_BINUTILS_FORMAT_SHEBANG: lua_pushliteral(lua, "shebang"); break;
case XM_BINUTILS_FORMAT_APE: lua_pushliteral(lua, "ape"); break;
case XM_BINUTILS_FORMAT_WASM: lua_pushliteral(lua, "wasm"); break;
default: lua_pushliteral(lua, "unknown"); break;
}
ok = tb_true;
} while (0);
if (istream) {
tb_stream_exit(istream);
}
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/macho/bin2macho.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bin2macho.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bin2macho"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_binutils_bin2macho_dump_64(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_char_t const *symbol_prefix,
tb_char_t const *plat,
tb_char_t const *arch,
tb_char_t const *basename,
tb_uint32_t minos,
tb_uint32_t sdk,
tb_bool_t zeroend) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
// get file size
tb_hong_t filesize = tb_stream_size(istream);
if (filesize < 0 || filesize > 0xffffffffU) {
return tb_false;
}
tb_uint32_t datasize = (tb_uint32_t)filesize;
// add null terminator if zeroend is true
if (zeroend) {
if (datasize >= 0xffffffffU) {
return tb_false; // would overflow
}
datasize++;
}
// generate symbol names from filename
tb_char_t symbol_name[256] = {0};
tb_char_t symbol_start[256] = {0};
tb_char_t symbol_end[256] = {0};
// use basename or default to "data"
if (!basename || !basename[0]) {
basename = "data";
}
// build symbol name
// On macOS, C compiler adds an underscore prefix, so we generate symbols with two underscores
// (C code declares _binary_xxx, compiler generates __binary_xxx in object file, so we define __binary_xxx)
if (symbol_prefix) {
tb_snprintf(symbol_name, sizeof(symbol_name), "_%s%s", symbol_prefix, basename);
} else {
tb_snprintf(symbol_name, sizeof(symbol_name), "__binary_%s", basename);
}
// replace non-alphanumeric with underscore
xm_binutils_sanitize_symbol_name(symbol_name);
tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name);
tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name);
// calculate offsets
tb_uint32_t header_size = sizeof(xm_macho_header_64_t);
tb_uint32_t segment_cmd_size = sizeof(xm_macho_segment_command_64_t);
tb_uint32_t section_size = sizeof(xm_macho_section_64_t);
tb_uint32_t symtab_cmd_size = sizeof(xm_macho_symtab_command_t);
tb_uint32_t build_version_cmd_size = sizeof(xm_macho_build_version_command_t);
tb_uint32_t segment_cmd_total_size = segment_cmd_size + section_size;
tb_uint32_t data_offset = xm_binutils_macho_align(header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size, 8);
tb_uint32_t data_size = datasize;
tb_uint32_t data_end_offset = data_offset + data_size;
tb_uint32_t symtab_offset = xm_binutils_macho_align(data_end_offset, 8);
tb_uint32_t nlist_size = sizeof(xm_macho_nlist_64_t);
tb_uint32_t nlist_count = 2; // start, end
tb_uint32_t strtab_offset = symtab_offset + nlist_size * nlist_count;
tb_uint32_t strtab_size = 4; // initial 4-byte size field
tb_size_t start_len = tb_strlen(symbol_start);
tb_size_t end_len = tb_strlen(symbol_end);
strtab_size += (tb_uint32_t)(start_len + 1);
strtab_size += (tb_uint32_t)(end_len + 1);
strtab_size = xm_binutils_macho_align(strtab_size, 8);
// write Mach-O header
xm_macho_header_64_t header;
tb_memset(&header, 0, sizeof(header));
header.magic = XM_MACHO_MAGIC_64;
header.cputype = xm_binutils_macho_get_cputype(arch);
header.cpusubtype = xm_binutils_macho_get_cpusubtype(arch);
header.filetype = XM_MACHO_FILE_TYPE_OBJECT;
header.ncmds = 3; // segment + symtab + build_version
header.sizeofcmds = segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size;
header.flags = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {
return tb_false;
}
// write segment command
xm_macho_segment_command_64_t segment;
tb_memset(&segment, 0, sizeof(segment));
segment.cmd = XM_MACHO_LC_SEGMENT_64;
segment.cmdsize = segment_cmd_total_size;
tb_strncpy(segment.segname, "__TEXT", 16);
segment.vmaddr = 0;
segment.vmsize = data_size;
segment.fileoff = data_offset;
segment.filesize = data_size;
segment.maxprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)
segment.initprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)
segment.nsects = 1;
segment.flags = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&segment, sizeof(segment))) {
return tb_false;
}
// write section
xm_macho_section_64_t section;
tb_memset(§ion, 0, sizeof(section));
tb_strncpy(section.sectname, "__const", 16);
tb_strncpy(section.segname, "__TEXT", 16);
section.addr = 0;
section.size = data_size;
section.offset = data_offset;
section.align = 3; // 2^3 = 8 bytes
section.reloff = 0;
section.nreloc = 0;
section.flags = XM_MACHO_SECT_TYPE_REGULAR | XM_MACHO_SECT_ATTR_SOME_INITS;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion, sizeof(section))) {
return tb_false;
}
// write symtab command
xm_macho_symtab_command_t symtab;
tb_memset(&symtab, 0, sizeof(symtab));
symtab.cmd = XM_MACHO_LC_SYMTAB;
symtab.cmdsize = symtab_cmd_size;
symtab.symoff = symtab_offset;
symtab.nsyms = nlist_count;
symtab.stroff = strtab_offset;
symtab.strsize = strtab_size;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&symtab, sizeof(symtab))) {
return tb_false;
}
// write build version command
xm_macho_build_version_command_t build_version;
tb_memset(&build_version, 0, sizeof(build_version));
build_version.cmd = XM_MACHO_LC_BUILD_VERSION;
build_version.cmdsize = build_version_cmd_size;
build_version.platform = xm_binutils_macho_get_platform(plat);
build_version.minos = minos;
build_version.sdk = sdk;
build_version.ntools = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&build_version, sizeof(build_version))) {
return tb_false;
}
// align to 8 bytes
tb_uint32_t padding = data_offset - (header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size);
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write section data
if (!xm_binutils_stream_copy(istream, ostream, filesize)) {
return tb_false;
}
// append null terminator if zeroend is true
if (zeroend) {
tb_byte_t zero = 0;
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
// align to 8 bytes
padding = symtab_offset - data_end_offset;
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write symbol table
// strx starts from 4 (after 4-byte size field)
tb_uint32_t strx = 4;
// symbol 0: _binary_xxx_start
xm_macho_nlist_64_t nlist_start;
tb_memset(&nlist_start, 0, sizeof(nlist_start));
nlist_start.strx = strx;
nlist_start.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT
nlist_start.sect = 1;
nlist_start.desc = 0;
nlist_start.value = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_start, sizeof(nlist_start))) {
return tb_false;
}
strx += (tb_uint32_t)(start_len + 1);
// symbol 1: _binary_xxx_end
xm_macho_nlist_64_t nlist_end;
tb_memset(&nlist_end, 0, sizeof(nlist_end));
nlist_end.strx = strx;
nlist_end.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT
nlist_end.sect = 1;
nlist_end.desc = 0;
nlist_end.value = data_size;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_end, sizeof(nlist_end))) {
return tb_false;
}
strx += (tb_uint32_t)(end_len + 1);
// align to 8 bytes
padding = strtab_offset - (symtab_offset + nlist_size * nlist_count);
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write string table
tb_stream_bwrit(ostream, (tb_byte_t const *)&strtab_size, 4);
tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len);
tb_byte_t null = 0;
tb_stream_bwrit(ostream, &null, 1);
tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len);
tb_stream_bwrit(ostream, &null, 1);
// align string table to 8 bytes
padding = strtab_size - (4 + (tb_uint32_t)start_len + 1 + (tb_uint32_t)end_len + 1);
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
return tb_true;
}
static tb_bool_t xm_binutils_bin2macho_dump_32(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_char_t const *symbol_prefix,
tb_char_t const *plat,
tb_char_t const *arch,
tb_char_t const *basename,
tb_uint32_t minos,
tb_uint32_t sdk,
tb_bool_t zeroend) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
// get file size
tb_hong_t filesize = tb_stream_size(istream);
if (filesize < 0 || filesize > 0xffffffffU) {
return tb_false;
}
tb_uint32_t datasize = (tb_uint32_t)filesize;
// add null terminator if zeroend is true
if (zeroend) {
if (datasize >= 0xffffffffU) {
return tb_false; // would overflow
}
datasize++;
}
// generate symbol names from filename
tb_char_t symbol_name[256] = {0};
tb_char_t symbol_start[256] = {0};
tb_char_t symbol_end[256] = {0};
// use basename or default to "data"
if (!basename || !basename[0]) {
basename = "data";
}
// build symbol name
// On macOS, C compiler adds an underscore prefix, so we generate symbols with two underscores
// (C code declares _binary_xxx, compiler generates __binary_xxx in object file, so we define __binary_xxx)
if (symbol_prefix) {
tb_snprintf(symbol_name, sizeof(symbol_name), "_%s%s", symbol_prefix, basename);
} else {
tb_snprintf(symbol_name, sizeof(symbol_name), "__binary_%s", basename);
}
// replace non-alphanumeric with underscore
xm_binutils_sanitize_symbol_name(symbol_name);
tb_snprintf(symbol_start, sizeof(symbol_start), "%s_start", symbol_name);
tb_snprintf(symbol_end, sizeof(symbol_end), "%s_end", symbol_name);
// calculate offsets
tb_uint32_t header_size = sizeof(xm_macho_header_32_t);
tb_uint32_t segment_cmd_size = sizeof(xm_macho_segment_command_t);
tb_uint32_t section_size = sizeof(xm_macho_section_t);
tb_uint32_t symtab_cmd_size = sizeof(xm_macho_symtab_command_t);
tb_uint32_t build_version_cmd_size = sizeof(xm_macho_build_version_command_t);
tb_uint32_t segment_cmd_total_size = segment_cmd_size + section_size;
tb_uint32_t data_offset = xm_binutils_macho_align(header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size, 4);
tb_uint32_t data_size = datasize;
tb_uint32_t data_end_offset = data_offset + data_size;
tb_uint32_t symtab_offset = xm_binutils_macho_align(data_end_offset, 4);
tb_uint32_t nlist_size = sizeof(xm_macho_nlist_t);
tb_uint32_t nlist_count = 2; // start, end
tb_uint32_t strtab_offset = symtab_offset + nlist_size * nlist_count;
tb_uint32_t strtab_size = 4; // initial 4-byte size field
tb_size_t start_len = tb_strlen(symbol_start);
tb_size_t end_len = tb_strlen(symbol_end);
strtab_size += (tb_uint32_t)(start_len + 1);
strtab_size += (tb_uint32_t)(end_len + 1);
strtab_size = xm_binutils_macho_align(strtab_size, 4);
// write Mach-O header
xm_macho_header_32_t header;
tb_memset(&header, 0, sizeof(header));
header.magic = XM_MACHO_MAGIC_32;
header.cputype = xm_binutils_macho_get_cputype(arch);
header.cpusubtype = xm_binutils_macho_get_cpusubtype(arch);
header.filetype = XM_MACHO_FILE_TYPE_OBJECT;
header.ncmds = 3; // segment + symtab + build_version
header.sizeofcmds = segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size;
header.flags = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&header, sizeof(header))) {
return tb_false;
}
// write segment command
xm_macho_segment_command_t segment;
tb_memset(&segment, 0, sizeof(segment));
segment.cmd = XM_MACHO_LC_SEGMENT;
segment.cmdsize = segment_cmd_total_size;
tb_strncpy(segment.segname, "__TEXT", 16);
segment.vmaddr = 0;
segment.vmsize = data_size;
segment.fileoff = data_offset;
segment.filesize = data_size;
segment.maxprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)
segment.initprot = XM_MACHO_VM_PROT_READ | XM_MACHO_VM_PROT_EXECUTE; // VM_PROT_READ | VM_PROT_EXECUTE (r-x)
segment.nsects = 1;
segment.flags = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&segment, sizeof(segment))) {
return tb_false;
}
// write section
xm_macho_section_t section;
tb_memset(§ion, 0, sizeof(section));
tb_strncpy(section.sectname, "__const", 16);
tb_strncpy(section.segname, "__TEXT", 16);
section.addr = 0;
section.size = data_size;
section.offset = data_offset;
section.align = 2; // 2^2 = 4 bytes
section.reloff = 0;
section.nreloc = 0;
section.flags = XM_MACHO_SECT_TYPE_REGULAR | XM_MACHO_SECT_ATTR_SOME_INITS;
section.reserved1 = 0;
section.reserved2 = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)§ion, sizeof(section))) {
return tb_false;
}
// write symtab command
xm_macho_symtab_command_t symtab;
tb_memset(&symtab, 0, sizeof(symtab));
symtab.cmd = XM_MACHO_LC_SYMTAB;
symtab.cmdsize = symtab_cmd_size;
symtab.symoff = symtab_offset;
symtab.nsyms = nlist_count;
symtab.stroff = strtab_offset;
symtab.strsize = strtab_size;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&symtab, sizeof(symtab))) {
return tb_false;
}
// write build version command
xm_macho_build_version_command_t build_version;
tb_memset(&build_version, 0, sizeof(build_version));
build_version.cmd = XM_MACHO_LC_BUILD_VERSION;
build_version.cmdsize = build_version_cmd_size;
build_version.platform = xm_binutils_macho_get_platform(plat);
build_version.minos = minos;
build_version.sdk = sdk;
build_version.ntools = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&build_version, sizeof(build_version))) {
return tb_false;
}
// align to 4 bytes
tb_uint32_t padding = data_offset - (header_size + segment_cmd_total_size + symtab_cmd_size + build_version_cmd_size);
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write section data
if (!xm_binutils_stream_copy(istream, ostream, filesize)) {
return tb_false;
}
// append null terminator if zeroend is true
if (zeroend) {
tb_byte_t zero = 0;
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
// align to 4 bytes
padding = symtab_offset - data_end_offset;
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write symbol table
// strx starts from 4 (after 4-byte size field)
tb_uint32_t strx = 4;
// symbol 0: _binary_xxx_start
xm_macho_nlist_t nlist_start;
tb_memset(&nlist_start, 0, sizeof(nlist_start));
nlist_start.strx = strx;
nlist_start.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT
nlist_start.sect = 1;
nlist_start.desc = 0;
nlist_start.value = 0;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_start, sizeof(nlist_start))) {
return tb_false;
}
strx += (tb_uint32_t)(start_len + 1);
// symbol 1: _binary_xxx_end
xm_macho_nlist_t nlist_end;
tb_memset(&nlist_end, 0, sizeof(nlist_end));
nlist_end.strx = strx;
nlist_end.type = XM_MACHO_N_TYPE_SECT | XM_MACHO_N_EXT; // N_SECT | N_EXT
nlist_end.sect = 1;
nlist_end.desc = 0;
nlist_end.value = data_size;
if (!tb_stream_bwrit(ostream, (tb_byte_t const *)&nlist_end, sizeof(nlist_end))) {
return tb_false;
}
strx += (tb_uint32_t)(end_len + 1);
// align to 4 bytes
padding = strtab_offset - (symtab_offset + nlist_size * nlist_count);
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
// write string table
tb_stream_bwrit(ostream, (tb_byte_t const *)&strtab_size, 4);
tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_start, start_len);
tb_byte_t null = 0;
tb_stream_bwrit(ostream, &null, 1);
tb_stream_bwrit(ostream, (tb_byte_t const *)symbol_end, end_len);
tb_stream_bwrit(ostream, &null, 1);
// align string table to 4 bytes
padding = strtab_size - (4 + (tb_uint32_t)start_len + 1 + (tb_uint32_t)end_len + 1);
if (padding > 0) {
tb_byte_t zero = 0;
while (padding-- > 0) {
if (!tb_stream_bwrit(ostream, &zero, 1)) {
return tb_false;
}
}
}
return tb_true;
}
static tb_bool_t xm_binutils_bin2macho_dump(tb_stream_ref_t istream,
tb_stream_ref_t ostream,
tb_char_t const *symbol_prefix,
tb_char_t const *plat,
tb_char_t const *arch,
tb_char_t const *basename,
tb_uint32_t minos,
tb_uint32_t sdk,
tb_bool_t zeroend) {
if (xm_binutils_macho_is_64bit(arch)) {
return xm_binutils_bin2macho_dump_64(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend);
} else {
return xm_binutils_bin2macho_dump_32(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend);
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* generate Mach-O object file from binary file
*
* local ok, errors = binutils.bin2macho(binaryfile, outputfile, symbol_prefix, plat, arch, basename)
*/
tb_int_t xm_binutils_bin2macho(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binaryfile
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// get the outputfile
tb_char_t const *outputfile = luaL_checkstring(lua, 2);
tb_check_return_val(outputfile, 0);
// get symbol prefix (optional)
tb_char_t const *symbol_prefix = lua_isstring(lua, 3) ? lua_tostring(lua, 3) : tb_null;
// get plat (optional)
tb_char_t const *plat = lua_isstring(lua, 4) ? lua_tostring(lua, 4) : tb_null;
// get arch (optional)
tb_char_t const *arch = lua_isstring(lua, 5) ? lua_tostring(lua, 5) : tb_null;
// get basename (optional)
tb_char_t const *basename = lua_isstring(lua, 6) ? lua_tostring(lua, 6) : tb_null;
// get minos version string (optional)
tb_char_t const *minos_str = lua_isstring(lua, 7) ? lua_tostring(lua, 7) : tb_null;
tb_uint32_t minos = xm_binutils_macho_parse_version(minos_str);
// get sdk version string (optional)
tb_char_t const *sdk_str = lua_isstring(lua, 8) ? lua_tostring(lua, 8) : tb_null;
tb_uint32_t sdk = xm_binutils_macho_parse_version(sdk_str);
// get zeroend (optional, default: false)
tb_bool_t zeroend = lua_toboolean(lua, 9);
// do dump
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
tb_stream_ref_t ostream = tb_stream_init_from_file(outputfile,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2macho: open %s failed", binaryfile);
break;
}
if (!tb_stream_open(ostream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2macho: open %s failed", outputfile);
break;
}
if (!xm_binutils_bin2macho_dump(istream, ostream, symbol_prefix, plat, arch, basename, minos, sdk, zeroend)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "bin2macho: dump data failed");
break;
}
ok = tb_true;
lua_pushboolean(lua, ok);
} while (0);
if (istream) {
tb_stream_clos(istream);
}
istream = tb_null;
if (ostream) {
tb_stream_clos(ostream);
}
ostream = tb_null;
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/macho/deplibs.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file deplibs.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "deplibs_macho"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_bool_t xm_binutils_macho_deplibs(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// init Mach-O context
xm_macho_context_t context;
if (!xm_binutils_macho_context_init(istream, base_offset, &context)) {
return tb_false;
}
// skip header to reach load commands
tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t);
if (!tb_stream_seek(istream, base_offset + header_size)) {
return tb_false;
}
lua_newtable(lua);
tb_size_t result_count = 0;
// iterate load commands
for (tb_uint32_t i = 0; i < context.ncmds; i++) {
xm_macho_load_command_t lc;
tb_hize_t current_cmd_offset = tb_stream_offset(istream);
if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) {
return tb_false;
}
xm_binutils_macho_swap_load_command(&lc, context.swap);
// check for LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_ID_DYLIB
if (lc.cmd == XM_MACHO_LC_LOAD_DYLIB || lc.cmd == XM_MACHO_LC_ID_DYLIB ||
lc.cmd == XM_MACHO_LC_LOAD_WEAK_DYLIB || lc.cmd == XM_MACHO_LC_REEXPORT_DYLIB) {
xm_macho_dylib_command_t dc;
if (tb_stream_seek(istream, current_cmd_offset)) {
if (tb_stream_bread(istream, (tb_byte_t*)&dc, sizeof(dc))) {
xm_binutils_macho_swap_dylib_command(&dc, context.swap);
tb_uint32_t name_offset = dc.dylib.offset;
if (name_offset < lc.cmdsize) {
// name is at current_cmd_offset + name_offset
if (tb_stream_seek(istream, current_cmd_offset + name_offset)) {
tb_char_t dylib_path[1024];
tb_size_t max_len = lc.cmdsize - name_offset;
if (max_len > sizeof(dylib_path) - 1) max_len = sizeof(dylib_path) - 1;
tb_size_t pos = 0;
tb_byte_t c;
while (pos < max_len) {
if (!tb_stream_bread(istream, &c, 1)) break;
if (c == 0) break;
dylib_path[pos++] = (tb_char_t)c;
}
dylib_path[pos] = '\0';
if (pos > 0) {
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, dylib_path);
lua_settable(lua, -3);
result_count++;
}
}
}
}
}
}
// move to next command
if (!tb_stream_seek(istream, current_cmd_offset + lc.cmdsize)) {
break;
}
}
return tb_true;
}
================================================
FILE: core/src/xmake/binutils/macho/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_MACHO_PREFIX_H
#define XM_BINUTILS_MACHO_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_MACHO_MAGIC_32 0xfeedface // MH_MAGIC - little endian
#define XM_MACHO_MAGIC_64 0xfeedfacf // MH_MAGIC_64 - little endian
#define XM_MACHO_MAGIC_32_BE 0xcefaedfe // MH_CIGAM - big endian
#define XM_MACHO_MAGIC_64_BE 0xcffaedfe // MH_CIGAM_64 - big endian
#define XM_MACHO_MAGIC_FAT 0xcafebabe
#define XM_MACHO_CPU_TYPE_X86 7
#define XM_MACHO_CPU_TYPE_X86_64 0x01000007
#define XM_MACHO_CPU_TYPE_ARM 12
#define XM_MACHO_CPU_TYPE_ARM64 0x0100000c
#define XM_MACHO_CPU_SUBTYPE_X86 3
#define XM_MACHO_CPU_SUBTYPE_X86_64 3
#define XM_MACHO_CPU_SUBTYPE_ARM 9
#define XM_MACHO_CPU_SUBTYPE_ARM64 0
#define XM_MACHO_FILE_TYPE_OBJECT 1
#define XM_MACHO_LC_SEGMENT 0x1
#define XM_MACHO_LC_SEGMENT_64 0x19
#define XM_MACHO_LC_SYMTAB 0x2
#define XM_MACHO_LC_LOAD_DYLIB 0xc
#define XM_MACHO_LC_ID_DYLIB 0xd
#define XM_MACHO_LC_RPATH (0x1c | 0x80000000)
#define XM_MACHO_LC_LOAD_WEAK_DYLIB (0x18 | 0x80000000)
#define XM_MACHO_LC_REEXPORT_DYLIB (0x1f | 0x80000000)
#define XM_MACHO_LC_BUILD_VERSION 0x32
#define XM_MACHO_PLATFORM_MACOS 1
#define XM_MACHO_PLATFORM_IOS 2
#define XM_MACHO_PLATFORM_TVOS 3
#define XM_MACHO_PLATFORM_WATCHOS 4
#define XM_MACHO_SECT_TYPE_REGULAR 0x0
#define XM_MACHO_SECT_ATTR_SOME_INITS 0x400
#define XM_MACHO_SECT_ATTR_PURE_INSTRUCTIONS 0x80000000
#define XM_MACHO_N_TYPE_MASK 0x0e
#define XM_MACHO_N_TYPE_SECT 0x0e
#define XM_MACHO_N_EXT 0x01
#define XM_MACHO_VM_PROT_READ 1
#define XM_MACHO_VM_PROT_WRITE 2
#define XM_MACHO_VM_PROT_EXECUTE 4
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
#include "tbox/prefix/packed.h"
typedef struct __xm_macho_header_32_t {
tb_uint32_t magic;
tb_uint32_t cputype;
tb_uint32_t cpusubtype;
tb_uint32_t filetype;
tb_uint32_t ncmds;
tb_uint32_t sizeofcmds;
tb_uint32_t flags;
} __tb_packed__ xm_macho_header_32_t;
typedef struct __xm_macho_header_64_t {
tb_uint32_t magic;
tb_uint32_t cputype;
tb_uint32_t cpusubtype;
tb_uint32_t filetype;
tb_uint32_t ncmds;
tb_uint32_t sizeofcmds;
tb_uint32_t flags;
tb_uint32_t reserved;
} __tb_packed__ xm_macho_header_64_t;
typedef struct __xm_macho_rpath_command_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
tb_uint32_t path_offset;
} __tb_packed__ xm_macho_rpath_command_t;
typedef struct __xm_macho_segment_command_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
tb_char_t segname[16];
tb_uint32_t vmaddr;
tb_uint32_t vmsize;
tb_uint32_t fileoff;
tb_uint32_t filesize;
tb_uint32_t maxprot;
tb_uint32_t initprot;
tb_uint32_t nsects;
tb_uint32_t flags;
} __tb_packed__ xm_macho_segment_command_t;
typedef struct __xm_macho_segment_command_64_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
tb_char_t segname[16];
tb_uint64_t vmaddr;
tb_uint64_t vmsize;
tb_uint64_t fileoff;
tb_uint64_t filesize;
tb_uint32_t maxprot;
tb_uint32_t initprot;
tb_uint32_t nsects;
tb_uint32_t flags;
} __tb_packed__ xm_macho_segment_command_64_t;
typedef struct __xm_macho_section_t {
tb_char_t sectname[16];
tb_char_t segname[16];
tb_uint32_t addr;
tb_uint32_t size;
tb_uint32_t offset;
tb_uint32_t align;
tb_uint32_t reloff;
tb_uint32_t nreloc;
tb_uint32_t flags;
tb_uint32_t reserved1;
tb_uint32_t reserved2;
} __tb_packed__ xm_macho_section_t;
typedef struct __xm_macho_section_64_t {
tb_char_t sectname[16];
tb_char_t segname[16];
tb_uint64_t addr;
tb_uint64_t size;
tb_uint32_t offset;
tb_uint32_t align;
tb_uint32_t reloff;
tb_uint32_t nreloc;
tb_uint32_t flags;
tb_uint32_t reserved1;
tb_uint32_t reserved2;
tb_uint32_t reserved3;
} __tb_packed__ xm_macho_section_64_t;
typedef struct __xm_macho_symtab_command_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
tb_uint32_t symoff;
tb_uint32_t nsyms;
tb_uint32_t stroff;
tb_uint32_t strsize;
} __tb_packed__ xm_macho_symtab_command_t;
typedef struct __xm_macho_build_version_command_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
tb_uint32_t platform;
tb_uint32_t minos;
tb_uint32_t sdk;
tb_uint32_t ntools;
} __tb_packed__ xm_macho_build_version_command_t;
typedef struct __xm_macho_nlist_t {
tb_uint32_t strx;
tb_uint8_t type;
tb_uint8_t sect;
tb_int16_t desc;
tb_uint32_t value;
} __tb_packed__ xm_macho_nlist_t;
typedef struct __xm_macho_nlist_64_t {
tb_uint32_t strx;
tb_uint8_t type;
tb_uint8_t sect;
tb_uint16_t desc;
tb_uint64_t value;
} __tb_packed__ xm_macho_nlist_64_t;
typedef struct __xm_macho_load_command_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
} __tb_packed__ xm_macho_load_command_t;
typedef struct __xm_macho_dylib_t {
tb_uint32_t offset;
tb_uint32_t timestamp;
tb_uint32_t current_version;
tb_uint32_t compatibility_version;
} __tb_packed__ xm_macho_dylib_t;
typedef struct __xm_macho_dylib_command_t {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
xm_macho_dylib_t dylib;
} __tb_packed__ xm_macho_dylib_command_t;
typedef struct __xm_macho_context_t {
union {
xm_macho_header_32_t header32;
xm_macho_header_64_t header64;
} header;
tb_bool_t is64;
tb_bool_t swap;
tb_uint32_t ncmds;
tb_uint32_t sizeofcmds;
} __tb_packed__ xm_macho_context_t;
#include "tbox/prefix/packed.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
// byte-swap Mach-O header fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_header_32(xm_macho_header_32_t *header, tb_bool_t swap) {
if (swap) {
header->magic = tb_bits_swap_u32(header->magic);
header->cputype = tb_bits_swap_u32(header->cputype);
header->cpusubtype = tb_bits_swap_u32(header->cpusubtype);
header->filetype = tb_bits_swap_u32(header->filetype);
header->ncmds = tb_bits_swap_u32(header->ncmds);
header->sizeofcmds = tb_bits_swap_u32(header->sizeofcmds);
header->flags = tb_bits_swap_u32(header->flags);
}
}
// byte-swap Mach-O header 64 fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_header_64(xm_macho_header_64_t *header, tb_bool_t swap) {
if (swap) {
header->magic = tb_bits_swap_u32(header->magic);
header->cputype = tb_bits_swap_u32(header->cputype);
header->cpusubtype = tb_bits_swap_u32(header->cpusubtype);
header->filetype = tb_bits_swap_u32(header->filetype);
header->ncmds = tb_bits_swap_u32(header->ncmds);
header->sizeofcmds = tb_bits_swap_u32(header->sizeofcmds);
header->flags = tb_bits_swap_u32(header->flags);
header->reserved = tb_bits_swap_u32(header->reserved);
}
}
// init Mach-O context
static __tb_inline__ tb_bool_t xm_binutils_macho_context_init(tb_stream_ref_t istream, tb_hize_t base_offset, xm_macho_context_t* context) {
tb_assert_and_check_return_val(istream && context, tb_false);
// read Mach-O header
if (!tb_stream_seek(istream, base_offset)) return tb_false;
if (!tb_stream_bread(istream, (tb_byte_t*)&context->header.header32, sizeof(xm_macho_header_32_t))) return tb_false;
// check magic
tb_uint32_t magic = context->header.header32.magic;
if (magic == XM_MACHO_MAGIC_32) {
context->is64 = tb_false;
context->swap = tb_false;
} else if (magic == XM_MACHO_MAGIC_32_BE) {
context->is64 = tb_false;
context->swap = tb_true;
} else if (magic == XM_MACHO_MAGIC_64) {
context->is64 = tb_true;
context->swap = tb_false;
} else if (magic == XM_MACHO_MAGIC_64_BE) {
context->is64 = tb_true;
context->swap = tb_true;
} else {
return tb_false; // Not a Mach-O file
}
if (context->is64) {
if (!tb_stream_seek(istream, base_offset)) return tb_false;
if (!tb_stream_bread(istream, (tb_byte_t*)&context->header.header64, sizeof(xm_macho_header_64_t))) return tb_false;
xm_binutils_macho_swap_header_64(&context->header.header64, context->swap);
context->ncmds = context->header.header64.ncmds;
context->sizeofcmds = context->header.header64.sizeofcmds;
} else {
xm_binutils_macho_swap_header_32(&context->header.header32, context->swap);
context->ncmds = context->header.header32.ncmds;
context->sizeofcmds = context->header.header32.sizeofcmds;
}
return tb_true;
}
// byte-swap load command fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_load_command(xm_macho_load_command_t *lc, tb_bool_t swap) {
if (swap) {
lc->cmd = tb_bits_swap_u32(lc->cmd);
lc->cmdsize = tb_bits_swap_u32(lc->cmdsize);
}
}
// byte-swap dylib command fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_dylib_command(xm_macho_dylib_command_t *dc, tb_bool_t swap) {
if (swap) {
dc->cmd = tb_bits_swap_u32(dc->cmd);
dc->cmdsize = tb_bits_swap_u32(dc->cmdsize);
dc->dylib.offset = tb_bits_swap_u32(dc->dylib.offset);
dc->dylib.timestamp = tb_bits_swap_u32(dc->dylib.timestamp);
dc->dylib.current_version = tb_bits_swap_u32(dc->dylib.current_version);
dc->dylib.compatibility_version = tb_bits_swap_u32(dc->dylib.compatibility_version);
}
}
// byte-swap rpath command fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_rpath_command(xm_macho_rpath_command_t *rc, tb_bool_t swap) {
if (swap) {
rc->cmd = tb_bits_swap_u32(rc->cmd);
rc->cmdsize = tb_bits_swap_u32(rc->cmdsize);
rc->path_offset = tb_bits_swap_u32(rc->path_offset);
}
}
// byte-swap symtab command fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_symtab_command(xm_macho_symtab_command_t *cmd, tb_bool_t swap) {
if (swap) {
cmd->cmd = tb_bits_swap_u32(cmd->cmd);
cmd->cmdsize = tb_bits_swap_u32(cmd->cmdsize);
cmd->symoff = tb_bits_swap_u32(cmd->symoff);
cmd->nsyms = tb_bits_swap_u32(cmd->nsyms);
cmd->stroff = tb_bits_swap_u32(cmd->stroff);
cmd->strsize = tb_bits_swap_u32(cmd->strsize);
}
}
// byte-swap nlist 32 fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_32(xm_macho_nlist_t *nlist, tb_bool_t swap) {
if (swap) {
nlist->strx = tb_bits_swap_u32(nlist->strx);
nlist->desc = tb_bits_swap_u16(nlist->desc);
nlist->value = tb_bits_swap_u32(nlist->value);
}
}
// byte-swap nlist 64 fields if needed
static __tb_inline__ tb_void_t xm_binutils_macho_swap_nlist_64(xm_macho_nlist_64_t *nlist, tb_bool_t swap) {
if (swap) {
nlist->strx = tb_bits_swap_u32(nlist->strx);
nlist->desc = tb_bits_swap_u16(nlist->desc);
nlist->value = tb_bits_swap_u64(nlist->value);
}
}
/* get CPU type from architecture string
*
* @param arch the architecture string (e.g., "x86_64", "i386", "arm64")
* @return the CPU type
*/
static __tb_inline__ tb_uint32_t xm_binutils_macho_get_cputype(tb_char_t const *arch) {
if (!arch) {
return XM_MACHO_CPU_TYPE_X86_64;
}
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return XM_MACHO_CPU_TYPE_X86_64;
} else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) {
return XM_MACHO_CPU_TYPE_ARM64;
} else if (tb_strcmp(arch, "arm") == 0) {
return XM_MACHO_CPU_TYPE_ARM;
} else if (tb_strcmp(arch, "x86") == 0 || tb_strcmp(arch, "i386") == 0) {
return XM_MACHO_CPU_TYPE_X86;
}
return XM_MACHO_CPU_TYPE_X86_64;
}
/* get CPU subtype from architecture string
*
* @param arch the architecture string
* @return the CPU subtype
*/
static __tb_inline__ tb_uint32_t xm_binutils_macho_get_cpusubtype(tb_char_t const *arch) {
if (!arch) {
return XM_MACHO_CPU_SUBTYPE_X86_64;
}
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return XM_MACHO_CPU_SUBTYPE_X86_64;
} else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) {
return XM_MACHO_CPU_SUBTYPE_ARM64;
} else if (tb_strcmp(arch, "arm") == 0) {
return XM_MACHO_CPU_SUBTYPE_ARM;
} else if (tb_strcmp(arch, "x86") == 0 || tb_strcmp(arch, "i386") == 0) {
return XM_MACHO_CPU_SUBTYPE_X86;
}
return XM_MACHO_CPU_SUBTYPE_X86_64;
}
/* check if architecture is 64-bit
*
* @param arch the architecture string
* @return tb_true if 64-bit, tb_false otherwise
*/
static __tb_inline__ tb_bool_t xm_binutils_macho_is_64bit(tb_char_t const *arch) {
if (!arch) {
return tb_true;
}
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return tb_true;
} else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0) {
return tb_true;
} else if (tb_strcmp(arch, "arm") == 0) {
return tb_false;
} else if (tb_strcmp(arch, "x86") == 0 || tb_strcmp(arch, "i386") == 0) {
return tb_false;
}
return tb_true;
}
/* align value to specified alignment
*
* @param value the value to align
* @param align the alignment (must be power of 2)
* @return the aligned value
*/
static __tb_inline__ tb_uint32_t xm_binutils_macho_align(tb_uint32_t value, tb_uint32_t align) {
return ((value + align - 1) & ~(align - 1));
}
/* get platform from platform string
*
* @param platform the platform string (e.g., "macosx", "ios", "tvos", "watchos")
* @return the platform constant
*/
static __tb_inline__ tb_uint32_t xm_binutils_macho_get_platform(tb_char_t const *platform) {
if (!platform) {
return XM_MACHO_PLATFORM_MACOS;
}
if (tb_strcmp(platform, "macosx") == 0 || tb_strcmp(platform, "macos") == 0) {
return XM_MACHO_PLATFORM_MACOS;
} else if (tb_strcmp(platform, "iphoneos") == 0 || tb_strcmp(platform, "ios") == 0) {
return XM_MACHO_PLATFORM_IOS;
} else if (tb_strcmp(platform, "appletvos") == 0 || tb_strcmp(platform, "tvos") == 0) {
return XM_MACHO_PLATFORM_TVOS;
} else if (tb_strcmp(platform, "watchos") == 0) {
return XM_MACHO_PLATFORM_WATCHOS;
}
return XM_MACHO_PLATFORM_MACOS;
}
/* parse version string to Mach-O format
*
* @param version_str the version string (e.g., "10.0" or "18.2")
* @return the version in Mach-O format (major << 16) | (minor << 8) | patch
*/
static __tb_inline__ tb_uint32_t xm_binutils_macho_parse_version(tb_char_t const *version_str) {
if (!version_str || !version_str[0]) {
return 0x000a0000; // default: 10.0.0
}
tb_uint32_t major = 0;
tb_uint32_t minor = 0;
tb_uint32_t patch = 0;
tb_char_t const *p = version_str;
// parse major
while (*p && tb_isdigit(*p)) {
major = major * 10 + (*p - '0');
p++;
}
if (*p == '.') {
p++;
// parse minor
while (*p && tb_isdigit(*p)) {
minor = minor * 10 + (*p - '0');
p++;
}
if (*p == '.') {
p++;
// parse patch
while (*p && tb_isdigit(*p)) {
patch = patch * 10 + (*p - '0');
p++;
}
}
}
return (major << 16) | (minor << 8) | patch;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* readsyms inline implementation
*/
/* read string from Mach-O string table
*
* @param istream the input stream
* @param strtab_offset the string table offset
* @param offset the string offset (nlist.strx, relative to string table start, including 4-byte size field)
* @param name the buffer to store the string
* @param name_size the size of the buffer
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_macho_read_string(tb_stream_ref_t istream, tb_hize_t strtab_offset, tb_uint32_t offset, tb_char_t *name, tb_size_t name_size) {
tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);
// nlist.strx is offset from string table start (including 4-byte size field)
tb_hize_t saved_pos = tb_stream_offset(istream);
if (!tb_stream_seek(istream, strtab_offset + offset)) {
return tb_false;
}
tb_size_t pos = 0;
tb_byte_t c;
while (pos < name_size - 1) {
if (!tb_stream_bread(istream, &c, 1)) {
tb_stream_seek(istream, saved_pos);
return tb_false;
}
if (c == 0) {
break;
}
name[pos++] = (tb_char_t)c;
}
name[pos] = '\0';
tb_stream_seek(istream, saved_pos);
return tb_true;
}
/* get symbol type character (nm-style) from Mach-O symbol
*
* @param type the symbol type byte
* @param sect the section number (0 = undefined)
* @return the type character (T/t/D/d/B/b/U)
*/
static __tb_inline__ tb_char_t xm_binutils_macho_get_symbol_type_char(tb_uint8_t type, tb_uint8_t sect) {
// undefined symbol
if (sect == 0) {
return 'U';
}
// check if external
tb_bool_t is_external = (type & XM_MACHO_N_EXT) != 0;
// check if in section
tb_uint8_t n_type = type & XM_MACHO_N_TYPE_MASK;
if (n_type == XM_MACHO_N_TYPE_SECT) {
// section 1 is usually __TEXT,__text (text)
// section 2 is usually __DATA,__data (data)
// section 3 is usually __DATA,__bss (bss)
// For simplicity, we'll use section number to determine type
// This is a heuristic and may not be 100% accurate
if (sect == 1) {
return is_external ? 'T' : 't'; // text section
} else if (sect == 2) {
return is_external ? 'D' : 'd'; // data section
} else if (sect == 3) {
return is_external ? 'B' : 'b'; // bss section
} else {
return is_external ? 'S' : 's'; // other section
}
}
return '?'; // unknown
}
/* get symbol bind string from Mach-O symbol type
*
* @param type the symbol type byte
* @return the bind string
*/
static __tb_inline__ tb_char_t const *xm_binutils_macho_get_symbol_bind(tb_uint8_t type) {
if (type & XM_MACHO_N_EXT) {
return "external";
}
return "local";
}
#endif
================================================
FILE: core/src/xmake/binutils/macho/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "readsyms_macho"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
tb_bool_t xm_binutils_macho_read_symbols_32(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) {
tb_assert_and_check_return_val(istream && lua && context, tb_false);
// find LC_SYMTAB command
xm_macho_symtab_command_t symtab_cmd;
tb_bool_t found_symtab = tb_false;
tb_uint32_t offset = sizeof(xm_macho_header_32_t);
for (tb_uint32_t i = 0; i < context->ncmds; i++) {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
if (!tb_stream_seek(istream, base_offset + offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) {
return tb_false;
}
if (context->swap) {
cmd = tb_bits_swap_u32(cmd);
cmdsize = tb_bits_swap_u32(cmdsize);
}
if (cmd == XM_MACHO_LC_SYMTAB) {
if (!tb_stream_seek(istream, base_offset + offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) {
return tb_false;
}
xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap);
found_symtab = tb_true;
break;
}
offset += cmdsize;
}
if (!found_symtab) {
lua_newtable(lua);
return tb_true;
}
// create result table
lua_newtable(lua);
// read symbols
if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) {
return tb_false;
}
tb_uint32_t result_count = 0;
for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) {
xm_macho_nlist_t nlist;
if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) {
return tb_false;
}
xm_binutils_macho_swap_nlist_32(&nlist, context->swap);
// skip NULL symbols
if (nlist.strx == 0) {
continue;
}
// get symbol name
tb_char_t name[256];
if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) {
continue;
}
// skip internal symbols (starting with .)
if (name[0] == '.') {
continue;
}
// create symbol table entry
lua_pushinteger(lua, result_count + 1);
lua_newtable(lua);
// name
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
// type (nm-style: T/t/D/d/B/b/U)
tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect);
tb_char_t type_str[2] = {type_char, '\0'};
lua_pushstring(lua, "type");
lua_pushstring(lua, type_str);
lua_settable(lua, -3);
lua_settable(lua, -3);
result_count++;
}
return tb_true;
}
tb_bool_t xm_binutils_macho_read_symbols_64(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua, xm_macho_context_t* context) {
tb_assert_and_check_return_val(istream && lua && context, tb_false);
// find LC_SYMTAB command
xm_macho_symtab_command_t symtab_cmd;
tb_bool_t found_symtab = tb_false;
tb_uint32_t offset = sizeof(xm_macho_header_64_t);
for (tb_uint32_t i = 0; i < context->ncmds; i++) {
tb_uint32_t cmd;
tb_uint32_t cmdsize;
if (!tb_stream_seek(istream, base_offset + offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&cmd, 4)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&cmdsize, 4)) {
return tb_false;
}
if (context->swap) {
cmd = tb_bits_swap_u32(cmd);
cmdsize = tb_bits_swap_u32(cmdsize);
}
if (cmd == XM_MACHO_LC_SYMTAB) {
if (!tb_stream_seek(istream, base_offset + offset)) {
return tb_false;
}
if (!tb_stream_bread(istream, (tb_byte_t*)&symtab_cmd, sizeof(symtab_cmd))) {
return tb_false;
}
xm_binutils_macho_swap_symtab_command(&symtab_cmd, context->swap);
found_symtab = tb_true;
break;
}
offset += cmdsize;
}
if (!found_symtab) {
lua_newtable(lua);
return tb_true;
}
// create result table
lua_newtable(lua);
// read symbols
if (!tb_stream_seek(istream, base_offset + symtab_cmd.symoff)) {
return tb_false;
}
tb_uint32_t result_count = 0;
for (tb_uint32_t i = 0; i < symtab_cmd.nsyms; i++) {
xm_macho_nlist_64_t nlist;
if (!tb_stream_bread(istream, (tb_byte_t*)&nlist, sizeof(nlist))) {
return tb_false;
}
xm_binutils_macho_swap_nlist_64(&nlist, context->swap);
// skip NULL symbols
if (nlist.strx == 0) {
continue;
}
// get symbol name
tb_char_t name[256];
if (!xm_binutils_macho_read_string(istream, base_offset + symtab_cmd.stroff, nlist.strx, name, sizeof(name)) || !name[0]) {
continue;
}
// skip internal symbols (starting with .)
if (name[0] == '.') {
continue;
}
// create symbol table entry
lua_pushinteger(lua, result_count + 1);
lua_newtable(lua);
// name
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
// type (nm-style: T/t/D/d/B/b/U)
tb_char_t type_char = xm_binutils_macho_get_symbol_type_char(nlist.type, nlist.sect);
tb_char_t type_str[2] = {type_char, '\0'};
lua_pushstring(lua, "type");
lua_pushstring(lua, type_str);
lua_settable(lua, -3);
lua_settable(lua, -3);
result_count++;
}
return tb_true;
}
tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// init Mach-O context
xm_macho_context_t context;
if (!xm_binutils_macho_context_init(istream, base_offset, &context)) {
return tb_false;
}
if (!context.is64) {
return xm_binutils_macho_read_symbols_32(istream, base_offset, lua, &context);
} else {
return xm_binutils_macho_read_symbols_64(istream, base_offset, lua, &context);
}
}
================================================
FILE: core/src/xmake/binutils/macho/rpath.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rpath.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rpath_macho"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_bool_t xm_binutils_macho_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
tb_bool_t ok = tb_false;
do {
// init Mach-O context
xm_macho_context_t context;
if (!xm_binutils_macho_context_init(istream, base_offset, &context)) break;
// skip header to reach load commands
tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t);
if (!tb_stream_seek(istream, base_offset + header_size)) break;
tb_size_t result_count = 0;
// iterate load commands
tb_uint32_t i = 0;
for (i = 0; i < context.ncmds; i++) {
xm_macho_load_command_t lc;
tb_hize_t current_cmd_offset = tb_stream_offset(istream);
if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) break;
xm_binutils_macho_swap_load_command(&lc, context.swap);
// check for LC_RPATH
if (lc.cmd == XM_MACHO_LC_RPATH) {
xm_macho_rpath_command_t rc;
if (tb_stream_seek(istream, current_cmd_offset)) {
if (tb_stream_bread(istream, (tb_byte_t*)&rc, sizeof(rc))) {
xm_binutils_macho_swap_rpath_command(&rc, context.swap);
tb_uint32_t name_offset = rc.path_offset;
if (name_offset < lc.cmdsize) {
// name is at current_cmd_offset + name_offset
tb_char_t rpath[TB_PATH_MAXN];
if (xm_binutils_read_string(istream, current_cmd_offset + name_offset, rpath, sizeof(rpath))) {
if (tb_strlen(rpath) > 0) {
lua_pushinteger(lua, result_count + 1);
lua_pushstring(lua, rpath);
lua_settable(lua, -3);
result_count++;
}
}
}
}
}
}
// move to next command
if (!tb_stream_seek(istream, current_cmd_offset + lc.cmdsize)) break;
}
if (i < context.ncmds) break;
ok = tb_true;
} while (0);
return ok;
}
tb_bool_t xm_binutils_macho_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset) {
tb_assert_and_check_return_val(istream, tb_false);
tb_bool_t ok = tb_false;
tb_byte_t* buffer = tb_null;
do {
// init Mach-O context
xm_macho_context_t context;
if (!xm_binutils_macho_context_init(istream, base_offset, &context)) break;
tb_size_t header_size = context.is64 ? sizeof(xm_macho_header_64_t) : sizeof(xm_macho_header_32_t);
if (!tb_stream_seek(istream, base_offset + header_size)) break;
tb_hize_t read_offset = base_offset + header_size;
tb_hize_t write_offset = read_offset;
tb_uint32_t new_ncmds = 0;
tb_uint32_t new_sizeofcmds = 0;
tb_bool_t found = tb_false;
buffer = (tb_byte_t*)tb_malloc(64 * 1024); // 64KB should be enough for any load command
if (!buffer) break;
tb_uint32_t i = 0;
for (i = 0; i < context.ncmds; i++) {
xm_macho_load_command_t lc;
if (!tb_stream_seek(istream, read_offset)) break;
if (!tb_stream_bread(istream, (tb_byte_t*)&lc, sizeof(lc))) break;
xm_binutils_macho_swap_load_command(&lc, context.swap);
tb_bool_t remove = tb_false;
if (lc.cmd == XM_MACHO_LC_RPATH) {
remove = tb_true;
found = tb_true;
}
if (!remove) {
// copy command to write_offset
if (read_offset != write_offset) {
if (lc.cmdsize > 64 * 1024) break;
if (!tb_stream_seek(istream, read_offset)) break;
if (!tb_stream_bread(istream, buffer, lc.cmdsize)) break;
if (!tb_stream_seek(istream, write_offset)) break;
if (!tb_stream_bwrit(istream, buffer, lc.cmdsize)) break;
}
write_offset += lc.cmdsize;
new_ncmds++;
new_sizeofcmds += lc.cmdsize;
}
read_offset += lc.cmdsize;
}
if (i < context.ncmds) break;
if (found) {
// zero out the remaining space
if (read_offset > write_offset) {
tb_hize_t diff = read_offset - write_offset;
if (!tb_stream_seek(istream, write_offset)) break;
tb_byte_t zero = 0;
tb_bool_t write_ok = tb_true;
for (tb_hize_t k = 0; k < diff; k++) {
if (!tb_stream_bwrit(istream, &zero, 1)) {
write_ok = tb_false;
break;
}
}
if (!write_ok) break;
}
// update header
if (context.is64) {
context.header.header64.ncmds = new_ncmds;
context.header.header64.sizeofcmds = new_sizeofcmds;
xm_binutils_macho_swap_header_64(&context.header.header64, context.swap);
if (!tb_stream_seek(istream, base_offset)) break;
if (!tb_stream_bwrit(istream, (tb_byte_t const*)&context.header.header64, sizeof(xm_macho_header_64_t))) break;
} else {
context.header.header32.ncmds = new_ncmds;
context.header.header32.sizeofcmds = new_sizeofcmds;
xm_binutils_macho_swap_header_32(&context.header.header32, context.swap);
if (!tb_stream_seek(istream, base_offset)) break;
if (!tb_stream_bwrit(istream, (tb_byte_t const*)&context.header.header32, sizeof(xm_macho_header_32_t))) break;
}
}
ok = tb_true;
} while (0);
if (buffer) tb_free(buffer);
return ok;
}
================================================
FILE: core/src/xmake/binutils/mslib/extractlib.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file extractlib.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "mslib_extract"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* generate unique name for output file
*
* @param base_name the base name
* @param id the unique id
* @param output output buffer
* @param output_size output buffer size
* @param output_len output: actual output length
* @return tb_true on success, tb_false on failure
*/
static tb_bool_t xm_binutils_mslib_generate_unique_name(tb_char_t const *base_name, tb_uint32_t id, tb_char_t *output, tb_size_t output_size, tb_size_t* output_len) {
tb_assert_and_check_return_val(base_name && output && output_size > 0 && output_len, tb_false);
// find the last dot for extension
tb_char_t const *ext = tb_strrchr(base_name, '.');
tb_long_t n = -1;
if (ext) {
tb_size_t base_len = (tb_size_t)(ext - base_name);
tb_size_t ext_len = tb_strlen(ext);
if (base_len + ext_len + 16 < output_size) {
n = tb_snprintf(output, output_size, "%.*s_%u%s", (tb_int_t)base_len, base_name, id, ext);
}
} else {
// no extension
if (tb_strlen(base_name) + 16 < output_size) {
n = tb_snprintf(output, output_size, "%s_%u", base_name, id);
}
}
if (n >= 0) {
*output_len = (tb_size_t)n;
return tb_true;
}
return tb_false;
}
/* extract MSVC lib archive to directory
*
* @param istream the input stream
* @param outputdir the output directory
* @param plain extract all object files to the same directory
* @return tb_true on success, tb_false on failure
*/
tb_bool_t xm_binutils_mslib_extract(tb_stream_ref_t istream, tb_char_t const *outputdir, tb_bool_t plain) {
tb_assert_and_check_return_val(istream && outputdir, tb_false);
// check magic (!\n)
if (!xm_binutils_mslib_check_magic(istream)) {
return tb_false;
}
/* ensure output directory exists
* check if directory already exists
*/
if (!tb_file_info(outputdir, tb_null)) {
// directory doesn't exist, create it
if (!tb_directory_create(outputdir)) {
return tb_false;
}
}
tb_bool_t ok = tb_true;
tb_char_t* longnames = tb_null;
tb_size_t longnames_size = 0;
// iterate through members
while (ok) {
// read header
xm_mslib_header_t header;
if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
// end of file
break;
}
// parse member size
tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10);
if (member_size < 0) {
ok = tb_false;
break;
}
// parse member name
tb_char_t member_name[256] = {0};
tb_bool_t is_longname_table = tb_false;
if (header.name[0] == '/') {
if (header.name[1] == '/') {
// long name table (//)
is_longname_table = tb_true;
} else if (tb_isdigit(header.name[1])) {
// offset into long name table (/123)
tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15);
if (offset >= 0 && (tb_size_t)offset < longnames_size) {
/* copy from longnames
* names in longnames are null-terminated
*/
tb_strlcpy(member_name, longnames + offset, sizeof(member_name));
}
} else {
/* symbol table or other special member (/)
* usually symbol table is just "/"
*/
tb_strlcpy(member_name, "/", sizeof(member_name));
}
} else {
// short name, ends with /
tb_size_t i = 0;
for (i = 0; i < 16 && header.name[i] != '/'; i++) {
member_name[i] = header.name[i];
}
member_name[i] = '\0';
}
if (is_longname_table) {
tb_char_t* new_longnames = (tb_char_t*)tb_ralloc(longnames, (tb_size_t)member_size + 1);
if (!new_longnames) {
ok = tb_false;
break;
}
longnames = new_longnames;
if (!tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) {
ok = tb_false;
break;
}
longnames[member_size] = '\0';
longnames_size = (tb_size_t)member_size;
// align
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
continue;
}
/* check if we should extract
* skip empty names, symbol tables (/), long name table (//) - handled above,
* and __.SYMDEF (SysV/BSD style symbol table, just in case)
*/
if (member_name[0] == '\0' || tb_strcmp(member_name, "/") == 0 || tb_strcmp(member_name, "//") == 0 ||
tb_strncmp(member_name, "__.SYMDEF", 9) == 0) {
// skip member data
if (!tb_stream_skip(istream, member_size)) {
ok = tb_false;
break;
}
// align
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
continue;
}
/* construct output path
* replace \ with /
*/
tb_size_t name_len = tb_strlen(member_name);
for (tb_size_t i = 0; i < name_len; i++) {
if (member_name[i] == '\\') {
member_name[i] = '/';
}
}
// check output path length
tb_char_t output_path[1024];
if (plain) {
// get filename only
tb_char_t const* name = tb_strrchr(member_name, '/');
if (name) {
name++;
} else {
name = member_name;
}
// check conflicts
tb_char_t output_name[512];
tb_size_t output_name_len = tb_strlen(name);
tb_size_t outputdir_len = tb_strlen(outputdir);
if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {
ok = tb_false;
break;
}
tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, name);
if (tb_file_info(output_path, tb_null)) {
// name conflict, try different IDs
tb_uint32_t conflict_id = 1;
while (conflict_id < 10000) {
if (!xm_binutils_mslib_generate_unique_name(name, conflict_id, output_name, sizeof(output_name), &output_name_len)) {
ok = tb_false;
break;
}
if (outputdir_len + 1 + output_name_len >= sizeof(output_path)) {
ok = tb_false;
break;
}
tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, output_name);
if (!tb_file_info(output_path, tb_null)) {
break;
}
conflict_id++;
}
tb_check_break(ok);
if (conflict_id >= 10000) {
ok = tb_false;
break;
}
}
} else {
if (tb_strlen(outputdir) + 1 + name_len >= sizeof(output_path)) {
ok = tb_false;
break;
}
tb_snprintf(output_path, sizeof(output_path), "%s/%s", outputdir, member_name);
}
// ensure directory exists
tb_char_t const* p = tb_strrchr(output_path, '/');
if (p) {
tb_char_t dir[1024];
tb_size_t len = p - output_path;
if (len < sizeof(dir)) {
tb_strncpy(dir, output_path, len);
dir[len] = '\0';
if (!tb_file_info(dir, tb_null)) {
if (!tb_directory_create(dir)) {
ok = tb_false;
break;
}
}
}
}
// write file
tb_stream_ref_t ostream = tb_stream_init_from_file(output_path, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
if (ostream) {
if (tb_stream_open(ostream)) {
if (!xm_binutils_stream_copy(istream, ostream, member_size)) {
ok = tb_false;
}
} else {
ok = tb_false;
}
tb_stream_exit(ostream);
} else {
ok = tb_false;
}
tb_check_break(ok);
// align to 2-byte boundary
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
}
if (longnames) {
tb_free(longnames);
}
return ok;
}
================================================
FILE: core/src/xmake/binutils/mslib/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_MSLIB_PREFIX_H
#define XM_BINUTILS_MSLIB_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// MSVC lib header
#include "tbox/prefix/packed.h"
typedef struct __xm_mslib_header_t {
tb_char_t name[16];
tb_char_t date[12];
tb_char_t uid[6];
tb_char_t gid[6];
tb_char_t mode[8];
tb_char_t size[10];
tb_char_t fmag[2];
} __tb_packed__ xm_mslib_header_t;
#include "tbox/prefix/packed.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
static __tb_inline__ tb_int64_t xm_binutils_mslib_parse_decimal(tb_char_t const *p, tb_size_t n) {
tb_assert_and_check_return_val(p && n > 0, -1);
tb_int64_t v = 0;
tb_char_t const* e = p + n;
while (p < e && *p == ' ') {
p++;
}
while (p < e && *p >= '0' && *p <= '9') {
v = v * 10 + (*p - '0');
p++;
}
return v;
}
static __tb_inline__ tb_bool_t xm_binutils_mslib_check_magic(tb_stream_ref_t istream) {
tb_char_t magic[8];
if (!tb_stream_bread(istream, (tb_byte_t*)magic, 8)) {
return tb_false;
}
return tb_strncmp(magic, "!\n", 8) == 0;
}
#endif
================================================
FILE: core/src/xmake/binutils/mslib/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "mslib_readsyms"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* forward declarations
*/
extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
static tb_bool_t xm_binutils_mslib_parse_archive_symbols(tb_stream_ref_t istream, tb_hize_t member_size, lua_State* lua, int map_idx) {
// try to parse as Second Linker Member (LE)
tb_hize_t start_pos = tb_stream_offset(istream);
tb_uint32_t* offsets = tb_null;
tb_uint16_t* indices = tb_null;
tb_char_t* string_table = tb_null;
tb_bool_t ok = tb_false;
do {
// read number of members
tb_uint32_t num_members = 0;
if (!tb_stream_bread_u32_le(istream, &num_members)) {
break;
}
// sanity check
if (num_members == 0 || num_members > 65536 || num_members * 4 >= member_size) {
break;
}
// read offsets
offsets = tb_nalloc_type(num_members, tb_uint32_t);
tb_check_break(offsets);
tb_size_t i;
for (i = 0; i < num_members; i++) {
if (!tb_stream_bread_u32_le(istream, &offsets[i])) {
break;
}
}
if (i < num_members) {
break;
}
// read number of symbols
tb_uint32_t num_symbols = 0;
if (!tb_stream_bread_u32_le(istream, &num_symbols)) {
break;
}
if (num_symbols == 0 || num_symbols > 1000000) {
break;
}
// read indices
indices = tb_nalloc_type(num_symbols, tb_uint16_t);
tb_check_break(indices);
for (i = 0; i < num_symbols; i++) {
if (!tb_stream_bread_u16_le(istream, &indices[i])) {
break;
}
}
if (i < num_symbols) {
break;
}
// read string table
tb_hize_t current = tb_stream_offset(istream);
tb_hize_t string_table_size = member_size - (current - start_pos);
string_table = (tb_char_t*)tb_malloc_bytes((tb_size_t)string_table_size);
tb_check_break(string_table);
if (!tb_stream_bread(istream, (tb_byte_t*)string_table, (tb_size_t)string_table_size)) {
break;
}
// populate map
tb_char_t* p = string_table;
tb_char_t* end = string_table + string_table_size;
for (i = 0; i < num_symbols; i++) {
if (p >= end) {
break;
}
tb_char_t* sym_name = p;
tb_size_t sym_len = tb_strlen(sym_name);
p += sym_len + 1;
tb_uint16_t idx = indices[i];
if (idx > 0 && idx <= num_members) {
tb_uint32_t offset = offsets[idx - 1];
lua_pushinteger(lua, offset);
lua_rawget(lua, map_idx);
if (lua_isnil(lua, -1)) {
lua_pop(lua, 1);
lua_newtable(lua);
lua_pushinteger(lua, offset);
lua_pushvalue(lua, -2);
lua_rawset(lua, map_idx);
}
int count = (int)lua_objlen(lua, -1);
lua_pushstring(lua, sym_name);
lua_rawseti(lua, -2, count + 1);
lua_pop(lua, 1); // pop list
}
}
ok = tb_true;
} while (0);
if (offsets) {
tb_free(offsets);
}
if (indices) {
tb_free(indices);
}
if (string_table) {
tb_free(string_table);
}
if (!ok) {
tb_stream_seek(istream, start_pos);
}
return ok;
}
/* read symbols from MSVC lib archive
*
* @param istream the input stream
* @param base_offset the base offset
* @param lua the lua state
* @return tb_true on success, tb_false on failure
*/
tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State* lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
// check magic (!\n)
if (!xm_binutils_mslib_check_magic(istream)) {
return tb_false;
}
// create map table (offset -> symbols)
lua_newtable(lua);
int map_idx = lua_gettop(lua);
tb_bool_t ok = tb_true;
tb_size_t object_count = 0;
tb_char_t* longnames = tb_null;
tb_size_t longnames_size = 0;
// iterate through members
while (ok) {
// read header
xm_mslib_header_t header;
if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
// end of file
break;
}
// parse member size
tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10);
if (member_size < 0) {
ok = tb_false;
break;
}
// parse member name
tb_char_t member_name[256] = {0};
tb_bool_t is_longname_table = tb_false;
if (header.name[0] == '/') {
if (header.name[1] == '/') {
// long name table (//)
is_longname_table = tb_true;
} else if (tb_isdigit(header.name[1])) {
// offset into long name table (/123)
tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15);
if (offset >= 0 && (tb_size_t)offset < longnames_size) {
/* copy from longnames
* names in longnames are null-terminated
*/
tb_strlcpy(member_name, longnames + offset, sizeof(member_name));
}
} else {
/* symbol table or other special member (/)
* usually symbol table is just "/"
*/
tb_strlcpy(member_name, "/", sizeof(member_name));
}
} else {
// short name, ends with /
tb_size_t i = 0;
for (i = 0; i < 16 && header.name[i] != '/'; i++) {
member_name[i] = header.name[i];
}
member_name[i] = '\0';
}
if (is_longname_table) {
longnames = (tb_char_t*)tb_ralloc(longnames, (tb_size_t)member_size + 1);
if (!longnames || !tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) {
ok = tb_false;
break;
}
longnames[member_size] = '\0';
longnames_size = (tb_size_t)member_size;
// align
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
continue;
}
// check if we should process
/* skip empty names, long name table (//) - handled above,
* and __.SYMDEF (SysV/BSD style symbol table, just in case)
*/
if (member_name[0] == '\0' || tb_strcmp(member_name, "//") == 0 ||
tb_strncmp(member_name, "__.SYMDEF", 9) == 0) {
// skip member data
if (!tb_stream_skip(istream, member_size)) {
ok = tb_false;
break;
}
// align
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
continue;
}
if (tb_strcmp(member_name, "/") == 0) {
// try to parse archive symbols
if (!xm_binutils_mslib_parse_archive_symbols(istream, (tb_hize_t)member_size, lua, map_idx)) {
// if failed, skip member data
if (!tb_stream_skip(istream, member_size)) {
ok = tb_false;
break;
}
}
// align
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
continue;
}
// save current position
tb_hize_t current_pos = tb_stream_offset(istream);
tb_hize_t header_offset = current_pos - sizeof(xm_mslib_header_t);
// detect format
tb_int_t format = xm_binutils_format_detect(istream);
if (format != XM_BINUTILS_FORMAT_UNKNOWN && format != XM_BINUTILS_FORMAT_AR) {
// create entry table
lua_newtable(lua);
// object name
lua_pushstring(lua, "objectfile");
lua_pushstring(lua, member_name);
lua_settable(lua, -3);
// symbols
lua_pushstring(lua, "symbols");
tb_bool_t read_ok = tb_false;
if (format == XM_BINUTILS_FORMAT_COFF) {
read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua);
} else if (format == XM_BINUTILS_FORMAT_ELF) {
read_ok = xm_binutils_elf_read_symbols(istream, current_pos, lua);
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
read_ok = xm_binutils_macho_read_symbols(istream, current_pos, lua);
}
// if read failed or empty, try map
tb_bool_t has_symbols = tb_false;
if (read_ok) {
if (lua_objlen(lua, -1) > 0) {
has_symbols = tb_true;
} else {
lua_pop(lua, 1); // pop empty table
}
}
if (!has_symbols) {
// check map
lua_pushinteger(lua, (lua_Integer)header_offset);
lua_rawget(lua, map_idx);
if (lua_istable(lua, -1)) {
// convert list of names to list of {name=..., type="global"}
lua_newtable(lua); // result table
int count = (int)lua_objlen(lua, -2);
for (int i = 1; i <= count; i++) {
lua_rawgeti(lua, -2, i);
const char* name = lua_tostring(lua, -1);
if (name) {
lua_newtable(lua);
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
lua_pushstring(lua, "type");
lua_pushstring(lua, "T");
lua_settable(lua, -3);
lua_rawseti(lua, -3, i);
}
lua_pop(lua, 1); // pop name
}
lua_remove(lua, -2); // remove map entry list
has_symbols = tb_true;
} else {
lua_pop(lua, 1); // pop nil
}
}
if (has_symbols) {
lua_settable(lua, -3);
lua_rawseti(lua, map_idx - 1, (int)(++object_count));
} else {
lua_pop(lua, 2); // pop symbols key and entry table
}
}
// skip to next member
tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos;
tb_hize_t remaining_size = (tb_hize_t)member_size - member_data_read;
if (remaining_size > 0) {
if (!tb_stream_skip(istream, remaining_size)) {
ok = tb_false;
break;
}
} else if (remaining_size < 0) {
if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size)) {
ok = tb_false;
break;
}
}
// align to 2-byte boundary
if (member_size % 2) {
if (!tb_stream_skip(istream, 1)) {
ok = tb_false;
break;
}
}
}
if (longnames) {
tb_free(longnames);
}
lua_remove(lua, map_idx);
return ok;
}
================================================
FILE: core/src/xmake/binutils/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_PREFIX_H
#define XM_BINUTILS_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_BINUTILS_FORMAT_COFF 1
#define XM_BINUTILS_FORMAT_ELF 2
#define XM_BINUTILS_FORMAT_MACHO 3
#define XM_BINUTILS_FORMAT_AR 4
#define XM_BINUTILS_FORMAT_PE 5
#define XM_BINUTILS_FORMAT_SHEBANG 6
#define XM_BINUTILS_FORMAT_APE 7
#define XM_BINUTILS_FORMAT_WASM 8
#define XM_BINUTILS_FORMAT_UNKNOWN 0
// COFF machine types (for format detection)
#define XM_BINUTILS_COFF_MACHINE_I386 0x014c
#define XM_BINUTILS_COFF_MACHINE_AMD64 0x8664
#define XM_BINUTILS_COFF_MACHINE_ARM 0x01c0
#define XM_BINUTILS_COFF_MACHINE_ARM64 0xaa64
// PE/DOS offsets/signatures (for format detection)
#define XM_BINUTILS_PE_DOS_STUB_MIN_SIZE (0x40)
#define XM_BINUTILS_PE_DOS_ELFANEW_OFFSET (0x3c)
#define XM_BINUTILS_PE_NT_SIGNATURE (0x00004550) // "PE\0\0" little endian
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream);
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
/* read magic bytes from stream (preserves stream position)
*
* @param istream the input stream
* @param magic the buffer to store magic bytes (must be at least 4 bytes)
* @param size the number of bytes to read (typically 4)
*
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_read_magic(tb_stream_ref_t istream, tb_uint8_t *magic, tb_size_t size) {
tb_assert_and_check_return_val(istream && magic && size > 0, tb_false);
tb_hize_t saved_pos = tb_stream_offset(istream);
if (!tb_stream_seek(istream, 0)) {
return tb_false;
}
tb_bool_t ok = tb_false;
if (tb_stream_bread(istream, magic, size)) {
ok = tb_true;
}
tb_stream_seek(istream, saved_pos);
return ok;
}
/* copy data from input stream to output stream
*
* @param istream the input stream
* @param ostream the output stream
* @param size the size to copy
*
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_stream_copy(tb_stream_ref_t istream, tb_stream_ref_t ostream, tb_hize_t size) {
tb_assert_and_check_return_val(istream && ostream, tb_false);
if (size == 0) {
return tb_true;
}
tb_byte_t data[TB_STREAM_BLOCK_MAXN];
tb_hize_t writ = 0;
do {
tb_size_t need = (tb_size_t)tb_min(size - writ, (tb_hize_t)TB_STREAM_BLOCK_MAXN);
tb_check_break(need);
if (!tb_stream_bread(istream, data, need)) {
return tb_false;
}
if (!tb_stream_bwrit(ostream, data, need)) {
return tb_false;
}
writ += need;
tb_check_break(writ < size);
} while (1);
return tb_true;
}
/* sanitize symbol name (replace non-alphanumeric characters with underscores)
*
* @param name the symbol name
*/
static __tb_inline__ void xm_binutils_sanitize_symbol_name(tb_char_t* name) {
tb_assert_and_check_return(name);
for (tb_size_t i = 0; name[i]; i++) {
if (!tb_isalpha(name[i]) && !tb_isdigit(name[i]) && name[i] != '_') {
name[i] = '_';
}
}
}
/* read string from stream at specified offset
*
* @param istream the input stream
* @param offset the offset to read from
* @param name the buffer to store the string
* @param name_size the size of the buffer
*
* @return tb_true on success, tb_false on failure
*/
static __tb_inline__ tb_bool_t xm_binutils_read_string(tb_stream_ref_t istream, tb_hize_t offset, tb_char_t *name, tb_size_t name_size) {
tb_assert_and_check_return_val(istream && name && name_size > 0, tb_false);
tb_hize_t saved_pos = tb_stream_offset(istream);
if (!tb_stream_seek(istream, offset)) {
return tb_false;
}
tb_size_t pos = 0;
tb_byte_t c;
while (pos < name_size - 1) {
if (!tb_stream_bread(istream, &c, 1)) {
tb_stream_seek(istream, saved_pos);
return tb_false;
}
if (c == 0) {
break;
}
name[pos++] = (tb_char_t)c;
}
name[pos] = '\0';
tb_stream_seek(istream, saved_pos);
return tb_true;
}
/* check if architecture is 64-bit
*
* @param arch the architecture string
* @return tb_true if 64-bit, tb_false otherwise
*/
static __tb_inline__ tb_bool_t xm_binutils_arch_is_64bit(tb_char_t const *arch) {
if (!arch) {
return tb_true;
}
// x86_64
if (tb_strcmp(arch, "x86_64") == 0 || tb_strcmp(arch, "x64") == 0) {
return tb_true;
}
// ARM64
else if (tb_strcmp(arch, "arm64") == 0 || tb_strcmp(arch, "aarch64") == 0 ||
tb_strcmp(arch, "arm64-v8a") == 0) {
return tb_true;
}
// MIPS64
else if (tb_strncmp(arch, "mips64", 6) == 0) {
return tb_true;
}
// PowerPC64
else if (tb_strncmp(arch, "ppc64", 5) == 0 || tb_strncmp(arch, "powerpc64", 9) == 0) {
return tb_true;
}
// RISC-V 64
else if (tb_strncmp(arch, "riscv64", 7) == 0 ||
(tb_strncmp(arch, "riscv", 5) == 0 && tb_strstr(arch, "64"))) {
return tb_true;
}
// SPARC64
else if (tb_strncmp(arch, "sparc64", 7) == 0) {
return tb_true;
}
// s390x
else if (tb_strcmp(arch, "s390x") == 0) {
return tb_true;
}
// LoongArch64
else if (tb_strncmp(arch, "loongarch64", 11) == 0) {
return tb_true;
}
// WebAssembly 64
else if (tb_strcmp(arch, "wasm64") == 0) {
return tb_true;
}
// IA-64
else if (tb_strcmp(arch, "ia64") == 0 || tb_strcmp(arch, "itanium") == 0) {
return tb_true;
}
return tb_false;
}
#endif
================================================
FILE: core/src/xmake/binutils/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "readsyms"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "coff/prefix.h"
#include "elf/prefix.h"
#include "macho/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* forward declarations
*/
extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_elf_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_macho_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_ar_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
extern tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* read symbols from object file (auto-detect format)
*
* @param lua the lua state
* @return 1 on success (table on stack), 2 on failure (with error message on stack)
*/
tb_int_t xm_binutils_readsyms(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the object file path
tb_char_t const *objectfile = luaL_checkstring(lua, 1);
tb_check_return_val(objectfile, 0);
// open file
tb_stream_ref_t istream = tb_stream_init_from_file(objectfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "open %s failed", objectfile);
return 2;
}
tb_bool_t ok = tb_false;
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "open %s failed", objectfile);
break;
}
// detect format
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "cannot detect file format");
break;
}
// create result list
lua_newtable(lua);
// read symbols based on format
if (format == XM_BINUTILS_FORMAT_AR) {
// AR archive (.a or .lib)
tb_bool_t is_mslib = tb_false;
if (objectfile) {
tb_size_t len = tb_strlen(objectfile);
if (len > 4 && tb_stricmp(objectfile + len - 4, ".lib") == 0) {
is_mslib = tb_true;
}
}
if (is_mslib) {
if (!xm_binutils_mslib_read_symbols(istream, 0, lua)) {
// fallback to ar
if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "read AR/MSLIB archive symbols failed");
break;
}
}
} else {
if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "read AR archive symbols failed");
break;
}
}
} else {
// single object file (COFF, ELF, Mach-O)
// create entry table
lua_newtable(lua);
// object name
lua_pushstring(lua, "objectfile");
tb_char_t const* name = tb_strrchr(objectfile, '/');
if (!name) {
name = tb_strrchr(objectfile, '\\');
}
if (!name) {
name = objectfile;
} else {
name++;
}
lua_pushstring(lua, name);
lua_settable(lua, -3);
// symbols
lua_pushstring(lua, "symbols");
tb_bool_t read_ok = tb_false;
if (format == XM_BINUTILS_FORMAT_COFF) {
read_ok = xm_binutils_coff_read_symbols(istream, 0, lua);
} else if (format == XM_BINUTILS_FORMAT_ELF) {
read_ok = xm_binutils_elf_read_symbols(istream, 0, lua);
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
read_ok = xm_binutils_macho_read_symbols(istream, 0, lua);
} else if (format == XM_BINUTILS_FORMAT_WASM) {
read_ok = xm_binutils_wasm_read_symbols(istream, 0, lua);
}
if (read_ok) {
lua_settable(lua, -3);
lua_rawseti(lua, -2, 1);
} else {
lua_pop(lua, 2); // pop entry table and result list
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "read symbols failed");
break;
}
}
ok = tb_true;
} while (0);
if (istream) {
tb_stream_clos(istream);
}
istream = tb_null;
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/rpath.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rpath.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rpath"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "elf/prefix.h"
#include "macho/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
tb_bool_t xm_binutils_elf_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
tb_bool_t xm_binutils_macho_rpath_list(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua);
tb_bool_t xm_binutils_elf_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset);
tb_bool_t xm_binutils_macho_rpath_clean(tb_stream_ref_t istream, tb_hize_t base_offset);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* get rpath list from binary file (auto-detect format)
*
* @param lua the lua state
* @return 1 on success (table on stack), 2 on failure (with error message on stack)
*/
tb_int_t xm_binutils_rpath_list(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the binary file path
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// open file
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO);
if (!istream) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_list: open %s failed", binaryfile);
return 2;
}
tb_bool_t ok = tb_false;
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_list: open %s failed", binaryfile);
break;
}
// detect format
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_list: cannot detect file format");
break;
}
// create result list
lua_newtable(lua);
// get rpath list based on format
if (format == XM_BINUTILS_FORMAT_ELF) {
if (!xm_binutils_elf_rpath_list(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_list: failed to parse ELF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
if (!xm_binutils_macho_rpath_list(istream, 0, lua)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_list: failed to parse Mach-O");
break;
}
} else {
/* not supported or no rpath for this format
* return empty table
*/
}
ok = tb_true;
} while (0);
if (istream) tb_stream_exit(istream);
return ok ? 1 : 2;
}
/* clean all rpaths from binary file
*
* @param lua the lua state
* @return 1 on success, 2 on failure
*/
tb_int_t xm_binutils_rpath_clean(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get arguments
tb_char_t const *binaryfile = luaL_checkstring(lua, 1);
tb_check_return_val(binaryfile, 0);
// open file
tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RW);
if (!istream) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_clean: open %s failed", binaryfile);
return 2;
}
tb_bool_t ok = tb_false;
do {
if (!tb_stream_open(istream)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_clean: open %s failed", binaryfile);
break;
}
// detect format
tb_int_t format = xm_binutils_format_detect(istream);
if (format < 0) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_clean: cannot detect file format");
break;
}
// clean rpath
if (format == XM_BINUTILS_FORMAT_ELF) {
if (!xm_binutils_elf_rpath_clean(istream, 0)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_clean: failed to clean ELF");
break;
}
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
if (!xm_binutils_macho_rpath_clean(istream, 0)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_clean: failed to clean Mach-O");
break;
}
} else {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "rpath_clean: format not supported");
break;
}
lua_pushboolean(lua, tb_true);
ok = tb_true;
} while (0);
if (istream) tb_stream_exit(istream);
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/binutils/wasm/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BINUTILS_WASM_PREFIX_H
#define XM_BINUTILS_WASM_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// wasm file magic: \0asm
#define XM_WASM_MAGIC0 0x00
#define XM_WASM_MAGIC1 0x61
#define XM_WASM_MAGIC2 0x73
#define XM_WASM_MAGIC3 0x6d
// wasm header size: magic(4) + version(4)
#define XM_WASM_HEADER_SIZE 8
// wasm section ids
#define XM_WASM_SECTION_IMPORT 2
#define XM_WASM_SECTION_EXPORT 7
// wasm custom section names
#define XM_WASM_CUSTOM_LINKING "linking"
#define XM_WASM_CUSTOM_NAME "name"
// wasm import/export kinds
#define XM_WASM_KIND_FUNC 0
#define XM_WASM_KIND_TABLE 1
#define XM_WASM_KIND_MEMORY 2
#define XM_WASM_KIND_GLOBAL 3
#define XM_WASM_KIND_TAG 4
// wasm limits flags
#define XM_WASM_LIMITS_HAS_MAX 0x01
#define XM_WASM_LIMITS_MEM64 0x04
// leb128 max bytes
#define XM_WASM_U32_LEB_MAX 5
#define XM_WASM_U64_LEB_MAX 10
// linking custom section
#define XM_WASM_LINKING_VERSION_2 2
#define XM_WASM_LINKING_SUBSEC_SYMTAB 8
// symbol table kinds (linking section)
#define XM_WASM_SYMTAB_KIND_FUNCTION 0
#define XM_WASM_SYMTAB_KIND_DATA 1
#define XM_WASM_SYMTAB_KIND_GLOBAL 2
#define XM_WASM_SYMTAB_KIND_SECTION 3
#define XM_WASM_SYMTAB_KIND_EVENT 4
#define XM_WASM_SYMTAB_KIND_TABLE 5
#define XM_WASM_SYMTAB_KIND_TAG 6
// symbol table flags (linking section)
#define XM_WASM_SYMTAB_FLAG_UNDEFINED 0x10
// symbol types for binutils.readsyms
#define XM_WASM_SYM_UNDEF "U"
#define XM_WASM_SYM_TEXT "T"
#define XM_WASM_SYM_DATA "D"
/* //////////////////////////////////////////////////////////////////////////////////////
* inline implementation
*/
// decode unsigned leb128 (u32) from current stream offset
static __tb_inline__ tb_bool_t xm_binutils_wasm_read_u32_leb(tb_stream_ref_t istream, tb_uint32_t* out) {
tb_uint32_t result = 0;
tb_uint32_t shift = 0;
tb_byte_t byte = 0;
for (tb_size_t i = 0; i < XM_WASM_U32_LEB_MAX; i++) {
if (!tb_stream_bread(istream, &byte, 1)) {
return tb_false;
}
result |= ((tb_uint32_t)(byte & 0x7f)) << shift;
if (!(byte & 0x80)) {
*out = result;
return tb_true;
}
shift += 7;
}
return tb_false;
}
// decode unsigned leb128 (u64) from current stream offset
static __tb_inline__ tb_bool_t xm_binutils_wasm_read_u64_leb(tb_stream_ref_t istream, tb_uint64_t* out) {
tb_uint64_t result = 0;
tb_uint32_t shift = 0;
tb_byte_t byte = 0;
for (tb_size_t i = 0; i < XM_WASM_U64_LEB_MAX; i++) {
if (!tb_stream_bread(istream, &byte, 1)) {
return tb_false;
}
result |= ((tb_uint64_t)(byte & 0x7f)) << shift;
if (!(byte & 0x80)) {
*out = result;
return tb_true;
}
shift += 7;
}
return tb_false;
}
// read wasm "name" (u32 leb length + bytes), truncate to fit buffer and skip remaining bytes
static __tb_inline__ tb_bool_t xm_binutils_wasm_read_name(tb_stream_ref_t istream, tb_char_t* name, tb_size_t name_size) {
tb_uint32_t len = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &len)) {
return tb_false;
}
tb_size_t readn = (tb_size_t)tb_min((tb_uint32_t)(name_size > 0 ? name_size - 1 : 0), len);
if (readn && !tb_stream_bread(istream, (tb_byte_t*)name, readn)) {
return tb_false;
}
if (name_size) {
name[readn] = '\0';
}
if (len > readn) {
if (!tb_stream_skip(istream, (tb_hize_t)(len - readn))) {
return tb_false;
}
}
return tb_true;
}
// skip wasm limits used by table/memory types, supports wasm32 and wasm64(memory64)
static __tb_inline__ tb_bool_t xm_binutils_wasm_skip_limits(tb_stream_ref_t istream) {
tb_uint32_t flags = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) {
return tb_false;
}
if (flags & XM_WASM_LIMITS_MEM64) {
tb_uint64_t tmp64 = 0;
if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) {
return tb_false;
}
if (flags & XM_WASM_LIMITS_HAS_MAX) {
if (!xm_binutils_wasm_read_u64_leb(istream, &tmp64)) {
return tb_false;
}
}
} else {
tb_uint32_t tmp32 = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) {
return tb_false;
}
if (flags & XM_WASM_LIMITS_HAS_MAX) {
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp32)) {
return tb_false;
}
}
}
return tb_true;
}
// add one symbol table entry: {name=..., type=...}
static __tb_inline__ tb_void_t xm_binutils_wasm_add_symbol(lua_State* lua, tb_size_t* result_count, tb_char_t const* name, tb_char_t const* type) {
lua_pushinteger(lua, (lua_Integer)(*result_count + 1));
lua_newtable(lua);
lua_pushstring(lua, "name");
lua_pushstring(lua, name);
lua_settable(lua, -3);
lua_pushstring(lua, "type");
lua_pushstring(lua, type);
lua_settable(lua, -3);
lua_settable(lua, -3);
(*result_count)++;
}
// seek and validate wasm header at base_offset, leave stream offset after header
static __tb_inline__ tb_bool_t xm_binutils_wasm_check_header(tb_stream_ref_t istream, tb_hize_t base_offset) {
if (!tb_stream_seek(istream, base_offset)) {
return tb_false;
}
tb_uint8_t header[XM_WASM_HEADER_SIZE];
if (!tb_stream_bread(istream, header, XM_WASM_HEADER_SIZE)) {
return tb_false;
}
if (header[0] != XM_WASM_MAGIC0 || header[1] != XM_WASM_MAGIC1 || header[2] != XM_WASM_MAGIC2 || header[3] != XM_WASM_MAGIC3) {
return tb_false;
}
return tb_true;
}
#endif
================================================
FILE: core/src/xmake/binutils/wasm/readsyms.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readsyms.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "wasm_readsyms"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
static tb_bool_t xm_binutils_wasm_parse_linking_symtab(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) {
tb_uint32_t symcount = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &symcount)) {
return tb_false;
}
for (tb_uint32_t i = 0; i < symcount; i++) {
tb_byte_t kind = 0;
if (!tb_stream_bread(istream, &kind, 1)) {
return tb_false;
}
tb_uint32_t flags = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &flags)) {
return tb_false;
}
tb_bool_t is_undef = (flags & XM_WASM_SYMTAB_FLAG_UNDEFINED) != 0;
tb_char_t name[256] = {0};
if (kind == XM_WASM_SYMTAB_KIND_FUNCTION || kind == XM_WASM_SYMTAB_KIND_GLOBAL ||
kind == XM_WASM_SYMTAB_KIND_EVENT || kind == XM_WASM_SYMTAB_KIND_TABLE ||
kind == XM_WASM_SYMTAB_KIND_TAG) {
if (!is_undef) {
tb_uint32_t index = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &index)) {
return tb_false;
}
}
if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {
return tb_false;
}
} else if (kind == XM_WASM_SYMTAB_KIND_DATA) {
if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {
return tb_false;
}
if (!is_undef) {
tb_uint32_t tmp = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // segment
return tb_false;
}
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // offset
return tb_false;
}
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) { // size
return tb_false;
}
}
} else if (kind == XM_WASM_SYMTAB_KIND_SECTION) {
tb_uint32_t section_index = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, §ion_index)) {
return tb_false;
}
if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {
return tb_false;
}
} else {
return tb_false;
}
if (name[0]) {
tb_char_t const* type = XM_WASM_SYM_DATA;
if (is_undef) {
type = XM_WASM_SYM_UNDEF;
} else if (kind == XM_WASM_SYMTAB_KIND_FUNCTION) {
type = XM_WASM_SYM_TEXT;
}
xm_binutils_wasm_add_symbol(lua, result_count, name, type);
}
if (tb_stream_offset(istream) > payload_end) {
return tb_false;
}
}
return tb_true;
}
static tb_bool_t xm_binutils_wasm_parse_custom_linking(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) {
tb_uint32_t version = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &version)) {
return tb_false;
}
while (tb_stream_offset(istream) < payload_end) {
tb_byte_t subsec_type = 0;
if (!tb_stream_bread(istream, &subsec_type, 1)) {
return tb_false;
}
tb_uint32_t subsec_size = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) {
return tb_false;
}
tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size;
if (subsec_end > payload_end) {
return tb_false;
}
if (subsec_type == XM_WASM_LINKING_SUBSEC_SYMTAB) {
if (!xm_binutils_wasm_parse_linking_symtab(istream, subsec_end, lua, result_count)) {
return tb_false;
}
}
if (tb_stream_offset(istream) < subsec_end) {
if (!tb_stream_seek(istream, subsec_end)) {
return tb_false;
}
}
}
return version > 0 ? tb_true : tb_false;
}
static tb_bool_t xm_binutils_wasm_parse_custom_name(tb_stream_ref_t istream, tb_hize_t payload_end, lua_State* lua, tb_size_t* result_count) {
// only use the name section as a fallback when we have no symbols yet
if (*result_count != 0) {
return tb_true;
}
while (tb_stream_offset(istream) < payload_end) {
tb_byte_t subsec_type = 0;
if (!tb_stream_bread(istream, &subsec_type, 1)) {
return tb_false;
}
tb_uint32_t subsec_size = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &subsec_size)) {
return tb_false;
}
tb_hize_t subsec_end = tb_stream_offset(istream) + (tb_hize_t)subsec_size;
if (subsec_end > payload_end) {
return tb_false;
}
if (subsec_type == 1) {
tb_uint32_t count = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &count)) {
return tb_false;
}
for (tb_uint32_t i = 0; i < count; i++) {
tb_uint32_t index = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &index)) {
return tb_false;
}
tb_char_t name[256] = {0};
if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {
return tb_false;
}
if (name[0]) {
xm_binutils_wasm_add_symbol(lua, result_count, name, XM_WASM_SYM_TEXT);
}
if (tb_stream_offset(istream) > subsec_end) {
return tb_false;
}
}
}
if (tb_stream_offset(istream) < subsec_end) {
if (!tb_stream_seek(istream, subsec_end)) {
return tb_false;
}
}
}
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
tb_bool_t xm_binutils_wasm_read_symbols(tb_stream_ref_t istream, tb_hize_t base_offset, lua_State *lua) {
tb_assert_and_check_return_val(istream && lua, tb_false);
if (!xm_binutils_wasm_check_header(istream, base_offset)) {
return tb_false;
}
lua_newtable(lua);
tb_size_t result_count = 0;
// parse wasm sections until EOF, collect imports/exports as symbols
for (;;) {
tb_byte_t section_id = 0;
if (!tb_stream_bread(istream, §ion_id, 1)) {
break;
}
tb_uint32_t payload_len = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &payload_len)) {
break;
}
tb_hize_t payload_start = tb_stream_offset(istream);
tb_hize_t payload_end = payload_start + (tb_hize_t)payload_len;
if (payload_len == 0) {
continue;
}
if (section_id == 0) {
// custom section: name + custom payload
tb_char_t custom_name[64] = {0};
if (!xm_binutils_wasm_read_name(istream, custom_name, sizeof(custom_name))) {
break;
}
if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_LINKING)) {
if (!xm_binutils_wasm_parse_custom_linking(istream, payload_end, lua, &result_count)) {
break;
}
} else if (!tb_strcmp(custom_name, XM_WASM_CUSTOM_NAME)) {
if (!xm_binutils_wasm_parse_custom_name(istream, payload_end, lua, &result_count)) {
break;
}
}
} else if (section_id == XM_WASM_SECTION_IMPORT) {
// import section: (vec import), each import => undefined symbol
tb_uint32_t count = 0;
if (xm_binutils_wasm_read_u32_leb(istream, &count)) {
for (tb_uint32_t i = 0; i < count; i++) {
tb_char_t module[256] = {0};
tb_char_t field[256] = {0};
if (!xm_binutils_wasm_read_name(istream, module, sizeof(module))) {
break;
}
if (!xm_binutils_wasm_read_name(istream, field, sizeof(field))) {
break;
}
tb_byte_t kind = 0;
if (!tb_stream_bread(istream, &kind, 1)) {
break;
}
tb_uint32_t tmp = 0;
if (kind == XM_WASM_KIND_FUNC) {
// type index (u32)
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) {
break;
}
} else if (kind == XM_WASM_KIND_TABLE) {
// table type: elemtype + limits
if (!tb_stream_bread(istream, (tb_byte_t*)&kind, 1)) {
break;
}
if (!xm_binutils_wasm_skip_limits(istream)) {
break;
}
} else if (kind == XM_WASM_KIND_MEMORY) {
// memory type: limits
if (!xm_binutils_wasm_skip_limits(istream)) {
break;
}
} else if (kind == XM_WASM_KIND_GLOBAL) {
// global type: valtype + mut
tb_byte_t b = 0;
if (!tb_stream_bread(istream, &b, 1)) {
break;
}
if (!tb_stream_bread(istream, &b, 1)) {
break;
}
} else if (kind == XM_WASM_KIND_TAG) {
// tag: attribute + type index
if (!xm_binutils_wasm_read_u32_leb(istream, &tmp)) {
break;
}
} else {
break;
}
// keep consistent with nm-style output: use the imported field name as symbol name
if (field[0]) {
xm_binutils_wasm_add_symbol(lua, &result_count, field, XM_WASM_SYM_UNDEF);
} else if (module[0]) {
xm_binutils_wasm_add_symbol(lua, &result_count, module, XM_WASM_SYM_UNDEF);
}
}
}
} else if (section_id == XM_WASM_SECTION_EXPORT) {
// export section: (vec export), each export => defined symbol
tb_uint32_t count = 0;
if (xm_binutils_wasm_read_u32_leb(istream, &count)) {
for (tb_uint32_t i = 0; i < count; i++) {
tb_char_t name[256] = {0};
if (!xm_binutils_wasm_read_name(istream, name, sizeof(name))) {
break;
}
tb_byte_t kind = 0;
if (!tb_stream_bread(istream, &kind, 1)) {
break;
}
tb_uint32_t index = 0;
if (!xm_binutils_wasm_read_u32_leb(istream, &index)) {
break;
}
if (name[0]) {
// keep consistent with other formats: function => "T", others => "D"
tb_char_t const* type = XM_WASM_SYM_DATA;
if (kind == XM_WASM_KIND_FUNC) {
type = XM_WASM_SYM_TEXT;
}
xm_binutils_wasm_add_symbol(lua, &result_count, name, type);
}
}
}
}
// always seek to end of section payload to continue scanning
if (tb_stream_offset(istream) < payload_end) {
if (!tb_stream_seek(istream, payload_end)) {
break;
}
}
}
return tb_true;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_clear.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_clear.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_clear"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_clear(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// clear filter
tb_bloom_filter_clear(filter);
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// exit filter
tb_bloom_filter_exit(filter);
// save result: ok
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_data.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_data.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_data"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_data(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// get data
tb_pointer_t data = (tb_pointer_t)tb_bloom_filter_data(filter);
if (data) {
xm_lua_pushpointer(lua, data);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_data_set.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_data_set.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_data_set"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_data_set(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (xm_lua_isinteger(lua, 3)) {
size = (tb_size_t)lua_tointeger(lua, 3);
}
if (!data || !size) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// set data
tb_bool_t ok = tb_bloom_filter_data_set(filter, data, size);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_get.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_get.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_get"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_get(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// get item
tb_char_t const *item = luaL_checkstring(lua, 2);
tb_assert_and_check_return_val(item, 0);
// get item
tb_bool_t ok = tb_bloom_filter_get(filter, item);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get arguments
tb_int_t probability = (tb_int_t)lua_tointeger(lua, 1);
tb_int_t hash_count = (tb_int_t)lua_tointeger(lua, 2);
tb_int_t item_maxn = (tb_int_t)lua_tointeger(lua, 3);
if (hash_count > 16 || item_maxn < 0) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid hash count(%p) and item maxn(%d)!", hash_count, item_maxn);
return 2;
}
// init the bloom filter
tb_bloom_filter_ref_t filter = tb_bloom_filter_init(probability, hash_count, item_maxn, tb_element_str(tb_true));
if (filter) {
xm_lua_pushpointer(lua, (tb_pointer_t)filter);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_set.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_set.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_set"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_set(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// get item
tb_char_t const *item = luaL_checkstring(lua, 2);
tb_assert_and_check_return_val(item, 0);
// set item
tb_bool_t ok = tb_bloom_filter_set(filter, item);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/bloom_filter_size.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file bloom_filter_size.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "bloom_filter_size"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_bloom_filter_size(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the bloom filter
tb_bloom_filter_ref_t filter = (tb_bloom_filter_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(filter, 0);
// get size
tb_size_t size = tb_bloom_filter_size(filter);
lua_pushinteger(lua, (tb_int_t)size);
return 1;
}
================================================
FILE: core/src/xmake/bloom_filter/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except idata compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to idata writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_BLOOM_FILTER_PREFIX_H
#define XM_BLOOM_FILTER_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/config.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file config.h
*
*/
#ifndef XM_CORE_CONFIG_H
#define XM_CORE_CONFIG_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "xmake.config.h"
#endif
================================================
FILE: core/src/xmake/curses/curses.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file curses.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "curses"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#ifdef XM_CONFIG_API_HAVE_CURSES
#include "prefix.h"
#include
#if defined(PDCURSES)
// fix macro redefinition
#undef MOUSE_MOVED
#endif
#define NCURSES_MOUSE_VERSION 2
#ifdef TB_COMPILER_IS_MINGW
#include
#else
#include
#endif
#if defined(NCURSES_VERSION)
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_CURSES_STDSCR "curses.stdscr"
#define XM_CURSES_WINDOW "curses.window"
#define XM_CURSES_OK(v) (((v) == ERR) ? 0 : 1)
// define functions
#define XM_CURSES_NUMBER(n) \
static int xm_curses_##n(lua_State *lua) { \
lua_pushnumber(lua, n()); \
return 1; \
}
#define XM_CURSES_NUMBER2(n, v) \
static int xm_curses_##n(lua_State *lua) { \
lua_pushnumber(lua, v); \
return 1; \
}
#define XM_CURSES_BOOL(n) \
static int xm_curses_##n(lua_State *lua) { \
lua_pushboolean(lua, n()); \
return 1; \
}
#define XM_CURSES_BOOLOK(n) \
static int xm_curses_##n(lua_State *lua) { \
lua_pushboolean(lua, XM_CURSES_OK(n())); \
return 1; \
}
#define XM_CURSES_WINDOW_BOOLOK(n) \
static int xm_curses_window_##n(lua_State *lua) { \
WINDOW *w = xm_curses_window_check(lua, 1); \
lua_pushboolean(lua, XM_CURSES_OK(n(w))); \
return 1; \
}
// define constants
#define XM_CURSES_CONST_(n, v) \
lua_pushstring(lua, n); \
lua_pushnumber(lua, v); \
lua_settable(lua, lua_upvalueindex(1));
#define XM_CURSES_CONST(s) XM_CURSES_CONST_(#s, s)
#define XM_CURSES_CONST2(s, v) XM_CURSES_CONST_(#s, v)
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
// map key for pdcurses, keeping the keys consistent with ncurses
static int g_mapkey = 0;
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static chtype xm_curses_checkch(lua_State *lua, int index) {
if (lua_type(lua, index) == LUA_TNUMBER) {
return (chtype)luaL_checknumber(lua, index);
}
if (lua_type(lua, index) == LUA_TSTRING) {
return *lua_tostring(lua, index);
}
#ifdef USE_LUAJIT
luaL_typerror(lua, index, "chtype");
#endif
return (chtype)0;
}
// get character and map key
static int xm_curses_window_getch_impl(WINDOW *w) {
#ifdef PDCURSES
static int has_key = 0;
static int temp_key = 0;
int key;
if (g_mapkey && has_key) {
has_key = 0;
return temp_key;
}
key = wgetch(w);
if (key == KEY_RESIZE)
resize_term(0, 0);
if (key == ERR || !g_mapkey)
return key;
if (key >= ALT_A && key <= ALT_Z) {
has_key = 1;
temp_key = key - ALT_A + 'A';
} else if (key >= ALT_0 && key <= ALT_9) {
has_key = 1;
temp_key = key - ALT_0 + '0';
} else {
switch (key) {
case ALT_DEL:
temp_key = KEY_DC;
break;
case ALT_INS:
temp_key = KEY_IC;
break;
case ALT_HOME:
temp_key = KEY_HOME;
break;
case ALT_END:
temp_key = KEY_END;
break;
case ALT_PGUP:
temp_key = KEY_PPAGE;
break;
case ALT_PGDN:
temp_key = KEY_NPAGE;
break;
case ALT_UP:
temp_key = KEY_UP;
break;
case ALT_DOWN:
temp_key = KEY_DOWN;
break;
case ALT_RIGHT:
temp_key = KEY_RIGHT;
break;
case ALT_LEFT:
temp_key = KEY_LEFT;
break;
case ALT_BKSP:
temp_key = KEY_BACKSPACE;
break;
default:
return key;
}
}
has_key = 1;
return 27;
#else
return wgetch(w);
#endif
}
// new a window object
static void xm_curses_window_new(lua_State *lua, WINDOW *nw) {
if (nw) {
WINDOW **w = (WINDOW **)lua_newuserdata(lua, sizeof(WINDOW *));
luaL_getmetatable(lua, XM_CURSES_WINDOW);
lua_setmetatable(lua, -2);
*w = nw;
} else {
lua_pushliteral(lua, "failed to create window");
lua_error(lua);
}
}
// get window
static WINDOW **xm_curses_window_get(lua_State *lua, int index) {
WINDOW **w = (WINDOW **)luaL_checkudata(lua, index, XM_CURSES_WINDOW);
if (w == NULL)
luaL_argerror(lua, index, "bad curses window");
return w;
}
// get and check window
static WINDOW *xm_curses_window_check(lua_State *lua, int index) {
WINDOW **w = xm_curses_window_get(lua, index);
if (*w == NULL)
luaL_argerror(lua, index, "attempt to use closed curses window");
return *w;
}
// tostring(window)
static int xm_curses_window_tostring(lua_State *lua) {
WINDOW **w = xm_curses_window_get(lua, 1);
char const *s = NULL;
if (*w)
s = (char const *)lua_touserdata(lua, 1);
lua_pushfstring(lua, "curses window (%s)", s ? s : "closed");
return 1;
}
// window:move(y, x)
static int xm_curses_window_move(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int y = luaL_checkint(lua, 2);
int x = luaL_checkint(lua, 3);
lua_pushboolean(lua, XM_CURSES_OK(wmove(w, y, x)));
return 1;
}
// window:getyx(y, x)
static int xm_curses_window_getyx(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int y, x;
getyx(w, y, x);
lua_pushnumber(lua, y);
lua_pushnumber(lua, x);
return 2;
}
// window:getmaxyx(y, x)
static int xm_curses_window_getmaxyx(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int y, x;
getmaxyx(w, y, x);
lua_pushnumber(lua, y);
lua_pushnumber(lua, x);
return 2;
}
// window:delwin()
static int xm_curses_window_delwin(lua_State *lua) {
WINDOW **w = xm_curses_window_get(lua, 1);
if (*w && *w != stdscr) {
delwin(*w);
*w = NULL;
}
return 0;
}
// window:addch(ch)
static int xm_curses_window_addch(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
chtype ch = xm_curses_checkch(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(waddch(w, ch)));
return 1;
}
// window:addnstr(str)
static int xm_curses_window_addnstr(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
const char *str = luaL_checkstring(lua, 2);
int n = luaL_optint(lua, 3, -1);
if (n < 0)
n = (int)lua_strlen(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(waddnstr(w, str, n)));
return 1;
}
// window:keypad(true)
static int xm_curses_window_keypad(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int enabled = lua_isnoneornil(lua, 2) ? 1 : lua_toboolean(lua, 2);
if (enabled) {
// on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys,
// only makes sense when using keypad(true) and echo(false)
g_mapkey = 1;
}
lua_pushboolean(lua, XM_CURSES_OK(keypad(w, enabled)));
return 1;
}
// window:meta(true)
static int xm_curses_window_meta(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int enabled = lua_toboolean(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(meta(w, enabled)));
return 1;
}
// window:nodelay(true)
static int xm_curses_window_nodelay(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int enabled = lua_toboolean(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(nodelay(w, enabled)));
return 1;
}
// window:leaveok(true)
static int xm_curses_window_leaveok(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int enabled = lua_toboolean(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(leaveok(w, enabled)));
return 1;
}
// window:getch()
static int xm_curses_window_getch(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int c = xm_curses_window_getch_impl(w);
if (c == ERR)
return 0;
lua_pushnumber(lua, c);
return 1;
}
// window:attroff(attrs)
static int xm_curses_window_attroff(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int attrs = luaL_checkint(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(wattroff(w, attrs)));
return 1;
}
// window:attron(attrs)
static int xm_curses_window_attron(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int attrs = luaL_checkint(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(wattron(w, attrs)));
return 1;
}
// window:attrset(attrs)
static int xm_curses_window_attrset(lua_State *lua) {
WINDOW *w = xm_curses_window_check(lua, 1);
int attrs = luaL_checkint(lua, 2);
lua_pushboolean(lua, XM_CURSES_OK(wattrset(w, attrs)));
return 1;
}
// window:copywin(...)
static int xm_curses_window_copywin(lua_State *lua) {
WINDOW *srcwin = xm_curses_window_check(lua, 1);
WINDOW *dstwin = xm_curses_window_check(lua, 2);
int sminrow = luaL_checkint(lua, 3);
int smincol = luaL_checkint(lua, 4);
int dminrow = luaL_checkint(lua, 5);
int dmincol = luaL_checkint(lua, 6);
int dmaxrow = luaL_checkint(lua, 7);
int dmaxcol = luaL_checkint(lua, 8);
int overlay = lua_toboolean(lua, 9);
lua_pushboolean(lua,
XM_CURSES_OK(
copywin(srcwin, dstwin, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay)));
return 1;
}
// clean window after exiting program
static void xm_curses_cleanup() {
if (!isendwin()) {
wclear(stdscr);
wrefresh(stdscr);
endwin();
}
}
// register constants
static void xm_curses_register_constants(lua_State *lua) {
// colors
XM_CURSES_CONST(COLOR_BLACK)
XM_CURSES_CONST(COLOR_RED)
XM_CURSES_CONST(COLOR_GREEN)
XM_CURSES_CONST(COLOR_YELLOW)
XM_CURSES_CONST(COLOR_BLUE)
XM_CURSES_CONST(COLOR_MAGENTA)
XM_CURSES_CONST(COLOR_CYAN)
XM_CURSES_CONST(COLOR_WHITE)
// alternate character set
XM_CURSES_CONST(ACS_BLOCK)
XM_CURSES_CONST(ACS_BOARD)
XM_CURSES_CONST(ACS_BTEE)
XM_CURSES_CONST(ACS_TTEE)
XM_CURSES_CONST(ACS_LTEE)
XM_CURSES_CONST(ACS_RTEE)
XM_CURSES_CONST(ACS_LLCORNER)
XM_CURSES_CONST(ACS_LRCORNER)
XM_CURSES_CONST(ACS_URCORNER)
XM_CURSES_CONST(ACS_ULCORNER)
XM_CURSES_CONST(ACS_LARROW)
XM_CURSES_CONST(ACS_RARROW)
XM_CURSES_CONST(ACS_UARROW)
XM_CURSES_CONST(ACS_DARROW)
XM_CURSES_CONST(ACS_HLINE)
XM_CURSES_CONST(ACS_VLINE)
XM_CURSES_CONST(ACS_BULLET)
XM_CURSES_CONST(ACS_CKBOARD)
XM_CURSES_CONST(ACS_LANTERN)
XM_CURSES_CONST(ACS_DEGREE)
XM_CURSES_CONST(ACS_DIAMOND)
XM_CURSES_CONST(ACS_PLMINUS)
XM_CURSES_CONST(ACS_PLUS)
XM_CURSES_CONST(ACS_S1)
XM_CURSES_CONST(ACS_S9)
// attributes
XM_CURSES_CONST(A_NORMAL)
XM_CURSES_CONST(A_STANDOUT)
XM_CURSES_CONST(A_UNDERLINE)
XM_CURSES_CONST(A_REVERSE)
XM_CURSES_CONST(A_BLINK)
XM_CURSES_CONST(A_DIM)
XM_CURSES_CONST(A_BOLD)
XM_CURSES_CONST(A_PROTECT)
XM_CURSES_CONST(A_INVIS)
XM_CURSES_CONST(A_ALTCHARSET)
XM_CURSES_CONST(A_CHARTEXT)
// key functions
XM_CURSES_CONST(KEY_BREAK)
XM_CURSES_CONST(KEY_DOWN)
XM_CURSES_CONST(KEY_UP)
XM_CURSES_CONST(KEY_LEFT)
XM_CURSES_CONST(KEY_RIGHT)
XM_CURSES_CONST(KEY_HOME)
XM_CURSES_CONST(KEY_BACKSPACE)
XM_CURSES_CONST(KEY_DL)
XM_CURSES_CONST(KEY_IL)
XM_CURSES_CONST(KEY_DC)
XM_CURSES_CONST(KEY_IC)
XM_CURSES_CONST(KEY_EIC)
XM_CURSES_CONST(KEY_CLEAR)
XM_CURSES_CONST(KEY_EOS)
XM_CURSES_CONST(KEY_EOL)
XM_CURSES_CONST(KEY_SF)
XM_CURSES_CONST(KEY_SR)
XM_CURSES_CONST(KEY_NPAGE)
XM_CURSES_CONST(KEY_PPAGE)
XM_CURSES_CONST(KEY_STAB)
XM_CURSES_CONST(KEY_CTAB)
XM_CURSES_CONST(KEY_CATAB)
XM_CURSES_CONST(KEY_ENTER)
XM_CURSES_CONST(KEY_SRESET)
XM_CURSES_CONST(KEY_RESET)
XM_CURSES_CONST(KEY_PRINT)
XM_CURSES_CONST(KEY_LL)
XM_CURSES_CONST(KEY_A1)
XM_CURSES_CONST(KEY_A3)
XM_CURSES_CONST(KEY_B2)
XM_CURSES_CONST(KEY_C1)
XM_CURSES_CONST(KEY_C3)
XM_CURSES_CONST(KEY_BTAB)
XM_CURSES_CONST(KEY_BEG)
XM_CURSES_CONST(KEY_CANCEL)
XM_CURSES_CONST(KEY_CLOSE)
XM_CURSES_CONST(KEY_COMMAND)
XM_CURSES_CONST(KEY_COPY)
XM_CURSES_CONST(KEY_CREATE)
XM_CURSES_CONST(KEY_END)
XM_CURSES_CONST(KEY_EXIT)
XM_CURSES_CONST(KEY_FIND)
XM_CURSES_CONST(KEY_HELP)
XM_CURSES_CONST(KEY_MARK)
XM_CURSES_CONST(KEY_MESSAGE)
#ifdef PDCURSES
// https://github.com/xmake-io/xmake/issues/1610#issuecomment-971149885
XM_CURSES_CONST(KEY_C2)
XM_CURSES_CONST(KEY_A2)
XM_CURSES_CONST(KEY_B1)
XM_CURSES_CONST(KEY_B3)
#endif
#if !defined(XCURSES)
#ifndef NOMOUSE
XM_CURSES_CONST(KEY_MOUSE)
#endif
#endif
XM_CURSES_CONST(KEY_MOVE)
XM_CURSES_CONST(KEY_NEXT)
XM_CURSES_CONST(KEY_OPEN)
XM_CURSES_CONST(KEY_OPTIONS)
XM_CURSES_CONST(KEY_PREVIOUS)
XM_CURSES_CONST(KEY_REDO)
XM_CURSES_CONST(KEY_REFERENCE)
XM_CURSES_CONST(KEY_REFRESH)
XM_CURSES_CONST(KEY_REPLACE)
XM_CURSES_CONST(KEY_RESIZE)
XM_CURSES_CONST(KEY_RESTART)
XM_CURSES_CONST(KEY_RESUME)
XM_CURSES_CONST(KEY_SAVE)
XM_CURSES_CONST(KEY_SBEG)
XM_CURSES_CONST(KEY_SCANCEL)
XM_CURSES_CONST(KEY_SCOMMAND)
XM_CURSES_CONST(KEY_SCOPY)
XM_CURSES_CONST(KEY_SCREATE)
XM_CURSES_CONST(KEY_SDC)
XM_CURSES_CONST(KEY_SDL)
XM_CURSES_CONST(KEY_SELECT)
XM_CURSES_CONST(KEY_SEND)
XM_CURSES_CONST(KEY_SEOL)
XM_CURSES_CONST(KEY_SEXIT)
XM_CURSES_CONST(KEY_SFIND)
XM_CURSES_CONST(KEY_SHELP)
XM_CURSES_CONST(KEY_SHOME)
XM_CURSES_CONST(KEY_SIC)
XM_CURSES_CONST(KEY_SLEFT)
XM_CURSES_CONST(KEY_SMESSAGE)
XM_CURSES_CONST(KEY_SMOVE)
XM_CURSES_CONST(KEY_SNEXT)
XM_CURSES_CONST(KEY_SOPTIONS)
XM_CURSES_CONST(KEY_SPREVIOUS)
XM_CURSES_CONST(KEY_SPRINT)
XM_CURSES_CONST(KEY_SREDO)
XM_CURSES_CONST(KEY_SREPLACE)
XM_CURSES_CONST(KEY_SRIGHT)
XM_CURSES_CONST(KEY_SRSUME)
XM_CURSES_CONST(KEY_SSAVE)
XM_CURSES_CONST(KEY_SSUSPEND)
XM_CURSES_CONST(KEY_SUNDO)
XM_CURSES_CONST(KEY_SUSPEND)
XM_CURSES_CONST(KEY_UNDO)
// KEY_Fx 0 <= x <= 63
XM_CURSES_CONST(KEY_F0)
XM_CURSES_CONST2(KEY_F1, KEY_F(1))
XM_CURSES_CONST2(KEY_F2, KEY_F(2))
XM_CURSES_CONST2(KEY_F3, KEY_F(3))
XM_CURSES_CONST2(KEY_F4, KEY_F(4))
XM_CURSES_CONST2(KEY_F5, KEY_F(5))
XM_CURSES_CONST2(KEY_F6, KEY_F(6))
XM_CURSES_CONST2(KEY_F7, KEY_F(7))
XM_CURSES_CONST2(KEY_F8, KEY_F(8))
XM_CURSES_CONST2(KEY_F9, KEY_F(9))
XM_CURSES_CONST2(KEY_F10, KEY_F(10))
XM_CURSES_CONST2(KEY_F11, KEY_F(11))
XM_CURSES_CONST2(KEY_F12, KEY_F(12))
#if !defined(XCURSES)
#ifndef NOMOUSE
// mouse constants
XM_CURSES_CONST(BUTTON1_RELEASED)
XM_CURSES_CONST(BUTTON1_PRESSED)
XM_CURSES_CONST(BUTTON1_CLICKED)
XM_CURSES_CONST(BUTTON1_DOUBLE_CLICKED)
XM_CURSES_CONST(BUTTON1_TRIPLE_CLICKED)
XM_CURSES_CONST(BUTTON2_RELEASED)
XM_CURSES_CONST(BUTTON2_PRESSED)
XM_CURSES_CONST(BUTTON2_CLICKED)
XM_CURSES_CONST(BUTTON2_DOUBLE_CLICKED)
XM_CURSES_CONST(BUTTON2_TRIPLE_CLICKED)
XM_CURSES_CONST(BUTTON3_RELEASED)
XM_CURSES_CONST(BUTTON3_PRESSED)
XM_CURSES_CONST(BUTTON3_CLICKED)
XM_CURSES_CONST(BUTTON3_DOUBLE_CLICKED)
XM_CURSES_CONST(BUTTON3_TRIPLE_CLICKED)
XM_CURSES_CONST(BUTTON4_RELEASED)
XM_CURSES_CONST(BUTTON4_PRESSED)
XM_CURSES_CONST(BUTTON4_CLICKED)
XM_CURSES_CONST(BUTTON4_DOUBLE_CLICKED)
XM_CURSES_CONST(BUTTON4_TRIPLE_CLICKED)
XM_CURSES_CONST(BUTTON_CTRL)
XM_CURSES_CONST(BUTTON_SHIFT)
XM_CURSES_CONST(BUTTON_ALT)
XM_CURSES_CONST(REPORT_MOUSE_POSITION)
XM_CURSES_CONST(ALL_MOUSE_EVENTS)
#if NCURSES_MOUSE_VERSION > 1
XM_CURSES_CONST(BUTTON5_RELEASED)
XM_CURSES_CONST(BUTTON5_PRESSED)
XM_CURSES_CONST(BUTTON5_CLICKED)
XM_CURSES_CONST(BUTTON5_DOUBLE_CLICKED)
XM_CURSES_CONST(BUTTON5_TRIPLE_CLICKED)
#endif
#endif
#endif
}
// init curses
static int xm_curses_initscr(lua_State *lua) {
WINDOW *w = initscr();
if (!w)
return 0;
xm_curses_window_new(lua, w);
#if defined(NCURSES_VERSION)
// ESCDELAY = 0;
set_escdelay(0);
#endif
lua_pushstring(lua, XM_CURSES_STDSCR);
lua_pushvalue(lua, -2);
lua_rawset(lua, LUA_REGISTRYINDEX);
xm_curses_register_constants(lua);
#ifndef PDCURSES
atexit(xm_curses_cleanup);
#endif
return 1;
}
static int xm_curses_endwin(lua_State *lua) {
endwin();
#ifdef XCURSES
XCursesExit();
exit(0);
#endif
return 0;
}
static int xm_curses_stdscr(lua_State *lua) {
lua_pushstring(lua, XM_CURSES_STDSCR);
lua_rawget(lua, LUA_REGISTRYINDEX);
return 1;
}
#if !defined(XCURSES) && !defined(NOMOUSE)
static int xm_curses_getmouse(lua_State *lua) {
MEVENT e;
if (getmouse(&e) == OK) {
lua_pushinteger(lua, e.bstate);
lua_pushinteger(lua, e.x);
lua_pushinteger(lua, e.y);
lua_pushinteger(lua, e.z);
lua_pushinteger(lua, e.id);
return 5;
}
lua_pushnil(lua);
return 1;
}
static int xm_curses_mousemask(lua_State *lua) {
mmask_t m = luaL_checkint(lua, 1);
mmask_t om;
m = mousemask(m, &om);
lua_pushinteger(lua, m);
lua_pushinteger(lua, om);
return 2;
}
#endif
static int xm_curses_init_pair(lua_State *lua) {
short pair = luaL_checkint(lua, 1);
short f = luaL_checkint(lua, 2);
short b = luaL_checkint(lua, 3);
lua_pushboolean(lua, XM_CURSES_OK(init_pair(pair, f, b)));
return 1;
}
static int xm_curses_COLOR_PAIR(lua_State *lua) {
int n = luaL_checkint(lua, 1);
lua_pushnumber(lua, COLOR_PAIR(n));
return 1;
}
static int xm_curses_curs_set(lua_State *lua) {
int vis = luaL_checkint(lua, 1);
int state = curs_set(vis);
if (state == ERR)
return 0;
lua_pushnumber(lua, state);
return 1;
}
static int xm_curses_napms(lua_State *lua) {
int ms = luaL_checkint(lua, 1);
lua_pushboolean(lua, XM_CURSES_OK(napms(ms)));
return 1;
}
static int xm_curses_cbreak(lua_State *lua) {
if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) {
lua_pushboolean(lua, XM_CURSES_OK(cbreak()));
} else {
lua_pushboolean(lua, XM_CURSES_OK(nocbreak()));
}
return 1;
}
static int xm_curses_echo(lua_State *lua) {
if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) {
lua_pushboolean(lua, XM_CURSES_OK(echo()));
} else {
lua_pushboolean(lua, XM_CURSES_OK(noecho()));
}
return 1;
}
static int xm_curses_nl(lua_State *lua) {
if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) {
lua_pushboolean(lua, XM_CURSES_OK(nl()));
} else {
lua_pushboolean(lua, XM_CURSES_OK(nonl()));
}
return 1;
}
static int xm_curses_newpad(lua_State *lua) {
int nlines = luaL_checkint(lua, 1);
int ncols = luaL_checkint(lua, 2);
xm_curses_window_new(lua, newpad(nlines, ncols));
return 1;
}
XM_CURSES_NUMBER2(COLS, COLS)
XM_CURSES_NUMBER2(LINES, LINES)
XM_CURSES_BOOL(isendwin)
XM_CURSES_BOOLOK(start_color)
XM_CURSES_BOOL(has_colors)
XM_CURSES_BOOLOK(doupdate)
XM_CURSES_WINDOW_BOOLOK(wclear)
XM_CURSES_WINDOW_BOOLOK(wnoutrefresh)
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
static const luaL_Reg g_window_functions[] = {
{ "close", xm_curses_window_delwin },
{ "keypad", xm_curses_window_keypad },
{ "meta", xm_curses_window_meta },
{ "nodelay", xm_curses_window_nodelay },
{ "leaveok", xm_curses_window_leaveok },
{ "move", xm_curses_window_move },
{ "clear", xm_curses_window_wclear },
{ "noutrefresh", xm_curses_window_wnoutrefresh },
{ "attroff", xm_curses_window_attroff },
{ "attron", xm_curses_window_attron },
{ "attrset", xm_curses_window_attrset },
{ "getch", xm_curses_window_getch },
{ "getyx", xm_curses_window_getyx },
{ "getmaxyx", xm_curses_window_getmaxyx },
{ "addch", xm_curses_window_addch },
{ "addstr", xm_curses_window_addnstr },
{ "copy", xm_curses_window_copywin },
{ "__gc", xm_curses_window_delwin },
{ "__tostring", xm_curses_window_tostring },
{ NULL, NULL },
};
static const luaL_Reg g_curses_functions[] = {
{ "done", xm_curses_endwin },
{ "isdone", xm_curses_isendwin },
{ "main_window", xm_curses_stdscr },
{ "columns", xm_curses_COLS },
{ "lines", xm_curses_LINES },
{ "start_color", xm_curses_start_color },
{ "has_colors", xm_curses_has_colors },
{ "init_pair", xm_curses_init_pair },
{ "color_pair", xm_curses_COLOR_PAIR },
{ "napms", xm_curses_napms },
{ "cursor_set", xm_curses_curs_set },
{ "new_pad", xm_curses_newpad },
{ "doupdate", xm_curses_doupdate },
{ "cbreak", xm_curses_cbreak },
{ "echo", xm_curses_echo },
{ "nl", xm_curses_nl },
#if !defined(XCURSES)
#ifndef NOMOUSE
{ "mousemask", xm_curses_mousemask },
{ "getmouse", xm_curses_getmouse },
#endif
#endif
{ NULL, NULL },
};
/* //////////////////////////////////////////////////////////////////////////////////////
* implementations
*/
int xm_lua_curses_register(lua_State *lua, const char *module) {
// create new metatable for window objects
luaL_newmetatable(lua, XM_CURSES_WINDOW);
lua_pushliteral(lua, "__index");
lua_pushvalue(lua, -2); /* push metatable */
lua_rawset(lua, -3); /* metatable.__index = metatable */
luaL_setfuncs(lua, g_window_functions, 0);
lua_pop(lua, 1); /* remove metatable from stack */
// create global table with curses methods/variables/constants
lua_newtable(lua);
luaL_setfuncs(lua, g_curses_functions, 0);
// add curses.init()
lua_pushstring(lua, "init");
lua_pushvalue(lua, -2);
lua_pushcclosure(lua, xm_curses_initscr, 1);
lua_settable(lua, -3);
// register global curses module
lua_setglobal(lua, module);
/* since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function.
* that means that you have to call setlocale() in the application and encode Unicode strings using one of the system’s available encodings.
*
* and we need to link libncurses_window.so for drawing vline, hline characters
*/
#if defined(NCURSES_VERSION)
setlocale(LC_ALL, "");
#endif
return 1;
}
#endif
================================================
FILE: core/src/xmake/curses/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file prefix.h
*
*/
#ifndef XM_CURSES_PREFIX_H
#define XM_CURSES_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/engine.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file engine.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "engine"
#define TB_TRACE_MODULE_DEBUG (1)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "xmake.h"
#include "io/poller.h"
#if defined(TB_CONFIG_OS_WINDOWS)
#include
#include
#include
#elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)
#include
#include
#include
#elif defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || defined(TB_CONFIG_OS_ANDROID) || \
defined(TB_CONFIG_OS_HAIKU) || defined(TB_CONFIG_OS_SOLARIS)
#include
#include
#endif
#ifdef TB_CONFIG_OS_BSD
#include
#include
#include
#endif
#ifdef TB_CONFIG_OS_SOLARIS
#include
#include
#endif
#ifdef TB_CONFIG_OS_HAIKU
#include
#endif
#ifdef __COSMOPOLITAN__
#include
#endif
// for uid
#ifndef TB_CONFIG_OS_WINDOWS
#include
#include
#endif
// for embed files
#ifdef XM_EMBED_ENABLE
#include "lz4/prefix.h"
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// proc/self
#if defined(TB_CONFIG_OS_LINUX)
#define XM_PROC_SELF_FILE "/proc/self/exe"
#elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
#if defined(__NetBSD__)
#define XM_PROC_SELF_FILE "/proc/curproc/exe"
#else
#define XM_PROC_SELF_FILE "/proc/curproc/file"
#endif
#elif defined(TB_CONFIG_OS_SOLARIS)
#define XM_PROC_SELF_FILE "/proc/self/path/a.out"
#endif
// hook lua memory allocator
#define XM_HOOK_LUA_MEMALLOC (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the engine type
typedef struct __xm_engine_t {
// the lua
lua_State *lua;
// the engine name
tb_char_t name[64];
// the io poller
tb_poller_ref_t poller;
xm_poller_state_t poller_state;
#ifdef XM_EMBED_ENABLE
// the temporary directory
tb_char_t tmpdir[TB_PATH_MAXN];
// the embed files
tb_byte_t const *embeddata[32];
tb_size_t embedsize[32];
tb_size_t embedcount;
#endif
} xm_engine_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* declaration
*/
// the os functions
tb_int_t xm_os_argv(lua_State *lua);
tb_int_t xm_os_args(lua_State *lua);
tb_int_t xm_os_find(lua_State *lua);
tb_int_t xm_os_link(lua_State *lua);
tb_int_t xm_os_isdir(lua_State *lua);
tb_int_t xm_os_rmdir(lua_State *lua);
tb_int_t xm_os_mkdir(lua_State *lua);
tb_int_t xm_os_cpdir(lua_State *lua);
tb_int_t xm_os_chdir(lua_State *lua);
tb_int_t xm_os_mtime(lua_State *lua);
tb_int_t xm_os_sleep(lua_State *lua);
tb_int_t xm_os_mclock(lua_State *lua);
tb_int_t xm_os_curdir(lua_State *lua);
tb_int_t xm_os_tmpdir(lua_State *lua);
tb_int_t xm_os_islink(lua_State *lua);
tb_int_t xm_os_isfile(lua_State *lua);
tb_int_t xm_os_touch(lua_State *lua);
tb_int_t xm_os_rmfile(lua_State *lua);
tb_int_t xm_os_cpfile(lua_State *lua);
tb_int_t xm_os_fscase(lua_State *lua);
tb_int_t xm_os_rename(lua_State *lua);
tb_int_t xm_os_exists(lua_State *lua);
tb_int_t xm_os_setenv(lua_State *lua);
tb_int_t xm_os_getenv(lua_State *lua);
tb_int_t xm_os_getenvs(lua_State *lua);
tb_int_t xm_os_cpuinfo(lua_State *lua);
tb_int_t xm_os_meminfo(lua_State *lua);
tb_int_t xm_os_readlink(lua_State *lua);
tb_int_t xm_os_filesize(lua_State *lua);
tb_int_t xm_os_access(lua_State *lua);
tb_int_t xm_os_emptydir(lua_State *lua);
tb_int_t xm_os_syserror(lua_State *lua);
tb_int_t xm_os_strerror(lua_State *lua);
tb_int_t xm_os_getwinsize(lua_State *lua);
tb_int_t xm_os_getpid(lua_State *lua);
tb_int_t xm_os_signal(lua_State *lua);
#ifndef TB_CONFIG_OS_WINDOWS
tb_int_t xm_os_uid(lua_State *lua);
tb_int_t xm_os_gid(lua_State *lua);
tb_int_t xm_os_getown(lua_State *lua);
#endif
// the io/file functions
tb_int_t xm_io_stdfile(lua_State *lua);
tb_int_t xm_io_file_open(lua_State *lua);
tb_int_t xm_io_file_read(lua_State *lua);
tb_int_t xm_io_file_readable(lua_State *lua);
tb_int_t xm_io_file_seek(lua_State *lua);
tb_int_t xm_io_file_size(lua_State *lua);
tb_int_t xm_io_file_rawfd(lua_State *lua);
tb_int_t xm_io_file_write(lua_State *lua);
tb_int_t xm_io_file_flush(lua_State *lua);
tb_int_t xm_io_file_close(lua_State *lua);
tb_int_t xm_io_file_convert(lua_State *lua);
tb_int_t xm_io_file_isatty(lua_State *lua);
// the io/filelock functions
tb_int_t xm_io_filelock_open(lua_State *lua);
tb_int_t xm_io_filelock_lock(lua_State *lua);
tb_int_t xm_io_filelock_unlock(lua_State *lua);
tb_int_t xm_io_filelock_trylock(lua_State *lua);
tb_int_t xm_io_filelock_close(lua_State *lua);
// the io/socket functions
tb_int_t xm_io_socket_open(lua_State *lua);
tb_int_t xm_io_socket_rawfd(lua_State *lua);
tb_int_t xm_io_socket_peeraddr(lua_State *lua);
tb_int_t xm_io_socket_wait(lua_State *lua);
tb_int_t xm_io_socket_bind(lua_State *lua);
tb_int_t xm_io_socket_ctrl(lua_State *lua);
tb_int_t xm_io_socket_listen(lua_State *lua);
tb_int_t xm_io_socket_accept(lua_State *lua);
tb_int_t xm_io_socket_connect(lua_State *lua);
tb_int_t xm_io_socket_send(lua_State *lua);
tb_int_t xm_io_socket_sendto(lua_State *lua);
tb_int_t xm_io_socket_sendfile(lua_State *lua);
tb_int_t xm_io_socket_recv(lua_State *lua);
tb_int_t xm_io_socket_recvfrom(lua_State *lua);
tb_int_t xm_io_socket_kill(lua_State *lua);
tb_int_t xm_io_socket_close(lua_State *lua);
// the io/pipe functions
tb_int_t xm_io_pipe_open(lua_State *lua);
tb_int_t xm_io_pipe_openpair(lua_State *lua);
tb_int_t xm_io_pipe_close(lua_State *lua);
tb_int_t xm_io_pipe_read(lua_State *lua);
tb_int_t xm_io_pipe_write(lua_State *lua);
tb_int_t xm_io_pipe_wait(lua_State *lua);
tb_int_t xm_io_pipe_connect(lua_State *lua);
// the io/poller functions
tb_int_t xm_io_poller_insert(lua_State *lua);
tb_int_t xm_io_poller_modify(lua_State *lua);
tb_int_t xm_io_poller_remove(lua_State *lua);
tb_int_t xm_io_poller_spank(lua_State *lua);
tb_int_t xm_io_poller_support(lua_State *lua);
tb_int_t xm_io_poller_wait(lua_State *lua);
// the path functions
tb_int_t xm_path_relative(lua_State *lua);
tb_int_t xm_path_absolute(lua_State *lua);
tb_int_t xm_path_translate(lua_State *lua);
tb_int_t xm_path_directory(lua_State *lua);
tb_int_t xm_path_is_absolute(lua_State *lua);
// the hash functions
tb_int_t xm_hash_uuid4(lua_State *lua);
tb_int_t xm_hash_sha(lua_State *lua);
tb_int_t xm_hash_md5(lua_State *lua);
tb_int_t xm_hash_xxhash(lua_State *lua);
tb_int_t xm_hash_rand32(lua_State *lua);
tb_int_t xm_hash_rand64(lua_State *lua);
tb_int_t xm_hash_rand128(lua_State *lua);
// the base64 functions
tb_int_t xm_base64_encode(lua_State *lua);
tb_int_t xm_base64_decode(lua_State *lua);
// the lz4 functions
tb_int_t xm_lz4_compress(lua_State *lua);
tb_int_t xm_lz4_decompress(lua_State *lua);
tb_int_t xm_lz4_block_compress(lua_State *lua);
tb_int_t xm_lz4_block_decompress(lua_State *lua);
tb_int_t xm_lz4_compress_file(lua_State *lua);
tb_int_t xm_lz4_decompress_file(lua_State *lua);
tb_int_t xm_lz4_compress_stream_open(lua_State *lua);
tb_int_t xm_lz4_compress_stream_read(lua_State *lua);
tb_int_t xm_lz4_compress_stream_write(lua_State *lua);
tb_int_t xm_lz4_compress_stream_close(lua_State *lua);
tb_int_t xm_lz4_decompress_stream_open(lua_State *lua);
tb_int_t xm_lz4_decompress_stream_read(lua_State *lua);
tb_int_t xm_lz4_decompress_stream_write(lua_State *lua);
tb_int_t xm_lz4_decompress_stream_close(lua_State *lua);
// the bloom filter functions
tb_int_t xm_bloom_filter_open(lua_State *lua);
tb_int_t xm_bloom_filter_close(lua_State *lua);
tb_int_t xm_bloom_filter_clear(lua_State *lua);
tb_int_t xm_bloom_filter_data(lua_State *lua);
tb_int_t xm_bloom_filter_size(lua_State *lua);
tb_int_t xm_bloom_filter_get(lua_State *lua);
tb_int_t xm_bloom_filter_set(lua_State *lua);
tb_int_t xm_bloom_filter_data_set(lua_State *lua);
// the windows functions
#ifdef TB_CONFIG_OS_WINDOWS
tb_int_t xm_winos_cp_info(lua_State *lua);
tb_int_t xm_winos_console_cp(lua_State *lua);
tb_int_t xm_winos_console_output_cp(lua_State *lua);
tb_int_t xm_winos_ansi_cp(lua_State *lua);
tb_int_t xm_winos_oem_cp(lua_State *lua);
tb_int_t xm_winos_logical_drives(lua_State *lua);
tb_int_t xm_winos_registry_query(lua_State *lua);
tb_int_t xm_winos_registry_keys(lua_State *lua);
tb_int_t xm_winos_registry_values(lua_State *lua);
tb_int_t xm_winos_short_path(lua_State *lua);
tb_int_t xm_winos_processes(lua_State* lua);
tb_int_t xm_winos_set_error_mode(lua_State *lua);
tb_int_t xm_winos_file_signature(lua_State *lua);
#endif
// the utf8 functions
tb_int_t xm_utf8_len(lua_State *lua);
tb_int_t xm_utf8_char(lua_State *lua);
tb_int_t xm_utf8_byte(lua_State *lua);
tb_int_t xm_utf8_codepoint(lua_State *lua);
tb_int_t xm_utf8_offset(lua_State *lua);
tb_int_t xm_utf8_codes(lua_State *lua);
tb_int_t xm_utf8_sub(lua_State *lua);
tb_int_t xm_utf8_reverse(lua_State *lua);
tb_int_t xm_utf8_lastof(lua_State *lua);
tb_int_t xm_utf8_find(lua_State *lua);
tb_int_t xm_utf8_width(lua_State *lua);
// the string functions
tb_int_t xm_string_trim(lua_State *lua);
tb_int_t xm_string_split(lua_State *lua);
tb_int_t xm_string_lastof(lua_State *lua);
tb_int_t xm_string_convert(lua_State *lua);
tb_int_t xm_string_endswith(lua_State *lua);
tb_int_t xm_string_startswith(lua_State *lua);
tb_int_t xm_string_lower(lua_State *lua);
tb_int_t xm_string_upper(lua_State *lua);
// the process functions
tb_int_t xm_process_open(lua_State *lua);
tb_int_t xm_process_openv(lua_State *lua);
tb_int_t xm_process_wait(lua_State *lua);
tb_int_t xm_process_kill(lua_State *lua);
tb_int_t xm_process_close(lua_State *lua);
// the fwatcher functions
tb_int_t xm_fwatcher_open(lua_State *lua);
tb_int_t xm_fwatcher_add(lua_State *lua);
tb_int_t xm_fwatcher_remove(lua_State *lua);
tb_int_t xm_fwatcher_wait(lua_State *lua);
tb_int_t xm_fwatcher_close(lua_State *lua);
// the sandbox functions
tb_int_t xm_sandbox_interactive(lua_State *lua);
#ifdef XM_CONFIG_API_HAVE_READLINE
// the readline functions
tb_int_t xm_readline_readline(lua_State *lua);
tb_int_t xm_readline_history_list(lua_State *lua);
tb_int_t xm_readline_add_history(lua_State *lua);
tb_int_t xm_readline_clear_history(lua_State *lua);
#endif
// the semver functions
tb_int_t xm_semver_parse(lua_State *lua);
tb_int_t xm_semver_compare(lua_State *lua);
tb_int_t xm_semver_satisfies(lua_State *lua);
tb_int_t xm_semver_select(lua_State *lua);
// the libc functions
tb_int_t xm_libc_malloc(lua_State *lua);
tb_int_t xm_libc_free(lua_State *lua);
tb_int_t xm_libc_memcpy(lua_State *lua);
tb_int_t xm_libc_memmov(lua_State *lua);
tb_int_t xm_libc_memset(lua_State *lua);
tb_int_t xm_libc_strndup(lua_State *lua);
tb_int_t xm_libc_dataptr(lua_State *lua);
tb_int_t xm_libc_byteof(lua_State *lua);
tb_int_t xm_libc_setbyte(lua_State *lua);
// the tty functions
tb_int_t xm_tty_term_mode(lua_State *lua);
tb_int_t xm_tty_session_id(lua_State *lua);
// the package functions
tb_int_t xm_package_loadxmi(lua_State *lua);
// the binutils functions
tb_int_t xm_binutils_bin2c(lua_State *lua);
tb_int_t xm_binutils_bin2coff(lua_State *lua);
tb_int_t xm_binutils_bin2macho(lua_State *lua);
tb_int_t xm_binutils_bin2elf(lua_State *lua);
tb_int_t xm_binutils_readsyms(lua_State *lua);
tb_int_t xm_binutils_deplibs(lua_State *lua);
tb_int_t xm_binutils_rpath_list(lua_State *lua);
tb_int_t xm_binutils_rpath_clean(lua_State *lua);
tb_int_t xm_binutils_extractlib(lua_State *lua);
tb_int_t xm_binutils_format(lua_State *lua);
#ifdef XM_CONFIG_API_HAVE_CURSES
// register curses functions
tb_int_t xm_lua_curses_register(lua_State *lua, tb_char_t const *module);
#endif
// the thread functions
tb_int_t xm_thread_init(lua_State *lua);
tb_int_t xm_thread_exit(lua_State *lua);
tb_int_t xm_thread_wait(lua_State *lua);
tb_int_t xm_thread_suspend(lua_State *lua);
tb_int_t xm_thread_resume(lua_State *lua);
// the thread/mutex functions
tb_int_t xm_thread_mutex_init(lua_State *lua);
tb_int_t xm_thread_mutex_exit(lua_State *lua);
tb_int_t xm_thread_mutex_lock(lua_State *lua);
tb_int_t xm_thread_mutex_trylock(lua_State *lua);
tb_int_t xm_thread_mutex_unlock(lua_State *lua);
tb_int_t xm_thread_mutex_incref(lua_State *lua);
// the thread/event functions
tb_int_t xm_thread_event_init(lua_State *lua);
tb_int_t xm_thread_event_exit(lua_State *lua);
tb_int_t xm_thread_event_post(lua_State *lua);
tb_int_t xm_thread_event_wait(lua_State *lua);
tb_int_t xm_thread_event_incref(lua_State *lua);
// the thread/semaphore functions
tb_int_t xm_thread_semaphore_init(lua_State *lua);
tb_int_t xm_thread_semaphore_exit(lua_State *lua);
tb_int_t xm_thread_semaphore_post(lua_State *lua);
tb_int_t xm_thread_semaphore_wait(lua_State *lua);
tb_int_t xm_thread_semaphore_incref(lua_State *lua);
// the thread/queue functions
tb_int_t xm_thread_queue_init(lua_State *lua);
tb_int_t xm_thread_queue_exit(lua_State *lua);
tb_int_t xm_thread_queue_size(lua_State *lua);
tb_int_t xm_thread_queue_clear(lua_State *lua);
tb_int_t xm_thread_queue_incref(lua_State *lua);
tb_int_t xm_thread_queue_push(lua_State *lua);
tb_int_t xm_thread_queue_pop(lua_State *lua);
// the thread/sharedata functions
tb_int_t xm_thread_sharedata_init(lua_State *lua);
tb_int_t xm_thread_sharedata_exit(lua_State *lua);
tb_int_t xm_thread_sharedata_clear(lua_State *lua);
tb_int_t xm_thread_sharedata_incref(lua_State *lua);
tb_int_t xm_thread_sharedata_set(lua_State *lua);
tb_int_t xm_thread_sharedata_get_(lua_State *lua);
// open cjson
__tb_extern_c_enter__
tb_int_t luaopen_cjson(lua_State *l);
__tb_extern_c_leave__
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
// the os functions
static luaL_Reg const g_os_functions[] = {
{ "argv", xm_os_argv },
{ "args", xm_os_args },
{ "find", xm_os_find },
{ "link", xm_os_link },
{ "isdir", xm_os_isdir },
{ "rmdir", xm_os_rmdir },
{ "mkdir", xm_os_mkdir },
{ "cpdir", xm_os_cpdir },
{ "chdir", xm_os_chdir },
{ "mtime", xm_os_mtime },
{ "sleep", xm_os_sleep },
{ "mclock", xm_os_mclock },
{ "curdir", xm_os_curdir },
{ "tmpdir", xm_os_tmpdir },
{ "islink", xm_os_islink },
{ "isfile", xm_os_isfile },
{ "touch", xm_os_touch },
{ "rmfile", xm_os_rmfile },
{ "cpfile", xm_os_cpfile },
{ "fscase", xm_os_fscase },
{ "rename", xm_os_rename },
{ "exists", xm_os_exists },
{ "access", xm_os_access },
{ "setenv", xm_os_setenv },
{ "getenv", xm_os_getenv },
{ "getenvs", xm_os_getenvs },
{ "cpuinfo", xm_os_cpuinfo },
{ "meminfo", xm_os_meminfo },
{ "readlink", xm_os_readlink },
{ "emptydir", xm_os_emptydir },
{ "strerror", xm_os_strerror },
{ "syserror", xm_os_syserror },
{ "filesize", xm_os_filesize },
{ "getwinsize", xm_os_getwinsize },
{ "getpid", xm_os_getpid },
{ "signal", xm_os_signal },
#ifndef TB_CONFIG_OS_WINDOWS
{ "uid", xm_os_uid },
{ "gid", xm_os_gid },
{ "getown", xm_os_getown },
#endif
{ tb_null, tb_null },
};
// the windows functions
#ifdef TB_CONFIG_OS_WINDOWS
static luaL_Reg const g_winos_functions[] = {
{ "cp_info", xm_winos_cp_info },
{ "console_cp", xm_winos_console_cp },
{ "console_output_cp", xm_winos_console_output_cp },
{ "oem_cp", xm_winos_oem_cp },
{ "ansi_cp", xm_winos_ansi_cp },
{ "logical_drives", xm_winos_logical_drives },
{ "registry_query", xm_winos_registry_query },
{ "registry_keys", xm_winos_registry_keys },
{ "registry_values", xm_winos_registry_values },
{ "short_path", xm_winos_short_path },
{ "processes", xm_winos_processes },
{ "set_error_mode", xm_winos_set_error_mode },
{ "file_signature", xm_winos_file_signature },
{ tb_null, tb_null },
};
#endif
// the io functions
static luaL_Reg const g_io_functions[] = {
{ "stdfile", xm_io_stdfile },
{ "file_open", xm_io_file_open },
{ "file_read", xm_io_file_read },
{ "file_readable", xm_io_file_readable },
{ "file_seek", xm_io_file_seek },
{ "file_size", xm_io_file_size },
{ "file_write", xm_io_file_write },
{ "file_flush", xm_io_file_flush },
{ "file_isatty", xm_io_file_isatty },
{ "file_close", xm_io_file_close },
{ "file_convert", xm_io_file_convert },
{ "file_rawfd", xm_io_file_rawfd },
{ "filelock_open", xm_io_filelock_open },
{ "filelock_lock", xm_io_filelock_lock },
{ "filelock_trylock", xm_io_filelock_trylock },
{ "filelock_unlock", xm_io_filelock_unlock },
{ "filelock_close", xm_io_filelock_close },
{ "socket_open", xm_io_socket_open },
{ "socket_rawfd", xm_io_socket_rawfd },
{ "socket_peeraddr", xm_io_socket_peeraddr },
{ "socket_wait", xm_io_socket_wait },
{ "socket_bind", xm_io_socket_bind },
{ "socket_ctrl", xm_io_socket_ctrl },
{ "socket_listen", xm_io_socket_listen },
{ "socket_accept", xm_io_socket_accept },
{ "socket_connect", xm_io_socket_connect },
{ "socket_send", xm_io_socket_send },
{ "socket_sendto", xm_io_socket_sendto },
{ "socket_sendfile", xm_io_socket_sendfile },
{ "socket_recv", xm_io_socket_recv },
{ "socket_recvfrom", xm_io_socket_recvfrom },
{ "socket_kill", xm_io_socket_kill },
{ "socket_close", xm_io_socket_close },
{ "pipe_open", xm_io_pipe_open },
{ "pipe_openpair", xm_io_pipe_openpair },
{ "pipe_close", xm_io_pipe_close },
{ "pipe_read", xm_io_pipe_read },
{ "pipe_write", xm_io_pipe_write },
{ "pipe_wait", xm_io_pipe_wait },
{ "pipe_connect", xm_io_pipe_connect },
{ "poller_insert", xm_io_poller_insert },
{ "poller_modify", xm_io_poller_modify },
{ "poller_remove", xm_io_poller_remove },
{ "poller_spank", xm_io_poller_spank },
{ "poller_support", xm_io_poller_support },
{ "poller_wait", xm_io_poller_wait },
{ tb_null, tb_null },
};
// the path functions
static luaL_Reg const g_path_functions[] = {
{ "relative", xm_path_relative },
{ "absolute", xm_path_absolute },
{ "translate", xm_path_translate },
{ "directory", xm_path_directory },
{ "is_absolute", xm_path_is_absolute },
{ tb_null, tb_null },
};
// the hash functions
static luaL_Reg const g_hash_functions[] = {
{ "uuid4", xm_hash_uuid4 },
{ "sha", xm_hash_sha },
{ "md5", xm_hash_md5 },
{ "xxhash", xm_hash_xxhash },
{ "rand32", xm_hash_rand32 },
{ "rand64", xm_hash_rand64 },
{ "rand128", xm_hash_rand128 },
{ tb_null, tb_null },
};
// the base64 functions
static luaL_Reg const g_base64_functions[] = {
{ "encode", xm_base64_encode },
{ "decode", xm_base64_decode },
{ tb_null, tb_null },
};
// the lz4 functions
static luaL_Reg const g_lz4_functions[] = {
{ "compress", xm_lz4_compress },
{ "decompress", xm_lz4_decompress },
{ "block_compress", xm_lz4_block_compress },
{ "block_decompress", xm_lz4_block_decompress },
{ "compress_file", xm_lz4_compress_file },
{ "decompress_file", xm_lz4_decompress_file },
{ "compress_stream_open", xm_lz4_compress_stream_open },
{ "compress_stream_read", xm_lz4_compress_stream_read },
{ "compress_stream_write", xm_lz4_compress_stream_write },
{ "compress_stream_close", xm_lz4_compress_stream_close },
{ "decompress_stream_open", xm_lz4_decompress_stream_open },
{ "decompress_stream_read", xm_lz4_decompress_stream_read },
{ "decompress_stream_write", xm_lz4_decompress_stream_write },
{ "decompress_stream_close", xm_lz4_decompress_stream_close },
{ tb_null, tb_null },
};
// the bloom filter functions
static luaL_Reg const g_bloom_filter_functions[] = {
{ "open", xm_bloom_filter_open },
{ "close", xm_bloom_filter_close },
{ "clear", xm_bloom_filter_clear },
{ "data", xm_bloom_filter_data },
{ "size", xm_bloom_filter_size },
{ "get", xm_bloom_filter_get },
{ "set", xm_bloom_filter_set },
{ "data_set", xm_bloom_filter_data_set },
{ tb_null, tb_null },
};
// the utf8 functions
static luaL_Reg const g_utf8_functions[] = {
{"char", xm_utf8_char},
{"byte", xm_utf8_byte},
{"codes", xm_utf8_codes},
{"codepoint", xm_utf8_codepoint},
{"len", xm_utf8_len},
{"offset", xm_utf8_offset},
{"sub", xm_utf8_sub},
{"reverse", xm_utf8_reverse},
{"lastof", xm_utf8_lastof},
{"find", xm_utf8_find},
{"width", xm_utf8_width},
{"wcwidth", xm_utf8_width},
{"wcswidth", xm_utf8_width},
{tb_null, tb_null}
};
// the string functions
static luaL_Reg const g_string_functions[] = {
{ "trim", xm_string_trim },
{ "split", xm_string_split },
{ "lastof", xm_string_lastof },
{ "convert", xm_string_convert },
{ "endswith", xm_string_endswith },
{ "startswith", xm_string_startswith },
{ "lower", xm_string_lower },
{ "upper", xm_string_upper },
{ tb_null, tb_null },
};
// the process functions
static luaL_Reg const g_process_functions[] = {
{ "open", xm_process_open },
{ "openv", xm_process_openv },
{ "wait", xm_process_wait },
{ "kill", xm_process_kill },
{ "close", xm_process_close },
{ tb_null, tb_null },
};
// the fwatcher functions
static luaL_Reg const g_fwatcher_functions[] = {
{ "open", xm_fwatcher_open },
{ "add", xm_fwatcher_add },
{ "remove", xm_fwatcher_remove },
{ "wait", xm_fwatcher_wait },
{ "close", xm_fwatcher_close },
{ tb_null, tb_null },
};
// the sandbox functions
static luaL_Reg const g_sandbox_functions[] = {
{ "interactive", xm_sandbox_interactive },
{ tb_null, tb_null },
};
#ifdef XM_CONFIG_API_HAVE_READLINE
// the readline functions
static luaL_Reg const g_readline_functions[] = {
{ "readline", xm_readline_readline },
{ "history_list", xm_readline_history_list },
{ "add_history", xm_readline_add_history },
{ "clear_history", xm_readline_clear_history },
{ tb_null, tb_null },
};
#endif
// the semver functions
static luaL_Reg const g_semver_functions[] = {
{ "parse", xm_semver_parse },
{ "compare", xm_semver_compare },
{ "satisfies", xm_semver_satisfies },
{ "select", xm_semver_select },
{ tb_null, tb_null },
};
// the libc functions
static luaL_Reg const g_libc_functions[] = {
{ "malloc", xm_libc_malloc },
{ "free", xm_libc_free },
{ "memcpy", xm_libc_memcpy },
{ "memset", xm_libc_memset },
{ "memmov", xm_libc_memmov },
{ "strndup", xm_libc_strndup },
{ "dataptr", xm_libc_dataptr },
{ "byteof", xm_libc_byteof },
{ "setbyte", xm_libc_setbyte },
{ tb_null, tb_null },
};
// the tty functions
static luaL_Reg const g_tty_functions[] = {
{ "term_mode", xm_tty_term_mode },
{ "session_id", xm_tty_session_id },
{ tb_null, tb_null },
};
// the package functions
static luaL_Reg const g_package_functions[] = {
{ "loadxmi", xm_package_loadxmi },
{ tb_null, tb_null },
};
// the binutils functions
static luaL_Reg const g_binutils_functions[] = {
{ "bin2c", xm_binutils_bin2c },
{ "bin2coff", xm_binutils_bin2coff },
{ "bin2macho", xm_binutils_bin2macho },
{ "bin2elf", xm_binutils_bin2elf },
{ "readsyms", xm_binutils_readsyms },
{ "deplibs", xm_binutils_deplibs },
{ "rpath_list", xm_binutils_rpath_list },
{ "rpath_clean", xm_binutils_rpath_clean },
{ "extractlib", xm_binutils_extractlib },
{ "format", xm_binutils_format },
{ tb_null, tb_null },
};
// the thread functions
static luaL_Reg const g_thread_functions[] = {
{ "thread_init", xm_thread_init },
{ "thread_exit", xm_thread_exit },
{ "thread_wait", xm_thread_wait },
{ "thread_resume", xm_thread_resume },
{ "thread_suspend", xm_thread_suspend },
{ "mutex_init", xm_thread_mutex_init },
{ "mutex_exit", xm_thread_mutex_exit },
{ "mutex_lock", xm_thread_mutex_lock },
{ "mutex_trylock", xm_thread_mutex_trylock },
{ "mutex_unlock", xm_thread_mutex_unlock },
{ "mutex_incref", xm_thread_mutex_incref },
{ "event_init", xm_thread_event_init },
{ "event_exit", xm_thread_event_exit },
{ "event_post", xm_thread_event_post },
{ "event_wait", xm_thread_event_wait },
{ "event_incref", xm_thread_event_incref },
{ "semaphore_init", xm_thread_semaphore_init },
{ "semaphore_exit", xm_thread_semaphore_exit },
{ "semaphore_post", xm_thread_semaphore_post },
{ "semaphore_wait", xm_thread_semaphore_wait },
{ "semaphore_incref", xm_thread_semaphore_incref },
{ "queue_init", xm_thread_queue_init },
{ "queue_exit", xm_thread_queue_exit },
{ "queue_size", xm_thread_queue_size },
{ "queue_clear", xm_thread_queue_clear },
{ "queue_incref", xm_thread_queue_incref },
{ "queue_push", xm_thread_queue_push },
{ "queue_pop", xm_thread_queue_pop },
{ "sharedata_init", xm_thread_sharedata_init },
{ "sharedata_exit", xm_thread_sharedata_exit },
{ "sharedata_clear", xm_thread_sharedata_clear },
{ "sharedata_incref", xm_thread_sharedata_incref },
{ "sharedata_set", xm_thread_sharedata_set },
{ "sharedata_get", xm_thread_sharedata_get_ },
{ tb_null, tb_null },
};
// the utf8 functions
// the lua global instance for signal handler
static lua_State *g_lua = tb_null;
// the xmake script files data
#ifdef XM_EMBED_ENABLE
__tb_extern_c_enter__
extern tb_byte_t _binary_xmake_xmz_start[];
extern tb_byte_t _binary_xmake_xmz_end[];
__tb_extern_c_leave__
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_engine_save_arguments(xm_engine_t *engine, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv) {
tb_assert_and_check_return_val(engine && engine->lua && argc >= 1 && argv, tb_false);
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
tb_wchar_t **argvw = CommandLineToArgvW(GetCommandLineW(), &argc);
#endif
// put a new table into the stack
lua_newtable(engine->lua);
// patch the task arguments list
if (taskargv) {
tb_char_t **taskarg = taskargv;
while (*taskarg) {
lua_pushstring(engine->lua, *taskarg);
lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1);
taskarg++;
}
}
// save all arguments to the new table
tb_int_t i = 0;
for (i = 1; i < argc; i++) {
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
tb_char_t argvbuf[4096] = { 0 };
tb_wcstombs(argvbuf, argvw[i], tb_arrayn(argvbuf));
// table_new[table.getn(table_new) + 1] = argv[i]
lua_pushstring(engine->lua, argvbuf);
#else
lua_pushstring(engine->lua, argv[i]);
#endif
lua_rawseti(engine->lua, -2, (int)lua_objlen(engine->lua, -2) + 1);
}
// _ARGV = table_new
lua_setglobal(engine->lua, "_ARGV");
return tb_true;
}
static tb_bool_t xm_engine_get_program_file(xm_engine_t *engine, tb_char_t **argv, tb_char_t *path, tb_size_t maxn) {
tb_assert_and_check_return_val(engine && path && maxn, tb_false);
/* we cache it, because the current path will be changed in thread.
*
* The executable file compiled using cosmocc on macOS might retrieve a relative path to the programfile.
* If the root directory has been changed, the retrieved programfile will be a non-existent path.
*/
static tb_char_t s_program_filepath[TB_PATH_MAXN] = { 0 };
if (s_program_filepath[0]) {
tb_strlcpy(path, s_program_filepath, maxn);
lua_pushstring(engine->lua, s_program_filepath);
lua_setglobal(engine->lua, "_PROGRAM_FILE");
return tb_true;
}
tb_bool_t ok = tb_false;
do {
// get it from the environment variable first
if (tb_environment_first("XMAKE_PROGRAM_FILE", path, maxn) && tb_file_info(path, tb_null)) {
ok = tb_true;
break;
}
#if defined(TB_CONFIG_OS_WINDOWS)
// get the executale file path as program directory
tb_wchar_t buf[TB_PATH_MAXN] = { 0 };
tb_size_t size = (tb_size_t)GetModuleFileNameW(tb_null, buf, (DWORD)TB_PATH_MAXN);
tb_assert_and_check_break(size < TB_PATH_MAXN);
buf[size] = L'\0';
size = tb_wcstombs(path, buf, maxn);
tb_assert_and_check_break(size < maxn);
path[size] = '\0';
ok = tb_true;
#elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)
/*
* _NSGetExecutablePath() copies the path of the main executable into the buffer. The bufsize parameter
* should initially be the size of the buffer. The function returns 0 if the path was successfully copied,
* and *bufsize is left unchanged. It returns -1 if the buffer is not large enough, and *bufsize is set
* to the size required.
*
* Note that _NSGetExecutablePath will return "a path" to the executable not a "real path" to the executable.
* That is the path may be a symbolic link and not the real file. With deep directories the total bufsize
* needed could be more than MAXPATHLEN.
*/
tb_uint32_t bufsize = (tb_uint32_t)maxn;
if (!_NSGetExecutablePath(path, &bufsize)) {
ok = tb_true;
}
#elif defined(XM_PROC_SELF_FILE)
/* get the executale file path as program directory
*
* @see it may be a relative path
*/
ssize_t size = readlink(XM_PROC_SELF_FILE, path, (size_t)maxn);
if (size > 0 && size < maxn) {
path[size] = '\0';
// ignore cosmocc ape binary, we fallback to argv[0], .e.g /usr/bin/ape, /home/ruki/.ape-1.10
tb_char_t const* filename = tb_strrchr(path, '/');
if (!tb_strstr(filename ? filename + 1 : path, "ape")) {
ok = tb_true;
}
}
#elif defined(TB_CONFIG_OS_BSD) && defined(KERN_PROC_PATHNAME)
// only for FreeBSD and OpenBSD, https://github.com/xmake-io/xmake/issues/2948
tb_int_t mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
size_t size = maxn;
if (sysctl(mib, 4, path, &size, tb_null, 0) == 0 && size < maxn) {
path[size] = '\0';
ok = tb_true;
}
#elif defined(TB_CONFIG_OS_HAIKU)
int32 cookie = 0;
image_info info;
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
if (info.type == B_APP_IMAGE) {
tb_strlcpy(path, info.name, maxn);
ok = tb_true;
break;
}
}
#else
static tb_char_t const *s_paths[] = {
"~/.local/bin/xmake",
"/usr/local/bin/xmake",
"/usr/bin/xmake",
};
for (tb_size_t i = 0; i < tb_arrayn(s_paths); i++) {
tb_char_t const *p = s_paths[i];
if (tb_file_info(p, tb_null)) {
tb_strlcpy(path, p, maxn);
ok = tb_true;
break;
}
}
#endif
if (!ok && argv) {
tb_char_t const *p = argv[0];
if (p && tb_file_info(p, tb_null)) {
if (tb_path_is_absolute(p)) {
tb_strlcpy(path, p, maxn);
} else {
if (!tb_path_absolute(p, path, maxn)) {
tb_strlcpy(path, p, maxn);
}
}
ok = tb_true;
}
}
} while (0);
if (ok) {
tb_trace_d("programfile: %s", path);
// cache it
tb_strlcpy(s_program_filepath, path, sizeof(s_program_filepath));
// save the directory to the global variable: _PROGRAM_FILE
lua_pushstring(engine->lua, path);
lua_setglobal(engine->lua, "_PROGRAM_FILE");
}
return ok;
}
#ifdef XM_EMBED_ENABLE
static tb_bool_t xm_engine_get_temporary_directory(tb_char_t *path,
tb_size_t maxn,
tb_char_t const *name,
tb_char_t const *version_cstr) {
tb_char_t data[TB_PATH_MAXN] = { 0 };
if (tb_directory_temporary(data, sizeof(data))) {
// get euid
tb_int_t euid = 0;
#ifndef TB_CONFIG_OS_WINDOWS
euid = geteuid();
#endif
tb_snprintf(path, maxn, "%s/.%s%d/%s", data, name, euid, version_cstr);
return tb_true;
}
return tb_false;
}
#endif
static tb_bool_t xm_engine_get_program_directory(xm_engine_t *engine,
tb_char_t *path,
tb_size_t maxn,
tb_char_t const *programfile) {
tb_assert_and_check_return_val(engine && path && maxn, tb_false);
static tb_char_t s_program_directory[TB_PATH_MAXN] = { 0 };
if (s_program_directory[0]) {
tb_strlcpy(path, s_program_directory, maxn);
lua_pushstring(engine->lua, s_program_directory);
lua_setglobal(engine->lua, "_PROGRAM_DIR");
return tb_true;
}
tb_bool_t ok = tb_false;
tb_char_t data[TB_PATH_MAXN] = { 0 };
do {
#ifdef XM_EMBED_ENABLE
tb_size_t embedcount = engine->embedcount;
if (embedcount) {
tb_uint32_t crc32 = 0;
for (tb_size_t i = 0; i < embedcount; i++) {
crc32 += tb_crc32_make(engine->embeddata[i], engine->embedsize[i], 0);
}
tb_snprintf(path, maxn, "%s/%x", engine->tmpdir, crc32);
} else {
tb_strlcpy(path, engine->tmpdir, maxn);
}
ok = tb_true;
break;
#endif
// get it from the environment variable first
if (tb_environment_first("XMAKE_PROGRAM_DIR", data, sizeof(data)) && tb_path_absolute(data, path, maxn)) {
ok = tb_true;
break;
}
// get it from program file path
if (programfile) {
// get real program file path from the symbol link
#if !defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_CONFIG_OS_IOS)
tb_char_t programpath[TB_PATH_MAXN];
tb_long_t size = readlink(programfile, programpath, sizeof(programpath));
if (size >= 0 && size < sizeof(programpath)) {
programpath[size] = '\0';
// soft link to relative path? fix it
if (!tb_path_is_absolute(programpath)) {
tb_char_t buff[TB_PATH_MAXN];
tb_char_t const *rootdir = tb_path_directory(programfile, buff, sizeof(buff));
if (rootdir && tb_path_absolute_to(
rootdir,
programpath,
path,
maxn)) { // @note path and programfile are same buffer
tb_strlcpy(programpath, path, maxn);
}
}
} else
tb_strlcpy(programpath, programfile, sizeof(programpath));
#else
tb_char_t const *programpath = programfile;
#endif
// get the root directory
tb_char_t data[TB_PATH_MAXN];
tb_char_t const *rootdir = tb_path_directory(programpath, data, sizeof(data));
tb_assert_and_check_break(rootdir);
// init share/name sub-directory
tb_char_t sharedir[128];
tb_snprintf(sharedir, sizeof(sharedir), "../share/%s", engine->name);
// find the program (lua) directory
tb_size_t i;
tb_file_info_t info;
tb_char_t scriptpath[TB_PATH_MAXN];
tb_char_t const *subdirs[] = {
".",
sharedir,
};
for (i = 0; i < tb_arrayn(subdirs); i++) {
// get program directory
if (tb_path_absolute_to(rootdir, subdirs[i], path, maxn) &&
tb_path_absolute_to(path, "core/_xmake_main.lua", scriptpath, sizeof(scriptpath)) &&
tb_file_info(scriptpath, &info) && info.type == TB_FILE_TYPE_FILE) {
ok = tb_true;
break;
}
}
}
} while (0);
if (ok) {
tb_trace_d("programdir: %s", path);
// cache it
tb_strlcpy(s_program_directory, path, sizeof(s_program_directory));
// save the directory to the global variable: _PROGRAM_DIR
lua_pushstring(engine->lua, path);
lua_setglobal(engine->lua, "_PROGRAM_DIR");
}
return ok;
}
static tb_bool_t xm_engine_get_project_directory(xm_engine_t *engine, tb_char_t *path, tb_size_t maxn) {
tb_assert_and_check_return_val(engine && path && maxn, tb_false);
tb_bool_t ok = tb_false;
do {
// attempt to get it from the environment variable first
tb_char_t data[TB_PATH_MAXN] = { 0 };
if (!tb_environment_first("XMAKE_PROJECT_DIR", data, sizeof(data)) || !tb_path_absolute(data, path, maxn)) {
// get it from the current directory
if (!tb_directory_current(path, maxn)) {
break;
}
}
tb_trace_d("project: %s", path);
// save the directory to the global variable: _PROJECT_DIR
lua_pushstring(engine->lua, path);
lua_setglobal(engine->lua, "_PROJECT_DIR");
ok = tb_true;
} while (0);
// failed?
if (!ok) {
tb_printf("error: not found the project directory!\n");
}
return ok;
}
#if defined(TB_CONFIG_OS_WINDOWS) || defined(SIGINT)
static tb_void_t xm_engine_dump_traceback(lua_State *lua) {
// @note it's not safe, but it doesn't matter, we're just trying to get the stack backtrace for debugging
lua_getglobal(lua, "debug");
lua_getfield(lua, -1, "traceback");
lua_replace(lua, -2);
lua_pushvalue(lua, 1);
lua_call(lua, 1, 1);
tb_trace_i("%s", lua_tostring(lua, -1));
}
#endif
#if defined(TB_CONFIG_OS_WINDOWS)
static BOOL WINAPI xm_engine_signal_handler(DWORD signo) {
if (signo == CTRL_C_EVENT && g_lua) {
xm_engine_dump_traceback(g_lua);
tb_abort();
}
return TRUE;
}
#elif defined(SIGINT)
static tb_void_t xm_engine_signal_handler(tb_int_t signo) {
if (signo == SIGINT && g_lua) {
xm_engine_dump_traceback(g_lua);
tb_abort();
}
}
#endif
static tb_void_t xm_engine_init_host(xm_engine_t *engine) {
tb_assert_and_check_return(engine && engine->lua);
// init system host
tb_char_t const *syshost = tb_null;
#if defined(__COSMOPOLITAN__)
struct utsname buffer;
if (uname(&buffer) == 0) {
if (tb_strstr(buffer.sysname, "Darwin")) {
syshost = "macosx";
} else if (tb_strstr(buffer.sysname, "Linux")) {
syshost = "linux";
} else if (tb_strstr(buffer.sysname, "Windows")) {
syshost = "windows";
}
}
#elif defined(TB_CONFIG_OS_WINDOWS)
syshost = "windows";
#elif defined(TB_CONFIG_OS_MACOSX)
syshost = "macosx";
#elif defined(TB_CONFIG_OS_LINUX)
syshost = "linux";
#elif defined(TB_CONFIG_OS_BSD)
syshost = "bsd";
#elif defined(TB_CONFIG_OS_SOLARIS)
syshost = "solaris";
#elif defined(TB_CONFIG_OS_IOS)
syshost = "ios";
#elif defined(TB_CONFIG_OS_ANDROID)
syshost = "android";
#elif defined(TB_CONFIG_OS_HAIKU)
syshost = "haiku";
#endif
lua_pushstring(engine->lua, syshost ? syshost : "unknown");
lua_setglobal(engine->lua, "_HOST");
// init subsystem host
tb_char_t const *subhost = syshost;
#if defined(TB_CONFIG_OS_WINDOWS)
#if defined(TB_COMPILER_ON_MSYS)
subhost = "msys";
#elif defined(TB_COMPILER_ON_CYGWIN)
subhost = "cygwin";
#else
{
tb_char_t data[64] = { 0 };
if (tb_environment_first("MSYSTEM", data, sizeof(data))) {
// on msys?
if (!tb_strnicmp(data, "mingw", 5) // mingw32/64 on msys2
|| !tb_strnicmp(data,
"clang",
5) // clang32/64 on msys2, @see https://github.com/xmake-io/xmake/issues/3060
|| !tb_stricmp(data, "ucrt64") // ucrt64 https://www.msys2.org/docs/environments/
|| !tb_stricmp(data, "msys")) { // on msys2
subhost = "msys";
}
}
}
#endif
#endif
lua_pushstring(engine->lua, subhost ? subhost : "unknown");
lua_setglobal(engine->lua, "_SUBHOST");
}
static __tb_inline__ tb_char_t const *xm_engine_xmake_arch() {
tb_char_t const *arch = tb_null;
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#if defined(TB_ARCH_x64)
arch = "x64";
#elif defined(TB_ARCH_ARM64)
arch = "arm64";
#elif defined(TB_ARCH_ARM)
arch = "arm";
#else
arch = "x86";
#endif
#elif defined(TB_ARCH_x64)
arch = "x86_64";
#elif defined(TB_ARCH_x86)
arch = "i386";
#elif defined(TB_ARCH_ARM64)
arch = "arm64";
#else
arch = TB_ARCH_STRING;
#endif
return arch;
}
static tb_void_t xm_engine_init_arch(xm_engine_t *engine) {
tb_assert_and_check_return(engine && engine->lua);
// init xmake arch
tb_char_t const *xmakearch = xm_engine_xmake_arch();
lua_pushstring(engine->lua, xmakearch);
lua_setglobal(engine->lua, "_XMAKE_ARCH");
// init system architecture
tb_char_t const *sysarch = tb_null;
#if defined(__COSMOPOLITAN__)
struct utsname buffer;
if (uname(&buffer) == 0) {
sysarch = buffer.machine;
if (tb_strstr(buffer.sysname, "Windows")) {
if (!tb_strcmp(buffer.machine, "x86_64")) {
sysarch = "x64";
} else if (!tb_strcmp(buffer.machine, "i686") || !tb_strcmp(buffer.machine, "i386")) {
sysarch = "x86";
}
} else if (!tb_strcmp(buffer.machine, "aarch64")) {
sysarch = "arm64";
}
}
#elif defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
// the GetNativeSystemInfo function type
typedef void(WINAPI * GetNativeSystemInfo_t)(LPSYSTEM_INFO);
// get system info
SYSTEM_INFO systeminfo = { 0 };
GetNativeSystemInfo_t pGetNativeSystemInfo = tb_null;
tb_dynamic_ref_t kernel32 = tb_dynamic_init("kernel32.dll");
if (kernel32) {
pGetNativeSystemInfo = (GetNativeSystemInfo_t)tb_dynamic_func(kernel32, "GetNativeSystemInfo");
}
if (pGetNativeSystemInfo) {
pGetNativeSystemInfo(&systeminfo);
} else {
GetSystemInfo(&systeminfo);
}
// init architecture
switch (systeminfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
sysarch = "x64";
break;
#if defined(PROCESSOR_ARCHITECTURE_ARM64)
case PROCESSOR_ARCHITECTURE_ARM64:
sysarch = "arm64";
break;
#endif
case PROCESSOR_ARCHITECTURE_ARM:
sysarch = "arm";
break;
case PROCESSOR_ARCHITECTURE_INTEL:
sysarch = "x86";
break;
default:
break;
}
#endif
if (!sysarch) {
sysarch = xmakearch;
}
lua_pushstring(engine->lua, sysarch);
lua_setglobal(engine->lua, "_ARCH");
// init subsystem architecture
tb_char_t const *subarch = sysarch;
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
// get architecture from msys environment
tb_char_t data[64] = { 0 };
if (tb_environment_first("MSYSTEM_CARCH", data, sizeof(data))) {
if (!tb_strcmp(data, "i686")) {
subarch = "i386";
} else {
subarch = data;
}
}
#endif
lua_pushstring(engine->lua, subarch);
lua_setglobal(engine->lua, "_SUBARCH");
}
static tb_void_t xm_engine_init_features(xm_engine_t *engine) {
tb_assert_and_check_return(engine && engine->lua);
// init features
lua_newtable(engine->lua);
// get path seperator
lua_pushstring(engine->lua, "path_sep");
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
lua_pushstring(engine->lua, "\\");
#else
lua_pushstring(engine->lua, "/");
#endif
lua_settable(engine->lua, -3);
// get environment path seperator
lua_pushstring(engine->lua, "path_envsep");
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
lua_pushstring(engine->lua, ";");
#else
lua_pushstring(engine->lua, ":");
#endif
lua_settable(engine->lua, -3);
lua_setglobal(engine->lua, "_FEATURES");
}
static tb_void_t xm_engine_init_signal(xm_engine_t *engine) {
// we enable it to catch the current lua stack in ctrl-c signal handler if XMAKE_PROFILE=stuck
tb_char_t data[64] = { 0 };
if (!tb_environment_first("XMAKE_PROFILE", data, sizeof(data)) || tb_strcmp(data, "stuck")) {
return;
}
g_lua = engine->lua;
#if defined(TB_CONFIG_OS_WINDOWS)
SetConsoleCtrlHandler(xm_engine_signal_handler, TRUE);
#elif defined(SIGINT)
signal(SIGINT, xm_engine_signal_handler);
#endif
}
#if XM_HOOK_LUA_MEMALLOC
// udata is unused, it has been used by engine. see xm_engine_bind_to_lua()
static tb_pointer_t xm_engine_lua_realloc(tb_pointer_t udata, tb_pointer_t data, size_t osize, size_t nsize) {
tb_pointer_t ptr = tb_null;
if (nsize == 0 && data) {
tb_free(data);
} else if (!data) {
ptr = tb_malloc((tb_size_t)nsize);
} else if (nsize != osize) {
ptr = tb_ralloc(data, (tb_size_t)nsize);
} else {
ptr = data;
}
return ptr;
}
#endif
#ifdef XM_EMBED_ENABLE
static tb_bool_t xm_engine_extract_programfiles_impl(xm_engine_t *engine,
tb_char_t const *programdir,
tb_byte_t const *data,
tb_size_t size) {
// do decompress
tb_bool_t ok = tb_false;
LZ4F_errorCode_t code;
LZ4F_decompressionContext_t ctx = tb_null;
tb_buffer_t result;
do {
tb_buffer_init(&result);
code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
if (LZ4F_isError(code)) {
break;
}
tb_byte_t buffer[8192];
tb_bool_t failed = tb_false;
while (1) {
size_t advance = (size_t)size;
size_t buffer_size = sizeof(buffer);
code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null);
if (LZ4F_isError(code)) {
failed = tb_true;
break;
}
if (buffer_size == 0) {
break;
}
data += advance;
size -= advance;
tb_buffer_memncat(&result, buffer, buffer_size);
}
tb_assert_and_check_break(!failed && tb_buffer_size(&result));
ok = tb_true;
} while (0);
// extract files to programdir
if (ok) {
data = tb_buffer_data(&result);
size = tb_buffer_size(&result);
tb_byte_t const *p = data;
tb_byte_t const *e = data + size;
tb_size_t n = 0;
tb_char_t filepath[TB_PATH_MAXN];
tb_long_t pos = tb_snprintf(filepath, sizeof(filepath), "%s/", programdir);
while (p < e) {
// get filepath
n = (tb_size_t)tb_bits_get_u16_be(p);
p += 2;
tb_assert_and_check_break(pos + n + 1 < sizeof(filepath));
tb_strncpy(filepath + pos, (tb_char_t const *)p, n);
filepath[pos + n] = '\0';
p += n;
// get filedata
n = (tb_size_t)tb_bits_get_u32_be(p);
p += 4;
// write file
tb_trace_d("extracting %s, %lu bytes ..", filepath, n);
tb_stream_ref_t stream = tb_stream_init_from_file(filepath,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT |
TB_FILE_MODE_TRUNC);
tb_assert_and_check_break(stream);
if (tb_stream_open(stream)) {
tb_stream_bwrit(stream, p, n);
tb_stream_exit(stream);
}
p += n;
}
ok = (p == e);
if (!ok) {
tb_trace_e("extract program files failed");
}
} else {
tb_trace_e("decompress program files failed, %s", LZ4F_getErrorName(code));
}
if (ctx) {
LZ4F_freeDecompressionContext(ctx);
ctx = tb_null;
}
tb_buffer_exit(&result);
return ok;
}
static tb_bool_t xm_engine_extract_programfiles(xm_engine_t *engine, tb_char_t const *programdir) {
tb_file_info_t info = { 0 };
if (!tb_file_info(programdir, &info)) {
tb_byte_t const *data = _binary_xmake_xmz_start;
tb_size_t size = _binary_xmake_xmz_end - _binary_xmake_xmz_start;
if (!xm_engine_extract_programfiles_impl(engine, programdir, data, size)) {
return tb_false;
}
tb_size_t embedcount = engine->embedcount;
for (tb_size_t i = 0; i < embedcount; i++) {
data = engine->embeddata[i];
size = engine->embedsize[i];
if (!xm_engine_extract_programfiles_impl(engine, programdir, data, size)) {
return tb_false;
}
}
}
return tb_true;
}
#endif
static tb_void_t xm_engine_bind_to_lua(lua_State *lua, xm_engine_t *engine) {
lua_pushlightuserdata(lua, engine);
lua_setglobal(lua, "__global_engine");
}
// load and execute the main script
static tb_bool_t xm_engine_load_main_script(xm_engine_t *engine, tb_char_t const *mainfile) {
#ifdef TB_CONFIG_OS_WINDOWS
// use tb_file_init to support unicode file path on windows
tb_bool_t ok = tb_false;
tb_file_ref_t file = tb_null;
tb_byte_t *data = tb_null;
do {
// open file
file = tb_file_init(mainfile, TB_FILE_MODE_RO);
if (!file) {
tb_printf("error: cannot open file: %s\n", mainfile);
break;
}
// get file size
tb_size_t size = (tb_size_t)tb_file_size(file);
tb_assert_and_check_break(size);
// allocate buffer
data = (tb_byte_t *)tb_malloc(size);
tb_assert_and_check_break(data);
// read file content
if (!tb_file_read(file, data, size)) {
tb_printf("error: cannot read file: %s\n", mainfile);
break;
}
// load lua buffer
if (luaL_loadbuffer(engine->lua, (tb_char_t const *)data, size, mainfile)) {
tb_printf("error: %s\n", lua_tostring(engine->lua, -1));
break;
}
// execute lua script
if (lua_pcall(engine->lua, 0, LUA_MULTRET, 0)) {
tb_printf("error: %s\n", lua_tostring(engine->lua, -1));
break;
}
ok = tb_true;
} while (0);
if (data) {
tb_free(data);
}
if (file) {
tb_file_exit(file);
}
return ok;
#else
if (luaL_dofile(engine->lua, mainfile)) {
tb_printf("error: %s\n", lua_tostring(engine->lua, -1));
return tb_false;
}
return tb_true;
#endif
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
xm_engine_ref_t xm_engine_init(tb_char_t const *name, xm_engine_lni_initalizer_cb_t lni_initalizer) {
tb_bool_t ok = tb_false;
xm_engine_t *engine = tb_null;
do {
// init self
engine = tb_malloc0_type(xm_engine_t);
tb_assert_and_check_break(engine);
// init name
tb_strlcpy(engine->name, name, sizeof(engine->name));
// init lua
#if XM_HOOK_LUA_MEMALLOC
engine->lua = lua_newstate(xm_engine_lua_realloc, tb_null);
#else
engine->lua = luaL_newstate();
#endif
tb_assert_and_check_break(engine->lua);
// open lua libraries
luaL_openlibs(engine->lua);
// bind os functions
xm_lua_register(engine->lua, "os", g_os_functions);
// bind io functions
xm_lua_register(engine->lua, "io", g_io_functions);
// bind path functions
xm_lua_register(engine->lua, "path", g_path_functions);
// bind hash functions
xm_lua_register(engine->lua, "hash", g_hash_functions);
// bind lz4 functions
xm_lua_register(engine->lua, "lz4", g_lz4_functions);
// bind bloom filter functions
xm_lua_register(engine->lua, "bloom_filter", g_bloom_filter_functions);
// bind base64 functions
xm_lua_register(engine->lua, "base64", g_base64_functions);
// bind utf8 functions
xm_lua_register(engine->lua, "utf8", g_utf8_functions);
// bind string functions
xm_lua_register(engine->lua, "string", g_string_functions);
// bind process functions
xm_lua_register(engine->lua, "process", g_process_functions);
// bind fwatcher functions
xm_lua_register(engine->lua, "fwatcher", g_fwatcher_functions);
// bind sandbox functions
xm_lua_register(engine->lua, "sandbox", g_sandbox_functions);
// bind windows functions
#ifdef TB_CONFIG_OS_WINDOWS
xm_lua_register(engine->lua, "winos", g_winos_functions);
#endif
#ifdef XM_CONFIG_API_HAVE_READLINE
// bind readline functions
xm_lua_register(engine->lua, "readline", g_readline_functions);
#endif
// bind semver functions
xm_lua_register(engine->lua, "semver", g_semver_functions);
// bind libc functions
xm_lua_register(engine->lua, "libc", g_libc_functions);
// bind tty functions
xm_lua_register(engine->lua, "tty", g_tty_functions);
// bind package functions
xm_lua_register(engine->lua, "package", g_package_functions);
// bind binutils functions
xm_lua_register(engine->lua, "binutils", g_binutils_functions);
// bind thread functions
xm_lua_register(engine->lua, "thread", g_thread_functions);
#ifdef XM_CONFIG_API_HAVE_CURSES
// bind curses
xm_lua_curses_register(engine->lua, "curses");
#endif
#ifdef XM_CONFIG_API_HAVE_LUA_CJSON
// bind cjson
luaopen_cjson(engine->lua);
lua_setglobal(engine->lua, "cjson");
#endif
// bind engine to lua
xm_engine_bind_to_lua(engine->lua, engine);
// init host
xm_engine_init_host(engine);
// init architecture
xm_engine_init_arch(engine);
// init features
xm_engine_init_features(engine);
// init signal
xm_engine_init_signal(engine);
// get version
tb_version_t const *version = xm_version();
tb_assert_and_check_break(version);
// init version string
tb_char_t version_cstr[256] = { 0 };
if (tb_strcmp(XM_CONFIG_VERSION_BRANCH, "") && tb_strcmp(XM_CONFIG_VERSION_COMMIT, "")) {
tb_snprintf(version_cstr,
sizeof(version_cstr),
"%u.%u.%u+%s.%s",
version->major,
version->minor,
version->alter,
XM_CONFIG_VERSION_BRANCH,
XM_CONFIG_VERSION_COMMIT);
} else {
tb_snprintf(version_cstr,
sizeof(version_cstr),
"%u.%u.%u+%llu",
version->major,
version->minor,
version->alter,
(unsigned long long)version->build);
}
lua_pushstring(engine->lua, version_cstr);
lua_setglobal(engine->lua, "_VERSION");
#ifdef XM_EMBED_ENABLE
// init the temporary directory
if (!xm_engine_get_temporary_directory(engine->tmpdir,
sizeof(engine->tmpdir),
name,
version_cstr)) {
break;
}
lua_pushboolean(engine->lua, tb_true);
lua_setglobal(engine->lua, "_EMBED");
#endif
// init short version string
tb_snprintf(version_cstr, sizeof(version_cstr), "%u.%u.%u", version->major, version->minor, version->alter);
lua_pushstring(engine->lua, version_cstr);
lua_setglobal(engine->lua, "_VERSION_SHORT");
// init engine name
lua_pushstring(engine->lua, name ? name : "xmake");
lua_setglobal(engine->lua, "_NAME");
// use luajit as runtime?
#ifdef USE_LUAJIT
lua_pushboolean(engine->lua, tb_true);
#else
lua_pushboolean(engine->lua, tb_false);
#endif
lua_setglobal(engine->lua, "_LUAJIT");
// init namespace: xmake
lua_newtable(engine->lua);
lua_setglobal(engine->lua, "xmake");
/* do lua initializer and init namespace: _lni
*
* we can get the lni modules for _lni or `import("lib.lni.xxx")` in sandbox
*/
lua_newtable(engine->lua);
if (lni_initalizer) {
lni_initalizer((xm_engine_ref_t)engine, engine->lua);
}
lua_setglobal(engine->lua, "_lni");
#ifdef TB_CONFIG_OS_WINDOWS
// enable terminal colors output for windows cmd
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
if (output != INVALID_HANDLE_VALUE) {
DWORD mode;
if (GetConsoleMode(output, &mode)) {
// attempt to enable 0x4: ENABLE_VIRTUAL_TERMINAL_PROCESSING
if (SetConsoleMode(output, mode | 0x4)) {
tb_environment_set("COLORTERM", "color256");
}
}
}
#endif
ok = tb_true;
} while (0);
if (!ok) {
if (engine) {
xm_engine_exit((xm_engine_ref_t)engine);
}
engine = tb_null;
}
return (xm_engine_ref_t)engine;
}
tb_void_t xm_engine_exit(xm_engine_ref_t self) {
xm_engine_t *engine = (xm_engine_t *)self;
tb_assert_and_check_return(engine);
// exit lua
if (engine->lua) {
lua_close(engine->lua);
}
engine->lua = tb_null;
// exit poller
if (engine->poller) {
tb_poller_exit(engine->poller);
}
engine->poller = tb_null;
// exit it
tb_free(engine);
}
tb_int_t xm_engine_main(xm_engine_ref_t self, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv) {
xm_engine_t *engine = (xm_engine_t *)self;
tb_assert_and_check_return_val(engine && engine->lua, -1);
#if defined(TB_CONFIG_OS_WINDOWS) && defined(TB_COMPILER_IS_MSVC)
// set "stdin" to have unicode mode
if (_isatty(_fileno(stdin))) {
_setmode(_fileno(stdin), _O_U16TEXT);
}
#endif
// save main arguments to the global variable: _ARGV
if (!xm_engine_save_arguments(engine, argc, argv, taskargv)) {
return -1;
}
// get the project directory
tb_char_t path[TB_PATH_MAXN] = { 0 };
if (!xm_engine_get_project_directory(engine, path, sizeof(path))) {
return -1;
}
// get the program file
if (!xm_engine_get_program_file(engine, argv, path, sizeof(path))) {
return -1;
}
// get the program directory
if (!xm_engine_get_program_directory(engine, path, sizeof(path), path)) {
return -1;
}
#ifdef XM_EMBED_ENABLE
if (!xm_engine_extract_programfiles(engine, path)) {
return -1;
}
#endif
// append the main script path
tb_strcat(path, "/core/_xmake_main.lua");
// exists this script?
if (!tb_file_info(path, tb_null)) {
tb_printf("not found main script: %s\n", path);
return -1;
}
tb_trace_d("main: %s", path);
// load and execute the main script
if (!xm_engine_load_main_script(engine, path)) {
return -1;
}
// set the error function
lua_getglobal(engine->lua, "debug");
lua_getfield(engine->lua, -1, "traceback");
// call the main function
lua_getglobal(engine->lua, "_xmake_main");
if (lua_pcall(engine->lua, 0, 1, -2)) {
tb_printf("error: %s\n", lua_tostring(engine->lua, -1));
return -1;
}
// get the error code
return (tb_int_t)lua_tonumber(engine->lua, -1);
}
tb_void_t xm_engine_register(xm_engine_ref_t self, tb_char_t const *module, luaL_Reg const funcs[]) {
xm_engine_t *engine = (xm_engine_t *)self;
tb_assert_and_check_return(engine && engine->lua && module && funcs);
// do register
lua_pushstring(engine->lua, module);
lua_newtable(engine->lua);
xm_lua_register(engine->lua, tb_null, funcs);
lua_rawset(engine->lua, -3);
}
#ifdef XM_EMBED_ENABLE
tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t self, tb_byte_t const *data, tb_size_t size) {
xm_engine_t *engine = (xm_engine_t *)self;
tb_assert_and_check_return(engine && engine->embedcount < tb_arrayn(engine->embedsize) && data && size);
engine->embeddata[engine->embedcount] = data;
engine->embedsize[engine->embedcount] = size;
engine->embedcount++;
}
#endif
lua_State *xm_engine_lua(xm_engine_ref_t self) {
xm_engine_t *engine = (xm_engine_t *)self;
tb_assert_and_check_return_val(engine, tb_null);
return engine->lua;
}
tb_poller_ref_t xm_engine_poller(xm_engine_ref_t self) {
xm_engine_t *engine = (xm_engine_t *)self;
tb_assert_and_check_return_val(engine, tb_null);
if (!engine->poller) {
// init poller
engine->poller_state.lua = engine->lua;
tb_poller_ref_t poller = tb_poller_init(&engine->poller_state);
tb_assert_and_check_return_val(poller, tb_null);
// attach poller to the current thread
tb_poller_attach(poller);
engine->poller = poller;
}
return engine->poller;
}
tb_int_t xm_engine_run(tb_char_t const *name,
tb_int_t argc,
tb_char_t **argv,
tb_char_t **taskargv,
xm_engine_lni_initalizer_cb_t lni_initalizer) {
tb_int_t ok = -1;
if (xm_init()) {
xm_engine_ref_t engine = xm_engine_init(name, lni_initalizer);
if (engine) {
ok = xm_engine_main(engine, argc, argv, taskargv);
xm_engine_exit(engine);
}
xm_exit();
}
return ok;
}
xm_engine_ref_t xm_engine_get(lua_State *lua) {
tb_assert_and_check_return_val(lua, tb_null);
lua_getglobal(lua, "__global_engine");
return (xm_engine_ref_t)lua_touserdata(lua, -1);
}
================================================
FILE: core/src/xmake/engine.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file engine.h
*
*/
#ifndef XM_ENGINE_H
#define XM_ENGINE_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_enter__
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
/// the xmake engine type
typedef struct {
tb_int_t dummy;
} const *xm_engine_ref_t;
/// the lni initializer callback type
typedef tb_void_t (*xm_engine_lni_initalizer_cb_t)(xm_engine_ref_t engine, lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
/*! init the engine
*
* @param name the engine name
* @param lni_initalizer the lni initializer
*
* @return the engine
*/
xm_engine_ref_t xm_engine_init(tb_char_t const *name, xm_engine_lni_initalizer_cb_t lni_initalizer);
/*! exit the engine
*
* @param engine the engine
*/
tb_void_t xm_engine_exit(xm_engine_ref_t engine);
/*! do the main entry of the engine
*
* @param engine the engine
* @param argc the argument count of the console
* @param argv the argument list of the console
* @param taskargv the argument list of sub-task, e.g. taskargv(lua -vD lua.main) for xmake lua -vD lua.main arg1 arg2 ..
*
* @return the error code of main()
*/
tb_int_t xm_engine_main(xm_engine_ref_t engine, tb_int_t argc, tb_char_t **argv, tb_char_t **taskargv);
/*! register lni modules in the engine, @note we need to call it in lni_initalizer()
*
* @param engine the engine
* @param module the lni module name
* @param funcs the lni module functions
*/
tb_void_t xm_engine_register(xm_engine_ref_t engine, tb_char_t const *module, luaL_Reg const funcs[]);
/*! add the embed files
*
* @param engine the engine
* @param data the embedfiles data
* @param size the data size
*/
tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t engine, tb_byte_t const *data, tb_size_t size);
/* get lua state from engine
*
* @param engine the engine
*
* @return the lua state
*/
lua_State *xm_engine_lua(xm_engine_ref_t engine);
/* get poller from engine
*
* @param engine the engine
*
* @return the poller
*/
tb_poller_ref_t xm_engine_poller(xm_engine_ref_t engine);
/*! run main entry of the engine singleton
*
* @param name the engine name
* @param argc the argument count of the console
* @param argv the argument list of the console
* @param taskargv the argument list of sub-task, e.g. taskargv(lua -vD lua.main) for xmake lua -vD lua.main arg1 arg2 ..
* @param lni_initalizer the lni initializer
*
* @return the error code of main()
*/
tb_int_t xm_engine_run(tb_char_t const *name,
tb_int_t argc,
tb_char_t **argv,
tb_char_t **taskargv,
xm_engine_lni_initalizer_cb_t lni_initalizer);
/*! get engine from the given lua state
*
* @param lua the lua state
*
* @return the engine
*/
xm_engine_ref_t xm_engine_get(lua_State *lua);
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_leave__
#endif
================================================
FILE: core/src/xmake/engine_pool.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file engine_pool.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "engine_pool"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "xmake.h"
#include "engine.h"
#include "engine_pool.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// the max engine pool count
#define XM_ENGINE_POOL_MAXN (128)
// the singleton type of engine pool
#define XM_ENGINE_POOL (TB_SINGLETON_TYPE_USER + 4)
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_handle_t xm_engine_pool_instance_init(tb_cpointer_t *ppriv) {
xm_engine_pool_ref_t engine_pool = xm_engine_pool_init();
tb_assert_and_check_return_val(engine_pool, tb_null);
return (tb_handle_t)engine_pool;
}
static tb_void_t xm_engine_pool_instance_exit(tb_handle_t engine_pool, tb_cpointer_t priv) {
if (engine_pool) {
xm_engine_pool_exit((xm_engine_pool_ref_t)engine_pool);
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
xm_engine_pool_ref_t xm_engine_pool() {
return (xm_engine_pool_ref_t)tb_singleton_instance(
XM_ENGINE_POOL, xm_engine_pool_instance_init, xm_engine_pool_instance_exit, tb_null, tb_null);
}
xm_engine_pool_ref_t xm_engine_pool_init() {
return tb_single_list_init(0, tb_element_ptr(tb_null, tb_null));
}
tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool) {
if (engine_pool) {
tb_for_all(xm_engine_ref_t, engine, engine_pool) {
if (engine) {
xm_engine_exit(engine);
}
}
tb_single_list_exit(engine_pool);
}
}
xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool) {
xm_engine_ref_t engine = tb_null;
if (tb_single_list_size(engine_pool) > 0) {
engine = (xm_engine_ref_t)tb_single_list_head(engine_pool);
tb_single_list_remove_head(engine_pool);
}
return engine;
}
tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine) {
if (tb_single_list_size(engine_pool) < XM_ENGINE_POOL_MAXN) {
tb_single_list_insert_tail(engine_pool, engine);
return tb_true;
}
return tb_false;
}
================================================
FILE: core/src/xmake/engine_pool.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file engine_pool.h
*
*/
#ifndef XM_ENGINE_POOL_H
#define XM_ENGINE_POOL_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_enter__
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
/// the xmake engine pool type
typedef tb_single_list_ref_t xm_engine_pool_ref_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// get the engine pool singleton
xm_engine_pool_ref_t xm_engine_pool(tb_void_t);
/*! init the engine_pool
*
* @return the engine pool
*/
xm_engine_pool_ref_t xm_engine_pool_init(tb_void_t);
/*! exit the engine_pool
*
* @param engine_pool the engine_pool
*/
tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool);
/*! alloc a engine from the engine_pool
*
* @param engine_pool the engine_pool
*
* @return the engine
*/
xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool);
/*! free a engine to the engine_pool
*
* @param engine_pool the engine_pool
* @param engine the engine
*
* @return tb_true or tb_false
*/
tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine);
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_leave__
#endif
================================================
FILE: core/src/xmake/fwatcher/add.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file add.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "fwatcher.add"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// fwatcher.add(watchdir, recursion)
tb_int_t xm_fwatcher_add(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the fwatcher
tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(fwatcher, 0);
// get watchdir
tb_char_t const *watchdir = luaL_checkstring(lua, 2);
tb_check_return_val(watchdir, 0);
// get recursion
tb_bool_t recursion = lua_toboolean(lua, 3);
// add watchdir
tb_bool_t ok = tb_fwatcher_add(fwatcher, watchdir, recursion);
// save result
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/fwatcher/close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "fwatcher.close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// fwatcher.close(p)
tb_int_t xm_fwatcher_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the fwatcher
tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(fwatcher, 0);
// exit fwatcher
tb_fwatcher_exit(fwatcher);
// save result: ok
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/fwatcher/open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "fwatcher.open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_fwatcher_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// init fwatcher
tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)tb_fwatcher_init();
if (fwatcher) {
xm_lua_pushpointer(lua, (tb_pointer_t)fwatcher);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/fwatcher/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_FWATCHER_PREFIX_H
#define XM_FWATCHER_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/fwatcher/remove.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file remove.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "fwatcher.remove"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// fwatcher.remove(watchdir)
tb_int_t xm_fwatcher_remove(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the fwatcher
tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(fwatcher, 0);
// get watchdir
tb_char_t const *watchdir = luaL_checkstring(lua, 2);
tb_check_return_val(watchdir, 0);
// remove watchdir
tb_bool_t ok = tb_fwatcher_remove(fwatcher, watchdir);
// save result
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/fwatcher/wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "fwatcher.wait"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// fwatcher.wait(p)
tb_int_t xm_fwatcher_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the fwatcher
tb_fwatcher_ref_t fwatcher = (tb_fwatcher_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(fwatcher, 0);
// get the timeout
tb_long_t timeout = (tb_long_t)luaL_checkinteger(lua, 2);
// wait fwatcher event
tb_fwatcher_event_t event;
tb_long_t ok = tb_fwatcher_wait(fwatcher, &event, timeout);
// save result
lua_pushinteger(lua, ok);
if (ok > 0) {
lua_newtable(lua);
lua_pushstring(lua, "path");
lua_pushstring(lua, event.filepath);
lua_settable(lua, -3);
lua_pushstring(lua, "type");
lua_pushinteger(lua, event.event);
lua_settable(lua, -3);
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/hash/md5.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file md5.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "md5"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_md5(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is bytes? get data and size
if (xm_lua_isinteger(lua, 1) && xm_lua_isinteger(lua, 2)) {
tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);
tb_size_t size = (tb_size_t)lua_tointeger(lua, 2);
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// compute md5
tb_byte_t buffer[16];
tb_md5_make(data, size, buffer, sizeof(buffer));
// make md5 string
tb_char_t s[256];
tb_size_t n = xm_hash_make_cstr(s, buffer, 16);
// save result
lua_pushlstring(lua, s, n);
return 1;
}
// get the filename
tb_char_t const *filename = luaL_checkstring(lua, 1);
tb_check_return_val(filename, 0);
// load data from file
tb_bool_t ok = tb_false;
tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);
if (stream) {
// open stream
if (tb_stream_open(stream)) {
// init md5
tb_md5_t md5;
tb_md5_init(&md5, 0);
// read data and update md5
tb_byte_t data[TB_STREAM_BLOCK_MAXN];
while (!tb_stream_beof(stream)) {
// read data
tb_long_t real = tb_stream_read(stream, data, sizeof(data));
if (real > 0) {
tb_md5_spak(&md5, data, real);
// no data? continue it
} else if (!real) {
// wait
real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));
tb_check_break(real > 0);
// has read?
tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);
}
// failed or end?
else {
break;
}
}
// exit md5
tb_byte_t buffer[16];
tb_md5_exit(&md5, buffer, sizeof(buffer));
// make md5 string
tb_char_t s[256];
tb_size_t n = xm_hash_make_cstr(s, buffer, 16);
// save result
lua_pushlstring(lua, s, n);
ok = tb_true;
}
// exit stream
tb_stream_exit(stream);
}
if (!ok) {
lua_pushnil(lua);
// check if file exists to provide more specific error message
if (!tb_file_info(filename, tb_null)) {
lua_pushfstring(lua, "file not found: %s", filename);
} else {
lua_pushfstring(lua, "failed to read file: %s", filename);
}
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/hash/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_HASH_PREFIX_H
#define XM_HASH_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* helper implementation
*/
static __tb_inline__ tb_uint64_t xm_hash_xorshift64(tb_uint64_t x) {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
return x;
}
// http://xorshift.di.unimi.it/xorshift128plus.c
static __tb_inline__ tb_uint64_t xm_hash_xorshift128(tb_uint64_t *s) {
tb_uint64_t s1 = s[0];
tb_uint64_t const s0 = s[1];
s[0] = s0;
s1 ^= s1 << 23;
s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5);
return s[1] + s0;
}
static __tb_inline__ tb_size_t xm_hash_make_cstr(tb_char_t hash[256], tb_byte_t const *data, tb_size_t size) {
static tb_char_t const *digits_table = "0123456789abcdef";
tb_size_t i = 0;
tb_byte_t value;
tb_char_t *s = hash;
for (i = 0; i < size; ++i) {
value = data[i];
s[0] = digits_table[(value >> 4) & 15];
s[1] = digits_table[value & 15];
s += 2;
}
*s = '\0';
return s - hash;
}
#endif
================================================
FILE: core/src/xmake/hash/rand128.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rand128.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rand128"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_rand128(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
static union {
tb_byte_t b[16];
tb_uint64_t word[2];
} s_seed = { 0 };
if (!s_seed.word[0] && !s_seed.word[1]) {
s_seed.word[0] = (tb_uint64_t)tb_uclock();
s_seed.word[1] = (tb_uint64_t)tb_uclock();
}
s_seed.word[0] = xm_hash_xorshift128(s_seed.word);
s_seed.word[1] = xm_hash_xorshift128(s_seed.word);
tb_char_t s[256];
tb_size_t n = xm_hash_make_cstr(s, s_seed.b, 16);
lua_pushlstring(lua, s, n);
return 1;
}
================================================
FILE: core/src/xmake/hash/rand32.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rand32.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rand32"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_rand32(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
static tb_uint64_t s_seed = 0;
if (!s_seed) {
s_seed = (tb_uint64_t)tb_uclock();
}
s_seed = xm_hash_xorshift64(s_seed);
tb_char_t s[256];
tb_uint32_t word = (s_seed >> 32) ^ (s_seed & 0xffffffff);
tb_size_t n = xm_hash_make_cstr(s, (tb_byte_t const *)&word, 4);
lua_pushlstring(lua, s, n);
return 1;
}
================================================
FILE: core/src/xmake/hash/rand64.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rand64.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rand64"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_rand64(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
static union {
tb_byte_t b[8];
tb_uint64_t word;
} s_seed = { 0 };
if (!s_seed.word) {
s_seed.word = (tb_uint64_t)tb_uclock();
}
s_seed.word = xm_hash_xorshift64(s_seed.word);
tb_char_t s[256];
tb_size_t n = xm_hash_make_cstr(s, s_seed.b, 8);
lua_pushlstring(lua, s, n);
return 1;
}
================================================
FILE: core/src/xmake/hash/sha.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sha.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "sha"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_sha(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get mode
tb_size_t mode = (tb_size_t)lua_tointeger(lua, 1);
// is bytes? get data and size
if (xm_lua_isinteger(lua, 2) && xm_lua_isinteger(lua, 3)) {
tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
tb_size_t size = (tb_size_t)lua_tointeger(lua, 3);
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// compute sha
tb_sha_t sha;
tb_byte_t buffer[32];
tb_sha_init(&sha, mode);
tb_sha_spak(&sha, data, size);
tb_sha_exit(&sha, buffer, sizeof(buffer));
// make sha string
tb_char_t s[256];
tb_size_t n = sha.digest_len << 2;
tb_size_t len = xm_hash_make_cstr(s, buffer, n);
// save result
lua_pushlstring(lua, s, len);
return 1;
}
// get the filename
tb_char_t const *filename = luaL_checkstring(lua, 2);
tb_check_return_val(filename, 0);
// load data from file
tb_bool_t ok = tb_false;
tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);
if (stream) {
// open stream
if (tb_stream_open(stream)) {
// init sha
tb_sha_t sha;
tb_sha_init(&sha, mode);
// read data and update sha
tb_byte_t data[TB_STREAM_BLOCK_MAXN];
while (!tb_stream_beof(stream)) {
// read data
tb_long_t real = tb_stream_read(stream, data, sizeof(data));
if (real > 0) {
tb_sha_spak(&sha, data, real);
// no data? continue it
} else if (!real) {
// wait
real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));
tb_check_break(real > 0);
// has read?
tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);
}
// failed or end?
else {
break;
}
}
// exit sha
tb_byte_t buffer[32];
tb_sha_exit(&sha, buffer, sizeof(buffer));
// make sha string
tb_char_t s[256];
tb_size_t n = sha.digest_len << 2;
tb_size_t len = xm_hash_make_cstr(s, buffer, n);
// save result
lua_pushlstring(lua, s, len);
ok = tb_true;
}
// exit stream
tb_stream_exit(stream);
}
if (!ok) {
lua_pushnil(lua);
// check if file exists to provide more specific error message
if (!tb_file_info(filename, tb_null)) {
lua_pushfstring(lua, "file not found: %s", filename);
} else {
lua_pushfstring(lua, "failed to read file: %s", filename);
}
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/hash/uuid4.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file uuid4.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "uuid4"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_uuid4(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the name
tb_char_t const *name = luaL_optstring(lua, 1, tb_null);
// make uuid, use version 4
tb_char_t uuid[37];
lua_pushstring(lua, tb_uuid4_make_cstr(uuid, name));
return 1;
}
================================================
FILE: core/src/xmake/hash/xxhash.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file xxhash.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "xxhash"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#define XXH_NAMESPACE XM_
#define XXH_STATIC_LINKING_ONLY
#define XXH_IMPLEMENTATION
#include "xxhash/xxhash.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_hash_xxhash(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get mode
tb_size_t mode = (tb_size_t)lua_tointeger(lua, 1);
if (mode != 32 && mode != 64 && mode != 128) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid mode(%d)!", (tb_int_t)mode);
return 2;
}
// is bytes? get data and size
if (xm_lua_isinteger(lua, 2) && xm_lua_isinteger(lua, 3)) {
tb_byte_t const *data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
tb_size_t size = (tb_size_t)lua_tointeger(lua, 3);
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// compuate hash
tb_byte_t const *buffer = tb_null;
tb_uint32_t value32;
XXH64_hash_t value64;
XXH128_hash_t value128;
if (mode == 128) {
value128 = XM_XXH3_128bits(data, size);
buffer = (tb_byte_t const *)&value128;
} else if (mode == 64) {
value64 = XM_XXH3_64bits(data, size);
buffer = (tb_byte_t const *)&value64;
} else if (mode == 32) {
value64 = XM_XXH3_64bits(data, size);
value32 = (value64 >> 32) ^ (value64 & 0xffffffff);
buffer = (tb_byte_t const *)&value32;
}
if (!buffer) {
lua_pushnil(lua);
lua_pushfstring(lua, "empty buffer!");
return 2;
}
// make xxhash string
tb_char_t s[256];
tb_size_t n = mode >> 3;
tb_size_t len = xm_hash_make_cstr(s, buffer, n);
// save result
lua_pushlstring(lua, s, len);
return 1;
}
// get the filename
tb_char_t const *filename = luaL_checkstring(lua, 2);
tb_check_return_val(filename, 0);
// load data from file
tb_bool_t ok = tb_false;
tb_stream_ref_t stream = tb_stream_init_from_file(filename, TB_FILE_MODE_RO);
if (stream) {
// open stream
XXH3_state_t *state = XM_XXH3_createState();
if (tb_stream_open(stream) && state) {
// reset xxhash
if (mode == 32 || mode == 64) {
XM_XXH3_64bits_reset(state);
} else {
XM_XXH3_128bits_reset(state);
}
// read data and update xxhash
tb_byte_t data[TB_STREAM_BLOCK_MAXN];
while (!tb_stream_beof(stream)) {
// read data
tb_long_t real = tb_stream_read(stream, data, sizeof(data));
if (real > 0) {
if (mode == 32 || mode == 64) {
XM_XXH3_64bits_update(state, data, real);
} else {
XM_XXH3_128bits_update(state, data, real);
}
}
// no data? continue it
else if (!real) {
// wait
real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, tb_stream_timeout(stream));
tb_check_break(real > 0);
// has read?
tb_assert_and_check_break(real & TB_STREAM_WAIT_READ);
}
// failed or end?
else {
break;
}
}
// compuate hash
tb_byte_t const *buffer;
tb_uint32_t value32;
XXH64_hash_t value64;
XXH128_hash_t value128;
if (mode == 128) {
value128 = XM_XXH3_128bits_digest(state);
buffer = (tb_byte_t const *)&value128;
} else if (mode == 64) {
value64 = XM_XXH3_64bits_digest(state);
buffer = (tb_byte_t const *)&value64;
} else if (mode == 32) {
value64 = XM_XXH3_64bits_digest(state);
value32 = (value64 >> 32) ^ (value64 & 0xffffffff);
buffer = (tb_byte_t const *)&value32;
}
// make xxhash string
tb_char_t s[256];
tb_size_t n = mode >> 3;
tb_size_t len = xm_hash_make_cstr(s, buffer, n);
// save result
lua_pushlstring(lua, s, len);
ok = tb_true;
}
// exit stream
tb_stream_exit(stream);
// exit xxhash
if (state) {
XM_XXH3_freeState(state);
}
}
if (!ok) {
lua_pushnil(lua);
// check if file exists to provide more specific error message
if (!tb_file_info(filename, tb_null)) {
lua_pushfstring(lua, "file not found: %s", filename);
} else {
lua_pushfstring(lua, "failed to read file: %s", filename);
}
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/io/file_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.file_close(file)
tb_int_t xm_io_file_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1))
xm_io_return_error(lua, "close(invalid file)!");
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// close file
if (xm_io_file_is_file(file)) {
tb_assert(file->u.file_ref);
#ifdef TB_CONFIG_OS_WINDOWS
// write cached data first
tb_byte_t const *odata = tb_buffer_data(&file->wcache);
tb_size_t osize = tb_buffer_size(&file->wcache);
if (odata && osize) {
if (!tb_stream_bwrit(file->u.file_ref, odata, osize))
return tb_false;
tb_buffer_clear(&file->wcache);
}
#endif
// flush filter stream cache, TODO we should fix it in tbox/stream
if ((file->mode & TB_FILE_MODE_RW) == TB_FILE_MODE_RW && file->fstream) {
if (!tb_stream_sync(file->u.file_ref, tb_false))
return tb_false;
}
// close file
tb_stream_clos(file->u.file_ref);
file->u.file_ref = tb_null;
// exit fstream
if (file->fstream) {
tb_stream_exit(file->fstream);
}
file->fstream = tb_null;
// exit stream
if (file->stream) {
tb_stream_exit(file->stream);
}
file->stream = tb_null;
// exit the line cache buffer
tb_buffer_exit(&file->rcache);
tb_buffer_exit(&file->wcache);
// gc will free it if no any refs for lua_newuserdata()
// ...
lua_pushboolean(lua, tb_true);
return 1;
} else // for stdfile (gc/close)
{
// exit the line cache buffer
tb_buffer_exit(&file->rcache);
tb_buffer_exit(&file->wcache);
// gc will free it if no any refs for lua_newuserdata()
// ...
lua_pushboolean(lua, tb_true);
return 1;
}
}
================================================
FILE: core/src/xmake/io/file_convert.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file file_convert.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_convert"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../utils/charset.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* convert file
*
* @param srcpath the srcpath
* @param dstpath the dstpath
* @param ftype the from-charset type, e.g. ascii, gb2312, gbk, ios8859, ucs2, ucs4, utf8, utf16, utf32
* @param ttype the to-charset type
*
* @code
* io.convert(srcpath, dstpath, "gbk", "utf8")
* io.convert(srcpath, dstpath, "utf8", "gb2312")
* @endcode
*/
tb_int_t xm_io_file_convert(lua_State *lua) {
// check
tb_assert_and_check_return_val(lua, 0);
#ifdef TB_CONFIG_MODULE_HAVE_CHARSET
// get arguments
tb_char_t const *srcpath = luaL_checkstring(lua, 1);
tb_char_t const *dstpath = luaL_checkstring(lua, 2);
tb_char_t const *fname = luaL_checkstring(lua, 3);
tb_char_t const *tname = luaL_checkstring(lua, 4);
tb_check_return_val(srcpath && dstpath && fname && tname, 0);
// get charset type
tb_size_t ftype = TB_CHARSET_TYPE_UTF8;
tb_size_t ttype = TB_CHARSET_TYPE_UTF8;
xm_charset_entry_ref_t fentry = xm_charset_find_by_name(fname);
if (fentry) ftype = fentry->type;
else {
lua_pushfstring(lua, "invalid charset: %s", fname);
lua_error(lua);
}
xm_charset_entry_ref_t tentry = xm_charset_find_by_name(tname);
if (tentry) ttype = tentry->type;
else {
lua_pushfstring(lua, "invalid charset: %s", tname);
lua_error(lua);
}
// done
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_null;
tb_stream_ref_t ostream = tb_null;
tb_stream_ref_t fstream = tb_null;
do {
// init istream
istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO);
tb_assert_and_check_break(istream);
// open istream
if (!tb_stream_open(istream)) break;
// skip bom
tb_size_t skip = 0;
tb_byte_t* bom_data = tb_null;
tb_long_t bom_size = tb_stream_peek(istream, &bom_data, 3);
if (bom_size >= 3 && ftype == TB_CHARSET_TYPE_UTF8 && bom_data[0] == 0xef && bom_data[1] == 0xbb && bom_data[2] == 0xbf) {
skip = 3;
} else if (bom_size >= 2 && (ftype & TB_CHARSET_TYPE_UTF16)) {
if (bom_data[0] == 0xff && bom_data[1] == 0xfe) skip = 2;
else if (bom_data[0] == 0xfe && bom_data[1] == 0xff) skip = 2;
}
if (skip > 0 && !tb_stream_skip(istream, skip)) break;
// init ostream
ostream = tb_stream_init_from_file(dstpath, TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
tb_assert_and_check_break(ostream);
// open ostream
if (!tb_stream_open(ostream)) break;
// write bom
if (!tb_strcmp(tname, "utf8bom")) {
static tb_byte_t const k_bom[] = {0xef, 0xbb, 0xbf};
if (!tb_stream_bwrit(ostream, k_bom, 3)) break;
} else if (!tb_strcmp(tname, "utf16lebom")) {
static tb_byte_t const k_bom[] = {0xff, 0xfe};
if (!tb_stream_bwrit(ostream, k_bom, 2)) break;
} else if (!tb_strcmp(tname, "utf16bom")) {
#ifndef TB_WORDS_BIGENDIAN
static tb_byte_t const k_bom[] = {0xff, 0xfe};
#else
static tb_byte_t const k_bom[] = {0xfe, 0xff};
#endif
if (!tb_stream_bwrit(ostream, k_bom, 2)) break;
}
// init fstream
fstream = tb_stream_init_filter_from_charset(istream, ftype, ttype);
tb_assert_and_check_break(fstream);
// open fstream
if (!tb_stream_open(fstream)) break;
// transfer
tb_byte_t data[TB_STREAM_BLOCK_MAXN];
while (1) {
tb_long_t real = tb_stream_read(fstream, data, sizeof(data));
if (real > 0) {
if (!tb_stream_bwrit(ostream, data, real)) break;
} else if (real == 0) {
tb_long_t wait = tb_stream_wait(fstream, TB_STREAM_WAIT_READ, tb_stream_timeout(fstream));
if (wait <= 0) break;
} else break;
}
// ok
ok = tb_true;
} while (0);
// exit fstream
if (fstream) tb_stream_exit(fstream);
fstream = tb_null;
// exit istream
if (istream) tb_stream_exit(istream);
istream = tb_null;
// exit ostream
if (ostream) tb_stream_exit(ostream);
ostream = tb_null;
// ok?
lua_pushboolean(lua, ok);
return 1;
#else
lua_pushboolean(lua, tb_false);
return 1;
#endif
}
================================================
FILE: core/src/xmake/io/file_flush.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_flush.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_flush"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_io_std_flush_impl(xm_io_file_t *file) {
tb_assert_and_check_return_val(xm_io_file_is_std(file), tb_false);
return (file->u.std_ref != tb_stdfile_input()) ? tb_stdfile_flush(file->u.std_ref) : tb_false;
}
static tb_bool_t xm_io_file_flush_impl(xm_io_file_t *file) {
tb_assert_and_check_return_val(xm_io_file_is_file(file), tb_false);
#ifdef TB_CONFIG_OS_WINDOWS
// write cached data first
tb_byte_t const *odata = tb_buffer_data(&file->wcache);
tb_size_t osize = tb_buffer_size(&file->wcache);
if (odata && osize) {
if (!tb_stream_bwrit(file->u.file_ref, odata, osize))
return tb_false;
tb_buffer_clear(&file->wcache);
}
#endif
return tb_stream_sync(file->u.file_ref, tb_false);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.file_flush(file)
tb_int_t xm_io_file_flush(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1)) {
xm_io_return_error(lua, "flush(invalid file)!");
}
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// flush file
tb_bool_t ok = xm_io_file_is_file(file) ? xm_io_file_flush_impl(file) : xm_io_std_flush_impl(file);
if (ok) {
lua_pushboolean(lua, tb_true);
return 1;
} else {
xm_io_return_error(lua, "failed to flush file");
}
}
================================================
FILE: core/src/xmake/io/file_isatty.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu
* @file file_isatty.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_isatty"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.file_isatty(file)
tb_int_t xm_io_file_isatty(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1)) {
xm_io_return_error(lua, "isatty(invalid file)!");
}
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// is tty?
lua_pushboolean(lua, xm_io_file_is_tty(file));
return 1;
}
================================================
FILE: core/src/xmake/io/file_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// num of bytes read to guess encoding
#define CHECK_SIZE (1024)
// is utf-8 tail character
#define IS_UTF8_TAIL(c) (c >= 0x80 && c < 0xc0)
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_size_t xm_io_file_detect_charset(tb_byte_t const **data_ptr, tb_long_t size) {
tb_assert(data_ptr && *data_ptr);
tb_byte_t const *data = *data_ptr;
tb_size_t charset = XM_IO_FILE_ENCODING_BINARY;
do {
// is luajit bitcode? open as binary
if (size >= 3 && data[0] == 27 && data[1] == 'L' && data[2] == 'J') {
break;
}
// utf-8 with bom
if (size >= 3 && data[0] == 239 && data[1] == 187 && data[2] == 191) {
charset = TB_CHARSET_TYPE_UTF8;
data += 3; // skip bom
break;
}
if (size >= 2) {
// utf16be
if (data[0] == 254 && data[1] == 255) {
charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE;
data += 2; // skip bom
break;
}
// utf16le
else if (data[0] == 255 && data[1] == 254) {
charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE;
data += 2; // skip bom
break;
}
}
tb_sint16_t utf16be_conf = 0;
tb_sint16_t utf16le_conf = 0;
tb_sint16_t utf8_conf = 0;
tb_sint16_t ascii_conf = 0;
tb_sint16_t zero_count = 0;
for (tb_long_t i = 0; i < (size - 4) && i < CHECK_SIZE; i++) {
if (data[i] == 0) {
zero_count++;
}
if (data[i] < 0x80) {
ascii_conf++;
} else {
ascii_conf = TB_MINS16;
}
if (i % 2 == 0) {
if (data[i] == 0) {
utf16be_conf++;
}
if (data[i + 1] == 0) {
utf16le_conf++;
}
}
if (IS_UTF8_TAIL(data[i])) {
// continue
} else if (data[i] < 0x80) {
utf8_conf++;
} else if (data[i] >= 0xc0 && data[i] < 0xe0 && IS_UTF8_TAIL(data[i + 1])) {
utf8_conf++;
} else if (data[i] >= 0xe0 && data[i] < 0xf0 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2])) {
utf8_conf++;
} else if (data[i] >= 0xf0 && data[i] < 0xf8 && IS_UTF8_TAIL(data[i + 1]) && IS_UTF8_TAIL(data[i + 2]) &&
IS_UTF8_TAIL(data[i + 3])) {
utf8_conf++;
} else {
utf8_conf = TB_MINS16;
}
}
if (ascii_conf > 0 && zero_count <= 1) {
charset = TB_CHARSET_TYPE_UTF8;
break;
}
if (utf8_conf > 0 && zero_count <= 1) {
charset = TB_CHARSET_TYPE_UTF8;
break;
}
if (utf16be_conf > 0 && utf16be_conf > utf16le_conf) {
charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE;
break;
}
if (utf16le_conf > 0 && utf16le_conf >= utf16be_conf) {
charset = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE;
break;
}
if (utf8_conf > 0) {
charset = TB_CHARSET_TYPE_UTF8;
break;
}
#ifdef TB_CONFIG_OS_WINDOWS
charset = TB_CHARSET_TYPE_ANSI;
#endif
} while (0);
*data_ptr = data;
return charset;
}
static tb_size_t xm_io_file_detect_encoding(tb_stream_ref_t stream, tb_long_t *pbomoff) {
tb_assert_and_check_return_val(stream && pbomoff, XM_IO_FILE_ENCODING_BINARY);
// detect encoding
tb_byte_t *data = tb_null;
tb_size_t encoding = XM_IO_FILE_ENCODING_BINARY;
tb_long_t size = tb_stream_peek(stream, &data, CHECK_SIZE);
if (size > 0) {
tb_byte_t const *p = data;
encoding = xm_io_file_detect_charset(&p, size);
*pbomoff = p - data;
}
return encoding;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.file_open(path, modestr)
tb_int_t xm_io_file_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get file path and mode
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_char_t const *modestr = luaL_optstring(lua, 2, "r");
tb_assert_and_check_return_val(path && modestr, 0);
// get file mode value
tb_size_t mode;
switch (modestr[0]) {
case 'w':
mode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC;
break;
case 'a':
mode = TB_FILE_MODE_RW | TB_FILE_MODE_APPEND | TB_FILE_MODE_CREAT;
break;
case 'r':
default:
mode = TB_FILE_MODE_RO;
break;
}
// get file encoding
tb_long_t bomoff = 0;
tb_stream_ref_t stream = tb_null;
tb_bool_t update = !!tb_strchr(modestr, '+');
tb_size_t encoding = XM_IO_FILE_ENCODING_UNKNOWN;
if (modestr[1] == 'b' || (update && modestr[2] == 'b')) {
encoding = XM_IO_FILE_ENCODING_BINARY;
} else if (tb_strstr(modestr, "utf8") || tb_strstr(modestr, "utf-8")) {
encoding = TB_CHARSET_TYPE_UTF8;
} else if (tb_strstr(modestr, "utf16le") || tb_strstr(modestr, "utf-16le")) {
encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE;
} else if (tb_strstr(modestr, "utf16be") || tb_strstr(modestr, "utf-16be")) {
encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE;
} else if (tb_strstr(modestr, "utf16") || tb_strstr(modestr, "utf-16")) {
encoding = TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE;
} else if (tb_strstr(modestr, "ansi")) {
encoding = TB_CHARSET_TYPE_ANSI;
} else if (tb_strstr(modestr, "gbk")) {
encoding = TB_CHARSET_TYPE_GBK;
} else if (tb_strstr(modestr, "gb2312")) {
encoding = TB_CHARSET_TYPE_GB2312;
} else if (tb_strstr(modestr, "iso8859")) {
encoding = TB_CHARSET_TYPE_ISO8859;
} else if (modestr[0] == 'w' || modestr[0] == 'a') { // set to utf-8 if not specified for the writing mode
encoding = TB_CHARSET_TYPE_UTF8;
} else if (modestr[0] == 'r') { // detect encoding if not specified for the reading mode
stream = tb_stream_init_from_file(path, mode);
if (stream && tb_stream_open(stream)) {
encoding = xm_io_file_detect_encoding(stream, &bomoff);
} else {
if (stream) {
tb_stream_exit(stream);
}
xm_io_return_error(lua, "file not found!");
}
} else {
xm_io_return_error(lua, "invalid open mode!");
}
tb_assert_and_check_return_val(encoding != XM_IO_FILE_ENCODING_UNKNOWN, 0);
// write data with utf bom? e.g. utf8bom, utf16lebom, utf16bom
tb_bool_t utfbom = tb_false;
if (tb_strstr(modestr, "bom")) {
utfbom = tb_true;
}
// open file
tb_bool_t open_ok = tb_false;
tb_stream_ref_t file_ref = tb_null;
tb_stream_ref_t fstream = tb_null;
do {
// init stream from file
stream = stream ? stream : tb_stream_init_from_file(path, mode);
tb_assert_and_check_break(stream);
// is transcode?
tb_bool_t is_transcode = encoding != TB_CHARSET_TYPE_UTF8 && encoding != XM_IO_FILE_ENCODING_BINARY;
if (is_transcode) {
if (modestr[0] == 'r') {
fstream = tb_stream_init_filter_from_charset(stream, encoding, TB_CHARSET_TYPE_UTF8);
} else {
fstream = tb_stream_init_filter_from_charset(stream, TB_CHARSET_TYPE_UTF8, encoding);
}
tb_assert_and_check_break(fstream);
// use fstream as file
file_ref = fstream;
} else {
file_ref = stream;
}
// open file stream
if (!tb_stream_open(file_ref)) {
break;
}
// skip bom characters if exists
if (bomoff > 0 && !tb_stream_seek(stream, bomoff)) {
break;
}
open_ok = tb_true;
} while (0);
// open failed?
if (!open_ok) {
// exit stream
if (stream) {
tb_stream_exit(stream);
}
stream = tb_null;
// exit charset stream filter
if (fstream) {
tb_stream_exit(fstream);
}
fstream = tb_null;
// return errors
xm_io_return_error(lua, "failed to open file!");
}
// make file
xm_io_file_t *file = (xm_io_file_t *)lua_newuserdata(lua, sizeof(xm_io_file_t));
tb_assert_and_check_return_val(file, 0);
// init file
file->u.file_ref = file_ref;
file->stream = stream;
file->fstream = fstream;
file->mode = mode;
file->type = XM_IO_FILE_TYPE_FILE;
file->encoding = encoding;
file->utfbom = utfbom;
// init the read/write line cache buffer
tb_buffer_init(&file->rcache);
tb_buffer_init(&file->wcache);
return 1;
}
================================================
FILE: core/src/xmake/io/file_rawfd.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file file_rawfd.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_rawfd"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// file to fd
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#define xm_io_file2fd(file) (lua_Number)((tb_size_t)(file))
#else
#define xm_io_file2fd(file) (lua_Number) tb_file2fd(file)
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* io.file_rawfd(file)
*
* @note this interface is very dangerous and is only used in some special/hacking cases.
*
* e.g. set VS_UNICODE_OUTPUT=fd to enable vs unicode output, @see https://github.com/xmake-io/xmake/issues/528
*/
tb_int_t xm_io_file_rawfd(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1)) {
xm_io_return_error(lua, "get rawfd for invalid file!");
}
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// get file raw fd
if (xm_io_file_is_file(file)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(file->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile)) {
lua_pushnumber(lua, xm_io_file2fd(rawfile));
return 1;
}
}
// get rawfd failed
xm_io_return_error(lua, "get rawfd for invalid file!");
}
================================================
FILE: core/src/xmake/io/file_read.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_read.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_read"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
typedef enum __xm_pushline_state_e {
PL_EOF,
PL_FIN,
PL_CONL,
PL_FAIL,
} xm_pushline_state_e;
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
static tb_bool_t xm_io_file_stream_skip_sequential(tb_stream_ref_t stream, tb_hize_t size) {
tb_byte_t discard[TB_STREAM_BLOCK_MAXN];
tb_hize_t left = size;
while (left) {
tb_size_t need = left > (tb_hize_t)sizeof(discard) ? (tb_size_t)sizeof(discard) : (tb_size_t)left;
tb_long_t read = tb_stream_read(stream, discard, need);
if (read > 0) {
left -= read;
} else if (!read) {
read = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);
tb_check_return_val(read > 0, tb_false);
} else {
return tb_false;
}
}
return tb_true;
}
static tb_bool_t xm_io_file_stream_skip(tb_stream_ref_t stream, tb_hize_t size, tb_bool_t sequential) {
if (sequential) {
return xm_io_file_stream_skip_sequential(stream, size);
}
return tb_stream_skip(stream, size);
}
static tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_ref_t line) {
tb_assert_and_check_return_val(stream && line, -1);
// read line and reserve crlf
tb_bool_t eof = tb_false;
tb_hize_t offset = 0;
tb_byte_t *data = tb_null;
tb_hong_t size = tb_stream_size(stream);
tb_bool_t sequential_consume = (size == 0);
while (sequential_consume || (offset = tb_stream_offset(stream)) < size) {
tb_long_t real = tb_stream_peek(stream, &data, XM_IO_BLOCK_MAXN);
if (real > 0) {
tb_char_t const *e = tb_strnchr((tb_char_t const *)data, real, '\n');
if (e) {
tb_size_t n = (tb_byte_t const *)e + 1 - data;
tb_buffer_memncat(line, data, n);
if (!xm_io_file_stream_skip(stream, n, sequential_consume))
return -1;
break;
} else {
tb_buffer_memncat(line, data, real);
if (!xm_io_file_stream_skip(stream, (tb_hize_t)real, sequential_consume))
return -1;
}
} else if (!real) {
real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);
if (real <= 0) {
eof = tb_true;
break;
}
} else {
eof = tb_true;
break;
}
}
tb_size_t linesize = tb_buffer_size(line);
if (linesize) {
return linesize;
} else {
return (eof || tb_stream_beof(stream)) ? -1 : 0;
}
}
static tb_int_t xm_io_file_buffer_pushline(tb_buffer_ref_t buf,
xm_io_file_t *file,
tb_char_t const *continuation,
tb_bool_t keep_crlf) {
tb_assert(buf && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);
// is binary?
tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY;
if (is_binary) {
continuation = "";
keep_crlf = tb_true;
}
// clear line buffer
tb_buffer_clear(&file->rcache);
// read line data
tb_long_t size = xm_io_file_buffer_readline(file->u.file_ref, &file->rcache);
// translate line data
tb_int_t result = PL_FAIL;
tb_char_t *data = tb_null;
tb_size_t conlen = tb_strlen(continuation);
do {
// eof?
if (size < 0) {
result = PL_EOF;
break;
}
// patch two '\0'
tb_buffer_memncat(&file->rcache, (tb_byte_t const *)"\0\0", 2);
// get line data
data = (tb_char_t *)tb_buffer_data(&file->rcache);
tb_assert_and_check_break(data);
// no lf found
if (size > 0 && data[size - 1] != '\n') {
result = PL_FIN;
} else if (size > 1) {
// crlf? => lf
if (!is_binary && data[size - 2] == '\r') {
data[size - 2] = '\n';
size--;
}
// has continuation?
tb_bool_t has_conline = conlen && size >= conlen + 1 &&
tb_strncmp(continuation, (tb_char_t const *)(data + size - conlen - 1), conlen) ==
0;
// do not keep crlf, strip the last lf
if (!keep_crlf && !has_conline) {
size--;
}
// strip it if has continuation?
if (has_conline) {
size -= conlen + 1;
}
data[size] = '\0';
result = has_conline ? PL_CONL : PL_FIN;
} else {
// a single '\n'
if (!keep_crlf) {
size = 0;
}
result = PL_FIN;
}
} while (0);
// push line data
if (data && size > 0 && (result == PL_FIN || result == PL_CONL)) {
tb_buffer_memncat(buf, (tb_byte_t const *)data, size);
}
// return result
return result;
}
static tb_int_t xm_io_file_read_all_directly(lua_State *lua, xm_io_file_t *file) {
tb_assert(lua && file && xm_io_file_is_file(file) && file->u.file_ref);
// init buffer
tb_buffer_t buf;
if (!tb_buffer_init(&buf)) {
xm_io_return_error(lua, "init buffer failed!");
}
tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN);
if (!data) {
tb_buffer_exit(&buf);
xm_io_return_error(lua, "out of memory: failed to resize read cache");
}
// read all
tb_stream_ref_t stream = file->u.file_ref;
tb_hize_t offset = 0;
tb_hong_t size = tb_stream_size(stream);
tb_bool_t sequential_consume = (size == 0);
while (sequential_consume || (offset = tb_stream_offset(stream)) < size) {
tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN);
if (real > 0) {
tb_buffer_memncat(&buf, data, real);
} else if (!real) {
real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);
tb_check_break(real > 0);
} else {
break;
}
}
if (tb_buffer_size(&buf)) {
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
} else {
lua_pushliteral(lua, "");
}
tb_buffer_exit(&buf);
return 1;
}
static tb_bool_t xm_io_file_read_all_to_buffer(xm_io_file_t *file, tb_buffer_ref_t buf) {
tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref && buf);
tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN);
tb_assert_and_check_return_val(data, tb_false);
tb_stream_ref_t stream = file->u.file_ref;
tb_hize_t offset = 0;
tb_hong_t size = tb_stream_size(stream);
tb_bool_t sequential_consume = (size == 0);
while (sequential_consume || (offset = tb_stream_offset(stream)) < size) {
tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN);
if (real > 0) {
tb_buffer_memncat(buf, data, real);
} else if (!real) {
real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1);
tb_check_break(real > 0);
} else {
break;
}
}
return tb_true;
}
static tb_int_t xm_io_file_read_all_with_continuation(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {
tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);
tb_buffer_t buf;
if (!tb_buffer_init(&buf)) {
xm_io_return_error(lua, "init buffer failed!");
}
while (1) {
tb_int_t state = xm_io_file_buffer_pushline(&buf, file, continuation, tb_true);
if (state == PL_EOF) {
break;
}
if (state == PL_FAIL) {
tb_buffer_exit(&buf);
xm_io_return_error(lua, "failed to readall");
}
}
if (tb_buffer_size(&buf)) {
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
} else {
lua_pushliteral(lua, "");
}
tb_buffer_exit(&buf);
return 1;
}
static tb_int_t xm_io_file_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {
tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);
// is binary? read all directly
tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY;
if (is_binary) {
return xm_io_file_read_all_directly(lua, file);
}
if (*continuation != '\0') {
return xm_io_file_read_all_with_continuation(lua, file, continuation);
}
tb_buffer_t raw;
tb_buffer_t out;
tb_bool_t raw_ok = tb_false;
tb_bool_t out_ok = tb_false;
tb_int_t result = 0;
tb_char_t const *errors = tb_null;
do {
if (!tb_buffer_init(&raw)) {
errors = "init buffer failed!";
result = 2;
break;
}
raw_ok = tb_true;
if (!xm_io_file_read_all_to_buffer(file, &raw)) {
errors = "failed to read all";
result = 2;
break;
}
tb_size_t rawsize = tb_buffer_size(&raw);
if (!tb_buffer_init(&out)) {
errors = "init buffer failed!";
result = 2;
break;
}
out_ok = tb_true;
if (!rawsize) {
lua_pushliteral(lua, "");
result = 1;
break;
}
tb_byte_t const *rawdata = (tb_byte_t const *)tb_buffer_data(&raw);
tb_byte_t const *p = rawdata;
tb_byte_t const *b = rawdata;
tb_byte_t const *e = rawdata + rawsize;
while (p < e) {
if (*p == '\r' && p + 1 < e && p[1] == '\n') {
if (p > b) {
tb_buffer_memncat(&out, b, p - b);
}
tb_buffer_memncat(&out, (tb_byte_t const *)"\n", 1);
p += 2;
b = p;
} else {
p++;
}
}
if (tb_buffer_size(&out)) {
if (e > b) {
tb_buffer_memncat(&out, b, e - b);
}
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&out), tb_buffer_size(&out));
result = 1;
break;
}
lua_pushlstring(lua, (tb_char_t const *)rawdata, rawsize);
result = 1;
} while (0);
if (out_ok) {
tb_buffer_exit(&out);
}
if (raw_ok) {
tb_buffer_exit(&raw);
}
if (result == 2) {
lua_pushnil(lua);
lua_pushstring(lua, errors);
}
return result;
}
static tb_int_t xm_io_file_read_line(lua_State *lua,
xm_io_file_t *file,
tb_char_t const *continuation,
tb_bool_t keep_crlf) {
tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);
// init buffer
tb_buffer_t buf;
if (!tb_buffer_init(&buf)) {
xm_io_return_error(lua, "init buffer failed!");
}
// read line
tb_bool_t has_content = tb_false;
while (1) {
switch (xm_io_file_buffer_pushline(&buf, file, continuation, keep_crlf)) {
case PL_EOF:
if (!has_content) {
lua_pushnil(lua);
} else {
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
}
tb_buffer_exit(&buf);
return 1;
case PL_FIN:
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
tb_buffer_exit(&buf);
return 1;
case PL_CONL:
has_content = tb_true;
continue;
case PL_FAIL:
default:
tb_buffer_exit(&buf);
xm_io_return_error(lua, "failed to readline");
break;
}
}
}
static tb_int_t xm_io_file_read_n(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_long_t n) {
tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref);
// check continuation
if (*continuation != '\0') {
xm_io_return_error(lua, "continuation is not supported for read number of bytes");
}
// check encoding
if (file->encoding != XM_IO_FILE_ENCODING_BINARY) {
xm_io_return_error(lua, "read number of bytes only allows binary file, reopen with 'rb' and try again");
}
tb_bool_t ok = tb_false;
if (n == 0) {
tb_byte_t *data = tb_null;
if (tb_stream_need(file->u.file_ref, &data, 1)) {
lua_pushliteral(lua, "");
ok = tb_true;
}
} else {
tb_byte_t *bufptr = tb_buffer_resize(&file->rcache, n + 1);
if (bufptr) {
if (tb_stream_bread(file->u.file_ref, bufptr, n)) {
lua_pushlstring(lua, (tb_char_t const *)bufptr, n);
ok = tb_true;
}
}
}
if (!ok) {
lua_pushnil(lua);
}
return 1;
}
static tb_size_t xm_io_file_std_buffer_pushline(tb_buffer_ref_t buf,
xm_io_file_t *file,
tb_char_t const *continuation,
tb_bool_t keep_crlf) {
tb_assert(buf && file && continuation && xm_io_file_is_std(file));
// get input buffer
tb_char_t strbuf[8192];
tb_size_t buflen = 0;
tb_size_t result = PL_FAIL;
if (tb_stdfile_gets(file->u.std_ref, strbuf, tb_arrayn(strbuf) - 1)) {
buflen = tb_strlen(strbuf);
} else {
return PL_EOF;
}
tb_size_t conlen = tb_strlen(continuation);
if (buflen > 0 && strbuf[buflen - 1] != '\n') {
// end of file, no lf found
result = PL_FIN;
} else if (buflen > 1) {
// crlf? => lf
if (strbuf[buflen - 2] == '\r') {
strbuf[buflen - 2] = '\n';
buflen--;
}
// has continuation?
tb_bool_t has_conline = conlen && buflen >= conlen + 1 &&
tb_strncmp(continuation, (strbuf + buflen - conlen - 1), conlen) == 0;
// do not keep crlf, strip the last lf
if (!keep_crlf && !has_conline) {
buflen--;
}
// strip it if has continuation?
if (has_conline) {
buflen -= conlen + 1;
}
strbuf[buflen] = '\0';
result = has_conline ? PL_CONL : PL_FIN;
} else {
// a single '\n'
if (!keep_crlf) {
buflen = 0;
}
result = PL_FIN;
}
if (result == PL_FIN || result == PL_CONL) {
tb_buffer_memncat(buf, (tb_byte_t const *)strbuf, buflen);
}
return result;
}
static tb_int_t xm_io_file_std_read_line(lua_State *lua,
xm_io_file_t *file,
tb_char_t const *continuation,
tb_bool_t keep_crlf) {
tb_assert(lua && file && continuation && xm_io_file_is_std(file));
// init buffer
tb_buffer_t buf;
if (!tb_buffer_init(&buf)) {
xm_io_return_error(lua, "init buffer failed!");
}
// read line
tb_bool_t has_content = tb_false;
while (1) {
switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, keep_crlf)) {
case PL_EOF:
if (!has_content) {
lua_pushnil(lua);
} else {
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
}
tb_buffer_exit(&buf);
return 1;
case PL_FIN:
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
tb_buffer_exit(&buf);
return 1;
case PL_CONL:
has_content = tb_true;
continue;
case PL_FAIL:
default:
tb_buffer_exit(&buf);
xm_io_return_error(lua, "failed to readline");
break;
}
}
}
static tb_int_t xm_io_file_std_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {
tb_assert(lua && file && continuation && xm_io_file_is_std(file));
// init buffer
tb_buffer_t buf;
if (!tb_buffer_init(&buf))
xm_io_return_error(lua, "init buffer failed!");
// read all
tb_bool_t has_content = tb_false;
while (1) {
switch (xm_io_file_std_buffer_pushline(&buf, file, continuation, tb_true)) {
case PL_EOF:
if (!has_content)
lua_pushliteral(lua, "");
else
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf));
tb_buffer_exit(&buf);
return 1;
case PL_FIN:
case PL_CONL:
has_content = tb_true;
continue;
case PL_FAIL:
default:
tb_buffer_exit(&buf);
xm_io_return_error(lua, "failed to readline");
break;
}
}
}
static tb_int_t xm_io_file_std_read_n(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation, tb_long_t n) {
tb_assert(lua && file && continuation && xm_io_file_is_std(file));
// check continuation
if (*continuation != '\0')
xm_io_return_error(lua, "continuation is not supported for std streams");
// io.read(0)
if (n == 0) {
tb_char_t ch;
if (!tb_stdfile_peek(file->u.std_ref, &ch))
lua_pushnil(lua);
else
lua_pushliteral(lua, "");
return 1;
}
// get line buffer
tb_byte_t *buf_ptr = tb_buffer_resize(&file->rcache, (tb_size_t)n);
tb_assert(buf_ptr);
// io.read(n)
if (tb_stdfile_read(file->u.std_ref, buf_ptr, (tb_size_t)n))
lua_pushlstring(lua, (tb_char_t const *)buf_ptr, (size_t)n);
else
lua_pushnil(lua);
return 1;
}
static tb_int_t xm_io_file_std_read_num(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) {
tb_assert(lua && file && continuation && xm_io_file_is_std(file));
// check continuation
if (*continuation != '\0')
xm_io_return_error(lua, "continuation is not supported for std streams");
// read number
tb_char_t strbuf[512];
if (tb_stdfile_gets(file->u.std_ref, strbuf, tb_arrayn(strbuf)))
lua_pushnumber(lua, tb_s10tod(strbuf)); // TODO check invalid float number string and push nil
else
lua_pushnil(lua);
return 1;
}
/* io.file_read(file, [mode, [continuation]])
* io.file_read(file, "all", "\\")
* io.file_read(file, "L")
* io.file_read(file, "l")
* io.file_read(file, "n")
* io.file_read(file, 10)
*/
tb_int_t xm_io_file_read(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1))
xm_io_return_error(lua, "read(invalid file)!");
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// get arguments
tb_char_t const *mode = luaL_optstring(lua, 2, "l");
tb_char_t const *continuation = luaL_optstring(lua, 3, "");
tb_assert_and_check_return_val(mode && continuation, 0);
tb_long_t count = -1;
if (lua_isnumber(lua, 2)) {
count = (tb_long_t)lua_tointeger(lua, 2);
if (count < 0)
xm_io_return_error(lua, "invalid read size, must be positive nubmber or 0");
} else if (*mode == '*')
mode++;
if (xm_io_file_is_file(file)) {
if (count >= 0)
return xm_io_file_read_n(lua, file, continuation, count);
switch (*mode) {
case 'a':
return xm_io_file_read_all(lua, file, continuation);
case 'L':
return xm_io_file_read_line(lua, file, continuation, tb_true);
case 'n':
xm_io_return_error(lua, "read number is not implemented");
case 'l':
return xm_io_file_read_line(lua, file, continuation, tb_false);
default:
xm_io_return_error(lua, "unknonwn read mode");
return 0;
}
} else {
if (count >= 0)
return xm_io_file_std_read_n(lua, file, continuation, count);
switch (*mode) {
case 'a':
return xm_io_file_std_read_all(lua, file, continuation);
case 'L':
return xm_io_file_std_read_line(lua, file, continuation, tb_true);
case 'n':
return xm_io_file_std_read_num(lua, file, continuation);
case 'l':
return xm_io_file_std_read_line(lua, file, continuation, tb_false);
default:
xm_io_return_error(lua, "unknonwn read mode");
return 0;
}
}
}
================================================
FILE: core/src/xmake/io/file_readable.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file file_readable.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_readable"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_io_file_readable(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1)) {
xm_io_return_error(lua, "read(invalid file)!");
}
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// has readable data?
tb_bool_t ok = tb_false;
if (xm_io_file_is_file(file)) {
ok = tb_stream_left(file->u.file_ref) > 0;
} else {
ok = tb_stdfile_readable(file->u.std_ref);
}
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/io/file_seek.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_seek.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_seek"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.file_seek(file, [whence [, offset]])
tb_int_t xm_io_file_seek(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1)) {
xm_io_return_error(lua, "seek(invalid file)!");
}
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// get whence and offset
tb_char_t const *whence = luaL_optstring(lua, 2, "cur");
tb_hong_t offset = (tb_hong_t)luaL_optnumber(lua, 3, 0);
tb_assert_and_check_return_val(whence, 0);
// seek file
if (xm_io_file_is_file(file)) {
tb_assert(file->u.file_ref);
switch (*whence) {
case 's': // "set"
break;
case 'e': // "end"
{
tb_hong_t size = tb_stream_size(file->u.file_ref);
if (size > 0 && size + offset <= size) {
offset = size + offset;
} else {
xm_io_return_error(lua, "seek failed, invalid offset!");
}
} break;
default: // "cur"
offset = tb_stream_offset(file->u.file_ref) + offset;
break;
}
if (tb_stream_seek(file->u.file_ref, offset)) {
lua_pushnumber(lua, (lua_Number)offset);
return 1;
} else {
xm_io_return_error(lua, "seek failed!");
}
} else {
xm_io_return_error(lua, "seek is not supported on this file");
}
}
================================================
FILE: core/src/xmake/io/file_size.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_size.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_size"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.file_size(file)
tb_int_t xm_io_file_size(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1)) {
xm_io_return_error(lua, "get size for invalid file!");
}
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// get file length
if (xm_io_file_is_file(file)) {
// get size from raw file stream, because we cannot get size from fstream
tb_assert(file->stream);
lua_pushnumber(lua, (lua_Number)tb_stream_size(file->stream));
return 1;
} else {
xm_io_return_error(lua, "get size for invalid file!");
}
}
================================================
FILE: core/src/xmake/io/file_write.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file file_write.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_write"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_io_file_write_file_utfbom(xm_io_file_t *file) {
tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref);
// write bom
switch (file->encoding) {
case TB_CHARSET_TYPE_UTF8: {
static tb_byte_t bom[] = { 0xef, 0xbb, 0xbf };
tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom));
} break;
case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE: {
static tb_byte_t bom[] = { 0xff, 0xfe };
tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom));
} break;
case TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE: {
static tb_byte_t bom[] = { 0xfe, 0xff };
tb_stream_bwrit(file->u.file_ref, bom, sizeof(bom));
} break;
default:
break;
}
}
static tb_void_t xm_io_file_write_file_directly(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) {
tb_assert(file && data && xm_io_file_is_file(file) && file->u.file_ref);
tb_stream_bwrit(file->u.file_ref, data, size);
}
static tb_void_t xm_io_file_write_file_transcrlf(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) {
tb_assert(file && data && xm_io_file_is_file(file) && file->u.file_ref);
#ifdef TB_CONFIG_OS_WINDOWS
// write cached data first
tb_byte_t const *odata = tb_buffer_data(&file->wcache);
tb_size_t osize = tb_buffer_size(&file->wcache);
if (odata && osize) {
if (!tb_stream_bwrit(file->u.file_ref, odata, osize))
return;
tb_buffer_clear(&file->wcache);
}
// write data by lines
tb_char_t const *p = (tb_char_t const *)data;
tb_char_t const *e = p + size;
tb_char_t const *lf = tb_null;
while (p < e) {
lf = tb_strnchr(p, e - p, '\n');
if (lf) {
if (lf > p && lf[-1] == '\r') {
if (!tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)p, lf + 1 - p))
break;
} else {
if (lf > p && !tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)p, lf - p))
break;
if (!tb_stream_bwrit(file->u.file_ref, (tb_byte_t const *)"\r\n", 2))
break;
}
// next line
p = lf + 1;
} else {
// cache the left data
tb_buffer_memncat(&file->wcache, (tb_byte_t const *)p, e - p);
p = e;
break;
}
}
#else
return xm_io_file_write_file_directly(file, data, size);
#endif
}
static tb_void_t xm_io_file_write_std(xm_io_file_t *file, tb_byte_t const *data, tb_size_t size) {
tb_assert(file && data && xm_io_file_is_std(file));
// check type
tb_size_t type = (file->type & ~XM_IO_FILE_FLAG_TTY);
tb_check_return(type != XM_IO_FILE_TYPE_STDIN);
// write data to stdout/stderr
tb_stdfile_writ(file->u.std_ref, data, size);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.file_write(file, ...)
tb_int_t xm_io_file_write(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is user data?
if (!lua_isuserdata(lua, 1))
xm_io_return_error(lua, "write(invalid file)!");
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 1);
tb_check_return_val(file, 0);
// write file data
tb_int_t narg = lua_gettop(lua);
if (narg > 1) {
tb_bool_t is_binary = file->encoding == XM_IO_FILE_ENCODING_BINARY;
for (tb_int_t i = 2; i <= narg; i++) {
// get data
size_t datasize = 0;
tb_byte_t const *data = tb_null;
if (lua_isstring(lua, i)) {
data = (tb_byte_t const *)luaL_checklstring(lua, i, &datasize);
} else if (lua_istable(lua, i)) {
// get bytes data
lua_pushstring(lua, "data");
lua_gettable(lua, i);
if (xm_lua_isinteger(lua, -1)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, -1);
}
lua_pop(lua, 1);
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
lua_pushstring(lua, "size");
lua_gettable(lua, i);
if (xm_lua_isinteger(lua, -1)) {
datasize = (tb_size_t)lua_tointeger(lua, -1);
}
lua_pop(lua, 1);
// mark as binary data
is_binary = tb_true;
}
tb_check_continue(datasize);
tb_assert_and_check_break(data);
// write data to std or file
if (xm_io_file_is_std(file)) {
xm_io_file_write_std(file, data, (tb_size_t)datasize);
} else if (is_binary) {
xm_io_file_write_file_directly(file, data, (tb_size_t)datasize);
} else {
// write utf bom first?
if (file->utfbom) {
xm_io_file_write_file_utfbom(file);
file->utfbom = tb_false;
}
xm_io_file_write_file_transcrlf(file, data, (tb_size_t)datasize);
}
}
}
lua_settop(lua, 1);
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/io/filelock_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file filelock_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "filelock_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.filelock_close(lock)
tb_int_t xm_io_filelock_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check lock?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get lock
tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(lock, 0);
// exit lock
tb_filelock_exit(lock);
// save result: ok
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/io/filelock_lock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file filelock_lock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "filelock_lock"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* lock file
*
* exclusive lock: io.filelock_lock(lock, "/xxxx/filelock")
* shared lock: io.filelock_lock(lock, "/xxxx/filelock", {shared = true})
*/
tb_int_t xm_io_filelock_lock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get option argument
tb_bool_t is_shared = tb_false;
if (lua_istable(lua, 2)) {
// is shared lock?
lua_pushstring(lua, "shared");
lua_gettable(lua, 2);
is_shared = (tb_bool_t)lua_toboolean(lua, -1);
lua_pop(lua, 1);
}
// check lock?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get lock
tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(lock, 0);
// lock it
tb_bool_t ok = tb_filelock_enter(lock, is_shared ? TB_FILELOCK_MODE_SH : TB_FILELOCK_MODE_EX);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/io/filelock_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file filelock_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "filelock_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/*
* io.filelock_open(path)
*/
tb_int_t xm_io_filelock_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get file path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_assert_and_check_return_val(path, 0);
// init file lock
tb_long_t tryn = 2;
tb_filelock_ref_t lock = tb_null;
while (!lock && tryn-- > 0) {
lock = tb_filelock_init_from_path(path,
tb_file_info(path, tb_null) ? TB_FILE_MODE_RW
: TB_FILE_MODE_RW | TB_FILE_MODE_CREAT);
}
if (lock) {
xm_lua_pushpointer(lua, (tb_pointer_t)lock);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/io/filelock_trylock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file filelock_trylock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "filelock_trylock"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* try to lock file
*
* exclusive lock: io.filelock_trylock("/xxxx/filelock")
* shared lock: io.filelock_trylock("/xxxx/filelock", {shared = true})
*/
tb_int_t xm_io_filelock_trylock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get option argument
tb_bool_t is_shared = tb_false;
if (lua_istable(lua, 2)) {
// is shared lock?
lua_pushstring(lua, "shared");
lua_gettable(lua, 2);
is_shared = (tb_bool_t)lua_toboolean(lua, -1);
lua_pop(lua, 1);
}
// check lock?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get lock
tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(lock, 0);
// try to lock it
tb_bool_t ok = tb_filelock_enter_try(lock, is_shared ? TB_FILELOCK_MODE_SH : TB_FILELOCK_MODE_EX);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/io/filelock_unlock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file filelock_unlock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "filelock_unlock"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.filelock_unlock(lock)
tb_int_t xm_io_filelock_unlock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check lock?
if (!xm_lua_topointer(lua, 1)) {
return 0;
}
// get lock
tb_filelock_ref_t lock = (tb_filelock_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(lock, 0);
// unlock it
tb_bool_t ok = tb_filelock_leave(lock);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/io/iscygpty.c
================================================
/*
* iscygpty.c -- part of ptycheck
* https://github.com/k-takata/ptycheck
*
* Copyright (c) 2015-2017 K.Takata
*
* You can redistribute it and/or modify it under the terms of either
* the MIT license (as described below) or the Vim license.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef _WIN32
#include
#include
#include
#include
#ifdef USE_FILEEXTD
/* VC 7.1 or earlier doesn't support SAL. */
#if !defined(_MSC_VER) || (_MSC_VER < 1400)
#define __out
#define __in
#define __in_opt
#endif
/* Win32 FileID API Library:
* http://www.microsoft.com/en-us/download/details.aspx?id=22599
* Needed for WinXP. */
#include
#else /* USE_FILEEXTD */
/* VC 8 or earlier. */
#if defined(_MSC_VER) && (_MSC_VER < 1500)
#ifdef ENABLE_STUB_IMPL
#define STUB_IMPL
#else
#error "Win32 FileID API Library is required for VC2005 or earlier."
#endif
#endif
#endif /* USE_FILEEXTD */
#if _WIN32_WINNT >= 0x0600
#define USE_DYNFILEID // we need to enable it for supporting xp
#endif
#ifdef USE_DYNFILEID
typedef BOOL(WINAPI *pfnGetFileInformationByHandleEx)(HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation,
DWORD dwBufferSize);
static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL;
#ifndef USE_FILEEXTD
static BOOL WINAPI stub_GetFileInformationByHandleEx(HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation,
DWORD dwBufferSize) {
return FALSE;
}
#endif
static void setup_fileid_api(void) {
if (pGetFileInformationByHandleEx != NULL) {
return;
}
pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx)
GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetFileInformationByHandleEx");
if (pGetFileInformationByHandleEx == NULL) {
#ifdef USE_FILEEXTD
pGetFileInformationByHandleEx = GetFileInformationByHandleEx;
#else
pGetFileInformationByHandleEx = stub_GetFileInformationByHandleEx;
#endif
}
}
#else
#define pGetFileInformationByHandleEx GetFileInformationByHandleEx
#define setup_fileid_api()
#endif
#define is_wprefix(s, prefix) (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0)
/* Check if the fd handle is a cygwin/msys's pty. */
int is_cygpty(HANDLE h) {
#if defined(STUB_IMPL)
return 0;
#elif _WIN32_WINNT >= 0x0600
int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1);
FILE_NAME_INFO *nameinfo;
WCHAR *p = NULL;
setup_fileid_api();
if (h == INVALID_HANDLE_VALUE) {
return 0;
}
/* Cygwin/msys's pty is a pipe. */
if (GetFileType(h) != FILE_TYPE_PIPE) {
return 0;
}
nameinfo = (FILE_NAME_INFO *)malloc(size + sizeof(WCHAR));
if (nameinfo == NULL) {
return 0;
}
/* Check the name of the pipe:
* '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' */
if (pGetFileInformationByHandleEx(h, FileNameInfo, nameinfo, size)) {
nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0';
p = nameinfo->FileName;
if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */
p += 8;
} else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */
p += 6;
} else {
p = NULL;
}
if (p != NULL) {
while (*p && isxdigit(*p)) { /* Skip 16-digit hexadecimal. */
++p;
}
if (is_wprefix(p, L"-pty")) {
p += 4;
} else {
p = NULL;
}
}
if (p != NULL) {
while (*p && isdigit(*p)) { /* Skip pty number. */
++p;
}
if (is_wprefix(p, L"-from-master")) {
//p += 12;
} else if (is_wprefix(p, L"-to-master")) {
//p += 10;
} else {
p = NULL;
}
}
}
free(nameinfo);
return (p != NULL);
#else
return 0;
#endif
}
#endif /* _WIN32 */
================================================
FILE: core/src/xmake/io/pipe_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.pipe_close(pipe)
tb_int_t xm_io_pipe_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check pipe?
if (!xm_pipe_file_is_valid(lua, 1)) {
return 0;
}
// get the pipe file
tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);
tb_check_return_val(pipefile, 0);
// exit pipe file
lua_pushboolean(lua, tb_pipe_file_exit(pipefile));
return 1;
}
================================================
FILE: core/src/xmake/io/pipe_connect.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_connect.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_connect"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.pipe_connect(pipefile)
tb_int_t xm_io_pipe_connect(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check pipe
if (!xm_lua_ispointer(lua, 1)) {
lua_pushnumber(lua, -1);
lua_pushliteral(lua, "invalid pipe!");
return 2;
}
// get pipe file
tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(pipefile, 0);
// connect pipe
lua_pushnumber(lua, (tb_int_t)tb_pipe_file_connect(pipefile));
return 1;
}
================================================
FILE: core/src/xmake/io/pipe_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/*
* io.pipe_open(name, mode, buffsize)
*/
tb_int_t xm_io_pipe_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get pipe name and mode
tb_char_t const *name = luaL_checkstring(lua, 1);
tb_char_t const *modestr = luaL_optstring(lua, 2, "r");
tb_assert_and_check_return_val(name && modestr, 0);
// get pipe mode value
tb_size_t mode = TB_PIPE_MODE_RO;
if (modestr[0] == 'w') {
mode = TB_PIPE_MODE_WO;
}
// set block mode
if (modestr[1] == 'B') {
mode |= TB_PIPE_MODE_BLOCK;
}
// get buffer size
tb_size_t buffsize = (tb_size_t)luaL_checknumber(lua, 3);
// open pipe file
tb_pipe_file_ref_t pipefile = tb_pipe_file_init(name, mode, buffsize);
if (pipefile) {
xm_lua_pushpointer(lua, (tb_pointer_t)pipefile);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/io/pipe_openpair.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_openpair.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_openpair"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/*
* io.pipe_openpair(mode, buffsize)
*/
tb_int_t xm_io_pipe_openpair(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get pipe mode
tb_char_t const *modestr = luaL_optstring(lua, 1, "AA");
tb_assert_and_check_return_val(modestr, 0);
// init mode
tb_size_t mode[2] = { 0 };
if (modestr[0] == 'B') {
mode[0] |= TB_PIPE_MODE_BLOCK;
}
if (modestr[1] == 'B') {
mode[1] |= TB_PIPE_MODE_BLOCK;
}
// get buffer size
tb_size_t buffsize = (tb_size_t)luaL_checknumber(lua, 2);
// init pipe
tb_pipe_file_ref_t pipefile[2];
if (tb_pipe_file_init_pair(pipefile, mode, buffsize)) {
xm_lua_pushpointer(lua, (tb_pointer_t)pipefile[0]);
xm_lua_pushpointer(lua, (tb_pointer_t)pipefile[1]);
} else {
lua_pushnil(lua);
lua_pushnil(lua);
}
return 2;
}
================================================
FILE: core/src/xmake/io/pipe_read.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_read.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_read"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// real, data_or_errors = io.pipe_read(pipefile, size)
tb_int_t xm_io_pipe_read(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check pipe file
if (!xm_pipe_file_is_valid(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid pipe file!");
return 2;
}
// get pipe file
tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);
tb_check_return_val(pipefile, 0);
// get data
tb_byte_t *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (!data) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p)!", data);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get size
tb_long_t size = 0;
if (xm_lua_isinteger(lua, 3)) {
size = (tb_long_t)lua_tointeger(lua, 3);
}
if (size <= 0) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size);
return 2;
}
// read data
tb_long_t real = tb_pipe_file_read(pipefile, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/io/pipe_wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_wait"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.pipe_wait(pipefile, events, timeout)
tb_int_t xm_io_pipe_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check pipe?
if (!xm_pipe_file_is_valid(lua, 1)) {
return 0;
}
// get pipe file
tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);
tb_check_return_val(pipefile, 0);
// get events
tb_size_t events = (tb_size_t)luaL_checknumber(lua, 2);
// get timeout
tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 3);
// wait pipe
lua_pushnumber(lua, (tb_int_t)tb_pipe_file_wait(pipefile, events, timeout));
return 1;
}
================================================
FILE: core/src/xmake/io/pipe_write.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file pipe_write.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "pipe_write"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.pipe_write(pipefile, data, start, last)
tb_int_t xm_io_pipe_write(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check pipe
if (!xm_pipe_file_is_valid(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid pipe file!");
return 2;
}
// get pipe file
tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1);
tb_check_return_val(pipefile, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (xm_lua_isinteger(lua, 3)) {
size = (tb_size_t)lua_tointeger(lua, 3);
}
if (!data || !size) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// write data
tb_long_t real = tb_pipe_file_write(pipefile, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/io/poller.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "poller.h"
#include "../engine.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_poller_ref_t xm_io_poller(lua_State *lua) {
tb_poller_ref_t poller = tb_null;
xm_engine_ref_t engine = xm_engine_get(lua);
if (engine) {
poller = xm_engine_poller(engine);
}
tb_assert(poller);
return poller;
}
================================================
FILE: core/src/xmake/io/poller.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller.h
*
*/
#ifndef XM_IO_POLLER_H
#define XM_IO_POLLER_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the poller state in wait events
typedef struct __xm_poller_state_t {
lua_State *lua;
tb_int_t events_count;
} xm_poller_state_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
/* get io poller
*
* @return the io poller
*/
tb_poller_ref_t xm_io_poller(lua_State *lua);
#endif
================================================
FILE: core/src/xmake/io/poller_insert.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller_insert.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller_insert"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "poller.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.poller_insert(obj:otype(), obj:cdata(), events)
tb_int_t xm_io_poller_insert(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 2)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "invalid poller object!");
return 2;
}
// get otype
tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1);
// get cdata
tb_char_t const *cdata_str = tb_null;
tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer2(lua, 2, &cdata_str);
tb_check_return_val(cdata, 0);
// get events
tb_size_t events = (tb_size_t)luaL_checknumber(lua, 3);
// insert events to poller
tb_poller_object_t object;
object.type = otype;
object.ref.ptr = cdata;
lua_pushboolean(lua, tb_poller_insert(xm_io_poller(lua), &object, events, cdata_str));
return 1;
}
================================================
FILE: core/src/xmake/io/poller_modify.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller_modify.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller_modify"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "poller.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.poller_modify(obj:otype(), obj:cdata(), events)
tb_int_t xm_io_poller_modify(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 2)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "invalid poller object!");
return 2;
}
// get otype
tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1);
// get cdata
tb_char_t const *cdata_str = tb_null;
tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer2(lua, 2, &cdata_str);
tb_check_return_val(cdata, 0);
// get events
tb_size_t events = (tb_size_t)luaL_checknumber(lua, 3);
// modify events in poller
tb_poller_object_t object;
object.type = otype;
object.ref.ptr = cdata;
lua_pushboolean(lua, tb_poller_modify(xm_io_poller(lua), &object, events, cdata_str));
return 1;
}
================================================
FILE: core/src/xmake/io/poller_remove.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller_remove.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller_remove"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "poller.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.poller_remove(obj:otype(), obj)
tb_int_t xm_io_poller_remove(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 2)) {
lua_pushboolean(lua, tb_false);
lua_pushfstring(lua, "invalid poller object!");
return 2;
}
// get otype
tb_uint8_t otype = (tb_uint8_t)luaL_checknumber(lua, 1);
// get cdata
tb_pointer_t cdata = (tb_pointer_t)xm_lua_topointer(lua, 2);
tb_check_return_val(cdata, 0);
// remove events from poller
tb_poller_object_t object;
object.type = otype;
object.ref.ptr = cdata;
lua_pushboolean(lua, tb_poller_remove(xm_io_poller(lua), &object));
return 1;
}
================================================
FILE: core/src/xmake/io/poller_spank.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller_spank.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller_spank"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "poller.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.poller_spank()
tb_int_t xm_io_poller_spank(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// spank the poller, break the tb_poller_wait() and return all events
tb_poller_spak(xm_io_poller(lua));
return 0;
}
================================================
FILE: core/src/xmake/io/poller_support.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller_support.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller_support"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "poller.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.poller_support(events)
tb_int_t xm_io_poller_support(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get events
tb_size_t events = (tb_size_t)luaL_checknumber(lua, 1);
// support events for poller
lua_pushboolean(lua, tb_poller_support(xm_io_poller(lua), events));
return 1;
}
================================================
FILE: core/src/xmake/io/poller_wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file poller_wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "poller_wait"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "poller.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_io_poller_event(tb_poller_ref_t poller,
tb_poller_object_ref_t object,
tb_long_t events,
tb_cpointer_t priv) {
xm_poller_state_t *state = (xm_poller_state_t *)tb_poller_priv(poller);
tb_assert_and_check_return(state && state->lua);
// save object and events
lua_State *lua = state->lua;
lua_newtable(lua);
lua_pushinteger(lua, (tb_int_t)object->type);
lua_rawseti(lua, -2, 1);
if (priv) {
lua_pushstring(lua, (tb_char_t const *)priv);
} else {
lua_pushlightuserdata(lua, object->ref.ptr);
}
lua_rawseti(lua, -2, 2);
if (object->type == TB_POLLER_OBJECT_FWATCHER) {
lua_newtable(lua);
tb_fwatcher_event_t *event = (tb_fwatcher_event_t *)events;
if (event) {
lua_pushstring(lua, "path");
lua_pushstring(lua, event->filepath);
lua_settable(lua, -3);
lua_pushstring(lua, "type");
lua_pushinteger(lua, event->event);
lua_settable(lua, -3);
}
} else {
lua_pushinteger(lua, (tb_int_t)events);
}
lua_rawseti(lua, -2, 3);
lua_rawseti(lua, -2, ++state->events_count);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// local events, count = io.poller_wait(timeout)
tb_int_t xm_io_poller_wait(lua_State *lua) {
tb_poller_ref_t poller = xm_io_poller(lua);
tb_assert_and_check_return_val(poller && lua, 0);
// get timeout
tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 1);
// reset events count
xm_poller_state_t *state = (xm_poller_state_t *)tb_poller_priv(poller);
state->events_count = 0;
// wait it
lua_newtable(lua);
tb_long_t count = tb_poller_wait(poller, xm_io_poller_event, timeout);
if (count > 0) {
lua_pushinteger(lua, (tb_int_t)count);
return 2;
} else if (!count) {
// timeout
lua_pop(lua, 1);
lua_pushnil(lua);
lua_pushinteger(lua, 0);
return 2;
}
lua_pop(lua, 1);
lua_pushnil(lua);
lua_pushinteger(lua, -1);
return 2;
}
================================================
FILE: core/src/xmake/io/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_IO_PREFIX_H
#define XM_IO_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_IO_BLOCK_MAXN (TB_STREAM_BLOCK_MAXN * 10)
// return io error
#define xm_io_return_error(lua, error) \
do { \
lua_pushnil(lua); \
lua_pushliteral(lua, error); \
return 2; \
} while (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
typedef enum __xm_io_file_type_e {
XM_IO_FILE_TYPE_FILE = 0 //!< disk file
,
XM_IO_FILE_TYPE_STDIN = 1,
XM_IO_FILE_TYPE_STDOUT = 2,
XM_IO_FILE_TYPE_STDERR = 3
,
XM_IO_FILE_FLAG_TTY = 0x10 //!< mark tty std stream
} xm_io_file_type_e;
/* use negetive numbers for this enum, its a extension for tb_charset_type_e
* before adding new values, make sure they have not conflicts with values in tb_charset_type_e
*/
typedef enum __xm_io_file_encoding_e {
XM_IO_FILE_ENCODING_UNKNOWN = -1,
XM_IO_FILE_ENCODING_BINARY = -2
} xm_io_file_encoding_e;
// the file type
typedef struct __xm_io_file_t {
union {
/* the normal file for XM_IO_FILE_TYPE_FILE
*
* direct: file_ref -> stream -> file
* transcode: file_ref -> fstream -> stream -> file
*/
tb_stream_ref_t file_ref;
// the standard io file
tb_stdfile_ref_t std_ref;
} u;
tb_stream_ref_t stream; // the file stream for XM_IO_FILE_TYPE_FILE
tb_stream_ref_t fstream; // the file charset stream filter
tb_size_t mode; // tb_file_mode_t
tb_size_t type; // xm_io_file_type_e
tb_size_t encoding; // value of xm_io_file_encoding_e or tb_charset_type_e
tb_bool_t utfbom; // write utf-bom for utf encoding?
tb_buffer_t rcache; // the read line cache buffer
tb_buffer_t wcache; // the write line cache buffer
} xm_io_file_t;
static __tb_inline__ tb_bool_t xm_io_file_is_file(xm_io_file_t const *file) {
return file && file->type == XM_IO_FILE_TYPE_FILE;
}
static __tb_inline__ tb_bool_t xm_io_file_is_std(xm_io_file_t const *file) {
return file && file->type != XM_IO_FILE_TYPE_FILE;
}
static __tb_inline__ tb_bool_t xm_io_file_is_tty(xm_io_file_t const *file) {
return file && (file->type & XM_IO_FILE_FLAG_TTY);
}
// check pipe file
static __tb_inline__ tb_bool_t xm_pipe_file_is_valid(lua_State *lua, tb_int_t index) {
return xm_lua_ispointer(lua, index) || xm_lua_isinteger(lua, index);
}
// get the pipe file from arguments
static __tb_inline__ tb_pipe_file_ref_t xm_pipe_file_get(lua_State *lua, tb_int_t index) {
tb_pipe_file_ref_t pipe_file = tb_null;
if (xm_lua_isinteger(lua, index))
pipe_file = (tb_pipe_file_ref_t)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);
else if (xm_lua_ispointer(lua, index))
pipe_file = (tb_pipe_file_ref_t)xm_lua_topointer(lua, index);
return pipe_file;
}
#endif
================================================
FILE: core/src/xmake/io/socket_accept.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_accept.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_accept"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// local sock = io.socket_accept(sock)
tb_int_t xm_io_socket_accept(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// accept socket
tb_socket_ref_t client = tb_socket_accept(sock, tb_null);
if (client) {
xm_lua_pushpointer(lua, (tb_pointer_t)client);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/io/socket_bind.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_bind.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_bind"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.socket_bind(sock, addr, port, family)
tb_int_t xm_io_socket_bind(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushboolean(lua, tb_false);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get address
tb_char_t const *address = lua_tostring(lua, 2);
tb_assert_and_check_return_val(address, 0);
// get family
tb_uint8_t family = (tb_uint8_t)luaL_checknumber(lua, 4);
// init address
tb_ipaddr_t addr;
if (family == TB_IPADDR_FAMILY_UNIX) {
tb_bool_t is_abstract = (tb_bool_t)lua_toboolean(lua, 3);
tb_ipaddr_unix_set_cstr(&addr, address, is_abstract);
} else {
tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 3);
tb_ipaddr_set(&addr, address, port, family);
}
// bind socket
lua_pushboolean(lua, tb_socket_bind(sock, &addr));
return 1;
}
================================================
FILE: core/src/xmake/io/socket_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.socket_close(sock)
tb_int_t xm_io_socket_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// exit socket
lua_pushboolean(lua, tb_socket_exit(sock));
return 1;
}
================================================
FILE: core/src/xmake/io/socket_connect.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_connect.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_connect"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.socket_connect(sock, addr, port, family)
tb_int_t xm_io_socket_connect(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushnumber(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get address
tb_char_t const *address = lua_tostring(lua, 2);
tb_assert_and_check_return_val(address, 0);
// get family
tb_uint8_t family = (tb_uint8_t)luaL_checknumber(lua, 4);
// init address
tb_ipaddr_t addr;
if (family == TB_IPADDR_FAMILY_UNIX) {
tb_bool_t is_abstract = (tb_bool_t)lua_toboolean(lua, 3);
tb_ipaddr_unix_set_cstr(&addr, address, is_abstract);
} else {
tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 3);
tb_ipaddr_set(&addr, address, port, family);
}
// connect socket
lua_pushnumber(lua, (tb_int_t)tb_socket_connect(sock, &addr));
return 1;
}
================================================
FILE: core/src/xmake/io/socket_ctrl.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_ctrl.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_ctrl"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.socket_ctrl(sock, code, value)
tb_int_t xm_io_socket_ctrl(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushnumber(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get code
tb_size_t code = (tb_size_t)luaL_checkinteger(lua, 2);
// get value
tb_size_t value = (tb_size_t)luaL_checkinteger(lua, 3);
// control socket
lua_pushboolean(lua, tb_socket_ctrl(sock, code, value));
return 1;
}
================================================
FILE: core/src/xmake/io/socket_kill.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_kill.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_kill"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// local sock = io.socket_kill(sock)
tb_int_t xm_io_socket_kill(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// kill socket
tb_socket_kill(sock, TB_SOCKET_KILL_RW);
return 0;
}
================================================
FILE: core/src/xmake/io/socket_listen.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_listen.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_listen"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.socket_listen(sock, backlog)
tb_int_t xm_io_socket_listen(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get backlog
tb_size_t backlog = (tb_size_t)luaL_checknumber(lua, 2);
// listen socket
lua_pushnumber(lua, (tb_int_t)tb_socket_listen(sock, backlog));
return 1;
}
================================================
FILE: core/src/xmake/io/socket_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/*
* io.socket_open(socktype, family)
*/
tb_int_t xm_io_socket_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get socket type
tb_size_t socktype = (tb_size_t)luaL_checknumber(lua, 1);
// get address family
tb_size_t family = (tb_size_t)luaL_checknumber(lua, 2);
// map socket type
switch (socktype) {
case 2:
socktype = TB_SOCKET_TYPE_UDP;
break;
case 3:
socktype = TB_SOCKET_TYPE_ICMP;
break;
default:
socktype = TB_SOCKET_TYPE_TCP;
break;
}
// init socket
tb_socket_ref_t sock = tb_socket_init(socktype, family);
if (sock) {
xm_lua_pushpointer(lua, (tb_pointer_t)sock);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/io/socket_peeraddr.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this sock except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @sock socket_peeraddr.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_peeraddr"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// socket to fd
#define xm_io_sock2fd(sock) (lua_Number) tb_sock2fd(sock)
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* io.socket_peeraddr(sock)
*/
tb_int_t xm_io_socket_peeraddr(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
xm_io_return_error(lua, "get peer address for invalid sock!");
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get peer address
tb_ipaddr_t addr;
tb_char_t data[256];
tb_char_t const *cstr = tb_null;
if (tb_socket_peer(sock, &addr) && (cstr = tb_ipaddr_cstr(&addr, data, sizeof(data)))) {
lua_pushstring(lua, cstr);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/io/socket_rawfd.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this sock except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @sock socket_rawfd.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_rawfd"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// socket to fd
#define xm_io_sock2fd(sock) (lua_Number) tb_sock2fd(sock)
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* io.socket_rawfd(sock)
*/
tb_int_t xm_io_socket_rawfd(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1))
xm_io_return_error(lua, "get rawfd for invalid sock!");
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// return result
lua_pushnumber(lua, xm_io_sock2fd(sock));
return 1;
}
================================================
FILE: core/src/xmake/io/socket_recv.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_recv.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_recv"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// real, data_or_errors = io.socket_recv(sock, size)
tb_int_t xm_io_socket_recv(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get data
tb_byte_t *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (!data) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p)!", data);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get size
tb_long_t size = 0;
if (xm_lua_isinteger(lua, 3)) {
size = (tb_long_t)lua_tointeger(lua, 3);
}
if (size <= 0) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size);
return 2;
}
// recv data
tb_long_t real = tb_socket_recv(sock, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/io/socket_recvfrom.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_recvfrom.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_recvfrom"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// real, data_or_errors, addr, port = io.socket_recvfrom(sock, size)
tb_int_t xm_io_socket_recvfrom(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get data
tb_byte_t *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (!data) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p)!", data);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get size
tb_long_t size = 0;
if (xm_lua_isinteger(lua, 3)) {
size = (tb_long_t)lua_tointeger(lua, 3);
}
if (size <= 0) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size);
return 2;
}
// recv data
tb_ipaddr_t ipaddr;
tb_ipaddr_clear(&ipaddr);
tb_int_t retn = 1;
tb_long_t real = tb_socket_urecv(sock, &ipaddr, data, size);
lua_pushinteger(lua, (tb_int_t)real);
if (real > 0) {
retn = 2;
lua_pushnil(lua);
if (!tb_ipaddr_is_empty(&ipaddr)) {
tb_char_t buffer[256];
tb_char_t const *ipstr = tb_ipaddr_ip_cstr(&ipaddr, buffer, sizeof(buffer));
if (ipstr) {
lua_pushstring(lua, ipstr);
lua_pushinteger(lua, (tb_int_t)tb_ipaddr_port(&ipaddr));
retn = 4;
}
}
}
return retn;
}
================================================
FILE: core/src/xmake/io/socket_send.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_send.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_send"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.socket_send(sock, data, start, last)
tb_int_t xm_io_socket_send(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (xm_lua_isinteger(lua, 3)) {
size = (tb_size_t)lua_tointeger(lua, 3);
}
if (!data || !size) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// send data
tb_long_t real = tb_socket_send(sock, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/io/socket_sendfile.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_sendfile.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_sendfile"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.socket_sendfile(sock, file, start, last)
tb_int_t xm_io_socket_sendfile(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// check file
if (!lua_isuserdata(lua, 2)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid file!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get file
xm_io_file_t *file = (xm_io_file_t *)lua_touserdata(lua, 2);
tb_check_return_val(file, 0);
// does not support stdfile
if (!xm_io_file_is_file(file) || !file->stream) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid file type!");
return 2;
}
// get file reference
tb_file_ref_t rawfile = tb_null;
if (!tb_stream_ctrl(file->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) || !rawfile) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "cannot get file reference!");
return 2;
}
// get file size
tb_hize_t filesize = tb_file_size(rawfile);
if (!filesize) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "cannot send empty file!");
return 2;
}
// get start
tb_long_t start = 1;
if (lua_isnumber(lua, 3)) {
start = (tb_long_t)lua_tonumber(lua, 3);
}
if (start < 1 || start > filesize) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid start position(%d)!", (tb_int_t)start);
return 2;
}
// get last
tb_long_t last = (tb_long_t)filesize;
if (lua_isnumber(lua, 4)) {
last = (tb_long_t)lua_tonumber(lua, 4);
}
if (last < start - 1 || last > filesize + start - 1) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid last position(%d)!", (tb_int_t)last);
return 2;
}
// send file data
tb_long_t real = (tb_long_t)tb_socket_sendf(sock, rawfile, start - 1, last - start + 1);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/io/socket_sendto.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_sendto.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_sendto"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// io.socket_sendto(sock, data, addr, port)
tb_int_t xm_io_socket_sendto(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid socket!");
return 2;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (xm_lua_isinteger(lua, 3)) {
size = (tb_size_t)lua_tointeger(lua, 3);
}
if (!data || !size) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get address
tb_char_t const *addr = lua_tostring(lua, 4);
tb_uint16_t port = (tb_uint16_t)luaL_checknumber(lua, 5);
if (!addr || !port) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid address!");
return 2;
}
// get address family
tb_size_t family = (tb_size_t)luaL_checknumber(lua, 6);
// init ip address
tb_ipaddr_t ipaddr;
tb_ipaddr_set(&ipaddr, addr, port, (tb_uint8_t)family);
// send data
tb_long_t real = tb_socket_usend(sock, &ipaddr, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/io/socket_wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file socket_wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "socket_wait"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.socket_wait(sock, events, timeout)
tb_int_t xm_io_socket_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check socket?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get socket
tb_socket_ref_t sock = (tb_socket_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(sock, 0);
// get events
tb_size_t events = (tb_size_t)luaL_checknumber(lua, 2);
// get timeout
tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 3);
// wait socket
lua_pushnumber(lua, (tb_int_t)tb_socket_wait(sock, events, timeout));
return 1;
}
================================================
FILE: core/src/xmake/io/stdfile.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu, ruki
* @file stdfile.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "stdfile"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef TB_CONFIG_OS_WINDOWS
#include
#include "iscygpty.c"
#else
#include
#include
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// the singleton type of stdfile
#define XM_IO_STDFILE_STDIN (TB_SINGLETON_TYPE_USER + 1)
#define XM_IO_STDFILE_STDOUT (TB_SINGLETON_TYPE_USER + 2)
#define XM_IO_STDFILE_STDERR (TB_SINGLETON_TYPE_USER + 3)
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_size_t xm_io_stdfile_isatty(tb_size_t type) {
tb_bool_t answer = tb_false;
#if defined(TB_CONFIG_OS_WINDOWS)
DWORD mode;
HANDLE console_handle = tb_null;
switch (type) {
case XM_IO_FILE_TYPE_STDIN:
console_handle = GetStdHandle(STD_INPUT_HANDLE);
break;
case XM_IO_FILE_TYPE_STDOUT:
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
break;
case XM_IO_FILE_TYPE_STDERR:
console_handle = GetStdHandle(STD_ERROR_HANDLE);
break;
}
answer = GetConsoleMode(console_handle, &mode);
/* we cannot call is_cygpty for stdin, because it will cause io.readable is always true
* https://github.com/xmake-io/xmake/issues/2504#issuecomment-1170130756
*/
if (!answer && type != XM_IO_FILE_TYPE_STDIN) {
answer = is_cygpty(console_handle);
}
#else
switch (type) {
case XM_IO_FILE_TYPE_STDIN:
answer = isatty(fileno(stdin));
break;
case XM_IO_FILE_TYPE_STDOUT:
answer = isatty(fileno(stdout));
break;
case XM_IO_FILE_TYPE_STDERR:
answer = isatty(fileno(stderr));
break;
}
#endif
if (answer) {
type |= XM_IO_FILE_FLAG_TTY;
}
return type;
}
// @see https://github.com/xmake-io/xmake/issues/2580
static tb_void_t xm_io_stdfile_init_buffer(tb_size_t type) {
#if !defined(TB_CONFIG_OS_WINDOWS)
struct stat stats;
tb_int_t size = BUFSIZ;
if (fstat(fileno(stdout), &stats) != -1) {
size = stats.st_blksize;
}
setvbuf(stdout, tb_null, _IOLBF, size);
#endif
}
static xm_io_file_t *xm_io_stdfile_new(lua_State *lua, tb_size_t type) {
// init stdfile
tb_stdfile_ref_t fp = tb_null;
switch (type) {
case XM_IO_FILE_TYPE_STDIN:
fp = tb_stdfile_input();
break;
case XM_IO_FILE_TYPE_STDOUT:
fp = tb_stdfile_output();
break;
case XM_IO_FILE_TYPE_STDERR:
fp = tb_stdfile_error();
break;
}
// new file
xm_io_file_t *file = (xm_io_file_t *)lua_newuserdata(lua, sizeof(xm_io_file_t));
tb_assert_and_check_return_val(file, tb_null);
// init file
file->u.std_ref = fp;
file->stream = tb_null;
file->fstream = tb_null;
file->type = xm_io_stdfile_isatty(type);
file->encoding = TB_CHARSET_TYPE_UTF8;
// init stdio buffer
xm_io_stdfile_init_buffer(type);
// init the read/write line cache buffer
tb_buffer_init(&file->rcache);
tb_buffer_init(&file->wcache);
return file;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
// io.stdfile(stdin: 1, stdout: 2, stderr: 3)
tb_int_t xm_io_stdfile(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get std type
tb_long_t type = (tb_long_t)lua_tointeger(lua, 1);
/* push a new stdfile
*
* @note we need to ensure that it is a singleton in the external lua script, and will only be created once, e.g. io.stdin, io.stdout, io.stderr
*/
xm_io_file_t *file = xm_io_stdfile_new(lua, type);
if (file) {
return 1;
} else {
xm_io_return_error(lua, "invalid stdfile type!");
}
}
================================================
FILE: core/src/xmake/libc/byteof.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file byteof.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "byteof"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_byteof(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data
tb_pointer_t data = tb_null;
if (lua_isnumber(lua, 1)) {
data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1);
} else if (lua_isstring(lua, 1)) {
data = (tb_pointer_t)luaL_checkstring(lua, 1);
} else {
xm_libc_return_error(lua, "libc.byteof(invalid data)!");
}
// get offset
tb_int_t offset = 0;
if (lua_isnumber(lua, 2)) {
offset = (tb_int_t)lua_tointeger(lua, 2);
} else {
xm_libc_return_error(lua, "libc.byteof(invalid offset)!");
}
lua_pushinteger(lua, ((tb_byte_t const *)data)[offset]);
return 1;
}
================================================
FILE: core/src/xmake/libc/dataptr.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file dataptr.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "dataptr"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_dataptr(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_pointer_t data = tb_null;
if (lua_isstring(lua, 1)) {
data = (tb_pointer_t)luaL_checkstring(lua, 1);
} else if (lua_isnumber(lua, 1)) {
data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1);
} else if (xm_lua_ispointer(lua, 1)) {
data = (tb_pointer_t)xm_lua_topointer(lua, 1);
} else {
xm_libc_return_error(lua, "libc.dataptr(invalid data)!");
}
lua_pushinteger(lua, (lua_Integer)(tb_long_t)data);
return 1;
}
================================================
FILE: core/src/xmake/libc/free.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file free.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "free"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_free(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// do free
tb_pointer_t data = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);
if (data) {
tb_free(data);
}
return 0;
}
================================================
FILE: core/src/xmake/libc/malloc.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file malloc.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "malloc"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_malloc(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// do malloc
tb_pointer_t data = tb_null;
tb_long_t size = (tb_long_t)luaL_checkinteger(lua, 1);
if (size > 0) {
data = tb_malloc(size);
}
lua_pushinteger(lua, (lua_Integer)(tb_long_t)data);
return 1;
}
================================================
FILE: core/src/xmake/libc/memcpy.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file memcpy.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "memcpy"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_memcpy(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// do memcpy
tb_pointer_t dst = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);
tb_pointer_t src = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 2);
tb_int_t size = (tb_int_t)lua_tointeger(lua, 3);
if (dst && src && size > 0) {
tb_memcpy(dst, src, size);
}
return 0;
}
================================================
FILE: core/src/xmake/libc/memmov.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file memmov.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "memmov"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_memmov(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// do memmov
tb_pointer_t dst = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);
tb_pointer_t src = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 2);
tb_int_t size = (tb_int_t)lua_tointeger(lua, 3);
if (dst && src && size > 0) {
tb_memmov(dst, src, size);
}
return 0;
}
================================================
FILE: core/src/xmake/libc/memset.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file memset.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "memset"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_memset(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// do memset
tb_pointer_t data = (tb_pointer_t)(tb_size_t)luaL_checkinteger(lua, 1);
tb_char_t ch = (tb_char_t)lua_tointeger(lua, 2);
tb_int_t size = (tb_int_t)lua_tointeger(lua, 3);
if (data && size > 0) {
tb_memset(data, ch, size);
}
return 0;
}
================================================
FILE: core/src/xmake/libc/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_LIBC_PREFIX_H
#define XM_LIBC_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// return libc error
#define xm_libc_return_error(lua, error) \
do { \
lua_pushnil(lua); \
lua_pushliteral(lua, error); \
return 2; \
} while (0)
#endif
================================================
FILE: core/src/xmake/libc/setbyte.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file setbyte.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "setbyte"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_setbyte(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data
tb_pointer_t data = tb_null;
if (lua_isnumber(lua, 1)) {
data = (tb_pointer_t)(tb_size_t)lua_tointeger(lua, 1);
} else if (lua_isstring(lua, 1)) {
data = (tb_pointer_t)luaL_checkstring(lua, 1);
} else {
xm_libc_return_error(lua, "libc.setbyte(invalid data)!");
}
// get offset
tb_int_t offset = 0;
if (lua_isnumber(lua, 2)) {
offset = (tb_int_t)lua_tointeger(lua, 2);
} else {
xm_libc_return_error(lua, "libc.setbyte(invalid offset)!");
}
// set byte
if (lua_isnumber(lua, 3)) {
((tb_byte_t *)data)[offset] = (tb_byte_t)lua_tointeger(lua, 3);
} else {
xm_libc_return_error(lua, "libc.setbyte(invalid value)!");
}
return 0;
}
================================================
FILE: core/src/xmake/libc/strndup.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file strndup.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "strndup"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_libc_strndup(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// do strndup
tb_char_t const *s = tb_null;
if (lua_isnumber(lua, 1)) {
s = (tb_char_t const *)(tb_size_t)lua_tointeger(lua, 1);
} else if (lua_isstring(lua, 2)) {
s = lua_tostring(lua, 2);
} else {
xm_libc_return_error(lua, "libc.strndup(invalid args)!");
}
tb_int_t n = (tb_int_t)lua_tointeger(lua, 2);
if (s && n >= 0) {
lua_pushlstring(lua, s, n);
} else {
lua_pushliteral(lua, "");
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/block_compress.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file block_compress.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "block_compress"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_block_compress(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data and size
tb_int_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 1)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);
}
if (xm_lua_isinteger(lua, 2)) {
size = (tb_int_t)lua_tointeger(lua, 2);
}
if (!data || !size || size > LZ4_MAX_INPUT_SIZE) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// do compress
tb_bool_t ok = tb_false;
tb_byte_t *output_data = tb_null;
tb_byte_t buffer[8192];
do {
tb_int_t output_size = LZ4_compressBound(size);
tb_assert_and_check_break(output_size);
output_data = output_size <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(output_size);
tb_assert_and_check_break(output_data);
tb_int_t real = LZ4_compress_default((tb_char_t const *)data, (tb_char_t *)output_data, size, output_size);
tb_assert_and_check_break(real > 0);
lua_pushlstring(lua, (tb_char_t const *)output_data, real);
ok = tb_true;
} while (0);
if (output_data && output_data != buffer) {
tb_free(output_data);
output_data = tb_null;
}
if (!ok) {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/block_decompress.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file block_decompress.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "block_decompress"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_block_decompress(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 1)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);
}
if (xm_lua_isinteger(lua, 2)) {
size = (tb_size_t)lua_tointeger(lua, 2);
}
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get real size
tb_int_t real = (tb_int_t)lua_tointeger(lua, 3);
if (real <= 0) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid output size(%d)!", real);
return 2;
}
// do decompress
tb_bool_t ok = tb_false;
tb_byte_t *output_data = tb_null;
tb_byte_t buffer[8192];
do {
output_data = real <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(real);
tb_assert_and_check_break(output_data);
tb_int_t r = LZ4_decompress_safe((tb_char_t const *)data, (tb_char_t *)output_data, (tb_int_t)size, real);
tb_assert_and_check_break(r > 0);
lua_pushlstring(lua, (tb_char_t const *)output_data, r);
ok = tb_true;
} while (0);
if (output_data && output_data != buffer) {
tb_free(output_data);
output_data = tb_null;
}
if (!ok) {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/compress.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file compress.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compress"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_compress(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 1)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);
}
if (xm_lua_isinteger(lua, 2)) {
size = (tb_size_t)lua_tointeger(lua, 2);
}
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// do compress
tb_bool_t ok = tb_false;
tb_char_t const *error = tb_null;
tb_byte_t *output_data = tb_null;
tb_byte_t buffer[8192];
do {
tb_size_t output_size = LZ4F_compressFrameBound(size, tb_null);
tb_assert_and_check_break(output_size);
output_data = output_size <= sizeof(buffer) ? buffer : (tb_byte_t *)tb_malloc(output_size);
tb_assert_and_check_break(output_data);
tb_size_t real_or_errs = LZ4F_compressFrame(output_data, output_size, data, size, tb_null);
if (LZ4F_isError(real_or_errs)) {
error = LZ4F_getErrorName(real_or_errs);
break;
}
lua_pushlstring(lua, (tb_char_t const *)output_data, real_or_errs);
ok = tb_true;
} while (0);
if (output_data && output_data != buffer) {
tb_free(output_data);
output_data = tb_null;
}
if (!ok) {
lua_pushnil(lua);
lua_pushstring(lua, error ? error : "unknown");
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/compress_file.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file compress_file.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compress_file"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_compress_file(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the file paths
tb_char_t const *srcpath = luaL_checkstring(lua, 1);
tb_char_t const *dstpath = luaL_checkstring(lua, 2);
tb_check_return_val(srcpath && dstpath, 0);
// init lz4 stream
xm_lz4_cstream_t *stream_lz4 = xm_lz4_cstream_init();
tb_check_return_val(stream_lz4, 0);
// do compress
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO);
tb_stream_ref_t ostream = tb_stream_init_from_file(dstpath,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
if (istream && ostream && tb_stream_open(istream) && tb_stream_open(ostream)) {
tb_bool_t write_ok = tb_false;
tb_byte_t idata[TB_STREAM_BLOCK_MAXN];
tb_byte_t odata[TB_STREAM_BLOCK_MAXN];
while (!tb_stream_beof(istream)) {
write_ok = tb_false;
tb_long_t ireal = (tb_long_t)tb_stream_read(istream, idata, sizeof(idata));
if (ireal > 0) {
tb_long_t r = xm_lz4_cstream_write(stream_lz4, idata, ireal, tb_stream_beof(istream));
tb_assert_and_check_break(r >= 0);
tb_check_continue(r > 0);
tb_long_t oreal;
while ((oreal = xm_lz4_cstream_read(stream_lz4, odata, sizeof(odata))) > 0) {
if (!tb_stream_bwrit(ostream, odata, oreal)) {
oreal = -1;
break;
}
}
tb_assert_and_check_break(oreal >= 0);
} else {
break;
}
write_ok = tb_true;
}
if (tb_stream_beof(istream) && write_ok) {
ok = tb_true;
}
}
// exit stream
if (istream) {
tb_stream_exit(istream);
istream = tb_null;
}
if (ostream) {
tb_stream_exit(ostream);
ostream = tb_null;
}
xm_lz4_cstream_exit(stream_lz4);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/lz4/compress_stream_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file compress_stream_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compress_stream_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_compress_stream_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the stream
xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(stream, 0);
// exit stream
xm_lz4_cstream_exit(stream);
// save result: ok
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/lz4/compress_stream_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file compress_stream_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compress_stream_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_compress_stream_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_lz4_cstream_t *stream = xm_lz4_cstream_init();
if (stream) {
xm_lua_pushpointer(lua, (tb_pointer_t)stream);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/compress_stream_read.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file compress_stream_read.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compress_stream_read"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_compress_stream_read(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check handle
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid handle!");
return 2;
}
// get stream
xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(stream, 0);
// get data
tb_byte_t *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (!data) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p)!", data);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get size
tb_long_t size = 0;
if (xm_lua_isinteger(lua, 3)) {
size = (tb_long_t)lua_tointeger(lua, 3);
}
if (size <= 0) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size);
return 2;
}
// read data
tb_long_t real = xm_lz4_cstream_read(stream, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/lz4/compress_stream_write.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file compress_stream_write.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compress_stream_write"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_compress_stream_write(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check handle
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid handle!");
return 2;
}
// get stream
xm_lz4_cstream_t *stream = (xm_lz4_cstream_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(stream, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (xm_lua_isinteger(lua, 3)) {
size = (tb_size_t)lua_tointeger(lua, 3);
}
if (!data || !size) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// is end?
tb_bool_t end = tb_false;
if (lua_isboolean(lua, 4)) {
end = lua_toboolean(lua, 4);
}
// write data
tb_long_t real = xm_lz4_cstream_write(stream, data, size, end);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/lz4/decompress.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file decompress.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "decompress"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_decompress(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 1)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 1);
}
if (xm_lua_isinteger(lua, 2)) {
size = (tb_size_t)lua_tointeger(lua, 2);
}
if (!data || !size) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// do decompress
tb_bool_t ok = tb_false;
LZ4F_errorCode_t code;
LZ4F_decompressionContext_t ctx = tb_null;
tb_buffer_t result;
do {
tb_buffer_init(&result);
code = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
if (LZ4F_isError(code)) {
break;
}
tb_byte_t buffer[8192];
tb_bool_t failed = tb_false;
while (1) {
size_t advance = (size_t)size;
size_t buffer_size = sizeof(buffer);
code = LZ4F_decompress(ctx, buffer, &buffer_size, data, &advance, tb_null);
if (LZ4F_isError(code)) {
failed = tb_true;
break;
}
if (buffer_size == 0) {
break;
}
data += advance;
size -= advance;
tb_buffer_memncat(&result, buffer, buffer_size);
}
tb_assert_and_check_break(!failed && tb_buffer_size(&result));
lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&result), tb_buffer_size(&result));
ok = tb_true;
} while (0);
if (ctx) {
LZ4F_freeDecompressionContext(ctx);
ctx = tb_null;
}
tb_buffer_exit(&result);
if (!ok) {
tb_char_t const *error = LZ4F_getErrorName(code);
lua_pushnil(lua);
lua_pushstring(lua, error ? error : "unknown");
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/decompress_file.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file dedecompress_file.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "dedecompress_file"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_decompress_file(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the file paths
tb_char_t const *srcpath = luaL_checkstring(lua, 1);
tb_char_t const *dstpath = luaL_checkstring(lua, 2);
tb_check_return_val(srcpath && dstpath, 0);
// init lz4 stream
xm_lz4_dstream_t *stream_lz4 = xm_lz4_dstream_init();
tb_check_return_val(stream_lz4, 0);
// do decompress
tb_bool_t ok = tb_false;
tb_stream_ref_t istream = tb_stream_init_from_file(srcpath, TB_FILE_MODE_RO);
tb_stream_ref_t ostream = tb_stream_init_from_file(dstpath,
TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_TRUNC);
if (istream && ostream && tb_stream_open(istream) && tb_stream_open(ostream)) {
tb_bool_t write_ok = tb_false;
tb_byte_t idata[TB_STREAM_BLOCK_MAXN];
tb_byte_t odata[TB_STREAM_BLOCK_MAXN];
while (!tb_stream_beof(istream)) {
write_ok = tb_false;
tb_long_t ireal = (tb_long_t)tb_stream_read(istream, idata, sizeof(idata));
if (ireal > 0) {
tb_long_t r = xm_lz4_dstream_write(stream_lz4, idata, ireal, tb_stream_beof(istream));
tb_assert_and_check_break(r >= 0);
tb_check_continue(r > 0);
tb_long_t oreal;
while ((oreal = xm_lz4_dstream_read(stream_lz4, odata, sizeof(odata))) > 0) {
if (!tb_stream_bwrit(ostream, odata, oreal)) {
oreal = -1;
break;
}
}
tb_assert_and_check_break(oreal >= 0);
} else {
break;
}
write_ok = tb_true;
}
if (tb_stream_beof(istream) && write_ok) {
ok = tb_true;
}
}
// exit stream
if (istream) {
tb_stream_exit(istream);
istream = tb_null;
}
if (ostream) {
tb_stream_exit(ostream);
ostream = tb_null;
}
xm_lz4_dstream_exit(stream_lz4);
lua_pushboolean(lua, ok);
return 1;
}
================================================
FILE: core/src/xmake/lz4/decompress_stream_close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file decompress_stream_close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "decompress_stream_close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_decompress_stream_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the stream
xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(stream, 0);
// exit stream
xm_lz4_dstream_exit(stream);
// save result: ok
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/lz4/decompress_stream_open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file decompress_stream_open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "decompress_stream_open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_decompress_stream_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_lz4_dstream_t *stream = xm_lz4_dstream_init();
if (stream) {
xm_lua_pushpointer(lua, (tb_pointer_t)stream);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/lz4/decompress_stream_read.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file decompress_stream_read.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "decompress_stream_read"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_decompress_stream_read(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check handle
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid handle!");
return 2;
}
// get stream
xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(stream, 0);
// get data
tb_byte_t *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (!data) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p)!", data);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// get size
tb_long_t size = 0;
if (xm_lua_isinteger(lua, 3)) {
size = (tb_long_t)lua_tointeger(lua, 3);
}
if (size <= 0) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid size(%d)!", (tb_int_t)size);
return 2;
}
// read data
tb_long_t real = xm_lz4_dstream_read(stream, data, size);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/lz4/decompress_stream_write.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file decompress_stream_write.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "decompress_stream_write"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_lz4_decompress_stream_write(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check handle
if (!xm_lua_ispointer(lua, 1)) {
lua_pushinteger(lua, -1);
lua_pushliteral(lua, "invalid handle!");
return 2;
}
// get stream
xm_lz4_dstream_t *stream = (xm_lz4_dstream_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(stream, 0);
// get data and size
tb_size_t size = 0;
tb_byte_t const *data = tb_null;
if (xm_lua_isinteger(lua, 2)) {
data = (tb_byte_t const *)(tb_size_t)(tb_long_t)lua_tointeger(lua, 2);
}
if (xm_lua_isinteger(lua, 3)) {
size = (tb_size_t)lua_tointeger(lua, 3);
}
if (!data || !size) {
lua_pushinteger(lua, -1);
lua_pushfstring(lua, "invalid data(%p) and size(%d)!", data, (tb_int_t)size);
return 2;
}
tb_assert_static(sizeof(lua_Integer) >= sizeof(tb_pointer_t));
// write data
tb_long_t real = xm_lz4_dstream_write(stream, data, size, tb_false);
lua_pushinteger(lua, (tb_int_t)real);
return 1;
}
================================================
FILE: core/src/xmake/lz4/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except idata compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to idata writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_LZ4_PREFIX_H
#define XM_LZ4_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#include "lz4frame.h"
#include "lz4.h"
#include "lz4hc.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// we need to define LZ4_byte if < 1.9.3
#if defined(LZ4_VERSION_NUMBER) && LZ4_VERSION_NUMBER < (1 * 100 * 100 + 9 * 100 + 3)
#if defined(__cplusplus) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
#include
typedef int8_t LZ4_i8;
typedef uint8_t LZ4_byte;
typedef uint16_t LZ4_u16;
typedef uint32_t LZ4_u32;
#else
typedef signed char LZ4_i8;
typedef unsigned char LZ4_byte;
typedef unsigned short LZ4_u16;
typedef unsigned int LZ4_u32;
#endif
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the lz4 compress stream type
typedef struct __xm_lz4_cstream_t {
LZ4F_cctx *cctx;
LZ4_byte *buffer;
tb_size_t buffer_size;
tb_size_t buffer_maxn;
tb_size_t write_maxn;
tb_size_t header_size;
LZ4_byte header[LZ4F_HEADER_SIZE_MAX];
} xm_lz4_cstream_t;
// the lz4 decompress stream type
typedef struct __xm_lz4_dstream_t {
LZ4F_dctx *dctx;
LZ4_byte *buffer;
tb_size_t buffer_size;
tb_size_t buffer_maxn;
tb_size_t header_size;
LZ4_byte header[LZ4F_HEADER_SIZE_MAX];
} xm_lz4_dstream_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
static __tb_inline__ tb_void_t xm_lz4_cstream_exit(xm_lz4_cstream_t *stream) {
if (stream) {
if (stream->cctx) {
LZ4F_freeCompressionContext(stream->cctx);
stream->cctx = tb_null;
}
if (stream->buffer) {
tb_free(stream->buffer);
stream->buffer = tb_null;
}
tb_free(stream);
}
}
static __tb_inline__ xm_lz4_cstream_t *xm_lz4_cstream_init() {
tb_size_t ret;
tb_bool_t ok = tb_false;
xm_lz4_cstream_t *stream = tb_null;
LZ4F_preferences_t const *prefsPtr = tb_null;
do {
stream = tb_malloc0_type(xm_lz4_cstream_t);
tb_assert_and_check_break(stream);
stream->write_maxn = 64 * 1024;
stream->buffer_maxn = LZ4F_compressBound(stream->write_maxn, prefsPtr);
stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn);
tb_assert_and_check_break(stream->buffer);
ret = LZ4F_createCompressionContext(&stream->cctx, LZ4F_getVersion());
if (LZ4F_isError(ret))
break;
ret = LZ4F_compressBegin(stream->cctx, stream->header, LZ4F_HEADER_SIZE_MAX, prefsPtr);
if (LZ4F_isError(ret))
break;
stream->header_size = ret;
ok = tb_true;
} while (0);
if (!ok && stream) {
xm_lz4_cstream_exit(stream);
stream = tb_null;
}
return stream;
}
static __tb_inline__ tb_long_t xm_lz4_cstream_write(xm_lz4_cstream_t *stream,
tb_byte_t const *idata,
tb_size_t isize,
tb_bool_t end) {
tb_assert_and_check_return_val(stream && stream->cctx && idata && isize, -1);
tb_assert_and_check_return_val(isize <= stream->write_maxn, -1);
tb_assert_and_check_return_val(stream->buffer_size + isize < stream->buffer_maxn, -1);
tb_size_t real = LZ4F_compressUpdate(stream->cctx,
stream->buffer + stream->buffer_size,
stream->buffer_maxn - stream->buffer_size,
idata,
isize,
tb_null);
if (LZ4F_isError(real))
return -1;
stream->buffer_size += real;
if (end) {
tb_size_t ret = LZ4F_compressEnd(stream->cctx,
stream->buffer + stream->buffer_size,
stream->buffer_maxn - stream->buffer_size,
tb_null);
if (LZ4F_isError(ret))
return -1;
real += ret;
stream->buffer_size += ret;
}
return isize;
}
static __tb_inline__ tb_long_t xm_lz4_cstream_read(xm_lz4_cstream_t *stream, tb_byte_t *odata, tb_size_t osize) {
tb_assert_and_check_return_val(stream && stream->cctx && odata && osize, -1);
tb_assert_and_check_return_val(osize >= stream->header_size, -1);
tb_size_t read = 0;
if (stream->header_size) {
tb_memcpy(odata, stream->header, stream->header_size);
read += stream->header_size;
osize -= stream->header_size;
stream->header_size = 0;
}
tb_size_t need = tb_min(stream->buffer_size, osize);
tb_memcpy(odata + read, stream->buffer, need);
if (need < stream->buffer_size)
tb_memmov(stream->buffer, stream->buffer + need, stream->buffer_size - need);
stream->buffer_size -= need;
read += need;
return read;
}
static __tb_inline__ tb_void_t xm_lz4_dstream_exit(xm_lz4_dstream_t *stream) {
if (stream) {
if (stream->dctx) {
LZ4F_freeDecompressionContext(stream->dctx);
stream->dctx = tb_null;
}
if (stream->buffer) {
tb_free(stream->buffer);
stream->buffer = tb_null;
}
tb_free(stream);
}
}
static __tb_inline__ xm_lz4_dstream_t *xm_lz4_dstream_init() {
LZ4F_errorCode_t ret;
tb_bool_t ok = tb_false;
xm_lz4_dstream_t *stream = tb_null;
do {
stream = tb_malloc0_type(xm_lz4_dstream_t);
tb_assert_and_check_break(stream);
ret = LZ4F_createDecompressionContext(&stream->dctx, LZ4F_getVersion());
if (LZ4F_isError(ret))
break;
ok = tb_true;
} while (0);
if (!ok && stream) {
xm_lz4_dstream_exit(stream);
stream = tb_null;
}
return stream;
}
static __tb_inline__ tb_long_t xm_lz4_dstream_write(xm_lz4_dstream_t *stream,
tb_byte_t const *idata,
tb_size_t isize,
tb_bool_t end) {
tb_assert_and_check_return_val(stream && stream->dctx && idata && isize, -1);
// read header first
const tb_size_t header_size = sizeof(stream->header);
if (stream->header_size < header_size) {
tb_size_t size = tb_min(header_size - stream->header_size, isize);
tb_memcpy(stream->header + stream->header_size, idata, size);
stream->header_size += size;
idata += size;
isize -= size;
// get frame info if header is ok
if (stream->header_size == header_size) {
LZ4F_frameInfo_t info;
size_t consumed_size = header_size;
LZ4F_errorCode_t ret = LZ4F_getFrameInfo(stream->dctx, &info, stream->header, &consumed_size);
if (LZ4F_isError(ret))
return -1;
switch (info.blockSizeID) {
case LZ4F_default:
case LZ4F_max64KB:
stream->buffer_maxn = 64 * 1024;
break;
case LZ4F_max256KB:
stream->buffer_maxn = 256 * 1024;
break;
case LZ4F_max1MB:
stream->buffer_maxn = 1 * 1024 * 1024;
break;
case LZ4F_max4MB:
stream->buffer_maxn = 4 * 1024 * 1024;
break;
default:
return -1;
}
stream->buffer = (LZ4_byte *)tb_malloc(stream->buffer_maxn);
tb_assert_and_check_return_val(stream->buffer, -1);
stream->buffer_size = header_size - consumed_size;
tb_memcpy(stream->buffer, stream->header + consumed_size, stream->buffer_size);
}
}
tb_check_return_val(stream->header_size == header_size && isize, 0);
tb_assert_and_check_return_val(stream->buffer && stream->buffer_size + isize <= stream->buffer_maxn, -1);
// append the input data
tb_memcpy(stream->buffer + stream->buffer_size, idata, isize);
stream->buffer_size += isize;
return isize;
}
static __tb_inline__ tb_long_t xm_lz4_dstream_read(xm_lz4_dstream_t *stream, tb_byte_t *odata, tb_size_t osize) {
tb_assert_and_check_return_val(stream && stream->dctx && stream->buffer && odata && osize, -1);
tb_check_return_val(stream->buffer_size, 0);
// do decompress
size_t srcsize = stream->buffer_size;
size_t dstsize = osize;
tb_size_t ret = LZ4F_decompress(stream->dctx, odata, &dstsize, stream->buffer, &srcsize, tb_null);
if (LZ4F_isError(ret))
return -1;
// move the left input data
if (srcsize < stream->buffer_size)
tb_memmov(stream->buffer, stream->buffer + srcsize, stream->buffer_size - srcsize);
stream->buffer_size -= srcsize;
return dstsize;
}
#endif
================================================
FILE: core/src/xmake/os/access.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file access.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "access"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_access(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const* path = luaL_checkstring(lua, 1);
tb_char_t const* mode_str = luaL_checkstring(lua, 2);
tb_check_return_val(path && mode_str, 0);
// parse mode
tb_size_t mode = 0;
while (*mode_str) {
switch (*mode_str) {
case 'r': mode |= TB_FILE_MODE_RO; break;
case 'w': mode |= TB_FILE_MODE_WO; break;
case 'x': mode |= TB_FILE_MODE_EXEC; break;
default: break;
}
mode_str++;
}
// os.access(path, mode)
lua_pushboolean(lua, tb_file_access(path, mode));
return 1;
}
================================================
FILE: core/src/xmake/os/args.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file args.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "os.args"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t tb_os_args_append(
tb_string_ref_t result, tb_char_t const *cstr, tb_size_t size, tb_bool_t escape, tb_bool_t nowrap) {
tb_assert_and_check_return(size < TB_PATH_MAXN);
// need wrap quote?
tb_char_t ch;
tb_char_t const *p = cstr;
tb_bool_t wrap_quote = tb_false;
if (!nowrap) {
while ((ch = *p)) {
if (ch == ' ') {
wrap_quote = tb_true;
}
p++;
}
}
// wrap begin quote
if (wrap_quote) {
tb_string_chrcat(result, '\"');
}
// escape characters
p = cstr;
while ((ch = *p)) {
// escape '"' or '\\'
if (ch == '\"' || ((escape || wrap_quote) && ch == '\\')) {
tb_string_chrcat(result, '\\');
}
tb_string_chrcat(result, ch);
p++;
}
// wrap end quote
if (wrap_quote) {
tb_string_chrcat(result, '\"');
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// os.args({"xx", "yy"}, {escape = true})
tb_int_t xm_os_args(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// escape '\\' characters in global?
tb_bool_t escape = tb_false;
if (lua_istable(lua, 2)) {
// is escape?
lua_pushstring(lua, "escape");
lua_gettable(lua, 2);
escape = lua_toboolean(lua, -1);
lua_pop(lua, 1);
}
// disable to wrap quote characters in global?
tb_bool_t nowrap = tb_false;
if (lua_istable(lua, 2)) {
// is nowrap?
lua_pushstring(lua, "nowrap");
lua_gettable(lua, 2);
nowrap = lua_toboolean(lua, -1);
lua_pop(lua, 1);
}
// init result
tb_string_t result;
tb_string_init(&result);
// make string from arguments list
if (lua_istable(lua, 1)) {
tb_size_t i = 0;
tb_size_t n = (tb_size_t)lua_objlen(lua, 1);
for (i = 1; i <= n; i++) {
// add space
if (i != 1) {
tb_string_chrcat(&result, ' ');
}
// add argument
lua_pushnumber(lua, (tb_int_t)i);
lua_rawget(lua, 1);
if (lua_istable(lua, -1)) { // is path instance?
lua_pushstring(lua, "_STR");
lua_gettable(lua, -2);
size_t size = 0;
tb_char_t const *cstr = luaL_checklstring(lua, -1, &size);
if (cstr && size) {
tb_os_args_append(&result, cstr, size, escape, nowrap);
}
lua_pop(lua, 1);
} else {
size_t size = 0;
tb_char_t const *cstr = luaL_checklstring(lua, -1, &size);
if (cstr && size) {
tb_os_args_append(&result, cstr, size, escape, nowrap);
}
}
lua_pop(lua, 1);
}
} else {
size_t size = 0;
tb_char_t const *cstr = luaL_checklstring(lua, 1, &size);
if (cstr && size) {
tb_os_args_append(&result, cstr, size, escape, nowrap);
}
}
// return result
tb_size_t size = tb_string_size(&result);
if (size) {
lua_pushlstring(lua, tb_string_cstr(&result), size);
} else {
lua_pushliteral(lua, "");
}
tb_string_exit(&result);
return 1;
}
================================================
FILE: core/src/xmake/os/argv.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file argv.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "os.argv"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_argv(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the argument string
tb_char_t const *args = luaL_checkstring(lua, 1);
tb_check_return_val(args, 0);
// split only? do not escape
tb_bool_t splitonly = tb_false;
if (lua_istable(lua, 2)) {
lua_pushstring(lua, "splitonly");
lua_gettable(lua, 2);
splitonly = lua_toboolean(lua, -1);
lua_pop(lua, 1);
}
// parse argument list
tb_string_t arg;
do {
// init table
lua_newtable(lua);
// init arg
if (!tb_string_init(&arg)) {
break;
}
// parse command to the arguments
tb_int_t i = 1;
tb_int_t skip = 0;
tb_int_t escape = 0;
tb_char_t quote = 0;
tb_char_t ch = 0;
tb_char_t const *p = args;
while ((ch = *p)) {
// no escape now?
if (!escape) {
// enter quote?
if (!quote && (ch == '\"' || ch == '\'')) {
quote = ch;
skip = 1;
} else if (ch == quote) { // leave quote?
quote = 0;
skip = 1;
} else if (ch == '\\' && (p[1] == '\\' || p[1] == '\"')) { // escape character? only escape \\ and \"
escape = 1;
skip = 1;
} else if (!quote && tb_isspace(ch)) { // is argument end with ' '?
// save this argument
tb_string_ltrim(&arg);
if (tb_string_size(&arg)) {
// save argument
lua_pushstring(lua, tb_string_cstr(&arg));
lua_rawseti(lua, -2, i++);
}
// clear argument
tb_string_clear(&arg);
}
}
// save this charactor to argument
if (splitonly || !skip) {
tb_string_chrcat(&arg, ch);
}
// step and cancel escape
if (escape == 1) {
escape++;
} else if (escape == 2) {
escape = 0;
}
// clear skip
skip = 0;
// next
p++;
}
// save this argument
tb_string_ltrim(&arg);
if (tb_string_size(&arg)) {
// save argument
lua_pushstring(lua, tb_string_cstr(&arg));
lua_rawseti(lua, -2, i++);
}
} while (0);
// exit arg
tb_string_exit(&arg);
return 1;
}
================================================
FILE: core/src/xmake/os/chdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file chdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "chdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_chdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// done os.chdir(path)
lua_pushboolean(lua, tb_directory_current_set(path));
return 1;
}
================================================
FILE: core/src/xmake/os/cpdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file cpdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "cpdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_cpdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the source and destination
tb_char_t const *src = luaL_checkstring(lua, 1);
tb_char_t const *dst = luaL_checkstring(lua, 2);
tb_check_return_val(src && dst, 0);
// init copy flags
tb_size_t flags = TB_FILE_COPY_NONE;
tb_bool_t is_symlink = lua_toboolean(lua, 3);
if (is_symlink) {
flags |= TB_FILE_COPY_LINK;
}
tb_bool_t copy_if_different = lua_toboolean(lua, 4);
if (copy_if_different) {
flags |= TB_FILE_COPY_IF_DIFFERENT;
}
// do copy
lua_pushboolean(lua, tb_directory_copy(src, dst, flags));
return 1;
}
================================================
FILE: core/src/xmake/os/cpfile.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file cpfile.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "cpfile"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_cpfile(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the source and destination
tb_char_t const *src = luaL_checkstring(lua, 1);
tb_char_t const *dst = luaL_checkstring(lua, 2);
tb_check_return_val(src && dst, 0);
// init copy flags
tb_size_t flags = TB_FILE_COPY_NONE;
tb_bool_t is_symlink = lua_toboolean(lua, 3);
if (is_symlink) {
flags |= TB_FILE_COPY_LINK;
}
tb_bool_t is_writeable = lua_toboolean(lua, 4);
if (is_writeable) {
flags |= TB_FILE_COPY_WRITEABLE;
}
tb_bool_t copy_if_different = lua_toboolean(lua, 5);
if (copy_if_different) {
flags |= TB_FILE_COPY_IF_DIFFERENT;
}
// do copy
lua_pushboolean(lua, tb_file_copy(src, dst, flags));
return 1;
}
================================================
FILE: core/src/xmake/os/cpuinfo.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file cpuinfo.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "cpuinfo"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#if defined(TB_CONFIG_OS_MACOSX)
#include
#include
#include
#include
#include
#elif defined(TB_CONFIG_OS_WINDOWS)
#include
#elif defined(TB_CONFIG_OS_LINUX)
#include
#elif defined(TB_CONFIG_OS_BSD)
#include
#include
#include
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
#if defined(TB_CONFIG_OS_WINDOWS)
static tb_uint64_t xm_os_cpuinfo_subtract_times(FILETIME const *one, FILETIME const *two) {
LARGE_INTEGER a, b;
a.LowPart = one->dwLowDateTime;
a.HighPart = one->dwHighDateTime;
b.LowPart = two->dwLowDateTime;
b.HighPart = two->dwHighDateTime;
return (tb_uint64_t)(a.QuadPart - b.QuadPart);
}
#endif
static tb_float_t xm_os_cpuinfo_usagerate() {
#if defined(TB_CONFIG_OS_MACOSX)
tb_float_t usagerate = 0;
natural_t cpu_count = 0;
processor_info_array_t cpuinfo;
mach_msg_type_number_t cpuinfo_count;
static tb_hong_t s_time = 0;
if (tb_mclock() - s_time > 1000 &&
host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, &cpuinfo, &cpuinfo_count) ==
KERN_SUCCESS) {
static processor_info_array_t s_cpuinfo_prev = tb_null;
static mach_msg_type_number_t s_cpuinfo_count_prev = 0;
for (tb_int_t i = 0; i < cpu_count; ++i) {
tb_int_t use, total;
if (s_cpuinfo_prev) {
use = (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] -
s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_USER]) +
(cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] -
s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM]) +
(cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE] -
s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_NICE]);
total = use + (cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] -
s_cpuinfo_prev[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]);
} else {
use = cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] +
cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE];
total = use + cpuinfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE];
}
usagerate += total > 0 ? ((tb_float_t)use / (tb_float_t)total) : 0;
}
if (s_cpuinfo_prev) {
vm_deallocate(mach_task_self(), (vm_address_t)s_cpuinfo_prev, sizeof(integer_t) * s_cpuinfo_count_prev);
}
s_time = tb_mclock();
s_cpuinfo_prev = cpuinfo;
s_cpuinfo_count_prev = cpuinfo_count;
}
return cpu_count > 0 ? usagerate / cpu_count : 0;
#elif defined(TB_CONFIG_OS_WINDOWS)
// kernel include idle_time
tb_float_t usagerate = 0;
FILETIME idle, kernel, user;
if (GetSystemTimes(&idle, &kernel, &user)) {
static FILETIME idle_prev = { 0 };
static FILETIME kernel_prev = { 0 };
static FILETIME user_prev = { 0 };
if (idle_prev.dwLowDateTime != 0 && idle_prev.dwHighDateTime != 0) {
tb_uint64_t idle_diff = xm_os_cpuinfo_subtract_times(&idle, &idle_prev);
tb_uint64_t kernel_diff = xm_os_cpuinfo_subtract_times(&kernel, &kernel_prev);
tb_uint64_t user_diff = xm_os_cpuinfo_subtract_times(&user, &user_prev);
// kernel_time - idle_time = kernel_time, because kernel include idle_time
tb_uint64_t sys_total = kernel_diff + user_diff;
tb_uint64_t kernel_total = kernel_diff - idle_diff;
// sometimes kernel_time > idle_time
if (sys_total > 0) {
usagerate = (tb_float_t)((tb_double_t)(kernel_total + user_diff) / sys_total);
}
}
idle_prev = idle;
kernel_prev = kernel;
user_prev = user;
}
return usagerate;
#elif defined(TB_CONFIG_OS_LINUX)
tb_float_t usagerate = 0;
if (tb_file_info("/proc/stat", tb_null)) {
FILE *fp = fopen("/proc/stat", "r");
if (fp) {
tb_char_t line[8192];
static tb_int64_t total_prev = 0;
static tb_int64_t active_prev = 0;
while (!feof(fp)) {
/* cpu 548760 0 867417 102226682 12430 0 9089 0 0 0
* cpu0 136863 0 218110 25632388 2706 0 2328 0 0 0
* cpu1 148383 0 213941 25627686 3925 0 2129 0 0 0
*
* The meanings of the columns are as follows, from left to right:
*
* user: normal processes executing in user mode
* nice: niced processes executing in user mode
* system: processes executing in kernel mode
* idle: twiddling thumbs
* iowait: waiting for I/O to complete
* irq: servicing interrupts
* softirq: servicing softirqs
* steal
* guest
* guest_nice
*/
if (fgets(line, sizeof(line), fp) && !tb_strncmp(line, "cpu ", 4)) {
long long user, nice, sys, idle, iowait, irq, softirq, steal, guest, guest_nice;
if (10 == sscanf(line,
"cpu %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld",
&user,
&nice,
&sys,
&idle,
&iowait,
&irq,
&softirq,
&steal,
&guest,
&guest_nice)) {
tb_int64_t active = (tb_int64_t)(user + nice + sys + irq + softirq + steal + guest +
guest_nice);
tb_int64_t total = (tb_int64_t)(user + nice + sys + idle + iowait + irq + softirq + steal +
guest + guest_nice);
if (total_prev > 0 && active_prev > 0) {
tb_int64_t total_diff = total - total_prev;
tb_int64_t active_diff = active - active_prev;
if (total_diff > 0) {
usagerate = (tb_float_t)((tb_double_t)active_diff / total_diff);
}
}
total_prev = total;
active_prev = active;
}
break;
}
}
fclose(fp);
}
}
return usagerate;
#elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__)
#define CP_USER 0
#define CP_NICE 1
#define CP_SYS 2
#define CP_INTR 3
#define CP_IDLE 4
#define CPUSTATES 5
static tb_int64_t total_prev = 0;
static tb_int64_t active_prev = 0;
tb_float_t usagerate = 0;
long states[CPUSTATES] = { 0 };
size_t states_size = sizeof(states);
if (sysctlbyname("kern.cp_time", &states, &states_size, tb_null, 0) == 0) {
tb_long_t user = states[CP_USER];
tb_long_t nice = states[CP_NICE];
tb_long_t sys = states[CP_SYS];
tb_long_t intr = states[CP_INTR];
tb_long_t idle = states[CP_IDLE];
tb_int64_t active = user + nice + sys + intr;
tb_int64_t total = user + nice + sys + idle + intr;
if (total_prev > 0 && active_prev > 0) {
tb_int64_t total_diff = total - total_prev;
tb_int64_t active_diff = active - active_prev;
if (total_diff > 0) {
usagerate = (tb_float_t)((tb_double_t)active_diff / total_diff);
}
}
total_prev = total;
active_prev = active;
}
return usagerate;
#else
return 0;
#endif
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* local cpuinfo = os.cpuinfo()
* {
* ncpu = 4,
* ...
* }
*/
tb_int_t xm_os_cpuinfo(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// init table
lua_newtable(lua);
// get cpu number
tb_int_t ncpu = (tb_int_t)tb_cpu_count();
lua_pushstring(lua, "ncpu");
lua_pushinteger(lua, ncpu > 0 ? ncpu : 1);
lua_settable(lua, -3);
// get cpu usage rate
tb_float_t usagerate = xm_os_cpuinfo_usagerate();
if (usagerate >= 0) {
lua_pushstring(lua, "usagerate");
lua_pushnumber(lua, usagerate);
lua_settable(lua, -3);
}
return 1;
}
================================================
FILE: core/src/xmake/os/curdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file curdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "curdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_curdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// os.curdir()
tb_char_t path[TB_PATH_MAXN];
if (tb_directory_current(path, sizeof(path))) {
lua_pushstring(lua, path);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/os/emptydir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file emptydir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "emptydir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_long_t xm_os_emptydir_walk(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {
tb_bool_t *is_emptydir = (tb_bool_t *)priv;
tb_assert_and_check_return_val(path && info && is_emptydir, TB_DIRECTORY_WALK_CODE_END);
// is emptydir?
if (info->type == TB_FILE_TYPE_FILE || info->type == TB_FILE_TYPE_DIRECTORY) {
*is_emptydir = tb_false;
return tb_false;
}
return TB_DIRECTORY_WALK_CODE_CONTINUE;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_emptydir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the directory
tb_char_t const *dir = luaL_checkstring(lua, 1);
tb_check_return_val(dir, 0);
// os.emptydir(dir)
tb_bool_t is_emptydir = tb_true;
tb_directory_walk(dir, tb_true, tb_true, xm_os_emptydir_walk, &is_emptydir);
// is emptydir?
lua_pushboolean(lua, is_emptydir);
return 1;
}
================================================
FILE: core/src/xmake/os/exists.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file exists.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "exists"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_exists(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// os.exists(path)
lua_pushboolean(lua, tb_file_info(path, tb_null));
return 1;
}
================================================
FILE: core/src/xmake/os/filesize.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file filesize.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "filesize"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_filesize(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// os.filesize(path)
tb_file_info_t info = { 0 };
if (tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE)) {
lua_pushinteger(lua, (lua_Integer)info.size);
} else {
lua_pushinteger(lua, 0);
}
return 1;
}
================================================
FILE: core/src/xmake/os/find.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file find.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "find"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_long_t xm_os_find_walk(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {
tb_value_ref_t tuple = (tb_value_ref_t)priv;
tb_assert_and_check_return_val(path && info && tuple, TB_DIRECTORY_WALK_CODE_END);
// the lua
lua_State *lua = (lua_State *)tuple[0].ptr;
tb_assert_and_check_return_val(lua, TB_DIRECTORY_WALK_CODE_END);
// the pattern
tb_char_t const *pattern = (tb_char_t const *)tuple[1].cstr;
tb_assert_and_check_return_val(pattern, TB_DIRECTORY_WALK_CODE_END);
// remove ./ for path
if (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
path = path + 2;
}
// the match mode
tb_long_t mode = tuple[2].l;
// the count
tb_size_t *pcount = &(tuple[3].ul);
tb_trace_d("path[%c]: %s", info->type == TB_FILE_TYPE_DIRECTORY ? 'd' : 'f', path);
// we can ignore it directly if this path is file, but we need directory
tb_size_t needtype = (mode == 1) ? TB_FILE_TYPE_DIRECTORY
: ((mode == 0) ? TB_FILE_TYPE_FILE : (TB_FILE_TYPE_FILE | TB_FILE_TYPE_DIRECTORY));
if (info->type == TB_FILE_TYPE_FILE && needtype == TB_FILE_TYPE_DIRECTORY) {
return TB_DIRECTORY_WALK_CODE_CONTINUE;
}
// do path:match(pattern)
lua_getfield(lua, -1, "match");
lua_pushstring(lua, path);
lua_pushstring(lua, pattern);
if (lua_pcall(lua, 2, 1, 0)) {
tb_printf("error: call string.match(%s, %s) failed: %s!\n", path, pattern, lua_tostring(lua, -1));
return TB_DIRECTORY_WALK_CODE_END;
}
// match ok?
tb_bool_t matched = tb_false;
tb_bool_t skip_recursion = tb_false;
if (lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1))) {
// exists excludes?
tb_bool_t excluded = tb_false;
if (lua_istable(lua, 5)) {
// the root directory
size_t rootlen = 0;
tb_char_t const *rootdir = luaL_checklstring(lua, 1, &rootlen);
tb_assert_and_check_return_val(rootdir && rootlen, TB_DIRECTORY_WALK_CODE_END);
tb_assert(!tb_strncmp(path, rootdir, rootlen));
tb_assert(rootlen + 1 <= tb_strlen(path));
// skip the rootdir if not "."
if (tb_strcmp(rootdir, ".")) {
path += rootlen + 1;
}
// exclude paths
tb_int_t i = 0;
tb_int_t count = (tb_int_t)lua_objlen(lua, 5);
for (i = 0; i < count && !excluded; i++) {
// get exclude
lua_rawgeti(lua, 5, i + 1);
tb_char_t const *exclude = lua_tostring(lua, -1);
if (exclude) {
// do path:match(exclude)
lua_getfield(lua, -3, "match");
lua_pushstring(lua, path);
lua_pushstring(lua, exclude);
if (lua_pcall(lua, 2, 1, 0)) {
tb_printf("error: call string.match(%s, %s) failed: %s!\n",
path,
exclude,
lua_tostring(lua, -1));
}
// matched?
excluded = lua_isstring(lua, -1) && !tb_strcmp(path, lua_tostring(lua, -1));
// pop the match result
lua_pop(lua, 1);
}
// pop exclude
lua_pop(lua, 1);
}
}
// does not exclude this path?
if (!excluded) {
// match file or directory?
if (info->type & needtype) {
// save it
lua_rawseti(lua, -3, (tb_int_t)(++*pcount));
// do callback function
if (lua_isfunction(lua, 6)) {
// do callback(path, isdir)
lua_pushvalue(lua, 6);
lua_pushstring(lua, path);
lua_pushboolean(lua, info->type == TB_FILE_TYPE_DIRECTORY);
lua_call(lua, 2, 1);
// is continue?
tb_bool_t is_continue = lua_toboolean(lua, -1);
lua_pop(lua, 1);
if (!is_continue) {
return TB_DIRECTORY_WALK_CODE_END;
}
}
matched = tb_true;
}
}
// we do not recurse sub-directories if this path has been excluded and it's directory
else {
skip_recursion = tb_true;
}
}
if (!matched) {
lua_pop(lua, 1);
}
return skip_recursion ? TB_DIRECTORY_WALK_CODE_SKIP_RECURSION : TB_DIRECTORY_WALK_CODE_CONTINUE;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_find(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the root directory
tb_char_t const *rootdir = luaL_checkstring(lua, 1);
tb_check_return_val(rootdir, 0);
// get the pattern
tb_char_t const *pattern = luaL_checkstring(lua, 2);
tb_check_return_val(pattern, 0);
// the recursion level
tb_long_t recursion = (tb_long_t)lua_tointeger(lua, 3);
// the match mode
tb_long_t mode = (tb_long_t)lua_tointeger(lua, 4);
// init table
lua_newtable(lua);
// get string package
lua_getglobal(lua, "string");
// do os.find(root, name)
tb_value_t tuple[4];
tuple[0].ptr = lua;
tuple[1].cstr = pattern;
tuple[2].l = mode;
tuple[3].ul = 0;
tb_directory_walk(rootdir, recursion, tb_true, xm_os_find_walk, tuple);
// pop string package
lua_pop(lua, 1);
// return count
lua_pushinteger(lua, tuple[3].ul);
return 2;
}
================================================
FILE: core/src/xmake/os/fscase.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file fscase.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "fscase"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_fscase(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
#if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 174
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
lua_pushinteger(lua, (tb_int_t)tb_file_fscase(path));
#else
lua_pushinteger(lua, -1);
#endif
return 1;
}
================================================
FILE: core/src/xmake/os/getenv.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file getenv.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "getenv"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// the separator
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#define XM_OS_ENV_SEP ';'
#else
#define XM_OS_ENV_SEP ':'
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_getenv(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the name
tb_char_t const *name = luaL_checkstring(lua, 1);
tb_check_return_val(name, 0);
// init values
tb_string_t values;
if (!tb_string_init(&values)) {
return 0;
}
// init environment
tb_environment_ref_t environment = tb_environment_init();
if (environment) {
// load variable
if (tb_environment_load(environment, name)) {
// make values
tb_bool_t is_first = tb_true;
tb_for_all_if(tb_char_t const *, value, environment, value) {
// append separator
if (!is_first) {
tb_string_chrcat(&values, XM_OS_ENV_SEP);
} else {
is_first = tb_false;
}
// append value
tb_string_cstrcat(&values, value);
}
}
// exit environment
tb_environment_exit(environment);
}
// save result
if (tb_string_size(&values)) {
lua_pushstring(lua, tb_string_cstr(&values));
} else {
lua_pushnil(lua);
}
// exit values
tb_string_exit(&values);
return 1;
}
================================================
FILE: core/src/xmake/os/getenvs.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file getenvs.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "getenvs"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// the separator
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#define XM_OS_ENV_SEP ';'
#else
#define XM_OS_ENV_SEP ':'
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
// the user environment
#if !defined(TB_CONFIG_OS_WINDOWS) || defined(TB_COMPILER_LIKE_UNIX)
extern tb_char_t **environ;
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
static tb_void_t xm_os_getenvs_trim(tb_char_t const **sstr, tb_char_t const **estr) {
tb_assert(sstr && estr && *sstr && *estr);
tb_char_t const *p = *sstr;
tb_char_t const *e = *estr;
// trim left
while (p < e && tb_isspace(*p)) {
p++;
}
// trim right
while (e > p && tb_isspace(*(e - 1))) {
e--;
}
// save trimmed string
*sstr = p;
*estr = e;
}
static tb_void_t xm_os_getenvs_process_line(lua_State *lua, tb_char_t const *line) {
tb_assert_and_check_return(lua && line);
tb_size_t n = tb_strlen(line);
tb_check_return(n > 0);
// find '=' separator
tb_char_t const *p = tb_strchr(line, '=');
tb_check_return(p);
// get key and value parts
tb_char_t const *key_start = line;
tb_char_t const *key_end = p;
tb_char_t const *value_start = p + 1;
tb_char_t const *value_end = line + n;
// trim key
xm_os_getenvs_trim(&key_start, &key_end);
if (key_start >= key_end) {
return;
}
// trim value
xm_os_getenvs_trim(&value_start, &value_end);
// get key and value lengths
tb_size_t key_len = key_end - key_start;
tb_size_t value_len = value_end > value_start ? value_end - value_start : 0;
// handle Windows-specific PATH conversion
tb_char_t const *final_key_start = key_start;
tb_size_t final_key_len = key_len;
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
if (key_len == 4 && tb_strnicmp(key_start, "path", 4) == 0) {
// use "PATH" instead of "path"
static tb_char_t const PATH_UPPER[] = "PATH";
final_key_start = PATH_UPPER;
final_key_len = 4;
}
#endif
// set key-value pair in Lua table using pushlstring to avoid length limits
lua_pushlstring(lua, final_key_start, final_key_len);
lua_pushlstring(lua, value_start, value_len);
lua_rawset(lua, -3);
}
tb_int_t xm_os_getenvs(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// init table
lua_newtable(lua);
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
tb_wchar_t const *p = (tb_wchar_t const *)GetEnvironmentStringsW();
if (p) {
tb_char_t *data = tb_null;
tb_size_t maxn = 0;
tb_char_t line[TB_PATH_MAXN];
tb_size_t n = 0;
while (*p) {
n = tb_wcslen(p);
if (n + 1 < tb_arrayn(line)) {
if (tb_wtoa(line, p, tb_arrayn(line)) >= 0) {
xm_os_getenvs_process_line(lua, line);
}
} else {
if (!data) {
maxn = n + 1;
data = (tb_char_t *)tb_malloc(maxn);
} else if (n >= maxn) {
maxn = n + TB_PATH_MAXN + 1;
data = (tb_char_t *)tb_ralloc(data, maxn);
}
tb_assert_and_check_break(data);
if (tb_wtoa(data, p, maxn) >= 0) {
xm_os_getenvs_process_line(lua, data);
}
}
p += n + 1;
}
if (data && data != line) {
tb_free(data);
}
data = tb_null;
}
#else
tb_char_t const **p = (tb_char_t const **)environ;
if (p) {
while (*p) {
xm_os_getenvs_process_line(lua, *p);
p++;
}
}
#endif
return 1;
}
================================================
FILE: core/src/xmake/os/getown.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file getown.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "getown"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifndef TB_CONFIG_OS_WINDOWS
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
#ifndef TB_CONFIG_OS_WINDOWS
// get owner by a given path
tb_int_t xm_os_getown(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the pathname
tb_char_t const *pathname = luaL_checkstring(lua, 1);
tb_check_return_val(pathname, 0);
// get stat
struct stat sts;
if (stat(pathname, &sts) != 0) {
return 0;
}
// push
lua_newtable(lua);
lua_pushstring(lua, "uid");
lua_pushinteger(lua, sts.st_uid);
lua_settable(lua, -3);
lua_pushstring(lua, "gid");
lua_pushinteger(lua, sts.st_gid);
lua_settable(lua, -3);
return 1;
}
#endif
================================================
FILE: core/src/xmake/os/getpid.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file getpid.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "getpid"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef TB_CONFIG_OS_WINDOWS
#include
#else
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_getpid(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
#ifdef TB_CONFIG_OS_WINDOWS
lua_pushinteger(lua, (tb_int_t)GetCurrentProcessId());
#else
lua_pushinteger(lua, (tb_int_t)getpid());
#endif
return 1;
}
================================================
FILE: core/src/xmake/os/getwinsize.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file getwinsize.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "getwinsize"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#include
#else
#include
#include // for errno
#include // for STDOUT_FILENO
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// get console window size
tb_int_t xm_os_getwinsize(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// init default window size (we will not consider winsize limit if cannot get it)
tb_int_t w = TB_MAXS16, h = TB_MAXS16;
// get winsize
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
w = (tb_int_t)csbi.dwSize.X;
h = (tb_int_t)csbi.dwSize.Y;
}
#elif defined(TB_CONFIG_OS_SOLARIS)
// Solaris doesn't support winsize/TIOCGWINSZ, use default values
#else
struct winsize size;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == 0) {
w = (tb_int_t)size.ws_col;
h = (tb_int_t)size.ws_row;
}
#endif
/* local winsize = os.getwinsize()
*
* return
* {
* width = -1 or ..
* , height = -1 or ..
* }
*/
lua_newtable(lua);
lua_pushstring(lua, "width");
lua_pushinteger(lua, w);
lua_settable(lua, -3);
lua_pushstring(lua, "height");
lua_pushinteger(lua, h);
lua_settable(lua, -3);
return 1;
}
================================================
FILE: core/src/xmake/os/gid.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file gid.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "gid"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifndef TB_CONFIG_OS_WINDOWS
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
#ifndef TB_CONFIG_OS_WINDOWS
// get & set gid
tb_int_t xm_os_gid(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_int_t rgidset = -1;
tb_int_t egidset = -1;
tb_int_t argc = lua_gettop(lua);
if (argc == 1) {
if (lua_istable(lua, 1)) {
// os.gid({["rgid"] = rgid, ["egid"] = egid})
lua_getfield(lua, 1, "rgid");
lua_getfield(lua, 1, "egid");
if (!lua_isnil(lua, -1)) {
if (!lua_isnumber(lua, -1)) {
lua_pushfstring(lua, "invalid field type(%s) in `egid` for os.gid", luaL_typename(lua, -1));
lua_error(lua);
return 0;
}
egidset = (tb_int_t)lua_tonumber(lua, -1);
}
lua_pop(lua, 1);
if (!lua_isnil(lua, -1)) {
if (!lua_isnumber(lua, -1)) {
lua_pushfstring(lua, "invalid field type(%s) in `rgid` for os.gid", luaL_typename(lua, -1));
lua_error(lua);
return 0;
}
rgidset = (tb_int_t)lua_tonumber(lua, -1);
}
lua_pop(lua, 1);
} else if (lua_isnumber(lua, 1)) {
// os.gid(gid)
rgidset = egidset = (tb_int_t)lua_tonumber(lua, 1);
} else {
lua_pushfstring(lua, "invalid argument type(%s) for os.gid", luaL_typename(lua, 1));
lua_error(lua);
return 0;
}
} else if (argc == 2) {
// os.gid(rgid, egid)
if (!lua_isnil(lua, 1)) {
if (!lua_isnumber(lua, 1)) {
lua_pushfstring(lua, "invalid argument type(%s) for os.gid", luaL_typename(lua, 1));
lua_error(lua);
return 0;
}
rgidset = (tb_int_t)lua_tonumber(lua, 1);
}
if (!lua_isnil(lua, 2)) {
if (!lua_isnumber(lua, 2)) {
lua_pushfstring(lua, "invalid argument type(%s) for os.gid", luaL_typename(lua, 2));
lua_error(lua);
return 0;
}
egidset = (tb_int_t)lua_tonumber(lua, 2);
}
} else if (argc != 0) {
lua_pushstring(lua, "invalid argument count for os.gid");
lua_error(lua);
return 0;
}
// store return value
lua_newtable(lua);
if (rgidset != -1 || egidset != -1) {
// set rgid & egid
lua_pushstring(lua, "errno");
lua_pushinteger(lua, setregid(rgidset, egidset) != 0 ? errno : 0);
lua_settable(lua, -3);
}
// get gid & egid
gid_t gid = getgid();
gid_t egid = getegid();
// push
lua_pushstring(lua, "rgid");
lua_pushinteger(lua, gid);
lua_settable(lua, -3);
lua_pushstring(lua, "egid");
lua_pushinteger(lua, egid);
lua_settable(lua, -3);
return 1;
}
#endif
================================================
FILE: core/src/xmake/os/isdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file isdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "isdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_isdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// is directory?
tb_file_info_t info = { 0 };
lua_pushboolean(lua, tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_DIRECTORY));
return 1;
}
================================================
FILE: core/src/xmake/os/isfile.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file isfile.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "isfile"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_isfile(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// is file?
tb_file_info_t info = { 0 };
lua_pushboolean(lua, tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE));
return 1;
}
================================================
FILE: core/src/xmake/os/islink.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file islink.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "islink"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_islink(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// is link?
tb_file_info_t info = { 0 };
lua_pushboolean(lua, tb_file_info(path, &info) && (info.flags & TB_FILE_FLAG_LINK));
return 1;
}
================================================
FILE: core/src/xmake/os/link.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file link.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "link"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_link(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the source and destination
tb_char_t const *src = luaL_checkstring(lua, 1);
tb_char_t const *dst = luaL_checkstring(lua, 2);
tb_check_return_val(src && dst, 0);
// do os.link(src, dst)
lua_pushboolean(lua, tb_file_link(src, dst));
return 1;
}
================================================
FILE: core/src/xmake/os/mclock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mclock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "mclock"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// os.mclock()
tb_int_t xm_os_mclock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// save result
lua_pushnumber(lua, (lua_Number)tb_mclock());
return 1;
}
================================================
FILE: core/src/xmake/os/meminfo.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file meminfo.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "meminfo"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#if defined(TB_CONFIG_OS_MACOSX)
#include
#include
#include
#include
#include
#include
#elif defined(TB_CONFIG_OS_LINUX)
#include
#include
#elif defined(TB_CONFIG_OS_WINDOWS)
#include
#elif defined(TB_CONFIG_OS_BSD)
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
#ifdef TB_CONFIG_OS_LINUX
static tb_int64_t xm_os_meminfo_get_value(tb_char_t const *buffer, tb_char_t const *name) {
tb_char_t const *p = tb_strstr(buffer, name);
return p ? tb_stoi64(p + tb_strlen(name)) : 0;
}
#endif
// get the used memory size (MB)
static tb_bool_t xm_os_meminfo_stats(tb_int_t *ptotalsize, tb_int_t *pavailsize) {
#if defined(TB_CONFIG_OS_MACOSX)
vm_statistics64_data_t vmstat;
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info_t)&vmstat, &count) == KERN_SUCCESS) {
tb_int_t pagesize = (tb_int_t)tb_page_size();
tb_int64_t totalsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count + vmstat.active_count +
vmstat.wire_count
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ vmstat.compressor_page_count
#endif
) *
pagesize;
/*
* NB: speculative pages are already accounted for in "free_count",
* so "speculative_count" is the number of "free" pages that are
* used to hold data that was read speculatively from disk but
* haven't actually been used by anyone so far.
*
*/
tb_int64_t availsize = (tb_int64_t)(vmstat.inactive_count + vmstat.free_count - vmstat.speculative_count) *
pagesize;
*ptotalsize = (tb_int_t)(totalsize / (1024 * 1024));
*pavailsize = (tb_int_t)(availsize / (1024 * 1024));
return tb_true;
}
#elif defined(TB_CONFIG_OS_LINUX)
/* we get meminfo from /proc/meminfo
*
* @see https://github.com/rfjakob/earlyoom/blob/cba1d599e4a7484c45ac017aa7702ff879f15846/meminfo.c#L52
*/
if (tb_file_info("/proc/meminfo", tb_null)) {
tb_bool_t ok = tb_false;
FILE *fp = fopen("/proc/meminfo", "r");
if (fp) {
// 8192 should be enough for the foreseeable future.
tb_char_t buffer[8192];
size_t len = fread(buffer, 1, sizeof(buffer) - 1, fp);
if (!ferror(fp) && len) {
tb_int64_t totalsize = xm_os_meminfo_get_value(buffer, "MemTotal:");
tb_int64_t availsize = xm_os_meminfo_get_value(buffer, "MemAvailable:");
if (availsize <= 0) {
tb_int64_t cachesize = xm_os_meminfo_get_value(buffer, "Cached:");
tb_int64_t freesize = xm_os_meminfo_get_value(buffer, "MemFree:");
tb_int64_t buffersize = xm_os_meminfo_get_value(buffer, "Buffers:");
tb_int64_t shmemsize = xm_os_meminfo_get_value(buffer, "Shmem:");
if (cachesize >= 0 && freesize >= 0 && buffersize >= 0 && shmemsize >= 0) {
availsize = freesize + buffersize + cachesize - shmemsize;
}
}
if (totalsize > 0 && availsize >= 0) {
*ptotalsize = (tb_int_t)(totalsize / 1024);
*pavailsize = (tb_int_t)(availsize / 1024);
ok = tb_true;
}
}
fclose(fp);
}
return ok;
} else {
struct sysinfo info = { 0 };
if (sysinfo(&info) == 0) {
*ptotalsize = (tb_int_t)(info.totalram / (1024 * 1024));
*pavailsize = (tb_int_t)((info.freeram + info.bufferram /* + cache size */) / (1024 * 1024));
return tb_true;
}
}
#elif defined(TB_CONFIG_OS_WINDOWS)
MEMORYSTATUSEX statex;
statex.dwLength = sizeof(statex);
if (GlobalMemoryStatusEx(&statex)) {
*ptotalsize = (tb_int_t)(statex.ullTotalPhys / (1024 * 1024));
*pavailsize = (tb_int_t)(statex.ullAvailPhys / (1024 * 1024));
return tb_true;
}
#elif defined(TB_CONFIG_OS_BSD) && !defined(__OpenBSD__)
unsigned long totalsize;
size_t size = sizeof(totalsize);
if (sysctlbyname("hw.physmem", &totalsize, &size, tb_null, 0) != 0) {
return tb_false;
}
// http://web.mit.edu/freebsd/head/usr.bin/systat/vmstat.c
tb_uint32_t v_free_count;
size = sizeof(v_free_count);
if (sysctlbyname("vm.stats.vm.v_free_count", &v_free_count, &size, tb_null, 0) != 0) {
return tb_false;
}
tb_uint32_t v_inactive_count;
size = sizeof(v_inactive_count);
if (sysctlbyname("vm.stats.vm.v_inactive_count", &v_inactive_count, &size, tb_null, 0) != 0) {
return tb_false;
}
*ptotalsize = (tb_int_t)(totalsize / (1024 * 1024));
*pavailsize = (tb_int_t)(((tb_int64_t)(v_free_count + v_inactive_count) * tb_page_size()) / (1024 * 1024));
return tb_true;
#endif
return tb_false;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_meminfo(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// init table
lua_newtable(lua);
// get the pagesize (bytes)
tb_int_t pagesize = (tb_int_t)tb_page_size();
lua_pushstring(lua, "pagesize");
lua_pushinteger(lua, pagesize);
lua_settable(lua, -3);
// get the memory size (MB)
tb_int_t availsize = 0;
tb_int_t totalsize = 0;
if (xm_os_meminfo_stats(&totalsize, &availsize)) {
lua_pushstring(lua, "totalsize");
lua_pushinteger(lua, totalsize);
lua_settable(lua, -3);
lua_pushstring(lua, "availsize");
lua_pushinteger(lua, availsize);
lua_settable(lua, -3);
}
return 1;
}
================================================
FILE: core/src/xmake/os/mkdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mkdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "mkdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_mkdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// os.mkdir(path)
tb_file_info_t info = { 0 };
if (!tb_file_info(path, &info) || (info.type != TB_FILE_TYPE_DIRECTORY)) {
lua_pushboolean(lua, tb_directory_create(path));
} else {
lua_pushboolean(lua, tb_true);
}
return 1;
}
================================================
FILE: core/src/xmake/os/mtime.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mtime.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "mtime"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_mtime(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// os.mtime(path)
tb_file_info_t info = { 0 };
if (tb_file_info(path, &info)) {
lua_pushinteger(lua, (lua_Integer)info.mtime);
} else {
lua_pushinteger(lua, 0);
}
return 1;
}
================================================
FILE: core/src/xmake/os/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_OS_PREFIX_H
#define XM_OS_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/os/processes.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file processes.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "processes"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef TB_CONFIG_OS_WINDOWS
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_winos_processes(lua_State* lua) {
#ifdef TB_CONFIG_OS_WINDOWS
// init result table
lua_newtable(lua);
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32W pe32;
pe32.dwSize = sizeof(PROCESSENTRY32W);
if (Process32FirstW(hSnapshot, &pe32)) {
tb_int_t i = 1;
do {
// new process entry table
lua_newtable(lua);
// name
tb_char_t name[MAX_PATH * 4];
tb_size_t size = tb_wtoa(name, pe32.szExeFile, sizeof(name));
if (size != -1) {
lua_pushlstring(lua, name, size);
} else {
lua_pushstring(lua, "");
}
lua_setfield(lua, -2, "name");
// pid
lua_pushinteger(lua, (tb_int_t)pe32.th32ProcessID);
lua_setfield(lua, -2, "pid");
// ppid
lua_pushinteger(lua, (tb_int_t)pe32.th32ParentProcessID);
lua_setfield(lua, -2, "parent_pid");
// result[i++] = entry
lua_rawseti(lua, -2, i++);
} while (Process32NextW(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
}
return 1;
#else
return 0;
#endif
}
================================================
FILE: core/src/xmake/os/readlink.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file readlink.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "readlink"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifndef TB_CONFIG_OS_WINDOWS
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_readlink(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// is link?
#if defined(TB_CONFIG_OS_WINDOWS)
lua_pushnil(lua);
#else
tb_char_t srcpath[TB_PATH_MAXN];
tb_long_t size = readlink(path, srcpath, TB_PATH_MAXN);
if (size == TB_PATH_MAXN) {
tb_size_t maxn = TB_PATH_MAXN * 2;
tb_char_t *data = (tb_char_t *)tb_malloc(maxn);
if (data) {
tb_long_t size = readlink(path, data, maxn);
if (size > 0 && size < maxn) {
data[size] = '\0';
lua_pushstring(lua, data);
} else {
lua_pushnil(lua);
}
tb_free(data);
}
} else if (size >= 0 && size < TB_PATH_MAXN) {
srcpath[size] = '\0';
lua_pushstring(lua, srcpath);
} else {
lua_pushnil(lua);
}
#endif
return 1;
}
================================================
FILE: core/src/xmake/os/rename.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rename.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rename"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_rename(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the source and destination
tb_char_t const *src = luaL_checkstring(lua, 1);
tb_char_t const *dst = luaL_checkstring(lua, 2);
tb_check_return_val(src && dst, 0);
// do rename
lua_pushboolean(lua, tb_file_rename(src, dst));
return 1;
}
================================================
FILE: core/src/xmake/os/rmdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rmdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rmdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_long_t xm_os_rmdir_empty(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {
tb_bool_t *is_emptydir = (tb_bool_t *)priv;
tb_assert_and_check_return_val(path && info && is_emptydir, TB_DIRECTORY_WALK_CODE_END);
// is emptydir?
if (info->type == TB_FILE_TYPE_DIRECTORY || info->type == TB_FILE_TYPE_FILE) {
// not emptydir
*is_emptydir = tb_false;
return TB_DIRECTORY_WALK_CODE_END;
}
return TB_DIRECTORY_WALK_CODE_CONTINUE;
}
static tb_long_t xm_os_rmdir_remove(tb_char_t const *path, tb_file_info_t const *info, tb_cpointer_t priv) {
tb_assert_and_check_return_val(path, TB_DIRECTORY_WALK_CODE_END);
// is directory?
if (info->type == TB_FILE_TYPE_DIRECTORY) {
// is emptydir?
tb_bool_t is_emptydir = tb_true;
tb_directory_walk(path, tb_false, tb_true, xm_os_rmdir_empty, &is_emptydir);
tb_trace_d("path: %s, emptydir: %u", path, is_emptydir);
// remove empty directory
if (is_emptydir) {
tb_directory_remove(path);
}
}
return TB_DIRECTORY_WALK_CODE_CONTINUE;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_rmdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// only remove empty directory?
tb_bool_t rmempty = lua_toboolean(lua, 2);
if (rmempty) {
// remove all empty directories
tb_directory_walk(path, tb_true, tb_false, xm_os_rmdir_remove, tb_null);
// remove empty root directory
tb_bool_t is_emptydir = tb_true;
tb_directory_walk(path, tb_false, tb_true, xm_os_rmdir_empty, &is_emptydir);
if (is_emptydir) {
tb_directory_remove(path);
}
tb_trace_d("path: %s, emptydir: %u", path, is_emptydir);
lua_pushboolean(lua, !tb_file_info(path, tb_null));
} else {
// os.rmdir(path)
lua_pushboolean(lua, tb_directory_remove(path));
}
return 1;
}
================================================
FILE: core/src/xmake/os/rmfile.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file rmfile.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "rmfile"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_rmfile(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// do remove
lua_pushboolean(lua, tb_file_remove(path));
return 1;
}
================================================
FILE: core/src/xmake/os/setenv.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file setenv.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "setenv"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// ok = os.setenv(name, value)
tb_int_t xm_os_setenv(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the name and value
size_t value_size = 0;
tb_char_t const *name = luaL_checkstring(lua, 1);
tb_char_t const *value = luaL_checklstring(lua, 2, &value_size);
tb_check_return_val(name, 0);
// set it
lua_pushboolean(lua, value ? tb_environment_set(name, value) : tb_false);
return 1;
}
================================================
FILE: core/src/xmake/os/signal.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file signal.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "signal"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)
#include
#include
#elif defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || defined(TB_CONFIG_OS_ANDROID) || \
defined(TB_CONFIG_OS_HAIKU)
#include
#include
#endif
#ifdef TB_CONFIG_OS_BSD
#include
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
typedef enum __xm_os_signal_e {
XM_OS_SIGINT = 2
} xm_os_signal_e;
typedef enum __xm_os_signal_handler_e {
XM_OS_SIGFUN = 0,
XM_OS_SIGDFL = 1,
XM_OS_SIGIGN = 2,
} xm_os_signal_handler_e;
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
static lua_State *g_lua = tb_null;
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_os_signal_handler_impl(tb_int_t signo) {
// do callback(signo)
lua_State *lua = g_lua;
if (lua) {
tb_char_t name[64] = { 0 };
tb_snprintf(name, sizeof(name), "_SIGNAL_HANDLER_%d", signo);
lua_getglobal(lua, name);
lua_pushinteger(lua, signo);
lua_call(lua, 1, 0);
}
}
#if defined(TB_CONFIG_OS_WINDOWS)
static BOOL WINAPI xm_os_signal_handler(DWORD ctrl_type) {
if (ctrl_type == CTRL_C_EVENT) {
xm_os_signal_handler_impl(XM_OS_SIGINT);
}
return TRUE;
}
#elif defined(SIGINT)
static tb_void_t xm_os_signal_handler(tb_int_t signo_native) {
tb_int_t signo = -1;
switch (signo_native) {
case SIGINT:
signo = XM_OS_SIGINT;
break;
default:
break;
}
if (signo >= 0) {
xm_os_signal_handler_impl(signo);
}
}
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_signal(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
g_lua = lua;
tb_int_t handler = XM_OS_SIGFUN;
// check signal handler
if (lua_isnumber(lua, 2)) {
handler = (tb_int_t)luaL_checkinteger(lua, 2);
} else if (!lua_isfunction(lua, 2)) {
return 0;
}
// save signal handler
tb_int_t signo = (tb_int_t)luaL_checkinteger(lua, 1);
if (handler == XM_OS_SIGFUN) {
tb_char_t name[64] = { 0 };
tb_snprintf(name, sizeof(name), "_SIGNAL_HANDLER_%d", signo);
lua_pushvalue(lua, 2);
lua_setglobal(lua, name);
}
#if defined(TB_CONFIG_OS_WINDOWS)
if (signo != XM_OS_SIGINT) {
return 0;
}
switch (handler) {
case XM_OS_SIGFUN:
SetConsoleCtrlHandler(xm_os_signal_handler, TRUE);
break;
case XM_OS_SIGDFL:
SetConsoleCtrlHandler(NULL, FALSE);
break;
case XM_OS_SIGIGN:
SetConsoleCtrlHandler(NULL, TRUE);
break;
default:
break;
}
#elif defined(SIGINT)
switch (signo) {
case XM_OS_SIGINT:
signo = SIGINT;
break;
default:
return 0;
}
switch (handler) {
case XM_OS_SIGFUN:
signal(signo, xm_os_signal_handler);
break;
case XM_OS_SIGDFL:
signal(signo, SIG_DFL);
break;
case XM_OS_SIGIGN:
signal(signo, SIG_IGN);
break;
default:
break;
}
#endif
return 0;
}
================================================
FILE: core/src/xmake/os/sleep.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sleep.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "sleep"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_sleep(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_long_t interval = (tb_long_t)luaL_checklong(lua, 1);
if (interval >= 0) {
tb_msleep(interval);
}
return 0;
}
================================================
FILE: core/src/xmake/os/strerror.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file strerror.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "strerror"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
#include
#else
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_strerror(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get syserror state
tb_size_t syserror = tb_syserror_state();
if (syserror != TB_STATE_SYSERROR_UNKNOWN_ERROR) {
tb_char_t const *strerr = "Unknown";
switch (syserror) {
case TB_STATE_SYSERROR_NOT_PERM:
strerr = "Permission denied";
break;
#if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 173
case TB_STATE_SYSERROR_NOT_ACCESS:
strerr = "Not access because it is busy";
break;
#endif
case TB_STATE_SYSERROR_NOT_FILEDIR:
strerr = "No such file or directory";
break;
default:
break;
}
lua_pushstring(lua, strerr);
} else {
#if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX)
tb_char_t strerr[128] = { 0 };
tb_snprintf(strerr, sizeof(strerr), "Unknown Error (%lu)", (tb_size_t)GetLastError());
lua_pushstring(lua, strerr);
#else
lua_pushstring(lua, strerror(errno));
#endif
}
return 1;
}
================================================
FILE: core/src/xmake/os/syserror.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file syserror.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "syserror"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_syserror(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get syserror state
tb_int_t err = 0;
tb_size_t syserror = tb_syserror_state();
switch (syserror) {
case TB_STATE_SYSERROR_NOT_PERM:
err = 1;
break;
case TB_STATE_SYSERROR_NOT_FILEDIR:
err = 2;
break;
#if ((TB_VERSION_MAJOR * 100) + (TB_VERSION_MINOR * 10) + TB_VERSION_ALTER) >= 173
case TB_STATE_SYSERROR_NOT_ACCESS:
err = 3;
break;
#endif
case TB_STATE_SYSERROR_UNKNOWN_ERROR:
err = -1;
break;
}
lua_pushinteger(lua, err);
return 1;
}
================================================
FILE: core/src/xmake/os/tmpdir.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file tmpdir.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "tmpdir"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_tmpdir(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// os.tmpdir()
tb_char_t path[TB_PATH_MAXN];
if (tb_directory_temporary(path, sizeof(path))) {
lua_pushstring(lua, path);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/os/touch.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file touch.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "touch"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_os_touch(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
tb_time_t atime = (tb_time_t)luaL_checknumber(lua, 2);
tb_time_t mtime = (tb_time_t)luaL_checknumber(lua, 3);
lua_pushboolean(lua, tb_file_touch(path, atime, mtime));
return 1;
}
================================================
FILE: core/src/xmake/os/uid.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file uid.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "uid"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifndef TB_CONFIG_OS_WINDOWS
#include
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
#ifndef TB_CONFIG_OS_WINDOWS
// get & set uid
tb_int_t xm_os_uid(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_int_t ruidset = -1;
tb_int_t euidset = -1;
tb_int_t argc = lua_gettop(lua);
if (argc == 1) {
if (lua_istable(lua, 1)) {
// os.uid({["ruid"] = ruid, ["euid"] = euid})
lua_getfield(lua, 1, "ruid");
lua_getfield(lua, 1, "euid");
if (!lua_isnil(lua, -1)) {
if (!lua_isnumber(lua, -1)) {
lua_pushfstring(lua, "invalid field type(%s) in `euid` for os.uid", luaL_typename(lua, -1));
lua_error(lua);
return 0;
}
euidset = (tb_int_t)lua_tonumber(lua, -1);
}
lua_pop(lua, 1);
if (!lua_isnil(lua, -1)) {
if (!lua_isnumber(lua, -1)) {
lua_pushfstring(lua, "invalid field type(%s) in `ruid` for os.uid", luaL_typename(lua, -1));
lua_error(lua);
return 0;
}
ruidset = (tb_int_t)lua_tonumber(lua, -1);
}
lua_pop(lua, 1);
} else if (lua_isnumber(lua, 1)) {
// os.uid(uid)
ruidset = euidset = (tb_int_t)lua_tonumber(lua, 1);
} else {
lua_pushfstring(lua, "invalid argument type(%s) for os.uid", luaL_typename(lua, 1));
lua_error(lua);
return 0;
}
} else if (argc == 2) {
// os.uid(ruid, euid)
if (!lua_isnil(lua, 1)) {
if (!lua_isnumber(lua, 1)) {
lua_pushfstring(lua, "invalid argument type(%s) for os.uid", luaL_typename(lua, 1));
lua_error(lua);
return 0;
}
ruidset = (tb_int_t)lua_tonumber(lua, 1);
}
if (!lua_isnil(lua, 2)) {
if (!lua_isnumber(lua, 2)) {
lua_pushfstring(lua, "invalid argument type(%s) for os.uid", luaL_typename(lua, 2));
lua_error(lua);
return 0;
}
euidset = (tb_int_t)lua_tonumber(lua, 2);
}
} else if (argc != 0) {
lua_pushstring(lua, "invalid argument count for os.uid");
lua_error(lua);
return 0;
}
// store return value
lua_newtable(lua);
if (ruidset != -1 || euidset != -1) {
// set ruid & euid
lua_pushstring(lua, "errno");
lua_pushinteger(lua, setreuid(ruidset, euidset) != 0 ? errno : 0);
lua_settable(lua, -3);
}
// get uid & euid
uid_t uid = getuid();
uid_t euid = geteuid();
// push
lua_pushstring(lua, "ruid");
lua_pushinteger(lua, uid);
lua_settable(lua, -3);
lua_pushstring(lua, "euid");
lua_pushinteger(lua, euid);
lua_settable(lua, -3);
return 1;
}
#endif
================================================
FILE: core/src/xmake/package/loadxmi.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file loadxmi.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "loadxmi"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef USE_LUAJIT
#define XMI_USE_LUAJIT
#endif
#include "xmi.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
typedef int (*xm_setup_func_t)(xmi_lua_ops_t *ops);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_package_loadxmi(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
tb_char_t const *name = luaL_checkstring(lua, 2);
tb_check_return_val(name, 0);
// load module library
tb_dynamic_ref_t lib = tb_dynamic_init(path);
if (!lib) {
lua_pushnil(lua);
lua_pushfstring(lua, "load %s failed", path);
return 2;
}
// get xmiopen_xxx function
lua_CFunction luaopen_func = (lua_CFunction)tb_dynamic_func(lib, name);
if (!luaopen_func) {
lua_pushnil(lua);
lua_pushfstring(lua, "cannot get symbol %s failed", name);
return 2;
}
// get xmisetup function
xm_setup_func_t xmisetup_func = (xm_setup_func_t)tb_dynamic_func(lib, "xmisetup");
if (!xmisetup_func) {
lua_pushnil(lua);
lua_pushfstring(lua, "cannot get symbol xmisetup failed");
return 2;
}
// setup lua interfaces
static xmi_lua_ops_t s_luaops = { 0 };
static tb_bool_t s_luaops_inited = tb_false;
if (!s_luaops_inited) {
// get functions
#ifdef XMI_USE_LUAJIT
s_luaops._lua_newuserdata = &lua_newuserdata;
#else
s_luaops._lua_getglobal = &lua_getglobal;
s_luaops._lua_geti = &lua_geti;
s_luaops._lua_rawgetp = &lua_rawgetp;
s_luaops._lua_getiuservalue = &lua_getiuservalue;
s_luaops._lua_newuserdatauv = &lua_newuserdatauv;
#endif
s_luaops._lua_gettable = &lua_gettable;
s_luaops._lua_getfield = &lua_getfield;
s_luaops._lua_rawget = &lua_rawget;
s_luaops._lua_rawgeti = &lua_rawgeti;
s_luaops._lua_createtable = &lua_createtable;
s_luaops._lua_getmetatable = &lua_getmetatable;
// set functions
#ifndef XMI_USE_LUAJIT
s_luaops._lua_setglobal = &lua_setglobal;
s_luaops._lua_seti = &lua_seti;
s_luaops._lua_rawsetp = &lua_rawsetp;
s_luaops._lua_setiuservalue = &lua_setiuservalue;
#endif
s_luaops._lua_settable = &lua_settable;
s_luaops._lua_setfield = &lua_setfield;
s_luaops._lua_rawset = &lua_rawset;
s_luaops._lua_rawseti = &lua_rawseti;
s_luaops._lua_setmetatable = &lua_setmetatable;
// access functions
s_luaops._lua_isnumber = &lua_isnumber;
s_luaops._lua_isstring = &lua_isstring;
s_luaops._lua_iscfunction = &lua_iscfunction;
s_luaops._lua_isuserdata = &lua_isuserdata;
s_luaops._lua_type = &lua_type;
s_luaops._lua_typename = &lua_typename;
#ifndef XMI_USE_LUAJIT
s_luaops._lua_isinteger = &lua_isinteger;
#endif
s_luaops._lua_tonumberx = &lua_tonumberx;
s_luaops._lua_tointegerx = &lua_tointegerx;
s_luaops._lua_toboolean = &lua_toboolean;
s_luaops._lua_tolstring = &lua_tolstring;
s_luaops._lua_tocfunction = &lua_tocfunction;
s_luaops._lua_touserdata = &lua_touserdata;
s_luaops._lua_tothread = &lua_tothread;
s_luaops._lua_topointer = &lua_topointer;
#ifndef XMI_USE_LUAJIT
s_luaops._lua_rawlen = &lua_rawlen;
#endif
// push functions
s_luaops._lua_pushnil = &lua_pushnil;
s_luaops._lua_pushinteger = &lua_pushinteger;
s_luaops._lua_pushboolean = &lua_pushboolean;
s_luaops._lua_pushnumber = &lua_pushnumber;
s_luaops._lua_pushlstring = &lua_pushlstring;
s_luaops._lua_pushstring = &lua_pushstring;
s_luaops._lua_pushvfstring = &lua_pushvfstring;
s_luaops._lua_pushfstring = &lua_pushfstring;
s_luaops._lua_pushcclosure = &lua_pushcclosure;
s_luaops._lua_pushlightuserdata = &lua_pushlightuserdata;
s_luaops._lua_pushthread = &lua_pushthread;
// stack functions
#ifdef XMI_USE_LUAJIT
s_luaops._lua_insert = &lua_insert;
s_luaops._lua_remove = &lua_remove;
s_luaops._lua_replace = &lua_replace;
#else
s_luaops._lua_absindex = &lua_absindex;
s_luaops._lua_rotate = &lua_rotate;
#endif
s_luaops._lua_gettop = &lua_gettop;
s_luaops._lua_settop = &lua_settop;
s_luaops._lua_pushvalue = &lua_pushvalue;
s_luaops._lua_copy = &lua_copy;
s_luaops._lua_checkstack = &lua_checkstack;
s_luaops._lua_xmove = &lua_xmove;
// miscellaneous functions
s_luaops._lua_error = &lua_error;
s_luaops._lua_next = &lua_next;
s_luaops._lua_concat = &lua_concat;
s_luaops._lua_getallocf = &lua_getallocf;
s_luaops._lua_setallocf = &lua_setallocf;
#ifndef XMI_USE_LUAJIT
s_luaops._lua_len = &lua_len;
s_luaops._lua_toclose = &lua_toclose;
s_luaops._lua_closeslot = &lua_closeslot;
s_luaops._lua_stringtonumber = &lua_stringtonumber;
#endif
// 'load' and 'call' functions
#ifdef XMI_USE_LUAJIT
s_luaops._lua_call = &lua_call;
s_luaops._lua_pcall = &lua_pcall;
#else
s_luaops._lua_callk = &lua_callk;
s_luaops._lua_pcallk = &lua_pcallk;
#endif
s_luaops._lua_load = &lua_load;
s_luaops._lua_dump = &lua_dump;
// luaL functions
#ifndef XMI_USE_LUAJIT
s_luaops._luaL_tolstring = &luaL_tolstring;
s_luaops._luaL_typeerror = &luaL_typeerror;
#endif
s_luaops._luaL_getmetafield = &luaL_getmetafield;
s_luaops._luaL_callmeta = &luaL_callmeta;
s_luaops._luaL_argerror = &luaL_argerror;
s_luaops._luaL_checklstring = &luaL_checklstring;
s_luaops._luaL_optlstring = &luaL_optlstring;
s_luaops._luaL_checknumber = &luaL_checknumber;
s_luaops._luaL_optnumber = &luaL_optnumber;
s_luaops._luaL_checkinteger = &luaL_checkinteger;
s_luaops._luaL_optinteger = &luaL_optinteger;
s_luaops._luaL_checkstack = &luaL_checkstack;
s_luaops._luaL_checktype = &luaL_checktype;
s_luaops._luaL_checkany = &luaL_checkany;
s_luaops._luaL_newmetatable = &luaL_newmetatable;
s_luaops._luaL_testudata = &luaL_testudata;
s_luaops._luaL_checkudata = &luaL_checkudata;
s_luaops._luaL_where = &luaL_where;
s_luaops._luaL_error = &luaL_error;
s_luaops._luaL_checkoption = &luaL_checkoption;
s_luaops._luaL_fileresult = &luaL_fileresult;
s_luaops._luaL_execresult = &luaL_execresult;
s_luaops._luaL_setfuncs = &luaL_setfuncs;
s_luaops._luaL_loadfilex = &luaL_loadfilex;
s_luaops._luaL_loadstring = &luaL_loadstring;
s_luaops_inited = tb_true;
}
xmisetup_func(&s_luaops);
// load module
lua_pushcfunction(lua, luaopen_func);
return 1;
}
================================================
FILE: core/src/xmake/package/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_PACKAGE_PREFIX_H
#define XM_PACKAGE_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/path/absolute.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file absolute.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "absolute"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_path_absolute(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// get the root
tb_char_t const *root = luaL_optstring(lua, 2, tb_null);
// do path:absolute(root)
tb_char_t data[TB_PATH_MAXN];
lua_pushstring(lua, tb_path_absolute_to(root, path, data, sizeof(data) - 1));
return 1;
}
================================================
FILE: core/src/xmake/path/directory.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file directory.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "directory"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_path_directory(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// do path:directory()
tb_char_t data[TB_PATH_MAXN];
tb_char_t const *dir = tb_path_directory(path, data, sizeof(data));
if (dir) {
lua_pushstring(lua, dir);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/path/is_absolute.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file is_absolute.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "is_absolute"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_path_is_absolute(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// path:is_absolute()
lua_pushboolean(lua, tb_path_is_absolute(path));
return 1;
}
================================================
FILE: core/src/xmake/path/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_PATH_PREFIX_H
#define XM_PATH_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/path/relative.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file relative.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "relative"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_path_relative(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
tb_char_t const *path = luaL_checkstring(lua, 1);
tb_check_return_val(path, 0);
// get the root
tb_char_t const *root = luaL_optstring(lua, 2, tb_null);
// path:relative(root)
tb_char_t data[TB_PATH_MAXN];
lua_pushstring(lua, tb_path_relative_to(root, path, data, sizeof(data) - 1));
return 1;
}
================================================
FILE: core/src/xmake/path/translate.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file translate.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "translate"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_path_translate(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the path
size_t path_size = 0;
tb_char_t const *path = luaL_checklstring(lua, 1, &path_size);
tb_check_return_val(path, 0);
// get the option argument, e.g. {normalize = true}
tb_bool_t normalize = tb_false;
if (lua_istable(lua, 2)) {
lua_pushstring(lua, "normalize");
lua_gettable(lua, 2);
if (lua_toboolean(lua, -1)) {
normalize = tb_true;
}
lua_pop(lua, 1);
}
// do path:translate()
tb_char_t data[TB_PATH_MAXN];
tb_size_t size = tb_path_translate_to(path, (tb_size_t)path_size, data, sizeof(data), normalize);
if (size) {
lua_pushlstring(lua, data, (size_t)size);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/prefix/config.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file config.h
*
*/
#ifndef XM_PREFIX_CONFIG_H
#define XM_PREFIX_CONFIG_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../config.h"
#include "tbox/tbox.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
/*! @def __xm_small__
*
* small mode
*/
#if XM_CONFIG_SMALL
#define __xm_small__
#endif
/*! @def __xm_debug__
*
* debug mode
*/
#ifdef __tb_debug__
#define __xm_debug__
#endif
/* unix/gcc on msys/cygwin? do not support it now!
*
* @see https://github.com/xmake-io/xmake/issues/681
*
* on msys:
* pacman -S mingw-w64-i686-gcc
* pacman -S mingw-w64-x86_64-gcc
*
* e.g.
* $ pacman -S mingw-w64-x86_64-gcc
* $ which gcc
* /mingw64/bin/gcc
* $ cd xmake
* $ make build
* $ make install prefix=/mingw64
*/
#if defined(TB_CONFIG_OS_WINDOWS) && defined(TB_COMPILER_LIKE_UNIX)
#error "do not support gcc on msys/cygwin, please uses mingw-w64-[i686|x86_64]-gcc"
#endif
#endif
================================================
FILE: core/src/xmake/prefix/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_PREFIX_PREFIX_H
#define XM_PREFIX_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "config.h"
#include "version.h"
#endif
================================================
FILE: core/src/xmake/prefix/version.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file version.h
*
*/
#ifndef XM_PREFIX_VERSION_H
#define XM_PREFIX_VERSION_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "config.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
/// the major version
#define XM_VERSION_MAJOR XM_CONFIG_VERSION_MAJOR
/// the minor version
#define XM_VERSION_MINOR XM_CONFIG_VERSION_MINOR
/// the alter version
#define XM_VERSION_ALTER XM_CONFIG_VERSION_ALTER
/// the build version
#ifndef XM_CONFIG_VERSION_BUILD
#define XM_CONFIG_VERSION_BUILD 0
#endif
#define XM_VERSION_BUILD XM_CONFIG_VERSION_BUILD
/// the build version string
#define XM_VERSION_BUILD_STRING __tb_mstring_ex__(XM_CONFIG_VERSION_BUILD)
/// the version string
#define XM_VERSION_STRING \
__tb_mstrcat6__("xmake_", \
__tb_mstring_ex__(__tb_mconcat8_ex__( \
v, XM_VERSION_MAJOR, _, XM_VERSION_MINOR, _, XM_VERSION_ALTER, _, XM_CONFIG_VERSION_BUILD)), \
"_", \
TB_ARCH_VERSION_STRING, \
" by ", \
TB_COMPILER_VERSION_STRING)
/// the short version string
#define XM_VERSION_SHORT_STRING \
__tb_mstrcat__("xmake_", \
__tb_mstring_ex__(__tb_mconcat8_ex__( \
v, XM_VERSION_MAJOR, _, XM_VERSION_MINOR, _, XM_VERSION_ALTER, _, XM_CONFIG_VERSION_BUILD)))
#endif
================================================
FILE: core/src/xmake/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_PREFIX_H
#define XM_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix/prefix.h"
#include "luaconf.h"
#if defined(TB_CONFIG_OS_WINDOWS) && defined(__cplusplus)
#undef LUA_API
#undef LUALIB_API
#define LUA_API extern "C"
#define LUALIB_API LUA_API
#endif
#ifdef USE_LUAJIT
#include "luajit.h"
#include "lualib.h"
#include "lauxlib.h"
#else
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// define lua_Unsigned for luajit/lua5.1
#if defined(USE_LUAJIT) || LUA_VERSION_NUM < 503
typedef size_t lua_Unsigned;
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* private interfaces
*/
// this issue has been fixed, @see https://github.com/LuaJIT/LuaJIT/commit/e9af1abec542e6f9851ff2368e7f196b6382a44c
#if 0 //TB_CPU_BIT64
/* we use this interface instead of lua_pushlightuserdata() to fix bad light userdata pointer bug
*
* @see https://github.com/xmake-io/xmake/issues/914
* https://github.com/LuaJIT/LuaJIT/pull/230
*
* @note we cannot lua_newuserdata() because we need pass this pointer to the external lua code
* in poller_wait()/event_callback, but lua_pushuserdata does not exists
*/
static __tb_inline__ tb_void_t xm_lua_pushpointer(lua_State* lua, tb_pointer_t ptr)
{
tb_uint64_t ptrval = (tb_uint64_t)ptr;
if ((ptrval >> 47) == 0)
lua_pushlightuserdata(lua, ptr);
else
{
tb_char_t str[64];
tb_long_t len = tb_snprintf(str, sizeof(str), "%p", ptr);
lua_pushlstring(lua, str, len);
}
}
static __tb_inline__ tb_bool_t xm_lua_ispointer(lua_State* lua, tb_int_t idx)
{
return lua_isuserdata(lua, idx) || lua_isstring(lua, idx);
}
static __tb_inline__ tb_pointer_t xm_lua_topointer2(lua_State* lua, tb_int_t idx, tb_char_t const** pstr)
{
tb_pointer_t ptr = tb_null;
if (lua_isuserdata(lua, idx))
{
ptr = lua_touserdata(lua, idx);
if (pstr) *pstr = tb_null;
}
else
{
size_t len = 0;
tb_char_t const* str = luaL_checklstring(lua, idx, &len);
if (str && len > 2 && str[0] == '0' && str[1] == 'x')
ptr = (tb_pointer_t)tb_s16tou64(str);
if (pstr) *pstr = str;
}
return ptr;
}
static __tb_inline__ tb_pointer_t xm_lua_topointer(lua_State* lua, tb_int_t idx)
{
return xm_lua_topointer2(lua, idx, tb_null);
}
#else
static __tb_inline__ tb_void_t xm_lua_pushpointer(lua_State *lua, tb_pointer_t ptr) {
lua_pushlightuserdata(lua, ptr);
}
static __tb_inline__ tb_bool_t xm_lua_ispointer(lua_State *lua, tb_int_t idx) {
return lua_isuserdata(lua, idx);
}
static __tb_inline__ tb_pointer_t xm_lua_topointer2(lua_State *lua, tb_int_t idx, tb_char_t const **pstr) {
if (pstr)
*pstr = tb_null;
return lua_touserdata(lua, idx);
}
static __tb_inline__ tb_pointer_t xm_lua_topointer(lua_State *lua, tb_int_t idx) {
return lua_touserdata(lua, idx);
}
#endif
static __tb_inline__ tb_void_t xm_lua_register(lua_State *lua, tb_char_t const *libname, luaL_Reg const *l) {
#if LUA_VERSION_NUM >= 504
if (libname) {
lua_getglobal(lua, libname);
if (lua_isnil(lua, -1)) {
lua_pop(lua, 1);
lua_newtable(lua);
}
luaL_setfuncs(lua, l, 0);
lua_setglobal(lua, libname);
} else {
luaL_setfuncs(lua, l, 0);
}
#else
luaL_register(lua, libname, l);
#endif
}
static __tb_inline__ tb_int_t xm_lua_isinteger(lua_State *lua, int idx) {
#ifdef USE_LUAJIT
return lua_isnumber(lua, idx);
#else
return lua_isinteger(lua, idx);
#endif
}
#endif
================================================
FILE: core/src/xmake/process/close.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file close.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "process.close"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// process.close(p)
tb_int_t xm_process_close(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the process
tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(process, 0);
// exit process
tb_process_exit(process);
// save result: ok
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/process/kill.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file kill.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "process.kill"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// process.kill(p)
tb_int_t xm_process_kill(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get the process
tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(process, 0);
// kill process
tb_process_kill(process);
return 0;
}
================================================
FILE: core/src/xmake/process/open.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file open.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "process.open"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../io/prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* p = process.open(command,
* {outpath = "", errpath = "", outfile = "",
* errfile = "", outpipe = "", errpipe = "",
* infile = "", inpipe = "", inpipe = "",
* envs = {"PATH=xxx", "XXX=yyy"}})
*/
tb_int_t xm_process_open(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get command
size_t command_size = 0;
tb_char_t const *command = luaL_checklstring(lua, 1, &command_size);
tb_check_return_val(command, 0);
// init attributes
tb_process_attr_t attr = { 0 };
// get option arguments
tb_size_t envn = 0;
tb_char_t const *envs[1024] = { 0 };
tb_char_t const *inpath = tb_null;
tb_char_t const *outpath = tb_null;
tb_char_t const *errpath = tb_null;
xm_io_file_t *infile = tb_null;
xm_io_file_t *outfile = tb_null;
xm_io_file_t *errfile = tb_null;
tb_pipe_file_ref_t inpipe = tb_null;
tb_pipe_file_ref_t outpipe = tb_null;
tb_pipe_file_ref_t errpipe = tb_null;
if (lua_istable(lua, 2)) {
// is detached?
lua_pushstring(lua, "detach");
lua_gettable(lua, 2);
if (lua_toboolean(lua, -1)) {
attr.flags |= TB_PROCESS_FLAG_DETACH;
}
lua_pop(lua, 1);
// get curdir
lua_pushstring(lua, "curdir");
lua_gettable(lua, 3);
attr.curdir = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get inpath
lua_pushstring(lua, "inpath");
lua_gettable(lua, 2);
inpath = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get outpath
lua_pushstring(lua, "outpath");
lua_gettable(lua, 2);
outpath = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get errpath
lua_pushstring(lua, "errpath");
lua_gettable(lua, 2);
errpath = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get infile
if (!inpath) {
lua_pushstring(lua, "infile");
lua_gettable(lua, 3);
infile = (xm_io_file_t *)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get outfile
if (!outpath) {
lua_pushstring(lua, "outfile");
lua_gettable(lua, 3);
outfile = (xm_io_file_t *)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get errfile
if (!errpath) {
lua_pushstring(lua, "errfile");
lua_gettable(lua, 3);
errfile = (xm_io_file_t *)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get inpipe
if (!inpath && !infile) {
lua_pushstring(lua, "inpipe");
lua_gettable(lua, 3);
inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get outpipe
if (!outpath && !outfile) {
lua_pushstring(lua, "outpipe");
lua_gettable(lua, 3);
outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get errpipe
if (!errpath && !errfile) {
lua_pushstring(lua, "errpipe");
lua_gettable(lua, 3);
errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get environments
lua_pushstring(lua, "envs");
lua_gettable(lua, 2);
if (lua_istable(lua, -1)) {
// get environment variables count
tb_size_t count = (tb_size_t)lua_objlen(lua, -1);
// get all passed environment variables
tb_size_t i;
for (i = 0; i < count; i++) {
// get envs[i]
lua_pushinteger(lua, i + 1);
lua_gettable(lua, -2);
// is string?
if (lua_isstring(lua, -1)) {
// add this environment value
if (envn + 1 < tb_arrayn(envs)) {
envs[envn++] = lua_tostring(lua, -1);
} else {
// error
lua_pushfstring(lua,
"envs is too large(%d > %d) for process.openv",
(tb_int_t)envn,
tb_arrayn(envs) - 1);
lua_error(lua);
}
} else {
// error
lua_pushfstring(lua,
"invalid envs[%d] type(%s) for process.openv",
(tb_int_t)i,
luaL_typename(lua, -1));
lua_error(lua);
}
// pop it
lua_pop(lua, 1);
}
}
lua_pop(lua, 1);
}
// redirect stdin?
if (inpath) {
// redirect stdin to file
attr.in.path = inpath;
attr.inmode = TB_FILE_MODE_RO;
attr.intype = TB_PROCESS_REDIRECT_TYPE_FILEPATH;
} else if (infile && xm_io_file_is_file(infile)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(infile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {
attr.in.file = rawfile;
attr.intype = TB_PROCESS_REDIRECT_TYPE_FILE;
}
} else if (inpipe) {
attr.in.pipe = inpipe;
attr.intype = TB_PROCESS_REDIRECT_TYPE_PIPE;
}
// redirect stdout?
if (outpath) {
// redirect stdout to file
attr.out.path = outpath;
attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;
attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH;
} else if (outfile && xm_io_file_is_file(outfile)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(outfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {
attr.out.file = rawfile;
attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILE;
}
} else if (outpipe) {
attr.out.pipe = outpipe;
attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE;
}
// redirect stderr?
if (errpath) {
// redirect stderr to file
attr.err.path = errpath;
attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;
attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH;
} else if (errfile && xm_io_file_is_file(errfile)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(errfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {
attr.err.file = rawfile;
attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILE;
}
} else if (errpipe) {
attr.err.pipe = errpipe;
attr.errtype = TB_PROCESS_REDIRECT_TYPE_PIPE;
}
// set the new environments
if (envn > 0) {
attr.envp = envs;
}
// init process
tb_process_ref_t process = (tb_process_ref_t)tb_process_init_cmd(command, &attr);
if (process) {
xm_lua_pushpointer(lua, (tb_pointer_t)process);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/process/openv.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file openv.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "process.openv"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../io/prefix.h"
#if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_LINUX) || defined(TB_CONFIG_OS_BSD) || \
defined(TB_CONFIG_OS_HAIKU) || defined(TB_COMPILER_IS_MINGW)
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* p = process.openv(shellname, argv,
* {outpath = "", errpath = "", outfile = "",
* errfile = "", outpipe = "", errpipe = "",
* infile = "", inpipe = "", inpipe = "",
* envs = {"PATH=xxx", "XXX=yyy"}})
*/
tb_int_t xm_process_openv(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// check argv
if (!lua_istable(lua, 2)) {
// error
lua_pushfstring(lua, "invalid argv type(%s) for process.openv", luaL_typename(lua, 2));
lua_error(lua);
return 0;
}
// get shellname
tb_char_t const *shellname = lua_tostring(lua, 1);
tb_check_return_val(shellname, 0);
// get the arguments count
tb_long_t argn = (tb_long_t)lua_objlen(lua, 2);
tb_check_return_val(argn >= 0, 0);
// get arguments
tb_size_t argi = 0;
tb_char_t const **argv = tb_nalloc0_type(1 + argn + 1, tb_char_t const *);
tb_check_return_val(argv, 0);
// fill arguments
argv[0] = shellname;
for (argi = 0; argi < argn; argi++) {
// get argv[i]
lua_pushinteger(lua, argi + 1);
lua_gettable(lua, 2);
// is string?
if (lua_isstring(lua, -1)) {
// pass this argument
argv[1 + argi] = lua_tostring(lua, -1);
}
// is path instance?
else if (lua_istable(lua, -1)) {
lua_pushstring(lua, "_STR");
lua_gettable(lua, -2);
argv[1 + argi] = lua_tostring(lua, -1);
lua_pop(lua, 1);
} else {
// error
lua_pushfstring(lua, "invalid argv[%d] type(%s) for process.openv", (tb_int_t)argi, luaL_typename(lua, -1));
lua_error(lua);
}
// pop it
lua_pop(lua, 1);
}
// init attributes
tb_process_attr_t attr = { 0 };
// get option arguments
tb_bool_t exclusive = tb_false;
tb_size_t envn = 0;
tb_char_t const *envs[1024] = { 0 };
tb_char_t const *inpath = tb_null;
tb_char_t const *outpath = tb_null;
tb_char_t const *errpath = tb_null;
xm_io_file_t *infile = tb_null;
xm_io_file_t *outfile = tb_null;
xm_io_file_t *errfile = tb_null;
tb_pipe_file_ref_t inpipe = tb_null;
tb_pipe_file_ref_t outpipe = tb_null;
tb_pipe_file_ref_t errpipe = tb_null;
if (lua_istable(lua, 3)) {
// is detached?
lua_pushstring(lua, "detach");
lua_gettable(lua, 3);
if (lua_toboolean(lua, -1)) {
attr.flags |= TB_PROCESS_FLAG_DETACH;
}
lua_pop(lua, 1);
// is exclusive?
lua_pushstring(lua, "exclusive");
lua_gettable(lua, 3);
if (lua_toboolean(lua, -1)) {
exclusive = tb_true;
}
lua_pop(lua, 1);
// get curdir
lua_pushstring(lua, "curdir");
lua_gettable(lua, 3);
attr.curdir = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get inpath
lua_pushstring(lua, "inpath");
lua_gettable(lua, 3);
inpath = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get outpath
lua_pushstring(lua, "outpath");
lua_gettable(lua, 3);
outpath = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get errpath
lua_pushstring(lua, "errpath");
lua_gettable(lua, 3);
errpath = lua_tostring(lua, -1);
lua_pop(lua, 1);
// get infile
if (!inpath) {
lua_pushstring(lua, "infile");
lua_gettable(lua, 3);
infile = (xm_io_file_t *)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get outfile
if (!outpath) {
lua_pushstring(lua, "outfile");
lua_gettable(lua, 3);
outfile = (xm_io_file_t *)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get errfile
if (!errpath) {
lua_pushstring(lua, "errfile");
lua_gettable(lua, 3);
errfile = (xm_io_file_t *)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get inpipe
if (!inpath && !infile) {
lua_pushstring(lua, "inpipe");
lua_gettable(lua, 3);
inpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get outpipe
if (!outpath && !outfile) {
lua_pushstring(lua, "outpipe");
lua_gettable(lua, 3);
outpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get errpipe
if (!errpath && !errfile) {
lua_pushstring(lua, "errpipe");
lua_gettable(lua, 3);
errpipe = (tb_pipe_file_ref_t)lua_touserdata(lua, -1);
lua_pop(lua, 1);
}
// get environments
lua_pushstring(lua, "envs");
lua_gettable(lua, 3);
if (lua_istable(lua, -1)) {
// get environment variables count
tb_size_t count = (tb_size_t)lua_objlen(lua, -1);
// get all passed environment variables
tb_size_t i;
for (i = 0; i < count; i++) {
// get envs[i]
lua_pushinteger(lua, i + 1);
lua_gettable(lua, -2);
// is string?
if (lua_isstring(lua, -1)) {
// add this environment value
if (envn + 1 < tb_arrayn(envs)) {
envs[envn++] = lua_tostring(lua, -1);
} else {
// error
lua_pushfstring(lua,
"envs is too large(%d > %d) for process.openv",
(tb_int_t)envn,
tb_arrayn(envs) - 1);
lua_error(lua);
}
} else {
// error
lua_pushfstring(lua,
"invalid envs[%d] type(%s) for process.openv",
(tb_int_t)i,
luaL_typename(lua, -1));
lua_error(lua);
}
// pop it
lua_pop(lua, 1);
}
}
lua_pop(lua, 1);
}
// redirect stdin?
if (inpath) {
// redirect stdin to file
attr.in.path = inpath;
attr.inmode = TB_FILE_MODE_RO;
attr.intype = TB_PROCESS_REDIRECT_TYPE_FILEPATH;
} else if (infile && xm_io_file_is_file(infile)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(infile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {
attr.in.file = rawfile;
attr.intype = TB_PROCESS_REDIRECT_TYPE_FILE;
}
} else if (inpipe) {
attr.in.pipe = inpipe;
attr.intype = TB_PROCESS_REDIRECT_TYPE_PIPE;
}
// redirect stdout?
if (outpath) {
// redirect stdout to file
attr.out.path = outpath;
attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;
attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH;
} else if (outfile && xm_io_file_is_file(outfile)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(outfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {
attr.out.file = rawfile;
attr.outtype = TB_PROCESS_REDIRECT_TYPE_FILE;
}
} else if (outpipe) {
attr.out.pipe = outpipe;
attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE;
}
// redirect stderr?
if (errpath) {
// redirect stderr to file
attr.err.path = errpath;
attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_TRUNC | TB_FILE_MODE_CREAT;
attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILEPATH;
} else if (errfile && xm_io_file_is_file(errfile)) {
tb_file_ref_t rawfile = tb_null;
if (tb_stream_ctrl(errfile->stream, TB_STREAM_CTRL_FILE_GET_FILE, &rawfile) && rawfile) {
attr.err.file = rawfile;
attr.errtype = TB_PROCESS_REDIRECT_TYPE_FILE;
}
} else if (errpipe) {
attr.err.pipe = errpipe;
attr.errtype = TB_PROCESS_REDIRECT_TYPE_PIPE;
}
// set the new environments
if (envn > 0) {
attr.envp = envs;
}
/* we need to ignore SIGINT and SIGQUIT if we enter exclusive mode
* @see https://github.com/xmake-io/xmake/discussions/2893
*/
#if defined(SIGINT)
if (exclusive) {
signal(SIGINT, SIG_IGN);
}
#endif
#if defined(SIGQUIT)
if (exclusive) {
signal(SIGQUIT, SIG_IGN);
}
#endif
// init process
tb_process_ref_t process = (tb_process_ref_t)tb_process_init(shellname, argv, &attr);
if (process) {
xm_lua_pushpointer(lua, (tb_pointer_t)process);
} else {
lua_pushnil(lua);
}
// exit argv
if (argv) {
tb_free(argv);
}
argv = tb_null;
return 1;
}
================================================
FILE: core/src/xmake/process/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_PROCESS_PREFIX_H
#define XM_PROCESS_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/process/wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "process.wait"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// ok, status = process.wait(proc, timeout)
tb_int_t xm_process_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
// error
lua_pushfstring(lua, "invalid argument type(%s) for process.wait", luaL_typename(lua, 1));
lua_error(lua);
return 0;
}
// get the process
tb_process_ref_t process = (tb_process_ref_t)xm_lua_topointer(lua, 1);
tb_check_return_val(process, 0);
// get the timeout
tb_long_t timeout = (tb_long_t)luaL_checkinteger(lua, 2);
// wait it
tb_long_t status = 0;
tb_long_t ok = tb_process_wait(process, &status, timeout);
// save result
lua_pushinteger(lua, ok);
lua_pushinteger(lua, status);
return 2;
}
================================================
FILE: core/src/xmake/readline/add_history.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file add_history.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "add_history"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
#ifdef XM_CONFIG_API_HAVE_READLINE
// add_history wrapper
tb_int_t xm_readline_add_history(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get history
tb_char_t const *history = luaL_checkstring(lua, 1);
tb_check_return_val(history, 0);
// call add_history
add_history(history);
return 0;
}
#endif
================================================
FILE: core/src/xmake/readline/clear_history.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file clear_history.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "clear_history"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
#ifdef XM_CONFIG_API_HAVE_READLINE
// clear_history wrapper
tb_int_t xm_readline_clear_history(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
#ifdef TB_CONFIG_OS_MACOSX
// call clear_history (will crash on macOS)
for (tb_int_t i = history_length - 1; i >= 0; --i) {
remove_history(i);
}
#else
clear_history();
#endif
return 0;
}
#endif
================================================
FILE: core/src/xmake/readline/history_list.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file history_list.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "history_list"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
#ifdef XM_CONFIG_API_HAVE_READLINE
// history_list wrapper
tb_int_t xm_readline_history_list(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// history list
lua_newtable(lua);
#ifdef TB_CONFIG_OS_MACOSX
for (tb_int_t i = 1; i <= history_length; ++i) {
lua_newtable(lua);
// field line
lua_pushstring(lua, "line");
lua_pushstring(lua, history_get(i)->line);
lua_settable(lua, -3);
// set back
lua_rawseti(lua, -2, i);
}
#else
tb_int_t i = 1;
for (HIST_ENTRY **p = history_list(); *p; ++p, ++i) {
lua_newtable(lua);
// field line
lua_pushstring(lua, "line");
lua_pushstring(lua, (*p)->line);
lua_settable(lua, -3);
// set back
lua_rawseti(lua, -2, i);
}
#endif
return 1;
}
#endif
================================================
FILE: core/src/xmake/readline/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file prefix.h
*
*/
#ifndef XM_READLINE_PREFIX_H
#define XM_READLINE_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#ifdef XM_CONFIG_API_HAVE_READLINE
#include // on some OS (like centos) required
#include
#include
#endif
#endif
================================================
FILE: core/src/xmake/readline/readline.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow
* @file readline.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "readline"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef XM_CONFIG_API_HAVE_READLINE
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// readline wrapper
tb_int_t xm_readline_readline(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the prompt
tb_char_t const *prompt = luaL_optstring(lua, 1, tb_null);
// call readline
tb_char_t *line = readline(prompt);
if (line) {
// return line
lua_pushstring(lua, line);
// free it
tb_free(line);
} else {
lua_pushnil(lua);
}
return 1;
}
#endif
================================================
FILE: core/src/xmake/sandbox/interactive.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file interactive.c
*
*/
/* Runs interactive commands, read-eval-print (REPL)
*
* Major portions taken verbatim or adapted from LuaJIT frontend and the Lua interpreter.
* Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "sandbox.interactive"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../winos/ansi.h"
#ifdef XM_CONFIG_API_HAVE_READLINE
#include
#include
#include
#include // on some OS (like centos) required
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
// buffer size for prompt
#define LUA_PROMPT_BUFSIZE 4096
// for lua5.4
#ifndef LUA_QL
#define LUA_QL(x) "'" x "'"
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
// report results
static tb_void_t xm_sandbox_report(lua_State *lua) {
if (!lua_isnil(lua, -1)) {
// get message
tb_char_t const *msg = lua_tostring(lua, -1);
if (!msg) {
msg = "(error object is not a string)";
}
// print it
tb_printl(msg);
tb_print_sync();
// pop this message
lua_pop(lua, 1);
}
}
// the traceback function
static tb_int_t xm_sandbox_traceback(lua_State *lua) {
if (!lua_isstring(lua, 1)) {
// non-string error object? try metamethod.
if (lua_isnoneornil(lua, 1) || !luaL_callmeta(lua, 1, "__tostring") || !lua_isstring(lua, -1)) {
return 1; // return non-string error object.
}
// replace object by result of __tostring metamethod.
lua_remove(lua, 1);
}
// return backtrace
luaL_traceback(lua, lua, lua_tostring(lua, 1), 1);
return 1;
}
// execute codes
static tb_int_t xm_sandbox_docall(lua_State *lua, tb_int_t narg, tb_int_t clear) {
/* get error function index
*
* stack: arg1(sandbox_scope) scriptfunc(top) -> ...
*/
tb_int_t errfunc = lua_gettop(lua) - narg;
// push traceback function
lua_pushcfunction(lua, xm_sandbox_traceback);
// put it under chunk and args
lua_insert(lua, errfunc);
/* execute it
*
* stack: errfunc arg1 scriptfunc -> ...
* after: errfunc arg1 [results] -> ...
*/
tb_int_t status = lua_pcall(lua, narg, (clear ? 0 : LUA_MULTRET), errfunc);
// remove traceback function
lua_remove(lua, errfunc);
// force a complete garbage collection in case of errors
if (status != 0) {
lua_gc(lua, LUA_GCCOLLECT, 0);
}
return status;
}
// this line is incomplete?
static tb_int_t xm_sandbox_incomplete(lua_State *lua, tb_int_t status) {
// syntax error?
if (status == LUA_ERRSYNTAX) {
size_t lmsg;
tb_char_t const *msg = lua_tolstring(lua, -1, &lmsg);
tb_char_t const *tp = msg + lmsg - (sizeof(LUA_QL("")) - 1);
if (tb_strstr(msg, LUA_QL("")) == tp) {
lua_pop(lua, 1);
return 1;
}
}
return 0;
}
// read line
static tb_size_t xm_sandbox_readline(tb_char_t *data, tb_size_t maxn, tb_char_t const *prompt) {
#ifdef XM_CONFIG_API_HAVE_READLINE
// get line
tb_char_t const *line = readline(prompt);
if (line) {
// add line to history
add_history(line);
// copy line to data
tb_size_t size = tb_strlcpy(data, line, maxn);
// free line
free((void *)line);
// truncated?
if (size >= maxn) {
return 0;
}
return size;
}
#else
// print prompt
tb_printf(prompt);
tb_print_sync();
// get input buffer
if (tb_stdfile_gets(tb_stdfile_input(), data, maxn)) {
return tb_strlen(data);
}
#endif
// no more input
return 0;
}
// read and push input line
static tb_int_t xm_sandbox_pushline(lua_State *lua, tb_char_t const *prompt2) {
// read line
tb_char_t data[LUA_PROMPT_BUFSIZE];
tb_size_t size = xm_sandbox_readline(data, sizeof(data), prompt2);
if (size) {
// split line '\0'
if (data[size - 1] == '\n') {
data[size - 1] = '\0';
}
// push line
lua_pushstring(lua, data);
return 1;
}
// no input
return 0;
}
// load code line
static tb_int_t xm_sandbox_loadline(lua_State *lua, tb_int_t top) {
// clear stack
lua_settop(lua, top);
// get prompt strings from arg1(sandbox_scope)
lua_pushstring(lua, "$interactive_prompt");
lua_gettable(lua, 1);
tb_char_t const *prompt = lua_tostring(lua, -1);
lua_pop(lua, 1);
lua_pushstring(lua, "$interactive_prompt2");
lua_gettable(lua, 1);
tb_char_t const *prompt2 = lua_tostring(lua, -1);
lua_pop(lua, 1);
// read first line
tb_int_t status;
tb_char_t data[LUA_PROMPT_BUFSIZE];
tb_size_t size = xm_sandbox_readline(data + 7, sizeof(data) - 7, prompt);
if (size) {
// split line '\0'
if (data[size - 1] == '\n') {
data[--size] = '\0';
}
// patch "return "
tb_memcpy(data, "return ", 7);
// attempt to load "return ..."
status = luaL_loadbuffer(lua, data, size + 7, "=stdin");
if (status != LUA_ERRSYNTAX) {
return status;
}
// pop error msg
lua_pop(lua, 1);
// push line to load it again
lua_pushstring(lua, data + 7);
} else
return -1;
// load input line
while (1) {
/* repeat until gets a complete line
*
* stack: arg1(sandbox_scope) scriptbuffer(top) -> ...
* after: arg1(sandbox_scope) scriptbuffer scriptfunc(top) -> ...
*/
status = luaL_loadbuffer(lua, lua_tostring(lua, -1), (size_t)lua_strlen(lua, -1), "=stdin");
// complete?
if (!xm_sandbox_incomplete(lua, status)) {
break;
}
// get more input
if (!xm_sandbox_pushline(lua, prompt2)) {
return -1;
}
// cancel multi-line input?
if (!tb_strcmp(lua_tostring(lua, -1), "q")) {
lua_pop(lua, 2);
lua_pushstring(lua, "return ");
continue;
}
/* add a new line
*
* stack: arg1 scriptbuffer scriptfunc scriptbuffer "\n"(top) -> ...
*/
lua_pushliteral(lua, "\n");
// between the two lines
lua_insert(lua, -2);
/* join them
*
* stack: arg1 scriptbuffer scriptfunc scriptbuffer scriptbuffer "\n"(top) -> ...
* after: arg1 scriptbuffer scriptfunc scriptbuffer+"\n"(top) -> ...
*/
lua_concat(lua, 3);
}
// remove redundant scriptbuffer
lua_remove(lua, -2);
return status;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// sandbox.interactive()
tb_int_t xm_sandbox_interactive(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
/* get init stack top
*
* stack: arg1(sandbox_scope)
*/
tb_int_t top = lua_gettop(lua);
// enter interactive
tb_int_t status;
while ((status = xm_sandbox_loadline(lua, top)) != -1) {
// execute codes
if (status == 0) {
/* bind sandbox
*
* stack: arg1(top) scriptfunc arg1(sandbox_scope) -> ...
*/
#ifdef USE_LUAJIT
lua_pushvalue(lua, 1);
lua_setfenv(lua, -2);
#else
// stack: arg1(top) scriptfunc $interactive_setfenv scriptfunc arg1(sandbox_scope) -> ...
lua_getfield(lua, 1, "$interactive_setfenv");
lua_pushvalue(lua, -2);
lua_pushvalue(lua, 1);
if (lua_pcall(lua, 2, 0, 0) != 0) {
tb_printl(lua_pushfstring(lua,
"error calling " LUA_QL("$interactive_setfenv") " (%s)",
lua_tostring(lua, -1)));
}
#endif
/* run script
*
* stack: arg1(top) scriptfunc -> ...
*/
status = xm_sandbox_docall(lua, 0, 0);
}
// report errors
if (status) {
xm_sandbox_report(lua);
}
// print any results
if (status == 0 && lua_gettop(lua) > top) {
// get results count
tb_int_t count = lua_gettop(lua) - top;
/* dump results
*
* stack: arg1(sandbox_scope) [results] -> ...
* after: arg1(sandbox_scope) $interactive_dump [results] -> ...
*/
lua_getfield(lua, 1, "$interactive_dump"); // load $interactive_dump() from sandbox_scope
lua_insert(lua, -(count + 1));
if (lua_pcall(lua, count, 0, 0) != 0) {
tb_printl(
lua_pushfstring(lua, "error calling " LUA_QL("$interactive_dump") " (%s)", lua_tostring(lua, -1)));
}
}
}
// clear stack
lua_settop(lua, top);
tb_printl("");
tb_print_sync();
return 0;
}
================================================
FILE: core/src/xmake/sandbox/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_SANDBOX_PREFIX_H
#define XM_SANDBOX_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/semver/compare.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file compare.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "compare"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// semver.compare("v1.0.1-beta", "1.2") > 0?
tb_int_t xm_semver_compare(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the version1 string
tb_char_t const *version1_str = luaL_checkstring(lua, 1);
tb_check_return_val(version1_str, 0);
// get the version2 string
tb_char_t const *version2_str = luaL_checkstring(lua, 2);
tb_check_return_val(version2_str, 0);
// try to parse version1 string
semver_t semver1 = { 0 };
if (semver_tryn(&semver1, version1_str, tb_strlen(version1_str))) {
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver '%s'", version1_str);
return 2;
}
// try to parse version2 string
semver_t semver2 = { 0 };
if (semver_tryn(&semver2, version2_str, tb_strlen(version2_str))) {
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver '%s'", version2_str);
return 2;
}
// do compare
lua_pushinteger(lua, semver_pcmp(&semver1, &semver2));
semver_dtor(&semver1);
semver_dtor(&semver2);
return 1;
}
================================================
FILE: core/src/xmake/semver/parse.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file parse.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "parse"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* version = semver.parse("v1.0.1-beta")
*
*
{
patch = 1
, raw = v1.0.1-beta
, version = v1.0.1-beta
, major = 1
, build =
{
}
, minor = 0
, prerelease =
{
beta
}
}
*
*/
tb_int_t xm_semver_parse(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the version string
tb_char_t const *version_str = luaL_checkstring(lua, 1);
tb_check_return_val(version_str, 0);
// try to parse version string
semver_t semver = { 0 };
if (semver_tryn(&semver, version_str, tb_strlen(version_str))) {
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver '%s'", version_str);
return 2;
}
lua_pushsemver(lua, &semver);
semver_dtor(&semver);
return 1;
}
================================================
FILE: core/src/xmake/semver/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file prefix.h
*
*/
#ifndef XM_SEMVER_PREFIX_H
#define XM_SEMVER_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#include "semver.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_enter__
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
/* push struct semver
*
* @param lua the lua context
* @param semver the semver struct
*
*/
tb_void_t
lua_pushsemver(lua_State *lua, semver_t const *semver);
/* //////////////////////////////////////////////////////////////////////////////////////
* leave
*/
__tb_extern_c_leave__
#endif
================================================
FILE: core/src/xmake/semver/satisfies.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file satisfies.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "satisfies"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* satisfies the given version range?
*
* semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') => true
*/
tb_int_t xm_semver_satisfies(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the version string
tb_char_t const *version_str = luaL_checkstring(lua, 1);
tb_char_t const *range_str = luaL_checkstring(lua, 2);
tb_assert_and_check_return_val(version_str && range_str, 0);
// parse the version range string
semver_range_t range = { 0 };
if (semver_rangen(&range, range_str, tb_strlen(range_str))) {
// range is branch name? try to match it
semver_t range_semver = { 0 };
if (!tb_strcmp(version_str, range_str)) {
lua_pushboolean(lua, tb_true);
return 1;
}
// range is a single version? try to compare it
else if (!semver_tryn(&range_semver, range_str, tb_strlen(range_str))) {
semver_t semver = { 0 };
if (!semver_tryn(&semver, version_str, tb_strlen(version_str))) {
lua_pushboolean(lua, semver_pcmp(&semver, &range_semver) == 0);
semver_dtor(&semver);
semver_dtor(&range_semver);
return 1;
} else {
semver_dtor(&range_semver);
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver '%s'", version_str);
return 2;
}
} else {
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver range '%s'", range_str);
return 2;
}
}
// try to parse the version string
semver_t semver = { 0 };
if (semver_tryn(&semver, version_str, tb_strlen(version_str))) {
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver '%s'", version_str);
return 2;
}
// satisfies this range?
lua_pushboolean(lua, semver_range_match(semver, range));
semver_dtor(&semver);
semver_range_dtor(&range);
return 1;
}
================================================
FILE: core/src/xmake/semver/select.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file select.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "select"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_semver_select_from_versions_tags1(
lua_State *lua, tb_int_t fromidx, semver_t *semver, semver_range_t const *range, semvers_t *matches) {
// clear matches
semvers_pclear(matches);
// select all matches
lua_Integer i = 0;
luaL_checktype(lua, fromidx, LUA_TTABLE);
for (i = lua_objlen(lua, fromidx); i > 0; --i) {
lua_pushinteger(lua, i);
lua_gettable(lua, fromidx);
tb_char_t const *source_str = luaL_checkstring(lua, -1);
if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) {
if (semver_range_pmatch(semver, range)) {
semvers_ppush(matches, *semver);
} else {
semver_dtor(semver);
}
}
lua_pop(lua, 1);
}
// no matches?
tb_check_return_val(matches->length, tb_false);
// sort matches
semvers_psort(matches);
// get the newest version
semver_t top = semvers_ppop(matches);
lua_createtable(lua, 0, 2);
// return results
lua_pushstring(lua, top.raw);
lua_setfield(lua, -2, "version");
lua_pushstring(lua, fromidx == 2 ? "version" : "tag");
lua_setfield(lua, -2, "source");
// exit the popped semver
semver_dtor(&top);
return tb_true;
}
static tb_bool_t xm_semver_select_from_versions_tags2(
lua_State *lua, tb_int_t fromidx, semver_t *semver, tb_char_t const *version_str, tb_size_t version_len) {
lua_Integer i = 0;
luaL_checktype(lua, fromidx, LUA_TTABLE);
for (i = lua_objlen(lua, fromidx); i > 0; --i) {
lua_pushinteger(lua, i);
lua_gettable(lua, fromidx);
tb_char_t const *source_str = luaL_checkstring(lua, -1);
tb_size_t source_len = tb_strlen(source_str);
lua_pop(lua, 1);
if (source_len == version_len && tb_strncmp(source_str, version_str, version_len) == 0) {
lua_createtable(lua, 0, 2);
lua_pushlstring(lua, source_str, source_len);
lua_setfield(lua, -2, "version");
lua_pushstring(lua, fromidx == 2 ? "version" : "tag");
lua_setfield(lua, -2, "source");
return tb_true;
}
}
return tb_false;
}
static tb_bool_t xm_semver_select_from_branches(lua_State *lua,
tb_int_t fromidx,
tb_char_t const *range_str,
tb_size_t range_len) {
lua_Integer i = 0;
luaL_checktype(lua, fromidx, LUA_TTABLE);
for (i = lua_objlen(lua, fromidx); i > 0; --i) {
lua_pushinteger(lua, i);
lua_gettable(lua, fromidx);
tb_char_t const *source_str = luaL_checkstring(lua, -1);
tb_size_t source_len = tb_strlen(source_str);
lua_pop(lua, 1);
if (source_len == range_len && tb_memcmp(source_str, range_str, source_len) == 0) {
lua_createtable(lua, 0, 2);
lua_pushlstring(lua, source_str, source_len);
lua_setfield(lua, -2, "version");
lua_pushstring(lua, "branch");
lua_setfield(lua, -2, "source");
return tb_true;
}
}
return tb_false;
}
static tb_bool_t xm_semver_select_latest_from_versions_tags(lua_State *lua,
tb_int_t fromidx,
semver_t *semver,
semvers_t *matches) {
// clear matches
semvers_pclear(matches);
// push all versions to matches
lua_Integer i = 0;
luaL_checktype(lua, fromidx, LUA_TTABLE);
for (i = lua_objlen(lua, fromidx); i > 0; --i) {
lua_pushinteger(lua, i);
lua_gettable(lua, fromidx);
tb_char_t const *source_str = luaL_checkstring(lua, -1);
if (source_str && semver_tryn(semver, source_str, tb_strlen(source_str)) == 0) {
semvers_ppush(matches, *semver);
}
lua_pop(lua, 1);
}
tb_check_return_val(matches->length, tb_false);
// sort matches
semvers_psort(matches);
// get the newest match
semver_t top = semvers_ppop(matches);
lua_createtable(lua, 0, 2);
// return results
lua_pushstring(lua, top.raw);
lua_setfield(lua, -2, "version");
lua_pushstring(lua, fromidx == 2 ? "version" : "tag");
lua_setfield(lua, -2, "source");
semver_dtor(&top);
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* select version
*
* local versioninfo, errors = semver.select(">=1.5.0 <1.6", {"1.5.0", "1.5.1"}, {"v1.5.0", ..}, {"latest", "dev"})
*/
tb_int_t xm_semver_select(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// select version
tb_bool_t ok = tb_false;
tb_bool_t is_range = tb_false;
tb_char_t const *range_str = tb_null;
semver_t semver = { 0 };
semvers_t matches = { 0 };
semver_range_t range = { 0 };
do {
// get the version range string
range_str = luaL_checkstring(lua, 1);
tb_check_break(range_str);
// get the range string length
tb_size_t range_len = tb_strlen(range_str);
// parse the version range string
is_range = semver_rangen(&range, range_str, range_len) == 0;
if (is_range) {
// attempt to select version from the versions list first
if (xm_semver_select_from_versions_tags1(lua, 2, &semver, &range, &matches)) {
ok = tb_true;
break;
}
// attempt to select version from the tags list
if (xm_semver_select_from_versions_tags1(lua, 3, &semver, &range, &matches)) {
ok = tb_true;
break;
}
} else {
// attempt to select version from the versions list first
if (xm_semver_select_from_versions_tags2(lua, 2, &semver, range_str, range_len)) {
ok = tb_true;
break;
}
// attempt to select version from the tags list
if (xm_semver_select_from_versions_tags2(lua, 3, &semver, range_str, range_len)) {
ok = tb_true;
break;
}
}
// attempt to select version from the branches
if (xm_semver_select_from_branches(lua, 4, range_str, range_len)) {
ok = tb_true;
break;
}
// select the latest version from the tags and versions if be latest
if (!tb_strcmp(range_str, "latest")) {
// attempt to select latest version from the versions list
if (xm_semver_select_latest_from_versions_tags(lua, 2, &semver, &matches)) {
ok = tb_true;
break;
}
// attempt to select latest version from the tags list
if (xm_semver_select_latest_from_versions_tags(lua, 3, &semver, &matches)) {
ok = tb_true;
break;
}
}
} while (0);
// exit matches
semvers_dtor(matches);
// exit range
semver_range_dtor(&range);
// failed?
if (!ok) {
if (!is_range) {
lua_pushnil(lua);
lua_pushfstring(lua, "unable to parse semver range '%s'", range_str);
}
lua_pushnil(lua);
lua_pushfstring(lua, "unable to select version for range '%s'", range_str);
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/semver/semver.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author uael
* @file semver.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "semver"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_void_t lua_pushsemver(lua_State *lua, semver_t const *semver) {
tb_assert(lua && semver);
// return a semver table
lua_createtable(lua, 0, 7);
lua_pushstring(lua, semver->raw);
lua_setfield(lua, -2, "raw");
lua_pushlstring(lua, semver->raw, semver->len);
lua_setfield(lua, -2, "version");
lua_pushinteger(lua, semver->major);
lua_setfield(lua, -2, "major");
lua_pushinteger(lua, semver->minor);
lua_setfield(lua, -2, "minor");
lua_pushinteger(lua, semver->patch);
lua_setfield(lua, -2, "patch");
// push prelease table
lua_pushstring(lua, "prerelease");
lua_newtable(lua);
tb_uchar_t i = 0;
semver_id_t const *id = &semver->prerelease;
while (id && id->len) {
if (id->numeric) {
lua_pushinteger(lua, id->num);
} else {
lua_pushlstring(lua, id->raw, id->len);
}
id = id->next;
lua_rawseti(lua, -2, ++i);
}
lua_settable(lua, -3);
// push the build table
i = 0;
lua_pushstring(lua, "build");
lua_newtable(lua);
id = &semver->build;
while (id && id->len) {
if (id->numeric) {
lua_pushinteger(lua, id->num);
} else {
lua_pushlstring(lua, id->raw, id->len);
}
id = id->next;
lua_rawseti(lua, -2, ++i);
}
lua_settable(lua, -3);
}
================================================
FILE: core/src/xmake/string/convert.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file convert.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "convert"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../utils/charset.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* convert string
*
* @param str the string
* @param ftype the from-charset type, e.g. ascii, gb2312, gbk, ios8859, ucs2, ucs4, utf8, utf16, utf32
* @param ttype the to-charset type
*
* @code
* local result = string.convert(str, "gbk", "utf8")
* local result = string.convert(str, "utf8", "gb2312")
* @endcode
*/
tb_int_t xm_string_convert(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the string and charset types
size_t src_size = 0;
tb_char_t const *src_cstr = luaL_checklstring(lua, 1, &src_size);
tb_char_t const *ftype_cstr = luaL_checkstring(lua, 2);
tb_char_t const *ttype_cstr = luaL_checkstring(lua, 3);
tb_check_return_val(src_cstr && ftype_cstr && ttype_cstr, 0);
// find charsets
xm_charset_entry_ref_t fcharset = xm_charset_find_by_name(ftype_cstr);
xm_charset_entry_ref_t tcharset = xm_charset_find_by_name(ttype_cstr);
luaL_argcheck(lua, fcharset, 2, "charset not found");
luaL_argcheck(lua, tcharset, 3, "charset not found");
tb_check_return_val(fcharset && tcharset, 0);
// empty string?
if (!src_size) {
lua_pushstring(lua, "");
} else {
// convert string
tb_long_t dst_size = 0;
tb_size_t dst_maxn = (tb_size_t)src_size << 2;
tb_byte_t *dst_data = tb_malloc_bytes(dst_maxn);
if (dst_data && dst_maxn &&
(dst_size = tb_charset_conv_data(fcharset->type,
tcharset->type,
(tb_byte_t const *)src_cstr,
(tb_size_t)src_size,
dst_data,
dst_maxn)) >= 0 &&
dst_size < dst_maxn) {
lua_pushlstring(lua, (tb_char_t const *)dst_data, dst_size);
} else {
lua_pushnil(lua);
}
tb_free(dst_data);
}
return 1;
}
================================================
FILE: core/src/xmake/string/endswith.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file endswith.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "endswith"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_string_endswith(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the string and suffix
size_t string_size = 0;
size_t suffix_size = 0;
tb_char_t const *string = luaL_checklstring(lua, 1, &string_size);
tb_char_t const *suffix = luaL_checklstring(lua, 2, &suffix_size);
tb_check_return_val(string && suffix, 0);
// string:endswith(suffix)?
lua_pushboolean(lua, string_size >= suffix_size && !tb_strcmp(string + string_size - suffix_size, suffix));
return 1;
}
================================================
FILE: core/src/xmake/string/lastof.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file lastof.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "string_lastof"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../utf8/utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* lastof string (only support plain text)
*
* @param str the string
* @param substr the substring
*/
tb_int_t xm_string_lastof(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get string
size_t nstr = 0;
tb_char_t const *cstr = luaL_checklstring(lua, 1, &nstr);
// get substring
size_t nsubstr = 0;
tb_char_t const *csubstr = luaL_checklstring(lua, 2, &nsubstr);
// lastof it
tb_long_t char_pos = xm_utf8_lastof_impl(cstr, nstr, csubstr, nsubstr);
if (char_pos > 0) {
lua_pushinteger(lua, char_pos);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/string/lower.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author luadebug, ruki
* @file lower.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* string.lower
*
* @param str the string
*
* @code
* local result = string.lower(str)
* @endcode
*/
tb_int_t xm_string_lower(lua_State *lua) {
// check
tb_assert_and_check_return_val(lua, 0);
// get string
size_t size = 0;
tb_char_t const* cstr = luaL_checklstring(lua, 1, &size);
tb_check_return_val(cstr, 0);
// empty?
if (!size) {
lua_pushstring(lua, "");
return 1;
}
// copy string to buffer
tb_char_t* buffer = (tb_char_t*)tb_malloc_bytes(size + 1);
if (buffer) {
tb_memcpy(buffer, cstr, size);
buffer[size] = '\0';
// to lower
tb_long_t real_size = tb_charset_utf8_tolower(buffer, size);
// push result
if (real_size >= 0) {
lua_pushlstring(lua, buffer, real_size);
} else {
lua_pushlstring(lua, cstr, size);
}
tb_free(buffer);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/string/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_STRING_PREFIX_H
#define XM_STRING_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/string/split.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file split.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "string_split"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_string_split_str(lua_State *lua,
tb_char_t const *cstr,
tb_size_t nstr,
tb_char_t const *cdls,
tb_size_t ndls,
tb_bool_t strict,
tb_int_t limit) {
tb_int_t num = 0;
tb_char_t const *end = cstr + nstr;
tb_char_t const *pos = tb_strstr(cstr, cdls); // faster than tb_strnstr()
while (pos && pos < end) {
if (pos > cstr || strict) {
if (limit > 0 && num + 1 >= limit) {
break;
}
lua_pushlstring(lua, cstr, pos - cstr);
lua_rawseti(lua, -2, ++num);
}
cstr = pos + ndls;
pos = tb_strstr(cstr, cdls);
}
if (cstr < end) {
lua_pushlstring(lua, cstr, end - cstr);
lua_rawseti(lua, -2, ++num);
} else if (strict && (limit < 0 || num < limit) && cstr == end) {
lua_pushliteral(lua, "");
lua_rawseti(lua, -2, ++num);
}
}
static tb_void_t xm_string_split_chr(
lua_State *lua, tb_char_t const *cstr, tb_size_t nstr, tb_char_t ch, tb_bool_t strict, tb_int_t limit) {
tb_int_t num = 0;
tb_char_t const *end = cstr + nstr;
tb_char_t const *pos = tb_strchr(cstr, ch); // faster than tb_strnchr()
while (pos && pos < end) {
if (pos > cstr || strict) {
if (limit > 0 && num + 1 >= limit) {
break;
}
lua_pushlstring(lua, cstr, pos - cstr);
lua_rawseti(lua, -2, ++num);
}
cstr = pos + 1;
pos = tb_strchr(cstr, ch);
}
if (cstr < end) {
lua_pushlstring(lua, cstr, end - cstr);
lua_rawseti(lua, -2, ++num);
} else if (strict && (limit < 0 || num < limit) && cstr == end) {
lua_pushliteral(lua, "");
lua_rawseti(lua, -2, ++num);
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* split string (only support plain text)
*
* @param str the string
* @param delimiter the delimiter
* @param strict is strict?
* @param limit the limit count
*/
tb_int_t xm_string_split(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get string
size_t nstr = 0;
tb_char_t const *cstr = luaL_checklstring(lua, 1, &nstr);
// get delimiter
size_t ndls = 0;
tb_char_t const *cdls = luaL_checklstring(lua, 2, &ndls);
// is strict?
tb_bool_t const strict = (tb_bool_t)lua_toboolean(lua, 3);
// get limit count
tb_int_t const limit = (tb_int_t)luaL_optinteger(lua, 4, -1);
// split it
lua_newtable(lua);
if (ndls == 1) {
xm_string_split_chr(lua, cstr, (tb_size_t)nstr, cdls[0], strict, limit);
} else {
xm_string_split_str(lua, cstr, (tb_size_t)nstr, cdls, ndls, strict, limit);
}
return 1;
}
================================================
FILE: core/src/xmake/string/startswith.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file startswith.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "startswith"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_string_startswith(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the string and prefix
size_t prefix_size = 0;
tb_char_t const *string = luaL_checkstring(lua, 1);
tb_char_t const *prefix = luaL_checklstring(lua, 2, &prefix_size);
tb_check_return_val(string && prefix, 0);
// string:startswith(prefix)?
lua_pushboolean(lua, !tb_strncmp(string, prefix, (tb_size_t)prefix_size));
return 1;
}
================================================
FILE: core/src/xmake/string/trim.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu
* @file trim.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "string_trim"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_string_trim_space(tb_char_t const **psstr, tb_char_t const **pestr, tb_int_t mode) {
tb_assert(psstr && pestr && *psstr && *pestr);
tb_char_t const *p = *psstr;
tb_char_t const *e = *pestr;
// trim left?
if (mode <= 0) {
while (p < e && tb_isspace(*p)) {
p++;
}
}
// trim right
if (mode >= 0) {
e--;
while (e >= p && tb_isspace(*e)) {
e--;
}
e++;
}
// save trimed string
*psstr = p;
*pestr = e;
}
static tb_char_t const *xm_string_ltrim(tb_char_t const *sstr,
tb_char_t const *estr,
tb_char_t const *ctrim,
size_t ntrim) {
tb_assert(sstr && estr && ctrim);
tb_char_t const *p = sstr;
while (p < estr && tb_strnchr(ctrim, ntrim, *p)) {
p++;
}
return p;
}
static tb_char_t const *xm_string_rtrim(tb_char_t const *sstr,
tb_char_t const *estr,
tb_char_t const *ctrim,
size_t ntrim) {
tb_assert(sstr && estr && ctrim);
tb_char_t const *p = estr - 1;
while (p >= sstr && tb_strnchr(ctrim, ntrim, *p)) {
p--;
}
return p + 1;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* trim string
*
* @param str the string
* @param trimchars the chars to trim
* @param trimtype 0 to trim left and right, -1 to trim left, 1 to trim right
*
* @code
* local result = string.trim(str, "\r\n \v\t", 0)
* local result = string.trim(str, "(", -1)
* @endcode
*/
tb_int_t xm_string_trim(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
size_t lstr, ltrim;
tb_char_t const *sstr = luaL_checklstring(lua, 1, &lstr);
tb_char_t const *estr = sstr + lstr;
tb_char_t const *trimchars = luaL_optlstring(lua, 2, "", <rim);
tb_int_t const trimtype = (tb_int_t)luaL_optinteger(lua, 3, 0);
do {
tb_assert_and_check_break(sstr && trimchars);
tb_check_break(lstr != 0);
tb_char_t const *const rsstr = sstr;
tb_char_t const *const restr = estr;
if (ltrim == 0) {
xm_string_trim_space(&sstr, &estr, trimtype);
} else {
// trim chars
if (trimtype <= 0) {
sstr = xm_string_ltrim(sstr, estr, trimchars, ltrim);
}
if (trimtype >= 0) {
estr = xm_string_rtrim(sstr, estr, trimchars, ltrim);
}
}
// no trimed chars
tb_check_break(sstr != rsstr || estr != restr);
lua_pushlstring(lua, sstr, estr - sstr);
return 1;
} while (0);
// return orignal value
lua_settop(lua, 1);
return 1;
}
================================================
FILE: core/src/xmake/string/upper.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author luadebug, ruki
* @file upper.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* string.upper
*
* @param str the string
*
* @code
* local result = (str)
* @endcode
*/
tb_int_t xm_string_upper(lua_State *lua) {
// check
tb_assert_and_check_return_val(lua, 0);
// get string
size_t size = 0;
tb_char_t const* cstr = luaL_checklstring(lua, 1, &size);
tb_check_return_val(cstr, 0);
// empty?
if (!size) {
lua_pushstring(lua, "");
return 1;
}
// copy string to buffer
tb_char_t* buffer = (tb_char_t*)tb_malloc_bytes(size + 1);
if (buffer) {
tb_memcpy(buffer, cstr, size);
buffer[size] = '\0';
// to upper
tb_long_t real_size = tb_charset_utf8_toupper(buffer, size);
// push result
if (real_size >= 0) {
lua_pushlstring(lua, buffer, real_size);
} else {
lua_pushlstring(lua, cstr, size);
}
tb_free(buffer);
} else {
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/event_exit.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file event_exit.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_event"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_event_exit(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);
tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);
if (tb_atomic_fetch_and_sub(&thread_event->refn, 1) == 1) {
if (thread_event->handle) {
tb_event_exit(thread_event->handle);
thread_event->handle = tb_null;
}
tb_free(thread_event);
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/event_incref.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file event_incref.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_event"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_event_incref(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);
tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);
lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_event->refn, 1) >= 1);
return 1;
}
================================================
FILE: core/src/xmake/thread/event_init.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file event_init.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_event"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_event_init(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_bool_t ok = tb_false;
xm_thread_event_t *thread_event = tb_null;
do {
thread_event = tb_malloc0_type(xm_thread_event_t);
tb_assert_and_check_break(thread_event);
thread_event->refn = 1;
thread_event->handle = tb_event_init();
tb_assert_and_check_break(thread_event->handle);
xm_lua_pushpointer(lua, (tb_pointer_t)thread_event);
ok = tb_true;
} while (0);
if (!ok) {
if (thread_event) {
if (thread_event->handle) {
tb_event_exit(thread_event->handle);
thread_event->handle = tb_null;
}
tb_free(thread_event);
}
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/event_post.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file event_post.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_event"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_event_post(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);
tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);
lua_pushboolean(lua, tb_event_post(thread_event->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/event_wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file event_wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_event"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_event_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_event_t *thread_event = xm_thread_event_get(lua, 1);
tb_assert_and_check_return_val(thread_event && thread_event->handle, 0);
tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2);
lua_pushinteger(lua, tb_event_wait(thread_event->handle, timeout));
return 1;
}
================================================
FILE: core/src/xmake/thread/mutex_exit.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mutex_exit.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_mutex"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_mutex_exit(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);
tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);
if (tb_atomic_fetch_and_sub(&thread_mutex->refn, 1) == 1) {
if (thread_mutex->handle) {
tb_mutex_exit(thread_mutex->handle);
thread_mutex->handle = tb_null;
}
tb_free(thread_mutex);
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/mutex_incref.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mutex_incref.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_mutex"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_mutex_incref(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);
tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);
lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_mutex->refn, 1) >= 1);
return 1;
}
================================================
FILE: core/src/xmake/thread/mutex_init.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mutex_init.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_mutex"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_mutex_init(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_bool_t ok = tb_false;
xm_thread_mutex_t *thread_mutex = tb_null;
do {
thread_mutex = tb_malloc0_type(xm_thread_mutex_t);
tb_assert_and_check_break(thread_mutex);
thread_mutex->refn = 1;
thread_mutex->handle = tb_mutex_init();
tb_assert_and_check_break(thread_mutex->handle);
xm_lua_pushpointer(lua, (tb_pointer_t)thread_mutex);
ok = tb_true;
} while (0);
if (!ok) {
if (thread_mutex) {
if (thread_mutex->handle) {
tb_mutex_exit(thread_mutex->handle);
thread_mutex->handle = tb_null;
}
tb_free(thread_mutex);
}
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/mutex_lock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mutex_lock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_mutex"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_mutex_lock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);
tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);
lua_pushboolean(lua, tb_mutex_enter(thread_mutex->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/mutex_trylock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mutex_trylock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_mutex"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_mutex_trylock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);
tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);
lua_pushboolean(lua, tb_mutex_enter_try(thread_mutex->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/mutex_unlock.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file mutex_unlock.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_mutex"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_mutex_unlock(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_mutex_t *thread_mutex = xm_thread_mutex_get(lua, 1);
tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0);
lua_pushboolean(lua, tb_mutex_leave(thread_mutex->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_THREAD_PREFIX_H
#define XM_THREAD_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the thread type
typedef struct __xm_thread_t {
tb_thread_ref_t handle;
tb_string_t callback;
tb_string_t callinfo;
} xm_thread_t;
// the thread value kind
typedef enum __xm_thread_value_kind_e {
XM_THREAD_VALUE_NIL = 0,
XM_THREAD_VALUE_BOOL = 1,
XM_THREAD_VALUE_INT = 2,
XM_THREAD_VALUE_NUM = 3,
XM_THREAD_VALUE_STR = 4
} xm_thread_value_kind_e;
// the thread value type
typedef struct __xm_thread_value_t {
tb_uint32_t kind : 3;
tb_uint32_t size : 29;
union {
tb_char_t *string;
tb_bool_t boolean;
lua_Integer integer;
lua_Number number;
} u;
} xm_thread_value_t;
// the thread event type
typedef struct __xm_thread_event_t {
tb_event_ref_t handle;
tb_atomic_t refn;
} xm_thread_event_t;
// the thread mutex type
typedef struct __xm_thread_mutex_t {
tb_mutex_ref_t handle;
tb_atomic_t refn;
} xm_thread_mutex_t;
// the thread semaphore type
typedef struct __xm_thread_semaphore_t {
tb_semaphore_ref_t handle;
tb_atomic_t refn;
} xm_thread_semaphore_t;
// the thread queue type
typedef struct __xm_thread_queue_t {
tb_queue_ref_t handle;
tb_atomic_t refn;
} xm_thread_queue_t;
// the thread sharedata type
typedef struct __xm_thread_sharedata_t {
xm_thread_value_t value;
tb_buffer_t buffer;
tb_atomic_t refn;
} xm_thread_sharedata_t;
// get the thread event from arguments
static __tb_inline__ xm_thread_event_t *xm_thread_event_get(lua_State *lua, tb_int_t index) {
xm_thread_event_t *thread_event = tb_null;
if (xm_lua_isinteger(lua, index)) {
thread_event = (xm_thread_event_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);
} else if (xm_lua_ispointer(lua, index)) {
thread_event = (xm_thread_event_t *)xm_lua_topointer(lua, index);
}
return thread_event;
}
// get the thread mutex from arguments
static __tb_inline__ xm_thread_mutex_t *xm_thread_mutex_get(lua_State *lua, tb_int_t index) {
xm_thread_mutex_t *thread_mutex = tb_null;
if (xm_lua_isinteger(lua, index)) {
thread_mutex = (xm_thread_mutex_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);
} else if (xm_lua_ispointer(lua, index)) {
thread_mutex = (xm_thread_mutex_t *)xm_lua_topointer(lua, index);
}
return thread_mutex;
}
// get the thread semaphore from arguments
static __tb_inline__ xm_thread_semaphore_t *xm_thread_semaphore_get(lua_State *lua, tb_int_t index) {
xm_thread_semaphore_t *thread_semaphore = tb_null;
if (xm_lua_isinteger(lua, index)) {
thread_semaphore = (xm_thread_semaphore_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);
} else if (xm_lua_ispointer(lua, index)) {
thread_semaphore = (xm_thread_semaphore_t *)xm_lua_topointer(lua, index);
}
return thread_semaphore;
}
// get the thread queue from arguments
static __tb_inline__ xm_thread_queue_t *xm_thread_queue_get(lua_State *lua, tb_int_t index) {
xm_thread_queue_t *thread_queue = tb_null;
if (xm_lua_isinteger(lua, index)) {
thread_queue = (xm_thread_queue_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);
} else if (xm_lua_ispointer(lua, index)) {
thread_queue = (xm_thread_queue_t *)xm_lua_topointer(lua, index);
}
return thread_queue;
}
// get the thread sharedata from arguments
static __tb_inline__ xm_thread_sharedata_t *xm_thread_sharedata_get(lua_State *lua, tb_int_t index) {
xm_thread_sharedata_t *thread_sharedata = tb_null;
if (xm_lua_isinteger(lua, index)) {
thread_sharedata = (xm_thread_sharedata_t *)(tb_size_t)(tb_long_t)lua_tointeger(lua, index);
} else if (xm_lua_ispointer(lua, index)) {
thread_sharedata = (xm_thread_sharedata_t *)xm_lua_topointer(lua, index);
}
return thread_sharedata;
}
#endif
================================================
FILE: core/src/xmake/thread/queue_clear.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_clear.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_clear(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);
tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);
tb_queue_clear(thread_queue->handle);
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/queue_exit.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_exit.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_exit(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);
tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);
if (tb_atomic_fetch_and_sub(&thread_queue->refn, 1) == 1) {
if (thread_queue->handle) {
tb_queue_exit(thread_queue->handle);
thread_queue->handle = tb_null;
}
tb_free(thread_queue);
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/queue_incref.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_incref.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_incref(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);
tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);
lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_queue->refn, 1) >= 1);
return 1;
}
================================================
FILE: core/src/xmake/thread/queue_init.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_init.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_thread_value_free(tb_element_ref_t element, tb_pointer_t buff) {
xm_thread_value_t *item = (xm_thread_value_t *)buff;
if (item) {
if (item->kind == XM_THREAD_VALUE_STR) {
if (item->u.string) {
tb_free((tb_pointer_t)item->u.string);
}
item->u.string = tb_null;
}
item->size = 0;
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_init(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_bool_t ok = tb_false;
xm_thread_queue_t *thread_queue = tb_null;
do {
thread_queue = tb_malloc0_type(xm_thread_queue_t);
tb_assert_and_check_break(thread_queue);
thread_queue->refn = 1;
thread_queue->handle = tb_queue_init(0,
tb_element_mem(sizeof(xm_thread_value_t), xm_thread_value_free, tb_null));
tb_assert_and_check_break(thread_queue->handle);
xm_lua_pushpointer(lua, (tb_pointer_t)thread_queue);
ok = tb_true;
} while (0);
if (!ok) {
if (thread_queue) {
if (thread_queue->handle) {
tb_queue_exit(thread_queue->handle);
thread_queue->handle = tb_null;
}
tb_free(thread_queue);
}
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/queue_pop.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_pop.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_pop(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);
tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);
if (tb_queue_null(thread_queue->handle)) {
lua_pushnil(lua);
lua_pushliteral(lua, "the thread queue is empty");
return 2;
}
xm_thread_value_t *item = (xm_thread_value_t *)tb_queue_get(thread_queue->handle);
tb_assert_and_check_return_val(item, 0);
tb_bool_t ok = tb_false;
switch (item->kind) {
case XM_THREAD_VALUE_STR:
if (item->size) {
lua_pushlstring(lua, item->u.string, item->size);
} else {
lua_pushliteral(lua, "");
}
ok = tb_true;
break;
case XM_THREAD_VALUE_INT:
lua_pushinteger(lua, item->u.integer);
ok = tb_true;
break;
case XM_THREAD_VALUE_NUM:
lua_pushnumber(lua, item->u.number);
ok = tb_true;
break;
case XM_THREAD_VALUE_BOOL:
lua_pushboolean(lua, item->u.boolean);
ok = tb_true;
break;
case XM_THREAD_VALUE_NIL:
lua_pushnil(lua);
ok = tb_true;
break;
default:
break;
}
if (!ok) {
lua_pushnil(lua);
lua_pushliteral(lua, "invalid thread queue item");
return 2;
}
tb_queue_pop(thread_queue->handle);
return 1;
}
================================================
FILE: core/src/xmake/thread/queue_push.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_push.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_push(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);
tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);
if (tb_queue_full(thread_queue->handle)) {
lua_pushboolean(lua, tb_false);
lua_pushliteral(lua, "the thread queue is full");
return 2;
}
xm_thread_value_t item;
if (lua_isstring(lua, 2)) {
size_t data_size = 0;
tb_char_t const *data = luaL_checklstring(lua, 2, &data_size);
tb_assert_and_check_return_val(data, 0);
item.kind = (tb_uint32_t)XM_THREAD_VALUE_STR;
item.size = (tb_uint32_t)data_size;
if (data_size) {
item.u.string = tb_malloc_cstr(data_size);
tb_assert_and_check_return_val(item.u.string, 0);
tb_memcpy(item.u.string, data, data_size);
}
} else if (xm_lua_isinteger(lua, 2)) {
item.kind = (tb_uint32_t)XM_THREAD_VALUE_INT;
item.u.integer = lua_tointeger(lua, 2);
} else if (lua_isnumber(lua, 2)) {
item.kind = (tb_uint32_t)XM_THREAD_VALUE_NUM;
item.u.number = lua_tonumber(lua, 2);
} else if (lua_isboolean(lua, 2)) {
item.kind = (tb_uint32_t)XM_THREAD_VALUE_BOOL;
item.u.boolean = lua_toboolean(lua, 2);
} else if (lua_isnil(lua, 2)) {
item.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL;
} else {
lua_pushboolean(lua, tb_false);
lua_pushliteral(lua, "unsupported thread queue item");
return 2;
}
tb_queue_put(thread_queue->handle, &item);
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/queue_size.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file queue_size.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_queue"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_queue_size(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_queue_t *thread_queue = xm_thread_queue_get(lua, 1);
tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0);
lua_pushinteger(lua, (tb_int_t)tb_queue_size(thread_queue->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/semaphore_exit.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file semaphore_exit.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_semaphore"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_semaphore_exit(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);
tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);
if (tb_atomic_fetch_and_sub(&thread_semaphore->refn, 1) == 1) {
if (thread_semaphore->handle) {
tb_semaphore_exit(thread_semaphore->handle);
thread_semaphore->handle = tb_null;
}
tb_free(thread_semaphore);
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/semaphore_incref.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file semaphore_incref.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_semaphore"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_semaphore_incref(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);
tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);
lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_semaphore->refn, 1) >= 1);
return 1;
}
================================================
FILE: core/src/xmake/thread/semaphore_init.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file semaphore_init.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_semaphore"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_semaphore_init(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_bool_t ok = tb_false;
xm_thread_semaphore_t *thread_semaphore = tb_null;
do {
tb_long_t value = (tb_long_t)luaL_checknumber(lua, 1);
thread_semaphore = tb_malloc0_type(xm_thread_semaphore_t);
tb_assert_and_check_break(thread_semaphore);
thread_semaphore->refn = 1;
thread_semaphore->handle = tb_semaphore_init(value);
tb_assert_and_check_break(thread_semaphore->handle);
xm_lua_pushpointer(lua, (tb_pointer_t)thread_semaphore);
ok = tb_true;
} while (0);
if (!ok) {
if (thread_semaphore) {
if (thread_semaphore->handle) {
tb_semaphore_exit(thread_semaphore->handle);
thread_semaphore->handle = tb_null;
}
tb_free(thread_semaphore);
}
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/semaphore_post.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file semaphore_post.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_semaphore"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_semaphore_post(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);
tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);
tb_long_t value = (tb_long_t)luaL_checknumber(lua, 2);
lua_pushboolean(lua, tb_semaphore_post(thread_semaphore->handle, value));
return 1;
}
================================================
FILE: core/src/xmake/thread/semaphore_wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file semaphore_wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_semaphore"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_semaphore_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_semaphore_t *thread_semaphore = xm_thread_semaphore_get(lua, 1);
tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0);
tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2);
lua_pushinteger(lua, tb_semaphore_wait(thread_semaphore->handle, timeout));
return 1;
}
================================================
FILE: core/src/xmake/thread/sharedata_clear.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sharedata_clear.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_sharedata"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_sharedata_clear(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);
tb_assert_and_check_return_val(thread_sharedata, 0);
thread_sharedata->value.kind = XM_THREAD_VALUE_NIL;
tb_buffer_clear(&thread_sharedata->buffer);
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/sharedata_exit.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sharedata_exit.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_sharedata"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_sharedata_exit(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);
tb_assert_and_check_return_val(thread_sharedata, 0);
if (tb_atomic_fetch_and_sub(&thread_sharedata->refn, 1) == 1) {
tb_buffer_exit(&thread_sharedata->buffer);
tb_free(thread_sharedata);
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/sharedata_get.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sharedata_get.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_sharedata"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_sharedata_get_(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);
tb_assert_and_check_return_val(thread_sharedata, 0);
tb_bool_t ok = tb_false;
switch (thread_sharedata->value.kind) {
case XM_THREAD_VALUE_STR:
if (tb_buffer_size(&thread_sharedata->buffer) > 0) {
lua_pushlstring(lua,
(tb_char_t *)tb_buffer_data(&thread_sharedata->buffer),
tb_buffer_size(&thread_sharedata->buffer));
} else {
lua_pushliteral(lua, "");
}
ok = tb_true;
break;
case XM_THREAD_VALUE_INT:
lua_pushinteger(lua, thread_sharedata->value.u.integer);
ok = tb_true;
break;
case XM_THREAD_VALUE_NUM:
lua_pushnumber(lua, thread_sharedata->value.u.number);
ok = tb_true;
break;
case XM_THREAD_VALUE_BOOL:
lua_pushboolean(lua, thread_sharedata->value.u.boolean);
ok = tb_true;
break;
case XM_THREAD_VALUE_NIL:
lua_pushnil(lua);
ok = tb_true;
break;
default:
break;
}
if (!ok) {
lua_pushnil(lua);
lua_pushliteral(lua, "invalid thread sharedata thread_sharedata");
return 2;
}
return 1;
}
================================================
FILE: core/src/xmake/thread/sharedata_incref.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sharedata_incref.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_sharedata"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_sharedata_incref(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);
tb_assert_and_check_return_val(thread_sharedata, 0);
lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_sharedata->refn, 1) >= 1);
return 1;
}
================================================
FILE: core/src/xmake/thread/sharedata_init.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sharedata_init.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_sharedata"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_sharedata_init(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_bool_t ok = tb_false;
xm_thread_sharedata_t *thread_sharedata = tb_null;
do {
thread_sharedata = tb_malloc0_type(xm_thread_sharedata_t);
tb_assert_and_check_break(thread_sharedata);
thread_sharedata->refn = 1;
thread_sharedata->value.kind = XM_THREAD_VALUE_NIL;
tb_buffer_init(&thread_sharedata->buffer);
xm_lua_pushpointer(lua, (tb_pointer_t)thread_sharedata);
ok = tb_true;
} while (0);
if (!ok) {
if (thread_sharedata) {
tb_buffer_exit(&thread_sharedata->buffer);
tb_free(thread_sharedata);
}
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/sharedata_set.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sharedata_set.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread_sharedata"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_sharedata_set(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
xm_thread_sharedata_t *thread_sharedata = xm_thread_sharedata_get(lua, 1);
tb_assert_and_check_return_val(thread_sharedata, 0);
if (lua_isstring(lua, 2)) {
size_t data_size = 0;
tb_char_t const *data = luaL_checklstring(lua, 2, &data_size);
tb_assert_and_check_return_val(data, 0);
thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_STR;
if (data_size) {
tb_buffer_memncpy(&thread_sharedata->buffer, (tb_byte_t const *)data, data_size);
} else {
tb_buffer_clear(&thread_sharedata->buffer);
}
} else if (xm_lua_isinteger(lua, 2)) {
thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_INT;
thread_sharedata->value.u.integer = lua_tointeger(lua, 2);
} else if (lua_isnumber(lua, 2)) {
thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NUM;
thread_sharedata->value.u.number = lua_tonumber(lua, 2);
} else if (lua_isboolean(lua, 2)) {
thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_BOOL;
thread_sharedata->value.u.boolean = lua_toboolean(lua, 2);
} else if (lua_isnil(lua, 2)) {
thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL;
} else {
lua_pushboolean(lua, tb_false);
lua_pushliteral(lua, "unsupported thread sharedata item");
return 2;
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/thread_exit.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file thread_exit.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_exit(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get thread
xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(thread, 0);
// exit thread
if (thread) {
tb_string_exit(&thread->callback);
tb_string_exit(&thread->callinfo);
if (thread->handle) {
tb_thread_exit(thread->handle);
thread->handle = tb_null;
}
tb_free(thread);
}
lua_pushboolean(lua, tb_true);
return 1;
}
================================================
FILE: core/src/xmake/thread/thread_init.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file thread_init.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "../engine.h"
#include "../engine_pool.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define XM_THREAD_ENGINE_NAME "xmake"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_int_t xm_thread_func(tb_cpointer_t priv) {
xm_thread_t *thread = (xm_thread_t *)priv;
tb_assert_and_check_return_val(thread, 0);
xm_engine_ref_t engine = xm_engine_pool_alloc(xm_engine_pool());
if (!engine) {
engine = xm_engine_init(XM_THREAD_ENGINE_NAME, tb_null);
}
if (engine) {
lua_State *lua = xm_engine_lua(engine);
tb_assert(lua);
// pass callback
tb_char_t const *callback_data = tb_string_cstr(&thread->callback);
tb_size_t callback_size = tb_string_size(&thread->callback);
if (callback_data && callback_size) {
lua_pushlstring(lua, callback_data, callback_size);
lua_setglobal(lua, "_THREAD_CALLBACK");
}
// pass callinfo
tb_char_t const *callinfo_data = tb_string_cstr(&thread->callinfo);
tb_size_t callinfo_size = tb_string_size(&thread->callinfo);
if (callinfo_data && callinfo_size) {
lua_pushlstring(lua, callinfo_data, callinfo_size);
lua_setglobal(lua, "_THREAD_CALLINFO");
}
// start engine
tb_char_t *argv[] = { XM_THREAD_ENGINE_NAME, tb_null };
xm_engine_main(engine, 1, argv, tb_null);
if (!xm_engine_pool_free(xm_engine_pool(), engine)) {
xm_engine_exit(engine);
}
}
return 0;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_init(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_bool_t ok = tb_false;
xm_thread_t *thread = tb_null;
do {
// get thread name
tb_char_t const *name = luaL_checkstring(lua, 1);
// get callback
size_t callback_size = 0;
tb_char_t const *callback_data = luaL_checklstring(lua, 2, &callback_size);
tb_assert_and_check_break(callback_data && callback_size);
// get callinfo
size_t callinfo_size = 0;
tb_char_t const *callinfo_data = luaL_checklstring(lua, 3, &callinfo_size);
tb_assert_and_check_break(callinfo_data && callinfo_size);
// get stack size
tb_size_t stacksize = (tb_size_t)luaL_checkinteger(lua, 4);
// init thread
thread = tb_malloc0_type(xm_thread_t);
tb_assert_and_check_break(thread);
tb_string_init(&thread->callback);
tb_string_cstrncpy(&thread->callback, callback_data, callback_size);
tb_string_init(&thread->callinfo);
tb_string_cstrncpy(&thread->callinfo, callinfo_data, callinfo_size);
// create and start thread
thread->handle = tb_thread_init(name, xm_thread_func, thread, stacksize);
tb_assert_and_check_break(thread->handle);
xm_lua_pushpointer(lua, (tb_pointer_t)thread);
ok = tb_true;
} while (0);
if (!ok) {
if (thread) {
tb_string_exit(&thread->callback);
tb_string_exit(&thread->callinfo);
if (thread->handle) {
tb_thread_exit(thread->handle);
thread->handle = tb_null;
}
tb_free(thread);
}
lua_pushnil(lua);
}
return 1;
}
================================================
FILE: core/src/xmake/thread/thread_resume.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file thread_resume.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_resume(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get thread
xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(thread && thread->handle, 0);
// resume thread
lua_pushboolean(lua, tb_thread_resume(thread->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/thread_suspend.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file thread_suspend.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_suspend(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get thread
xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(thread && thread->handle, 0);
// suspend thread
lua_pushboolean(lua, tb_thread_suspend(thread->handle));
return 1;
}
================================================
FILE: core/src/xmake/thread/thread_wait.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file thread_wait.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "thread"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_thread_wait(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// is pointer?
if (!xm_lua_ispointer(lua, 1)) {
return 0;
}
// get thread
xm_thread_t *thread = (xm_thread_t *)xm_lua_topointer(lua, 1);
tb_check_return_val(thread->handle, 0);
// get timeout
tb_size_t timeout = (tb_size_t)luaL_checkinteger(lua, 2);
// wait thread
tb_int_t retval;
lua_pushinteger(lua, (tb_int_t)tb_thread_wait(thread->handle, timeout, &retval));
return 1;
}
================================================
FILE: core/src/xmake/tty/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_TTY_PREFIX_H
#define XM_TTY_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/tty/session_id.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file session_id.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "session_id"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef TB_CONFIG_OS_WINDOWS
#include
#else
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// tty.session_id()
tb_int_t xm_tty_session_id(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
#ifdef TB_CONFIG_OS_WINDOWS
HWND hwnd = GetConsoleWindow();
if (hwnd) {
// use hex string of hwnd as session id
lua_pushfstring(lua, "%p", hwnd);
return 1;
}
#else
// we use the tty name as session id
tb_char_t const* name = ttyname(STDIN_FILENO);
if (name) {
lua_pushstring(lua, name);
return 1;
}
#endif
// failed
lua_pushnil(lua);
return 1;
}
================================================
FILE: core/src/xmake/tty/term_mode.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file term_mode.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "term_mode"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#ifdef TB_CONFIG_OS_WINDOWS
#include
#endif
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* local oldmode = tty.term_mode(stdtype)
* local oldmode = tty.term_mode(stdtype, newmode)
*/
tb_int_t xm_tty_term_mode(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
#ifdef TB_CONFIG_OS_WINDOWS
// get std type, (stdin: 1, stdout: 2, stderr: 3)
tb_int_t stdtype = (tb_int_t)luaL_checkinteger(lua, 1);
// get and set terminal mode
DWORD mode = 0;
HANDLE console_handle = INVALID_HANDLE_VALUE;
switch (stdtype) {
case 1:
console_handle = GetStdHandle(STD_INPUT_HANDLE);
break;
case 2:
console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
break;
case 3:
console_handle = GetStdHandle(STD_ERROR_HANDLE);
break;
}
GetConsoleMode(console_handle, &mode);
if (lua_isnumber(lua, 2)) {
tb_int_t newmode = (tb_int_t)lua_tointeger(lua, 2);
if (console_handle != INVALID_HANDLE_VALUE) {
SetConsoleMode(console_handle, (DWORD)newmode);
}
}
#else
tb_int_t mode = 0;
#endif
lua_pushinteger(lua, (tb_int_t)mode);
return 1;
}
================================================
FILE: core/src/xmake/utf8/byte.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file byte.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_utf8_byte_cb(xm_utf8_int_t code, tb_cpointer_t udata) {
lua_State* lua = (lua_State*)udata;
tb_assert_and_check_return_val(lua, tb_false);
luaL_checkstack(lua, 1, "too many results");
lua_pushinteger(lua, code);
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utf8.byte(s, i [, j])
*/
tb_int_t xm_utf8_byte(lua_State* lua) {
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_Integer i = luaL_optinteger(lua, 2, 1);
lua_Integer j = luaL_optinteger(lua, 3, i);
return (tb_int_t)xm_utf8_byte_impl(s, len, (tb_long_t)i, (tb_long_t)j, xm_utf8_byte_cb, lua);
}
================================================
FILE: core/src/xmake/utf8/char.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file char.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static void xm_utf8_char_push(lua_State *lua, tb_int_t arg) {
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(lua, arg);
luaL_argcheck(lua, code <= XM_UTF8_MAXUTF, arg, "value out of range");
tb_char_t buf[8];
tb_size_t n = xm_utf8_encode(buf, (xm_utf8_int_t)code);
if (n > 0) {
lua_pushlstring(lua, buf, n);
} else {
luaL_error(lua, "value out of range");
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utfchar(n1, n2, ...) -> char(n1)..char(n2)...
*/
tb_int_t xm_utf8_char(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_int_t n = lua_gettop(lua); // number of arguments
if (n == 1) { // optimize common case of single char
xm_utf8_char_push(lua, 1);
} else {
tb_int_t i;
luaL_Buffer b;
luaL_buffinit(lua, &b);
for (i = 1; i <= n; i++) {
xm_utf8_char_push(lua, i);
luaL_addvalue(&b);
}
luaL_pushresult(&b);
}
return 1;
}
================================================
FILE: core/src/xmake/utf8/codepoint.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file codepoint.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t xm_utf8_codepoint_cb(xm_utf8_int_t code, tb_cpointer_t udata) {
lua_State* lua = (lua_State*)udata;
tb_assert_and_check_return_val(lua, tb_false);
lua_pushinteger(lua, code);
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all
* characters that start in the range [i,j]
*/
tb_int_t xm_utf8_codepoint(lua_State *lua) {
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_Integer posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 2, 1), len);
lua_Integer pose = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, posi), len);
tb_bool_t lax = lua_toboolean(lua, 4);
luaL_argcheck(lua, posi >= 1, 2, "out of bounds");
luaL_argcheck(lua, pose <= (lua_Integer)len, 3, "out of bounds");
if (posi > pose) {
return 0; // empty interval; return no values
}
if (pose - posi >= INT_MAX) { // (lua_Integer -> int) overflow?
return luaL_error(lua, "string slice too long");
}
tb_int_t n = (tb_int_t)(pose - posi) + 1;
luaL_checkstack(lua, n, "string slice too long");
int nresults = lua_gettop(lua);
if (!xm_utf8_codepoint_impl(s, len, (tb_long_t)posi, (tb_long_t)pose, !lax, xm_utf8_codepoint_cb, lua)) {
return luaL_error(lua, XM_UTF8_MSGInvalid);
}
return lua_gettop(lua) - nresults;
}
================================================
FILE: core/src/xmake/utf8/codes.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file codes.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_int_t xm_utf8_codes_iter(lua_State *lua, tb_bool_t strict) {
tb_assert_and_check_return_val(lua, 0);
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(lua, 2);
if (n < len) {
while (n < len && xm_utf8_iscontp(s + n)) {
n++; // go to next character
}
}
if (n >= len) { // (also handles original 'n' being negative)
return 0; // no more codepoints
} else {
xm_utf8_int_t code;
tb_char_t const* next = xm_utf8_decode(s + n, &code, strict);
if (next == NULL || (next < s + len && xm_utf8_iscontp(next))) {
return luaL_error(lua, XM_UTF8_MSGInvalid);
}
lua_pushinteger(lua, n + 1);
lua_pushinteger(lua, code);
return 2;
}
}
static int xm_utf8_codes_iter_strict(lua_State *lua) {
return xm_utf8_codes_iter(lua, tb_true);
}
static int xm_utf8_codes_iter_lax(lua_State *lua) {
return xm_utf8_codes_iter(lua, tb_false);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_utf8_codes(lua_State *lua) {
tb_bool_t lax = lua_toboolean(lua, 2);
tb_char_t const* s = luaL_checkstring(lua, 1);
luaL_argcheck(lua, !xm_utf8_iscontp(s), 1, XM_UTF8_MSGInvalid);
lua_pushcfunction(lua, lax ? xm_utf8_codes_iter_lax : xm_utf8_codes_iter_strict);
lua_pushvalue(lua, 1);
lua_pushinteger(lua, 0);
return 3;
}
================================================
FILE: core/src/xmake/utf8/find.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file find.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_int_t xm_utf8_find_impl_plain(lua_State* lua, tb_char_t const* s, size_t len, tb_char_t const* sub, size_t sublen, lua_Integer init) {
tb_long_t char_end = 0;
tb_long_t char_start = xm_utf8_find_impl(s, len, sub, sublen, (tb_long_t)init, &char_end);
if (char_start > 0) {
lua_pushinteger(lua, char_start);
lua_pushinteger(lua, char_end);
return 2;
}
lua_pushnil(lua);
return 1;
}
static tb_int_t xm_utf8_find_impl_pattern(lua_State* lua, tb_char_t const* s, size_t len, lua_Integer init) {
int base = lua_gettop(lua);
tb_long_t byte_init = 1;
if (init > 0) {
if (init > 1) {
byte_init = xm_utf8_offset_impl(s, len, (tb_long_t)init, 1);
if (byte_init <= 0) {
lua_pushnil(lua);
return 1;
}
}
} else if (init < 0) {
byte_init = xm_utf8_offset_impl(s, len, (tb_long_t)init, len + 1);
if (byte_init <= 0) {
lua_pushnil(lua);
return 1;
}
}
lua_getglobal(lua, "string");
lua_getfield(lua, -1, "find");
lua_pushvalue(lua, 1); // s
lua_pushvalue(lua, 2); // pattern
lua_pushinteger(lua, byte_init); // init (byte)
lua_pushboolean(lua, 0); // plain
lua_call(lua, 4, LUA_MULTRET);
// Stack: [args, string_table, results...]
int nres = lua_gettop(lua) - (base + 1);
if (nres <= 0 || lua_isnil(lua, base + 2)) {
lua_pushnil(lua);
lua_remove(lua, base + 1);
return 1;
}
lua_Integer b_start = lua_tointeger(lua, base + 2);
lua_Integer b_end = lua_tointeger(lua, base + 3);
tb_long_t char_start = 1;
if (b_start > 1) {
tb_long_t count = xm_utf8_len_impl(s, len, 1, (tb_long_t)b_start - 1, tb_true, tb_null);
if (count < 0) {
lua_pushnil(lua);
lua_remove(lua, base + 1);
return 1;
}
char_start = count + 1;
}
tb_long_t match_char_len = 0;
if (b_end >= b_start) {
match_char_len = xm_utf8_len_impl(s, len, (tb_long_t)b_start, (tb_long_t)b_end, tb_true, tb_null);
if (match_char_len < 0) {
lua_pushnil(lua);
lua_remove(lua, base + 1);
return 1;
}
}
lua_pushinteger(lua, char_start);
lua_replace(lua, base + 2);
lua_pushinteger(lua, char_start + match_char_len - 1);
lua_replace(lua, base + 3);
lua_remove(lua, base + 1);
return nres;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utf8.find(s, target [, init [, plain]])
*/
tb_int_t xm_utf8_find(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
size_t sublen;
tb_char_t const* sub = luaL_checklstring(lua, 2, &sublen);
lua_Integer init = luaL_optinteger(lua, 3, 1);
tb_int_t plain = lua_toboolean(lua, 4);
if (plain) {
return xm_utf8_find_impl_plain(lua, s, len, sub, sublen, init);
} else {
return xm_utf8_find_impl_pattern(lua, s, len, init);
}
}
================================================
FILE: core/src/xmake/utf8/lastof.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file lastof.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utf8.lastof(s, pattern, plain)
*/
tb_int_t xm_utf8_lastof(lua_State *lua) {
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
size_t sublen;
tb_char_t const* sub = luaL_checklstring(lua, 2, &sublen);
tb_int_t plain = lua_toboolean(lua, 3);
tb_long_t byte_pos = 0;
if (plain) {
byte_pos = xm_utf8_lastof_impl(s, len, sub, sublen);
} else {
lua_getglobal(lua, "string");
lua_getfield(lua, -1, "lastof");
lua_pushvalue(lua, 1); // s
lua_pushvalue(lua, 2); // pattern
lua_pushboolean(lua, 0); // plain = false
lua_call(lua, 3, 1);
if (!lua_isnil(lua, -1)) {
byte_pos = (tb_long_t)lua_tointeger(lua, -1);
}
}
if (byte_pos > 0) {
tb_long_t char_pos = xm_utf8_charpos(s, len, byte_pos);
if (char_pos > 0) {
lua_pushinteger(lua, char_pos);
return 1;
}
}
lua_pushnil(lua);
return 1;
}
================================================
FILE: core/src/xmake/utf8/len.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file len.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utf8len(s [, i [, j [, lax]]]) --> number of characters that
* start in the range [i,j], or nil + current position if 's' is not
* well formed in that interval
*/
tb_int_t xm_utf8_len(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_Integer posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 2, 1), len);
lua_Integer posj = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, -1), len);
tb_bool_t lax = lua_toboolean(lua, 4);
luaL_argcheck(lua, 1 <= posi && --posi <= (lua_Integer)len, 2, "initial position out of bounds");
luaL_argcheck(lua, --posj < (lua_Integer)len, 3, "final position out of bounds");
tb_size_t errpos = 0;
tb_long_t n = xm_utf8_len_impl(s, len, (tb_long_t)posi + 1, (tb_long_t)posj + 1, !lax, &errpos);
if (n < 0) {
lua_pushnil(lua);
lua_pushinteger(lua, errpos);
return 2;
}
lua_pushinteger(lua, n);
return 1;
}
================================================
FILE: core/src/xmake/utf8/offset.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file offset.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* offset(s, n, [i]) -> index where n-th character counting from
* position 'i' starts; 0 means character at 'i'.
*/
tb_int_t xm_utf8_offset(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_Integer n = luaL_checkinteger(lua, 2);
lua_Integer posi = (n >= 0) ? 1 : len + 1;
posi = xm_utf8_posrelat((tb_long_t)luaL_optinteger(lua, 3, posi), len);
tb_long_t result = xm_utf8_offset_impl(s, len, (tb_long_t)n, (tb_long_t)posi);
if (result == -1) {
return luaL_argerror(lua, 3, "position out of bounds");
}
if (result == -2) {
return luaL_error(lua, "initial position is a continuation byte");
}
if (result == 0) {
lua_pushnil(lua);
return 1;
}
lua_pushinteger(lua, result);
return 1;
}
================================================
FILE: core/src/xmake/utf8/prefix.h
================================================
#ifndef XM_UTF8_PREFIX_H
#define XM_UTF8_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/utf8/reverse.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file reverse.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utf8.reverse(s)
*/
tb_int_t xm_utf8_reverse(lua_State *lua) {
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
if (len == 0) {
lua_pushliteral(lua, "");
return 1;
}
// do reverse
if (len < 1024) {
tb_char_t buf[1024 + 1];
xm_utf8_reverse_impl(s, len, buf);
lua_pushlstring(lua, buf, len);
} else {
tb_char_t* buf = (tb_char_t*)tb_malloc_bytes(len + 1);
if (buf) {
xm_utf8_reverse_impl(s, len, buf);
lua_pushlstring(lua, buf, len);
tb_free(buf);
} else {
lua_pushnil(lua);
}
}
return 1;
}
================================================
FILE: core/src/xmake/utf8/sub.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file sub.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* utf8.sub(s, i [, j])
*/
tb_int_t xm_utf8_sub(lua_State *lua) {
size_t len;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_Integer i = luaL_checkinteger(lua, 2);
lua_Integer j = luaL_optinteger(lua, 3, -1);
tb_size_t sublen = 0;
tb_char_t const* sub = xm_utf8_sub_impl(s, len, (tb_long_t)i, (tb_long_t)j, &sublen);
if (sub) {
lua_pushlstring(lua, sub, sublen);
} else {
lua_pushliteral(lua, "");
}
return 1;
}
================================================
FILE: core/src/xmake/utf8/utf8.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file utf8.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_char_t const* xm_utf8_decode(tb_char_t const* s, xm_utf8_int_t* val, tb_bool_t strict) {
static const xm_utf8_int_t limits[] = {~(xm_utf8_int_t)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
tb_uint32_t c = (tb_byte_t)s[0];
xm_utf8_int_t res = 0;
if (c < 0x80) {
res = c;
} else {
if (xm_utf8_iscont(c)) {
return tb_null;
}
tb_int_t count = 0;
for (; c & 0x40; c <<= 1) {
tb_uint32_t cc = (tb_byte_t)s[++count];
if (!xm_utf8_iscont(cc)) {
return tb_null;
}
res = (res << 6) | (cc & 0x3F);
}
res |= ((xm_utf8_int_t)(c & 0x7F) << (count * 5));
if (count > 5 || res > XM_UTF8_MAXUTF || res < limits[count]) {
return tb_null;
}
s += count;
}
if (strict) {
if (res > XM_UTF8_MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu)) {
return tb_null;
}
}
if (val) {
*val = res;
}
return s + 1;
}
tb_size_t xm_utf8_encode(tb_char_t* s, xm_utf8_int_t val) {
tb_assert_and_check_return_val(s, 0);
if (val < 0x80) {
s[0] = (tb_char_t)val;
return 1;
}
if (val < 0x800) {
s[0] = (tb_char_t)(0xc0 | ((val >> 6) & 0x1f));
s[1] = (tb_char_t)(0x80 | (val & 0x3f));
return 2;
}
if (val < 0x10000) {
s[0] = (tb_char_t)(0xe0 | ((val >> 12) & 0x0f));
s[1] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));
s[2] = (tb_char_t)(0x80 | (val & 0x3f));
return 3;
}
if (val <= 0x10FFFF) {
s[0] = (tb_char_t)(0xf0 | ((val >> 18) & 0x07));
s[1] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f));
s[2] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));
s[3] = (tb_char_t)(0x80 | (val & 0x3f));
return 4;
}
if (val <= 0x3FFFFFF) {
s[0] = (tb_char_t)(0xf8 | ((val >> 24) & 0x03));
s[1] = (tb_char_t)(0x80 | ((val >> 18) & 0x3f));
s[2] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f));
s[3] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));
s[4] = (tb_char_t)(0x80 | (val & 0x3f));
return 5;
}
if (val <= 0x7FFFFFFF) {
s[0] = (tb_char_t)(0xfc | ((val >> 30) & 0x01));
s[1] = (tb_char_t)(0x80 | ((val >> 24) & 0x3f));
s[2] = (tb_char_t)(0x80 | ((val >> 18) & 0x3f));
s[3] = (tb_char_t)(0x80 | ((val >> 12) & 0x3f));
s[4] = (tb_char_t)(0x80 | ((val >> 6) & 0x3f));
s[5] = (tb_char_t)(0x80 | (val & 0x3f));
return 6;
}
return 0;
}
tb_long_t xm_utf8_charpos(tb_char_t const* s, tb_size_t len, tb_long_t byte_pos) {
if (byte_pos <= 0) return 0;
if (byte_pos > len + 1) byte_pos = len + 1;
// adjust byte_pos to the start of the character
//
// performance:
// 0(1) complexity, because utf8 sequence is max 4 bytes
while (byte_pos > 1 && xm_utf8_iscont(s[byte_pos - 1])) {
byte_pos--;
}
// get character position
tb_long_t count = xm_utf8_len_impl(s, len, 1, byte_pos - 1, tb_true, tb_null);
return count >= 0? count + 1 : -1;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation interfaces
*/
static struct { xm_utf8_int_t first; xm_utf8_int_t last; } const g_non_spacing[] =
{
{0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489},
{0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
{0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603},
{0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670},
{0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
{0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
{0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902},
{0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D},
{0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981},
{0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD},
{0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C},
{0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
{0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC},
{0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD},
{0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C},
{0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D},
{0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
{0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
{0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC},
{0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
{0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D},
{0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6},
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
{0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
{0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
{0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
{0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97},
{0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
{0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039},
{0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F},
{0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
{0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD},
{0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD},
{0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922},
{0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B},
{0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34},
{0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42},
{0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF},
{0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063},
{0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F},
{0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
{0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
{0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB},
{0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
{0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},
{0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
{0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
{0xE0100, 0xE01EF}
};
tb_long_t xm_utf8_charwidth(xm_utf8_int_t val) {
// test for 8-bit control characters
if (val == 0) return 0;
if (val < 32 || (val >= 0x7f && val < 0xa0)) {
if (val == 0x09) return 4; // TAB
if (val == 0x08) return -1; // BS
return 0; // other control chars
}
// binary search in table of non-spacing characters
tb_long_t min = 0;
tb_long_t max = tb_arrayn(g_non_spacing) - 1;
if (val >= g_non_spacing[0].first && val <= g_non_spacing[max].last) {
while (max >= min) {
tb_long_t mid = (min + max) / 2;
if (val > g_non_spacing[mid].last) {
min = mid + 1;
} else if (val < g_non_spacing[mid].first) {
max = mid - 1;
} else {
return 0;
}
}
}
if (val >= 0x1100 && (val <= 0x115f || // Hangul Jamo init. consonants
val == 0x2329 || val == 0x232a ||
(val >= 0x2e80 && val <= 0xa4cf &&
val != 0x303f) || // CJK ... Yi
(val >= 0xac00 && val <= 0xd7a3) || // Hangul Syllables
(val >= 0xf900 && val <= 0xfaff) || // CJK Compatibility Ideographs
(val >= 0xfe10 && val <= 0xfe19) || // Vertical forms
(val >= 0xfe30 && val <= 0xfe6f) || // CJK Compatibility Forms
(val >= 0xff00 && val <= 0xff60) || // Fullwidth Forms
(val >= 0xffe0 && val <= 0xffe6) ||
(val >= 0x20000 && val <= 0x2fffd) ||
(val >= 0x30000 && val <= 0x3fffd))) {
return 2;
}
return 1;
}
tb_long_t xm_utf8_strwidth(tb_char_t const* s, tb_size_t len) {
tb_assert_and_check_return_val(s, -1);
tb_long_t width = 0;
tb_char_t const* p = s;
tb_char_t const* e = s + len;
while (p < e) {
xm_utf8_int_t val;
tb_char_t const* next = xm_utf8_decode(p, &val, tb_true);
if (next) {
tb_long_t w = xm_utf8_charwidth(val);
if (w < 0) return -1;
width += w;
p = next;
} else {
p++; // invalid byte, skip
}
}
return width;
}
tb_long_t xm_utf8_len_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, tb_size_t* errpos) {
tb_assert_and_check_return_val(s, -1);
tb_long_t n = 0;
while (posi <= posj) {
tb_char_t const* s1 = xm_utf8_decode(s + posi - 1, tb_null, strict);
if (s1 == tb_null) {
if (errpos) {
*errpos = posi;
}
return -1;
}
posi = s1 - s + 1;
n++;
}
return n;
}
tb_long_t xm_utf8_offset_impl(tb_char_t const* s, tb_size_t len, tb_long_t n, tb_long_t posi) {
tb_assert_and_check_return_val(s, -1);
// check
if (1 > posi || --posi > (tb_long_t)len) {
return -1; // error: position out of bounds
}
if (n == 0) {
// find beginning of current byte sequence
while (posi > 0 && xm_utf8_iscontp(s + posi)) {
posi--;
}
} else {
if (xm_utf8_iscontp(s + posi)) {
return -2; // error: initial position is a continuation byte
}
if (n < 0) {
while (n < 0 && posi > 0) {
do {
posi--;
} while (posi > 0 && xm_utf8_iscontp(s + posi));
n++;
}
} else {
n--;
while (n > 0 && posi < (tb_long_t)len) {
do {
posi++;
} while (xm_utf8_iscontp(s + posi));
n--;
}
}
}
if (n == 0) {
return posi + 1;
}
return 0; // nil
}
tb_bool_t xm_utf8_codepoint_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, xm_utf8_codepoint_func_t func, tb_cpointer_t udata) {
tb_assert_and_check_return_val(s, tb_false);
if (posi > posj) {
return tb_true;
}
tb_char_t const* se = s + posj;
for (s += posi - 1; s < se;) {
xm_utf8_int_t code;
s = xm_utf8_decode(s, &code, strict);
if (s == tb_null) {
return tb_false;
}
if (func && !func(code, udata)) {
return tb_false;
}
}
return tb_true;
}
tb_long_t xm_utf8_find_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen, tb_long_t init, tb_long_t* pchar_end) {
tb_assert_and_check_return_val(s && sub, 0);
if (sublen == 0) {
if (init > (tb_long_t)len + 1) init = len + 1;
tb_long_t start_byte = 1;
if (init > 0) {
start_byte = xm_utf8_offset_impl(s, len, init, 1);
} else if (init < 0) {
start_byte = xm_utf8_offset_impl(s, len, init, len + 1);
}
if (start_byte <= 0) start_byte = 1;
tb_long_t char_pos = 1;
if (start_byte > 1) {
tb_long_t c = xm_utf8_len_impl(s, len, 1, start_byte - 1, tb_true, tb_null);
if (c >= 0) char_pos = c + 1;
}
if (pchar_end) *pchar_end = char_pos - 1;
return char_pos;
}
tb_long_t start_byte = 1;
if (init > 0) {
start_byte = xm_utf8_offset_impl(s, len, init, 1);
} else if (init < 0) {
start_byte = xm_utf8_offset_impl(s, len, init, len + 1);
}
if (start_byte <= 0) return 0;
tb_char_t const* p = tb_strstr(s + start_byte - 1, sub);
if (!p) return 0;
tb_long_t found_byte_start = p - s + 1;
tb_long_t char_start = 1;
if (found_byte_start > 1) {
tb_long_t c = xm_utf8_len_impl(s, len, 1, found_byte_start - 1, tb_true, tb_null);
if (c < 0) return 0;
char_start = c + 1;
}
if (pchar_end) {
tb_long_t match_len = xm_utf8_len_impl(s, len, found_byte_start, found_byte_start + sublen - 1, tb_true, tb_null);
if (match_len < 0) return 0;
*pchar_end = char_start + match_len - 1;
}
return char_start;
}
tb_long_t xm_utf8_lastof_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen) {
tb_assert_and_check_return_val(s && sub, 0);
tb_check_return_val(sublen, 0);
// optimize for single character search
if (sublen == 1) {
tb_char_t const* p = tb_strrchr(s, sub[0]);
return p ? (tb_long_t)(p - s + 1) : 0;
}
tb_char_t const* p = s;
tb_char_t const* last = tb_null;
while (1) {
p = tb_strstr(p, sub);
if (!p) break;
last = p;
p += 1;
}
if (last) {
return (tb_long_t)(last - s + 1);
}
return 0;
}
tb_long_t xm_utf8_byte_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, xm_utf8_codepoint_func_t func, tb_cpointer_t udata) {
tb_size_t sublen = 0;
tb_char_t const* sub = xm_utf8_sub_impl(s, len, i, j, &sublen);
if (sub && sublen > 0) {
// decode and push codepoints
tb_long_t n = 0;
tb_char_t const* p = sub;
tb_char_t const* e = sub + sublen;
while (p < e) {
xm_utf8_int_t val;
tb_char_t const* next = xm_utf8_decode(p, &val, tb_true);
if (next) {
if (func && !func(val, udata)) break;
n++;
p = next;
} else {
p++;
}
}
return n;
}
return 0;
}
tb_char_t const* xm_utf8_sub_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, tb_size_t* psublen) {
tb_assert_and_check_return_val(s && psublen, tb_null);
*psublen = 0;
// map i (char index) to byte offset
tb_long_t start_byte = 0;
if (i > 0) {
start_byte = xm_utf8_offset_impl(s, len, i, 1);
} else if (i < 0) {
start_byte = xm_utf8_offset_impl(s, len, i, len + 1);
} else {
start_byte = 1;
}
if (start_byte == -1) {
if (i > 0) {
return "";
} else {
start_byte = 1;
}
} else if (start_byte == 0) {
if (i < 0) {
start_byte = 1;
} else {
return "";
}
}
// map j (char index) to byte offset (end)
tb_long_t end_byte = 0;
if (j >= 0) {
end_byte = xm_utf8_offset_impl(s, len, j + 1, 1);
} else {
end_byte = xm_utf8_offset_impl(s, len, j + 1, len + 1);
}
if (end_byte == -1) {
if (j >= 0) end_byte = len + 1;
else end_byte = 1;
} else if (end_byte == 0) {
if (j >= 0) end_byte = len + 1;
else end_byte = 1;
}
if (end_byte <= start_byte) {
return "";
}
*psublen = end_byte - start_byte;
return s + start_byte - 1;
}
tb_char_t* xm_utf8_reverse_impl(tb_char_t const* s, tb_size_t len, tb_char_t* buf) {
tb_assert_and_check_return_val(s && len && buf, tb_null);
tb_char_t const* p = s;
tb_char_t const* e = s + len;
tb_char_t* d = buf + len;
while (p < e) {
xm_utf8_int_t code;
tb_char_t const* next = xm_utf8_decode(p, &code, tb_false);
// invalid utf8? treat as 1 byte
tb_size_t n = 1;
if (next) {
n = next - p;
}
// safety check
if (p + n > e) n = e - p;
d -= n;
tb_memcpy(d, p, n);
p += n;
}
buf[len] = '\0';
return buf;
}
================================================
FILE: core/src/xmake/utf8/utf8.h
================================================
#ifndef XM_UTF8_UTF8_H
#define XM_UTF8_UTF8_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#define xm_utf8_iscont(c) (((c) & 0xC0) == 0x80)
#define xm_utf8_iscontp(p) xm_utf8_iscont(*(p))
#define XM_UTF8_MAXUNICODE 0x10FFFFu
#define XM_UTF8_MAXUTF 0x7FFFFFFFu
#define XM_UTF8_MSGInvalid "invalid UTF-8 code"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
typedef tb_uint32_t xm_utf8_int_t;
typedef tb_bool_t (*xm_utf8_codepoint_func_t)(xm_utf8_int_t code, tb_cpointer_t udata);
/* //////////////////////////////////////////////////////////////////////////////////////
* inline interfaces
*/
static __tb_inline__ tb_long_t xm_utf8_posrelat(tb_long_t pos, tb_size_t len) {
if (pos >= 0) {
return pos;
} else if (0u - (tb_size_t)pos > len) {
return 0;
} else {
return (tb_long_t)len + pos + 1;
}
}
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
tb_char_t const* xm_utf8_decode(tb_char_t const* s, xm_utf8_int_t* val, tb_bool_t strict);
tb_size_t xm_utf8_encode(tb_char_t* s, xm_utf8_int_t val);
tb_long_t xm_utf8_charpos(tb_char_t const* s, tb_size_t len, tb_long_t byte_pos);
tb_long_t xm_utf8_charwidth(xm_utf8_int_t val);
tb_long_t xm_utf8_strwidth(tb_char_t const* s, tb_size_t len);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation interfaces
*/
tb_long_t xm_utf8_len_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, tb_size_t* errpos);
tb_long_t xm_utf8_offset_impl(tb_char_t const* s, tb_size_t len, tb_long_t n, tb_long_t posi);
tb_bool_t xm_utf8_codepoint_impl(tb_char_t const* s, tb_size_t len, tb_long_t posi, tb_long_t posj, tb_bool_t strict, xm_utf8_codepoint_func_t func, tb_cpointer_t udata);
tb_long_t xm_utf8_find_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen, tb_long_t init, tb_long_t* pchar_end);
tb_long_t xm_utf8_lastof_impl(tb_char_t const* s, tb_size_t len, tb_char_t const* sub, tb_size_t sublen);
tb_long_t xm_utf8_byte_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, xm_utf8_codepoint_func_t func, tb_cpointer_t udata);
tb_char_t const* xm_utf8_sub_impl(tb_char_t const* s, tb_size_t len, tb_long_t i, tb_long_t j, tb_size_t* psublen);
tb_char_t* xm_utf8_reverse_impl(tb_char_t const* s, tb_size_t len, tb_char_t* buf);
#endif
================================================
FILE: core/src/xmake/utf8/width.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file width.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "utf8.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
/* utf8.width(char)
* utf8.width(str)
* utf8.width(codepoint)
*/
tb_int_t xm_utf8_width(lua_State* lua) {
if (lua_isnumber(lua, 1)) {
xm_utf8_int_t val = (xm_utf8_int_t)lua_tointeger(lua, 1);
lua_pushinteger(lua, xm_utf8_charwidth(val));
} else {
size_t len = 0;
tb_char_t const* s = luaL_checklstring(lua, 1, &len);
lua_pushinteger(lua, xm_utf8_strwidth(s, len));
}
return 1;
}
================================================
FILE: core/src/xmake/utils/charset.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file charset.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "charset"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "charset.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
// the charsets, @note: type & name is sorted
static xm_charset_entry_t g_charsets[] = {
{ TB_CHARSET_TYPE_ANSI, "ansi" },
{ TB_CHARSET_TYPE_ASCII, "ascii" },
{ TB_CHARSET_TYPE_GB2312, "gb2312" },
{ TB_CHARSET_TYPE_GBK, "gbk" },
{ TB_CHARSET_TYPE_ISO8859, "iso8859" },
{ TB_CHARSET_TYPE_UCS2 | TB_CHARSET_TYPE_NE, "ucs2" },
{ TB_CHARSET_TYPE_UCS4 | TB_CHARSET_TYPE_NE, "ucs4" },
{ TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE, "utf16" },
{ TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_BE, "utf16be" },
{ TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_NE, "utf16bom" },
{ TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, "utf16le" },
{ TB_CHARSET_TYPE_UTF16 | TB_CHARSET_TYPE_LE, "utf16lebom" },
{ TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_NE, "utf32" },
{ TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_BE, "utf32be" },
{ TB_CHARSET_TYPE_UTF32 | TB_CHARSET_TYPE_LE, "utf32le" },
{ TB_CHARSET_TYPE_UTF8, "utf8" },
{ TB_CHARSET_TYPE_UTF8, "utf8bom" },
};
/* //////////////////////////////////////////////////////////////////////////////////////
* finder
*/
static tb_long_t xm_charset_comp_by_name(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t name) {
return tb_stricmp(((xm_charset_entry_ref_t)item)->name, (tb_char_t const *)name);
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
xm_charset_entry_ref_t xm_charset_find_by_name(tb_char_t const *name) {
// make iterator
tb_array_iterator_t array_iterator;
tb_iterator_ref_t iterator =
tb_array_iterator_init_mem(&array_iterator, g_charsets, tb_arrayn(g_charsets), sizeof(xm_charset_entry_t));
tb_assert_and_check_return_val(iterator, tb_null);
// find it by the binary search
tb_size_t itor = tb_binary_find_all_if(iterator, xm_charset_comp_by_name, name);
if (itor != tb_iterator_tail(iterator)) {
return (xm_charset_entry_ref_t)tb_iterator_item(iterator, itor);
} else {
return tb_null;
}
}
================================================
FILE: core/src/xmake/utils/charset.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file charset.h
*
*/
#ifndef XM_UTILS_CHARSET_H
#define XM_UTILS_CHARSET_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the charset entry type
typedef struct __xm_charset_entry_t {
// the charset type
tb_size_t type;
// the charset name
tb_char_t const *name;
} xm_charset_entry_t, *xm_charset_entry_ref_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
/* find charset by name
*
* @param name the charset name
*
* @return the charset entry
*/
xm_charset_entry_ref_t xm_charset_find_by_name(tb_char_t const *name);
#endif
================================================
FILE: core/src/xmake/utils/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_UTILS_PREFIX_H
#define XM_UTILS_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#endif
================================================
FILE: core/src/xmake/winos/ansi.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu
* @file ansi.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "ansi"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "ansi.h"
#include
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
static tb_int_t xm_expand_cp(tb_int_t cp) {
tb_assert_and_check_return_val(cp >= 0 && cp <= 65535, 0);
if (cp == CP_OEMCP) {
return GetOEMCP();
}
if (cp == CP_ACP) {
return GetACP();
}
return cp;
}
tb_int_t xm_winos_console_cp(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_int_t n = lua_gettop(lua);
if (n >= 1) {
lua_Integer cp = luaL_checkinteger(lua, 1);
luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page");
cp = xm_expand_cp((tb_uint_t)cp);
luaL_argcheck(lua, SetConsoleCP((tb_uint_t)cp), 1, "failed to set code page");
lua_pushinteger(lua, cp);
return 1;
} else {
tb_uint_t cp = GetConsoleCP();
lua_pushinteger(lua, (lua_Integer)cp);
return 1;
}
}
tb_int_t xm_winos_console_output_cp(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_int_t n = lua_gettop(lua);
if (n >= 1) {
lua_Integer cp = luaL_checkinteger(lua, 1);
luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page");
cp = xm_expand_cp((tb_uint_t)cp);
luaL_argcheck(lua, SetConsoleOutputCP((tb_uint_t)cp), 1, "failed to set code page");
lua_pushinteger(lua, cp);
return 1;
} else {
tb_uint_t cp = GetConsoleOutputCP();
lua_pushinteger(lua, (lua_Integer)cp);
return 1;
}
}
tb_int_t xm_winos_cp_info(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
lua_Integer cp = luaL_checkinteger(lua, 1);
luaL_argcheck(lua, cp >= 0 && cp < 65536, 1, "invalid code page");
CPINFOEX cp_info;
luaL_argcheck(lua, GetCPInfoEx((tb_uint_t)cp, 0, &cp_info), 1, "invalid code page");
lua_newtable(lua);
lua_pushliteral(lua, "name");
tb_char_t *namebuf = tb_malloc_cstr(sizeof(cp_info.CodePageName) * 2);
tb_assert_and_check_return_val(namebuf, 0);
tb_size_t namelen = tb_wtoa(namebuf, (const tb_wchar_t *)cp_info.CodePageName, sizeof(cp_info.CodePageName) * 2);
tb_assert_and_check_return_val(namelen < sizeof(cp_info.CodePageName) * 2, 0);
lua_pushlstring(lua, namebuf, namelen);
tb_free(namebuf);
lua_settable(lua, -3);
lua_pushliteral(lua, "max_char_size");
lua_pushinteger(lua, (lua_Integer)cp_info.MaxCharSize);
lua_settable(lua, -3);
lua_pushliteral(lua, "id");
lua_pushinteger(lua, (lua_Integer)cp_info.CodePage);
lua_settable(lua, -3);
lua_pushliteral(lua, "default_char");
lua_pushstring(lua, (tb_char_t const *)cp_info.DefaultChar);
lua_settable(lua, -3);
lua_pushliteral(lua, "lead_byte");
lua_createtable(lua, MAX_LEADBYTES / 2, 0);
for (tb_size_t i = 0; i < MAX_LEADBYTES && cp_info.LeadByte[i] != 0 && cp_info.LeadByte[i + 1] != 0; i += 2) {
lua_pushinteger(lua, (i / 2) + 1);
lua_createtable(lua, 0, 2);
lua_pushliteral(lua, "from");
lua_pushinteger(lua, cp_info.LeadByte[i]);
lua_settable(lua, -3);
lua_pushliteral(lua, "to");
lua_pushinteger(lua, cp_info.LeadByte[i + 1]);
lua_settable(lua, -3);
lua_settable(lua, -3);
}
lua_settable(lua, -3);
return 1;
}
tb_int_t xm_winos_ansi_cp(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_uint_t cp = GetACP();
lua_pushinteger(lua, (lua_Integer)cp);
return 1;
}
tb_int_t xm_winos_oem_cp(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
tb_uint_t cp = GetOEMCP();
lua_pushinteger(lua, (lua_Integer)cp);
return 1;
}
================================================
FILE: core/src/xmake/winos/ansi.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author OpportunityLiu
* @file ansi.h
*
*/
#ifndef XM_WINOS_ANSI_H
#define XM_WINOS_ANSI_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#endif
================================================
FILE: core/src/xmake/winos/file_signature.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file file_signature.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "file_signature"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include
#include
#include
#include
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the file signature info type
typedef struct __tb_file_signature_info_t {
// is the file digitally signed?
tb_bool_t is_signed;
// is the signature valid and trusted by the OS?
tb_bool_t is_trusted;
/* the name of the signer (e.g., "Microsoft Corporation")
tbox uses UTF-8 by default for tb_char_t
*/
tb_char_t signer_name[256];
} tb_file_signature_info_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_bool_t tb_file_get_signature_info(tb_char_t const* filepath, tb_file_signature_info_t* info) {
tb_assert_and_check_return_val(filepath && info, tb_false);
// init info
tb_memset(info, 0, sizeof(tb_file_signature_info_t));
// convert path
tb_wchar_t wide_path[TB_PATH_MAXN];
if (!tb_path_absolute_w(filepath, wide_path, TB_PATH_MAXN)) {
return tb_false;
}
// init file info
WINTRUST_FILE_INFO file_data = {0};
file_data.cbStruct = sizeof(file_data);
file_data.pcwszFilePath = wide_path;
file_data.hFile = NULL;
file_data.pgKnownSubject = NULL;
// init trust data
WINTRUST_DATA trust_data = {0};
trust_data.cbStruct = sizeof(trust_data);
trust_data.dwUIChoice = WTD_UI_NONE;
trust_data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
trust_data.dwUnionChoice = WTD_CHOICE_FILE;
trust_data.dwStateAction = WTD_STATEACTION_VERIFY;
trust_data.hWVTStateData = NULL;
trust_data.pwszURLReference = NULL;
trust_data.dwProvFlags = WTD_SAFER_FLAG;
trust_data.dwUIContext = 0;
trust_data.pFile = &file_data;
// verify trust
GUID guid_action = WINTRUST_ACTION_GENERIC_VERIFY_V2;
LONG status = WinVerifyTrust(NULL, &guid_action, &trust_data);
// clean up
trust_data.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(NULL, &guid_action, &trust_data);
// check status
if (status == ERROR_SUCCESS) {
info->is_signed = tb_true;
info->is_trusted = tb_true;
} else if (status == TRUST_E_NOSIGNATURE) {
return tb_true;
} else if (status == TRUST_E_EXPLICIT_DISTRUST || status == TRUST_E_SUBJECT_NOT_TRUSTED) {
info->is_signed = tb_true;
info->is_trusted = tb_false;
} else {
return tb_false;
}
// extract signer name
if (info->is_signed) {
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
DWORD dwEncoding = 0;
DWORD dwContentType = 0;
DWORD dwFormatType = 0;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BOOL bResult = FALSE;
bResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
wide_path,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
NULL);
if (bResult) {
DWORD cbSignerInfo = 0;
if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cbSignerInfo)) {
pSignerInfo = (PCMSG_SIGNER_INFO)tb_malloc(cbSignerInfo);
if (pSignerInfo) {
if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (void*)pSignerInfo, &cbSignerInfo)) {
CERT_INFO certInfo;
certInfo.Issuer = pSignerInfo->Issuer;
certInfo.SerialNumber = pSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&certInfo,
NULL);
if (pCertContext) {
tb_wchar_t wName[256] = {0};
if (CertGetNameStringW(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
wName,
256)) {
tb_wtoa(info->signer_name, wName, sizeof(info->signer_name));
}
CertFreeCertificateContext(pCertContext);
}
}
tb_free(pSignerInfo);
}
}
}
if (hStore) CertCloseStore(hStore, 0);
if (hMsg) CryptMsgClose(hMsg);
}
return tb_true;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* get the file signature info
*
* local info = winos.file_signature(filepath)
* {
* is_signed = true,
* is_trusted = true,
* signer_name = "Microsoft Corporation"
* }
*/
tb_int_t xm_winos_file_signature(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the arguments
tb_char_t const *filepath = luaL_checkstring(lua, 1);
tb_check_return_val(filepath, 0);
// get signature info
tb_file_signature_info_t info = {0};
if (tb_file_get_signature_info(filepath, &info)) {
lua_newtable(lua);
lua_pushstring(lua, "is_signed");
lua_pushboolean(lua, info.is_signed);
lua_settable(lua, -3);
lua_pushstring(lua, "is_trusted");
lua_pushboolean(lua, info.is_trusted);
lua_settable(lua, -3);
if (info.is_signed) {
lua_pushstring(lua, "signer_name");
lua_pushstring(lua, info.signer_name);
lua_settable(lua, -3);
}
return 1;
}
return 0;
}
================================================
FILE: core/src/xmake/winos/logical_drives.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file logical_drives.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "logical_drives"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
// get the logical drives
tb_int_t xm_winos_logical_drives(lua_State *lua) {
// init table
lua_newtable(lua);
// get logical drives
tb_char_t *data = tb_null;
do {
// get buffer size
DWORD size = GetLogicalDriveStringsA(0, tb_null);
tb_assert_and_check_break(size);
// make data buffer
data = (tb_char_t *)tb_malloc0(size + 1);
tb_assert_and_check_break(data);
// get logical drives
size = GetLogicalDriveStringsA(size, data);
tb_assert_and_check_break(size);
// parse logical drives
tb_size_t i = 1;
tb_char_t const *p = data;
while (*p) {
// save drive
lua_pushinteger(lua, i++);
lua_pushstring(lua, p);
lua_settable(lua, -3);
// next drive
p += tb_strlen(p) + 1;
}
} while (0);
// exit data
if (data) {
tb_free(data);
}
data = tb_null;
return 1;
}
================================================
FILE: core/src/xmake/winos/prefix.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file prefix.h
*
*/
#ifndef XM_WINOS_PREFIX_H
#define XM_WINOS_PREFIX_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "../prefix.h"
#ifdef TB_CONFIG_OS_WINDOWS
#include
#endif
#endif
================================================
FILE: core/src/xmake/winos/registry_keys.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file registry_keys.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "registry_keys"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the enum info type
typedef struct __xm_winos_registry_enum_info_t {
lua_State *lua;
HKEY key;
tb_int_t ok;
tb_char_t const *error;
tb_int_t count;
tb_wchar_t key_name[1024];
tb_char_t key_path_a[TB_PATH_MAXN];
} xm_winos_registry_enum_info_t;
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static tb_void_t xm_winos_registry_enum_keys(xm_winos_registry_enum_info_t *info,
tb_wchar_t const *rootdir,
tb_long_t recursion) {
// enum keys
HKEY keynew = tb_null;
lua_State *lua = info->lua;
tb_wchar_t *key_path = tb_null;
tb_size_t key_path_maxn = TB_PATH_MAXN;
do {
// open registry key
if (RegOpenKeyExW(info->key, rootdir, 0, KEY_READ, &keynew) != ERROR_SUCCESS && keynew) {
info->ok = -1;
info->error = "open registry key failed";
break;
}
// query keys
DWORD key_name_num = 0;
DWORD key_name_maxn = 0;
if (RegQueryInfoKeyW(keynew,
tb_null,
tb_null,
tb_null,
&key_name_num,
&key_name_maxn,
tb_null,
tb_null,
tb_null,
tb_null,
tb_null,
tb_null) != ERROR_SUCCESS) {
// cannot query this key, we ignore it
break;
}
key_name_maxn++; // add `\0`
// ensure enough key path buffer
if (key_name_maxn > tb_arrayn(info->key_name)) {
info->ok = -1;
info->error = "no enough key path buffer";
break;
}
// init key path
key_path = (tb_wchar_t *)tb_malloc(key_path_maxn * sizeof(tb_wchar_t));
if (!key_path) {
info->ok = -1;
info->error = "no enough key path buffer";
break;
}
// get all keys
DWORD i = 0;
for (i = 0; i < key_name_num && info->ok > 0; i++) {
// get key name
info->key_name[0] = L'\0';
DWORD key_name_size = tb_arrayn(info->key_name);
if (RegEnumKeyExW(keynew, i, info->key_name, &key_name_size, tb_null, tb_null, tb_null, tb_null) !=
ERROR_SUCCESS) {
info->ok = -1;
info->error = "get registry key failed";
break;
}
// get key path
tb_swprintf(key_path, key_path_maxn, L"%s\\%s", rootdir, info->key_name);
// get key path (mbs)
tb_size_t key_path_a_size = tb_wtoa(info->key_path_a, key_path, sizeof(info->key_path_a));
if (key_path_a_size == -1) {
info->ok = -1;
info->error = "convert registry key path failed";
break;
}
// do callback(key_name)
lua_pushvalue(lua, 4);
lua_pushlstring(lua, info->key_path_a, key_path_a_size);
lua_call(lua, 1, 1);
info->count++;
// is continue?
tb_bool_t is_continue = lua_toboolean(lua, -1);
lua_pop(lua, 1);
if (!is_continue) {
info->ok = 0;
break;
}
// enum all subkeys
if (recursion > 0 || recursion < 0) {
xm_winos_registry_enum_keys(info, key_path, recursion > 0 ? recursion - 1 : recursion);
}
}
} while (0);
// exit registry key
if (keynew) {
RegCloseKey(keynew);
}
keynew = tb_null;
// free key path
if (key_path) {
tb_free(key_path);
}
key_path = tb_null;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* get registry keys
*
* local count, errors = winos.registry_keys("HKEY_LOCAL_MACHINE",
* "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug",
* function (key_path)
* return true -- continue or break
* end)
*/
tb_int_t xm_winos_registry_keys(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the arguments
tb_char_t const *rootkey = luaL_checkstring(lua, 1);
tb_char_t const *rootdir = luaL_checkstring(lua, 2);
tb_long_t recursion = (tb_long_t)lua_tointeger(lua, 3);
tb_bool_t is_function = lua_isfunction(lua, 4);
tb_check_return_val(rootkey && rootdir && is_function, 0);
// enum keys
tb_bool_t ok = tb_false;
tb_int_t count = 0;
HKEY key = tb_null;
do {
// get registry rootkey
if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) {
key = HKEY_CLASSES_ROOT;
} else if (!tb_strcmp(rootkey, "HKCR")) {
key = HKEY_CLASSES_ROOT;
} else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) {
key = HKEY_CURRENT_CONFIG;
} else if (!tb_strcmp(rootkey, "HKCC")) {
key = HKEY_CURRENT_CONFIG;
} else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) {
key = HKEY_CURRENT_USER;
} else if (!tb_strcmp(rootkey, "HKCU")) {
key = HKEY_CURRENT_USER;
} else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) {
key = HKEY_LOCAL_MACHINE;
} else if (!tb_strcmp(rootkey, "HKLM")) {
key = HKEY_LOCAL_MACHINE;
} else if (!tb_strcmp(rootkey, "HKEY_USERS")) {
key = HKEY_USERS;
} else {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey);
break;
}
// do enum
tb_wchar_t rootdir_w[TB_PATH_MAXN];
if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == -1) {
lua_pushnil(lua);
lua_pushfstring(lua, "rootdir is too long: %s", rootdir);
break;
}
xm_winos_registry_enum_info_t info;
info.lua = lua;
info.key = key;
info.count = 0;
info.ok = tb_true;
info.error = tb_null;
xm_winos_registry_enum_keys(&info, rootdir_w, recursion);
count = info.count;
ok = info.ok >= 0;
if (!ok) {
lua_pushnil(lua);
lua_pushfstring(lua, "%s: %s\\%s", info.error ? info.error : "enum registry keys failed", rootkey, rootdir);
}
} while (0);
if (ok) {
lua_pushinteger(lua, count);
return 1;
} else {
return 2;
}
}
================================================
FILE: core/src/xmake/winos/registry_query.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author TitanSnow, ruki
* @file registry_query.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "registry_query"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* types
*/
// the RegGetValueW func type
typedef BOOL(WINAPI *xm_RegGetValueW_t)(
HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* query registry
*
* local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", "Debugger")
*/
tb_int_t xm_winos_registry_query(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the arguments
tb_char_t const *rootkey = luaL_checkstring(lua, 1);
tb_char_t const *rootdir = luaL_checkstring(lua, 2);
tb_char_t const *valuename = luaL_checkstring(lua, 3);
tb_check_return_val(rootkey && rootdir && valuename, 0);
// query key-value
tb_bool_t ok = tb_false;
HKEY key = tb_null;
HKEY keynew = tb_null;
tb_char_t *value = tb_null;
tb_wchar_t *value_w = tb_null;
tb_size_t value_n = (tb_size_t)-1;
do {
// get registry rootkey
if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) {
key = HKEY_CLASSES_ROOT;
} else if (!tb_strcmp(rootkey, "HKCR")) {
key = HKEY_CLASSES_ROOT;
} else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) {
key = HKEY_CURRENT_CONFIG;
} else if (!tb_strcmp(rootkey, "HKCC")) {
key = HKEY_CURRENT_CONFIG;
} else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) {
key = HKEY_CURRENT_USER;
} else if (!tb_strcmp(rootkey, "HKCU")) {
key = HKEY_CURRENT_USER;
} else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) {
key = HKEY_LOCAL_MACHINE;
} else if (!tb_strcmp(rootkey, "HKLM")) {
key = HKEY_LOCAL_MACHINE;
} else if (!tb_strcmp(rootkey, "HKEY_USERS")) {
key = HKEY_USERS;
} else {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey);
break;
}
// convert rootdir to wide characters
tb_wchar_t rootdir_w[TB_PATH_MAXN];
if (tb_atow(rootdir_w, rootdir, TB_PATH_MAXN) == (tb_size_t)-1) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid registry rootkey:: %s", rootdir);
break;
}
// convert valuename to wide characters
tb_wchar_t valuename_w[TB_PATH_MAXN];
if (tb_atow(valuename_w, valuename, TB_PATH_MAXN) == (tb_size_t)-1) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid registry valuename: %s", valuename);
break;
}
// attempt to load RegGetValueW
static xm_RegGetValueW_t s_RegGetValueW = tb_null;
if (!s_RegGetValueW) {
// load the advapi32 module
tb_dynamic_ref_t module = (tb_dynamic_ref_t)GetModuleHandleA("advapi32.dll");
if (!module)
module = tb_dynamic_init("advapi32.dll");
if (module)
s_RegGetValueW = (xm_RegGetValueW_t)tb_dynamic_func(module, "RegGetValueW");
}
// get registry value
DWORD type = 0;
if (s_RegGetValueW) {
// get registry value size
DWORD valuesize_w = 0;
if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, 0, tb_null, &valuesize_w) != ERROR_SUCCESS) {
lua_pushnil(lua);
lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename);
break;
}
// make value buffer
DWORD valuesize = valuesize_w * 2;
value = (tb_char_t *)tb_malloc0(valuesize);
tb_assert_and_check_break(value);
value_w = (tb_wchar_t *)tb_malloc0(valuesize_w);
tb_assert_and_check_break(value_w);
// get value result, we attempt to do not expand value if get failed
type = 0;
if (s_RegGetValueW(key, rootdir_w, valuename_w, RRF_RT_ANY, &type, (PVOID)value_w, &valuesize_w) !=
ERROR_SUCCESS &&
s_RegGetValueW(
key, rootdir_w, valuename_w, RRF_RT_ANY | RRF_NOEXPAND, &type, (PVOID)value_w, &valuesize_w) !=
ERROR_SUCCESS) {
lua_pushnil(lua);
lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename);
break;
}
value_n = tb_wtoa(value, value_w, valuesize);
if (value_n == (tb_size_t)-1) {
lua_pushnil(lua);
lua_pushfstring(lua, "wtoa registry value failed: %s\\%s;%s", rootkey, rootdir, valuename);
break;
}
} else {
// open registry key
if (RegOpenKeyExW(key, rootdir_w, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) {
lua_pushnil(lua);
lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir);
break;
}
// get registry value size
DWORD valuesize_w = 0;
if (RegQueryValueExW(keynew, valuename_w, tb_null, tb_null, tb_null, &valuesize_w) != ERROR_SUCCESS) {
lua_pushnil(lua);
lua_pushfstring(lua, "get registry value size failed: %s\\%s;%s", rootkey, rootdir, valuename);
break;
}
// make value buffer
DWORD valuesize = valuesize_w * 2;
value = (tb_char_t *)tb_malloc0(valuesize);
tb_assert_and_check_break(value);
value_w = (tb_wchar_t *)tb_malloc0(valuesize_w);
tb_assert_and_check_break(value_w);
// get value result
type = 0;
if (RegQueryValueExW(keynew, valuename_w, tb_null, &type, (LPBYTE)value_w, &valuesize_w) != ERROR_SUCCESS) {
lua_pushnil(lua);
lua_pushfstring(lua, "get registry value failed: %s\\%s;%s", rootkey, rootdir, valuename);
break;
}
value_n = tb_wtoa(value, value_w, valuesize);
if (value_n == (tb_size_t)-1) {
lua_pushnil(lua);
lua_pushfstring(lua, "wtoa registry value failed: %s\\%s;%s", rootkey, rootdir, valuename);
break;
}
}
// save result
switch (type) {
case REG_SZ:
case REG_EXPAND_SZ:
lua_pushlstring(lua, value, value_n);
ok = tb_true;
break;
case REG_DWORD:
lua_pushfstring(lua, "%d", *((tb_int_t *)value));
ok = tb_true;
break;
case REG_QWORD:
lua_pushfstring(lua, "%lld", *((tb_int64_t *)value));
ok = tb_true;
break;
default:
lua_pushnil(lua);
lua_pushfstring(lua, "unsupported registry value type: %d", type);
break;
}
} while (0);
// exit registry key
if (keynew) {
RegCloseKey(keynew);
}
keynew = tb_null;
// exit value
if (value) {
tb_free(value);
}
value = tb_null;
if (value_w) {
tb_free(value_w);
}
value_w = tb_null;
return ok ? 1 : 2;
}
================================================
FILE: core/src/xmake/winos/registry_values.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file registry_values.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "registry_values"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* get registry values
*
* local count, errors = winos.registry_values("HKEY_LOCAL_MACHINE",
* "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug",
* function (value_name)
* return true -- continue or break
* end)
*/
tb_int_t xm_winos_registry_values(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the arguments
tb_char_t const *rootkey = luaL_checkstring(lua, 1);
tb_char_t const *rootdir = luaL_checkstring(lua, 2);
tb_bool_t is_function = lua_isfunction(lua, 3);
tb_check_return_val(rootkey && rootdir && is_function, 0);
// enum values
tb_bool_t ok = tb_false;
tb_int_t count = 0;
HKEY key = tb_null;
HKEY keynew = tb_null;
do {
// get registry rootkey
if (!tb_strcmp(rootkey, "HKEY_CLASSES_ROOT")) {
key = HKEY_CLASSES_ROOT;
} else if (!tb_strcmp(rootkey, "HKCR")) {
key = HKEY_CLASSES_ROOT;
} else if (!tb_strcmp(rootkey, "HKEY_CURRENT_CONFIG")) {
key = HKEY_CURRENT_CONFIG;
} else if (!tb_strcmp(rootkey, "HKCC")) {
key = HKEY_CURRENT_CONFIG;
} else if (!tb_strcmp(rootkey, "HKEY_CURRENT_USER")) {
key = HKEY_CURRENT_USER;
} else if (!tb_strcmp(rootkey, "HKCU")) {
key = HKEY_CURRENT_USER;
} else if (!tb_strcmp(rootkey, "HKEY_LOCAL_MACHINE")) {
key = HKEY_LOCAL_MACHINE;
} else if (!tb_strcmp(rootkey, "HKLM")) {
key = HKEY_LOCAL_MACHINE;
} else if (!tb_strcmp(rootkey, "HKEY_USERS")) {
key = HKEY_USERS;
} else {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid registry rootkey: %s", rootkey);
break;
}
// open registry key
if (RegOpenKeyExA(key, rootdir, 0, KEY_QUERY_VALUE, &keynew) != ERROR_SUCCESS && keynew) {
lua_pushnil(lua);
lua_pushfstring(lua, "open registry key failed: %s\\%s", rootkey, rootdir);
break;
}
// query values
DWORD value_name_num = 0;
DWORD value_name_maxn = 0;
if (RegQueryInfoKeyW(keynew,
tb_null,
tb_null,
tb_null,
tb_null,
tb_null,
tb_null,
&value_name_num,
&value_name_maxn,
tb_null,
tb_null,
tb_null) != ERROR_SUCCESS) {
lua_pushnil(lua);
lua_pushfstring(lua, "query registry info failed: %s\\%s", rootkey, rootdir);
break;
}
value_name_maxn++; // add `\0`
// ensure enough value name buffer
tb_wchar_t value_name[1024];
if (value_name_maxn > tb_arrayn(value_name)) {
lua_pushnil(lua);
lua_pushfstring(lua, "no enough value name buffer: %s\\%s", rootkey, rootdir);
break;
}
// get all values
DWORD i = 0;
tb_char_t value_name_a[1024];
for (i = 0; i < value_name_num; i++) {
// get value name
value_name[0] = L'\0';
DWORD value_name_size = tb_arrayn(value_name);
if (RegEnumValueW(keynew, i, value_name, &value_name_size, tb_null, tb_null, tb_null, tb_null) !=
ERROR_SUCCESS) {
lua_pushnil(lua);
lua_pushfstring(lua, "get registry value name(%d) failed: %s\\%s", i, rootkey, rootdir);
break;
}
// get value name (mbs)
tb_size_t value_name_a_size = tb_wtoa(value_name_a, value_name, sizeof(value_name_a));
if (value_name_a_size == -1) {
lua_pushnil(lua);
lua_pushfstring(lua, "convert registry value name(%d) failed: %s\\%s", i, rootkey, rootdir);
break;
}
// do callback(value_name)
lua_pushvalue(lua, 3);
lua_pushlstring(lua, value_name_a, value_name_a_size);
lua_call(lua, 1, 1);
count++;
// is continue?
tb_bool_t is_continue = lua_toboolean(lua, -1);
lua_pop(lua, 1);
if (!is_continue) {
ok = tb_true;
break;
}
}
if (i == value_name_num)
ok = tb_true;
} while (0);
// exit registry key
if (keynew) {
RegCloseKey(keynew);
}
keynew = tb_null;
if (ok) {
lua_pushinteger(lua, count);
return 1;
} else {
return 2;
}
}
================================================
FILE: core/src/xmake/winos/set_error_mode.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file set_error_mode.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "set_error_mode"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_int_t xm_winos_set_error_mode(lua_State *lua) {
tb_size_t mode = (tb_size_t)luaL_checkinteger(lua, 1);
lua_pushinteger(lua, (tb_int_t)SetErrorMode((UINT)mode));
return 1;
}
================================================
FILE: core/src/xmake/winos/short_path.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file short_path.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* trace
*/
#define TB_TRACE_MODULE_NAME "short_path"
#define TB_TRACE_MODULE_DEBUG (0)
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
/* get windows short path from long path
*
* local short_path, errors = winos.short_path(long_path)
*/
tb_int_t xm_winos_short_path(lua_State *lua) {
tb_assert_and_check_return_val(lua, 0);
// get the arguments
tb_char_t const *long_path = luaL_checkstring(lua, 1);
tb_check_return_val(long_path, 0);
// convert long path to wide characters
tb_wchar_t long_path_w[TB_PATH_MAXN];
if (tb_atow(long_path_w, long_path, TB_PATH_MAXN) == (tb_size_t)-1) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid long path: %s", long_path);
return 2;
}
// get short path
tb_wchar_t short_path_w[TB_PATH_MAXN];
if (GetShortPathNameW(long_path_w, short_path_w, TB_PATH_MAXN) == 0) {
lua_pushnil(lua);
lua_pushfstring(lua, "cannot get short path from: %s", long_path);
return 2;
}
// return result
tb_char_t *short_path_a = (tb_char_t *)long_path_w;
tb_size_t short_path_n = tb_wtoa(short_path_a, short_path_w, TB_PATH_MAXN);
if (short_path_n == (tb_size_t)-1) {
lua_pushnil(lua);
lua_pushfstring(lua, "invalid short path from %s!", long_path);
return 2;
}
lua_pushlstring(lua, short_path_a, short_path_n);
return 1;
}
================================================
FILE: core/src/xmake/xmake.c
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file xmake.c
*
*/
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "xmake.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
static __tb_inline__ tb_bool_t xm_check_mode(tb_size_t mode) {
#ifdef __xm_debug__
if (!(mode & TB_MODE_DEBUG)) {
tb_trace_e("libxmake.a has __tb_debug__ but xmake/xmake.h not");
return tb_false;
}
#else
if (mode & TB_MODE_DEBUG) {
tb_trace_e("xmake/xmake.h has __tb_debug__ but libxmake.a not");
return tb_false;
}
#endif
#ifdef __xm_small__
if (!(mode & TB_MODE_SMALL)) {
tb_trace_e("libxmake.a has __tb_small__ but xmake/xmake.h not");
return tb_false;
}
#else
if (mode & TB_MODE_SMALL) {
tb_trace_e("xmake/xmake.h has __tb_small__ but libxmake.a not");
return tb_false;
}
#endif
return tb_true;
}
static __tb_inline__ tb_bool_t xm_version_check(tb_hize_t build) {
// the version oly for link the static vtag string
tb_version_t const *version = xm_version();
tb_used(version);
if ((build / 100) == (XM_VERSION_BUILD / 100)) {
tb_trace_d("version: %s", XM_VERSION_STRING);
return tb_true;
} else {
tb_trace_w("version: %s != %llu", XM_VERSION_STRING, build);
}
// no
return tb_false;
}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
*/
tb_bool_t xm_init_(tb_size_t mode, tb_hize_t build) {
tb_trace_d("init: ..");
// check mode
if (!xm_check_mode(mode)) {
return tb_false;
}
// check version
xm_version_check(build);
#if 0
// init tbox, we always use the tbox's default allocator
if (!tb_init(tb_null, tb_default_allocator(tb_null, 0))) return tb_false;
#else
// init tbox, since small compilation mode is enabled, it still uses the native allocator
if (!tb_init(tb_null, tb_null)) {
return tb_false;
}
#endif
tb_trace_d("init: ok");
return tb_true;
}
tb_void_t xm_exit() {
// exit tbox
tb_exit();
}
tb_version_t const *xm_version() {
// init version tag for binary search
static __tb_volatile__ tb_char_t const *s_vtag = "[xmake]: [vtag]: " XM_VERSION_STRING;
tb_used(s_vtag);
// init version
static tb_version_t s_version = { 0 };
if (!s_version.major) {
s_version.major = XM_VERSION_MAJOR;
s_version.minor = XM_VERSION_MINOR;
s_version.alter = XM_VERSION_ALTER;
s_version.build = (tb_hize_t)tb_atoll(XM_VERSION_BUILD_STRING);
}
return &s_version;
}
================================================
FILE: core/src/xmake/xmake.config.h.in
================================================
#ifndef XM_CONFIG_H
#define XM_CONFIG_H
// version
#define XM_CONFIG_VERSION "${VERSION}"
#define XM_CONFIG_VERSION_MAJOR ${VERSION_MAJOR}
#define XM_CONFIG_VERSION_MINOR ${VERSION_MINOR}
#define XM_CONFIG_VERSION_ALTER ${VERSION_ALTER}
#define XM_CONFIG_VERSION_BUILD ${VERSION_BUILD}
#define XM_CONFIG_VERSION_BRANCH "${GIT_BRANCH}"
#define XM_CONFIG_VERSION_COMMIT "${GIT_COMMIT}"
#endif
================================================
FILE: core/src/xmake/xmake.h
================================================
/*!A cross-platform build utility based on Lua
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2015-present, Xmake Open Source Community.
*
* @author ruki
* @file xmake.h
*
*/
#ifndef XM_XMAKE_H
#define XM_XMAKE_H
/* //////////////////////////////////////////////////////////////////////////////////////
* includes
*/
#include "prefix.h"
#include "engine.h"
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_enter__
/* //////////////////////////////////////////////////////////////////////////////////////
* macros
*/
#ifdef __xm_debug__
#define __xm_mode_debug__ TB_MODE_DEBUG
#else
#define __xm_mode_debug__ (0)
#endif
#ifdef __xm_small__
#define __xm_mode_small__ TB_MODE_SMALL
#else
#define __xm_mode_small__ (0)
#endif
/*! init xmake
*
* @return tb_true or tb_false
*
* @code
#include "xmake/xmake.h"
int main(int argc, char** argv)
{
// init xmake
if (!xm_init()) return 0;
// exit xmake
xm_exit();
return 0;
}
* @endcode
*/
#define xm_init() xm_init_((tb_size_t)(__xm_mode_debug__ | __xm_mode_small__), XM_VERSION_BUILD)
/* //////////////////////////////////////////////////////////////////////////////////////
* interfaces
*/
/*! init the xmake library
*
* @param mode the compile mode for check __tb_small__ and __tb_debug__
* @param build the build version
*
* @return tb_true or tb_false
*/
tb_bool_t
xm_init_(tb_size_t mode, tb_hize_t build);
/// exit the xmake library
tb_void_t xm_exit(tb_noarg_t);
/*! the xmake version
*
* @return the xmake version
*/
tb_version_t const *xm_version(tb_noarg_t);
/* //////////////////////////////////////////////////////////////////////////////////////
* extern
*/
__tb_extern_c_leave__
#endif
================================================
FILE: core/src/xmake/xmake.lua
================================================
target("xmake")
set_kind("static")
-- add deps
add_deps("sv", "lz4")
if namespace then
add_deps("tbox::tbox")
else
add_deps("tbox")
end
if is_config("runtime", "luajit") then
add_deps("luajit")
else
add_deps("lua")
end
if has_config("lua_cjson") then
add_deps("lua-cjson")
end
if is_plat("windows") and has_config("pdcurses") then
add_deps("pdcurses")
end
-- add definitions
add_defines("__tb_prefix__=\"xmake\"")
if is_mode("debug") then
add_defines("__tb_debug__", {public = true})
end
-- set the auto-generated config.h
set_configdir("$(builddir)/$(plat)/$(arch)/$(mode)")
add_configfiles("xmake.config.h.in")
-- add includes directory
add_includedirs("..", {interface = true})
add_includedirs("$(builddir)/$(plat)/$(arch)/$(mode)", {public = true})
add_includedirs("../xxhash")
add_includedirs("$(projectdir)/../xmake/scripts/module")
-- add header files
add_headerfiles("../(xmake/*.h)")
add_headerfiles("../(xmake/prefix/*.h)")
add_headerfiles("$(builddir)/$(plat)/$(arch)/$(mode)/xmake.config.h", {prefixdir = "xmake"})
-- add the common source files
add_files("**.c|winos/*.c")
if is_plat("windows", "msys", "mingw", "cygwin") then
add_files("winos/*.c")
end
-- add options
add_options("readline")
if is_plat("windows") then
add_options("pdcurses")
else
add_options("curses")
end
-- add definitions
if is_plat("windows") then
add_defines("UNICODE", "_UNICODE")
end
-- embed all script files
add_rules("utils.bin2obj", {extensions = ".xmz"})
on_config(function (target)
import("utils.archive.archive")
if has_config("embed") then
local archivefile = path.join(target:autogendir(), "bin2obj", "xmake.xmz")
print("archiving %s ..", archivefile)
os.tryrm(archivefile)
local rootdir = path.normalize(path.join(os.projectdir(), "..", "xmake"))
archive(archivefile, rootdir, {recurse = true, curdir = rootdir})
target:add("files", archivefile)
target:add("defines", "XM_EMBED_ENABLE=1")
end
end)
================================================
FILE: core/src/xmake/xmake.sh
================================================
#!/bin/sh
target "xmake"
set_kind "static"
set_default false
# add deps
if has_config "external"; then
local libs="lz4 sv tbox"
for lib in $libs; do
if has_config "$lib"; then
add_options "$lib" "{public}"
fi
done
if is_config "runtime" "luajit"; then
if has_config "luajit"; then
add_options "luajit" "{public}"
fi
else
if has_config "lua"; then
add_options "lua" "{public}"
fi
fi
else
local libs="lua_cjson lz4 sv tbox"
for lib in $libs; do
add_deps "$lib"
done
if is_config "runtime" "luajit"; then
add_deps "luajit"
else
add_deps "lua"
fi
fi
# add options
add_options "readline" "curses" "{public}"
# add definitions
add_defines "__tb_prefix__=\"xmake\""
if is_mode "debug"; then
add_defines "__tb_debug__" "{public}"
fi
# set the auto-generated config.h
set_configdir "${builddir}/${plat}/${arch}/${mode}"
add_configfiles "xmake.config.h.in"
# add includes directory
add_includedirs ".." "{public}"
add_includedirs "${builddir}/${plat}/${arch}/${mode}" "{public}"
add_includedirs "../xxhash"
add_includedirs "${projectdir}/xmake/scripts/module"
# add the common source files
add_files "*.c"
add_files "base64/*.c"
add_files "bloom_filter/*.c"
add_files "curses/*.c"
add_files "fwatcher/*.c"
add_files "hash/*.c"
add_files "io/*.c"
add_files "libc/*.c"
add_files "lz4/*.c"
add_files "os/*.c"
add_files "path/*.c"
add_files "package/*.c"
add_files "process/*.c"
add_files "readline/*.c"
add_files "sandbox/*.c"
add_files "semver/*.c"
add_files "string/*.c"
add_files "utf8/*.c"
add_files "utils/*.c"
add_files "tty/*.c"
add_files "binutils/*.c"
add_files "binutils/coff/*.c"
add_files "binutils/macho/*.c"
add_files "binutils/elf/*.c"
add_files "binutils/wasm/*.c"
add_files "binutils/ar/*.c"
add_files "binutils/mslib/*.c"
add_files "thread/*.c"
if is_plat "mingw"; then
add_files "winos/*.c"
fi
================================================
FILE: core/src/xxhash/xxhash/LICENSE
================================================
xxHash Library
Copyright (c) 2012-2021 Yann Collet
All rights reserved.
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: core/src/xxhash/xxhash/xxhash.h
================================================
/*
* xxHash - Extremely Fast Hash algorithm
* Header File
* Copyright (C) 2012-2023 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at:
* - xxHash homepage: https://www.xxhash.com
* - xxHash source repository: https://github.com/Cyan4973/xxHash
*/
/*!
* @mainpage xxHash
*
* xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed
* limits.
*
* It is proposed in four flavors, in three families:
* 1. @ref XXH32_family
* - Classic 32-bit hash function. Simple, compact, and runs on almost all
* 32-bit and 64-bit systems.
* 2. @ref XXH64_family
* - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most
* 64-bit systems (but _not_ 32-bit systems).
* 3. @ref XXH3_family
* - Modern 64-bit and 128-bit hash function family which features improved
* strength and performance across the board, especially on smaller data.
* It benefits greatly from SIMD and 64-bit without requiring it.
*
* Benchmarks
* ---
* The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04.
* The open source benchmark program is compiled with clang v10.0 using -O3 flag.
*
* | Hash Name | ISA ext | Width | Large Data Speed | Small Data Velocity |
* | -------------------- | ------- | ----: | ---------------: | ------------------: |
* | XXH3_64bits() | @b AVX2 | 64 | 59.4 GB/s | 133.1 |
* | MeowHash | AES-NI | 128 | 58.2 GB/s | 52.5 |
* | XXH3_128bits() | @b AVX2 | 128 | 57.9 GB/s | 118.1 |
* | CLHash | PCLMUL | 64 | 37.1 GB/s | 58.1 |
* | XXH3_64bits() | @b SSE2 | 64 | 31.5 GB/s | 133.1 |
* | XXH3_128bits() | @b SSE2 | 128 | 29.6 GB/s | 118.1 |
* | RAM sequential read | | N/A | 28.0 GB/s | N/A |
* | ahash | AES-NI | 64 | 22.5 GB/s | 107.2 |
* | City64 | | 64 | 22.0 GB/s | 76.6 |
* | T1ha2 | | 64 | 22.0 GB/s | 99.0 |
* | City128 | | 128 | 21.7 GB/s | 57.7 |
* | FarmHash | AES-NI | 64 | 21.3 GB/s | 71.9 |
* | XXH64() | | 64 | 19.4 GB/s | 71.0 |
* | SpookyHash | | 64 | 19.3 GB/s | 53.2 |
* | Mum | | 64 | 18.0 GB/s | 67.0 |
* | CRC32C | SSE4.2 | 32 | 13.0 GB/s | 57.9 |
* | XXH32() | | 32 | 9.7 GB/s | 71.9 |
* | City32 | | 32 | 9.1 GB/s | 66.0 |
* | Blake3* | @b AVX2 | 256 | 4.4 GB/s | 8.1 |
* | Murmur3 | | 32 | 3.9 GB/s | 56.1 |
* | SipHash* | | 64 | 3.0 GB/s | 43.2 |
* | Blake3* | @b SSE2 | 256 | 2.4 GB/s | 8.1 |
* | HighwayHash | | 64 | 1.4 GB/s | 6.0 |
* | FNV64 | | 64 | 1.2 GB/s | 62.7 |
* | Blake2* | | 256 | 1.1 GB/s | 5.1 |
* | SHA1* | | 160 | 0.8 GB/s | 5.6 |
* | MD5* | | 128 | 0.6 GB/s | 7.8 |
* @note
* - Hashes which require a specific ISA extension are noted. SSE2 is also noted,
* even though it is mandatory on x64.
* - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic
* by modern standards.
* - Small data velocity is a rough average of algorithm's efficiency for small
* data. For more accurate information, see the wiki.
* - More benchmarks and strength tests are found on the wiki:
* https://github.com/Cyan4973/xxHash/wiki
*
* Usage
* ------
* All xxHash variants use a similar API. Changing the algorithm is a trivial
* substitution.
*
* @pre
* For functions which take an input and length parameter, the following
* requirements are assumed:
* - The range from [`input`, `input + length`) is valid, readable memory.
* - The only exception is if the `length` is `0`, `input` may be `NULL`.
* - For C++, the objects must have the *TriviallyCopyable* property, as the
* functions access bytes directly as if it was an array of `unsigned char`.
*
* @anchor single_shot_example
* **Single Shot**
*
* These functions are stateless functions which hash a contiguous block of memory,
* immediately returning the result. They are the easiest and usually the fastest
* option.
*
* XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits()
*
* @code{.c}
* #include
* #include "xxhash.h"
*
* // Example for a function which hashes a null terminated string with XXH32().
* XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed)
* {
* // NULL pointers are only valid if the length is zero
* size_t length = (string == NULL) ? 0 : strlen(string);
* return XXH32(string, length, seed);
* }
* @endcode
*
*
* @anchor streaming_example
* **Streaming**
*
* These groups of functions allow incremental hashing of unknown size, even
* more than what would fit in a size_t.
*
* XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset()
*
* @code{.c}
* #include
* #include
* #include "xxhash.h"
* // Example for a function which hashes a FILE incrementally with XXH3_64bits().
* XXH64_hash_t hashFile(FILE* f)
* {
* // Allocate a state struct. Do not just use malloc() or new.
* XXH3_state_t* state = XXH3_createState();
* assert(state != NULL && "Out of memory!");
* // Reset the state to start a new hashing session.
* XXH3_64bits_reset(state);
* char buffer[4096];
* size_t count;
* // Read the file in chunks
* while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) {
* // Run update() as many times as necessary to process the data
* XXH3_64bits_update(state, buffer, count);
* }
* // Retrieve the finalized hash. This will not change the state.
* XXH64_hash_t result = XXH3_64bits_digest(state);
* // Free the state. Do not use free().
* XXH3_freeState(state);
* return result;
* }
* @endcode
*
* Streaming functions generate the xxHash value from an incremental input.
* This method is slower than single-call functions, due to state management.
* For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
*
* An XXH state must first be allocated using `XXH*_createState()`.
*
* Start a new hash by initializing the state with a seed using `XXH*_reset()`.
*
* Then, feed the hash state by calling `XXH*_update()` as many times as necessary.
*
* The function returns an error code, with 0 meaning OK, and any other value
* meaning there is an error.
*
* Finally, a hash value can be produced anytime, by using `XXH*_digest()`.
* This function returns the nn-bits hash as an int or long long.
*
* It's still possible to continue inserting input into the hash state after a
* digest, and generate new hash values later on by invoking `XXH*_digest()`.
*
* When done, release the state using `XXH*_freeState()`.
*
*
* @anchor canonical_representation_example
* **Canonical Representation**
*
* The default return values from XXH functions are unsigned 32, 64 and 128 bit
* integers.
* This the simplest and fastest format for further post-processing.
*
* However, this leaves open the question of what is the order on the byte level,
* since little and big endian conventions will store the same number differently.
*
* The canonical representation settles this issue by mandating big-endian
* convention, the same convention as human-readable numbers (large digits first).
*
* When writing hash values to storage, sending them over a network, or printing
* them, it's highly recommended to use the canonical representation to ensure
* portability across a wider range of systems, present and future.
*
* The following functions allow transformation of hash values to and from
* canonical format.
*
* XXH32_canonicalFromHash(), XXH32_hashFromCanonical(),
* XXH64_canonicalFromHash(), XXH64_hashFromCanonical(),
* XXH128_canonicalFromHash(), XXH128_hashFromCanonical(),
*
* @code{.c}
* #include
* #include "xxhash.h"
*
* // Example for a function which prints XXH32_hash_t in human readable format
* void printXxh32(XXH32_hash_t hash)
* {
* XXH32_canonical_t cano;
* XXH32_canonicalFromHash(&cano, hash);
* size_t i;
* for(i = 0; i < sizeof(cano.digest); ++i) {
* printf("%02x", cano.digest[i]);
* }
* printf("\n");
* }
*
* // Example for a function which converts XXH32_canonical_t to XXH32_hash_t
* XXH32_hash_t convertCanonicalToXxh32(XXH32_canonical_t cano)
* {
* XXH32_hash_t hash = XXH32_hashFromCanonical(&cano);
* return hash;
* }
* @endcode
*
*
* @file xxhash.h
* xxHash prototypes and implementation
*/
#if defined(__cplusplus) && !defined(XXH_NO_EXTERNC_GUARD)
extern "C" {
#endif
/* ****************************
* INLINE mode
******************************/
/*!
* @defgroup public Public API
* Contains details on the public xxHash functions.
* @{
*/
#ifdef XXH_DOXYGEN
/*!
* @brief Gives access to internal state declaration, required for static allocation.
*
* Incompatible with dynamic linking, due to risks of ABI changes.
*
* Usage:
* @code{.c}
* #define XXH_STATIC_LINKING_ONLY
* #include "xxhash.h"
* @endcode
*/
# define XXH_STATIC_LINKING_ONLY
/* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */
/*!
* @brief Gives access to internal definitions.
*
* Usage:
* @code{.c}
* #define XXH_STATIC_LINKING_ONLY
* #define XXH_IMPLEMENTATION
* #include "xxhash.h"
* @endcode
*/
# define XXH_IMPLEMENTATION
/* Do not undef XXH_IMPLEMENTATION for Doxygen */
/*!
* @brief Exposes the implementation and marks all functions as `inline`.
*
* Use these build macros to inline xxhash into the target unit.
* Inlining improves performance on small inputs, especially when the length is
* expressed as a compile-time constant:
*
* https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html
*
* It also keeps xxHash symbols private to the unit, so they are not exported.
*
* Usage:
* @code{.c}
* #define XXH_INLINE_ALL
* #include "xxhash.h"
* @endcode
* Do not compile and link xxhash.o as a separate object, as it is not useful.
*/
# define XXH_INLINE_ALL
# undef XXH_INLINE_ALL
/*!
* @brief Exposes the implementation without marking functions as inline.
*/
# define XXH_PRIVATE_API
# undef XXH_PRIVATE_API
/*!
* @brief Emulate a namespace by transparently prefixing all symbols.
*
* If you want to include _and expose_ xxHash functions from within your own
* library, but also want to avoid symbol collisions with other libraries which
* may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix
* any public symbol from xxhash library with the value of @ref XXH_NAMESPACE
* (therefore, avoid empty or numeric values).
*
* Note that no change is required within the calling program as long as it
* includes `xxhash.h`: Regular symbol names will be automatically translated
* by this header.
*/
# define XXH_NAMESPACE /* YOUR NAME HERE */
# undef XXH_NAMESPACE
#endif
#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \
&& !defined(XXH_INLINE_ALL_31684351384)
/* this section should be traversed only once */
# define XXH_INLINE_ALL_31684351384
/* give access to the advanced API, required to compile implementations */
# undef XXH_STATIC_LINKING_ONLY /* avoid macro redef */
# define XXH_STATIC_LINKING_ONLY
/* make all functions private */
# undef XXH_PUBLIC_API
# if defined(__GNUC__)
# define XXH_PUBLIC_API static __inline __attribute__((__unused__))
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# define XXH_PUBLIC_API static inline
# elif defined(_MSC_VER)
# define XXH_PUBLIC_API static __inline
# else
/* note: this version may generate warnings for unused static functions */
# define XXH_PUBLIC_API static
# endif
/*
* This part deals with the special case where a unit wants to inline xxHash,
* but "xxhash.h" has previously been included without XXH_INLINE_ALL,
* such as part of some previously included *.h header file.
* Without further action, the new include would just be ignored,
* and functions would effectively _not_ be inlined (silent failure).
* The following macros solve this situation by prefixing all inlined names,
* avoiding naming collision with previous inclusions.
*/
/* Before that, we unconditionally #undef all symbols,
* in case they were already defined with XXH_NAMESPACE.
* They will then be redefined for XXH_INLINE_ALL
*/
# undef XXH_versionNumber
/* XXH32 */
# undef XXH32
# undef XXH32_createState
# undef XXH32_freeState
# undef XXH32_reset
# undef XXH32_update
# undef XXH32_digest
# undef XXH32_copyState
# undef XXH32_canonicalFromHash
# undef XXH32_hashFromCanonical
/* XXH64 */
# undef XXH64
# undef XXH64_createState
# undef XXH64_freeState
# undef XXH64_reset
# undef XXH64_update
# undef XXH64_digest
# undef XXH64_copyState
# undef XXH64_canonicalFromHash
# undef XXH64_hashFromCanonical
/* XXH3_64bits */
# undef XXH3_64bits
# undef XXH3_64bits_withSecret
# undef XXH3_64bits_withSeed
# undef XXH3_64bits_withSecretandSeed
# undef XXH3_createState
# undef XXH3_freeState
# undef XXH3_copyState
# undef XXH3_64bits_reset
# undef XXH3_64bits_reset_withSeed
# undef XXH3_64bits_reset_withSecret
# undef XXH3_64bits_update
# undef XXH3_64bits_digest
# undef XXH3_generateSecret
/* XXH3_128bits */
# undef XXH128
# undef XXH3_128bits
# undef XXH3_128bits_withSeed
# undef XXH3_128bits_withSecret
# undef XXH3_128bits_reset
# undef XXH3_128bits_reset_withSeed
# undef XXH3_128bits_reset_withSecret
# undef XXH3_128bits_reset_withSecretandSeed
# undef XXH3_128bits_update
# undef XXH3_128bits_digest
# undef XXH128_isEqual
# undef XXH128_cmp
# undef XXH128_canonicalFromHash
# undef XXH128_hashFromCanonical
/* Finally, free the namespace itself */
# undef XXH_NAMESPACE
/* employ the namespace for XXH_INLINE_ALL */
# define XXH_NAMESPACE XXH_INLINE_
/*
* Some identifiers (enums, type names) are not symbols,
* but they must nonetheless be renamed to avoid redeclaration.
* Alternative solution: do not redeclare them.
* However, this requires some #ifdefs, and has a more dispersed impact.
* Meanwhile, renaming can be achieved in a single place.
*/
# define XXH_IPREF(Id) XXH_NAMESPACE ## Id
# define XXH_OK XXH_IPREF(XXH_OK)
# define XXH_ERROR XXH_IPREF(XXH_ERROR)
# define XXH_errorcode XXH_IPREF(XXH_errorcode)
# define XXH32_canonical_t XXH_IPREF(XXH32_canonical_t)
# define XXH64_canonical_t XXH_IPREF(XXH64_canonical_t)
# define XXH128_canonical_t XXH_IPREF(XXH128_canonical_t)
# define XXH32_state_s XXH_IPREF(XXH32_state_s)
# define XXH32_state_t XXH_IPREF(XXH32_state_t)
# define XXH64_state_s XXH_IPREF(XXH64_state_s)
# define XXH64_state_t XXH_IPREF(XXH64_state_t)
# define XXH3_state_s XXH_IPREF(XXH3_state_s)
# define XXH3_state_t XXH_IPREF(XXH3_state_t)
# define XXH128_hash_t XXH_IPREF(XXH128_hash_t)
/* Ensure the header is parsed again, even if it was previously included */
# undef XXHASH_H_5627135585666179
# undef XXHASH_H_STATIC_13879238742
#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
/* ****************************************************************
* Stable API
*****************************************************************/
#ifndef XXHASH_H_5627135585666179
#define XXHASH_H_5627135585666179 1
/*! @brief Marks a global symbol. */
#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
# if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))
# ifdef XXH_EXPORT
# define XXH_PUBLIC_API __declspec(dllexport)
# elif XXH_IMPORT
# define XXH_PUBLIC_API __declspec(dllimport)
# endif
# else
# define XXH_PUBLIC_API /* do nothing */
# endif
#endif
#ifdef XXH_NAMESPACE
# define XXH_CAT(A,B) A##B
# define XXH_NAME2(A,B) XXH_CAT(A,B)
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
/* XXH32 */
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
/* XXH64 */
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
/* XXH3_64bits */
# define XXH3_64bits XXH_NAME2(XXH_NAMESPACE, XXH3_64bits)
# define XXH3_64bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecret)
# define XXH3_64bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSeed)
# define XXH3_64bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_withSecretandSeed)
# define XXH3_createState XXH_NAME2(XXH_NAMESPACE, XXH3_createState)
# define XXH3_freeState XXH_NAME2(XXH_NAMESPACE, XXH3_freeState)
# define XXH3_copyState XXH_NAME2(XXH_NAMESPACE, XXH3_copyState)
# define XXH3_64bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset)
# define XXH3_64bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSeed)
# define XXH3_64bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecret)
# define XXH3_64bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_reset_withSecretandSeed)
# define XXH3_64bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_update)
# define XXH3_64bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_64bits_digest)
# define XXH3_generateSecret XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret)
# define XXH3_generateSecret_fromSeed XXH_NAME2(XXH_NAMESPACE, XXH3_generateSecret_fromSeed)
/* XXH3_128bits */
# define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128)
# define XXH3_128bits XXH_NAME2(XXH_NAMESPACE, XXH3_128bits)
# define XXH3_128bits_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSeed)
# define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret)
# define XXH3_128bits_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecretandSeed)
# define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset)
# define XXH3_128bits_reset_withSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSeed)
# define XXH3_128bits_reset_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecret)
# define XXH3_128bits_reset_withSecretandSeed XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset_withSecretandSeed)
# define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update)
# define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest)
# define XXH128_isEqual XXH_NAME2(XXH_NAMESPACE, XXH128_isEqual)
# define XXH128_cmp XXH_NAME2(XXH_NAMESPACE, XXH128_cmp)
# define XXH128_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH128_canonicalFromHash)
# define XXH128_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH128_hashFromCanonical)
#endif
/* *************************************
* Compiler specifics
***************************************/
/* specific declaration modes for Windows */
#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
# if defined(_WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))
# ifdef XXH_EXPORT
# define XXH_PUBLIC_API __declspec(dllexport)
# elif XXH_IMPORT
# define XXH_PUBLIC_API __declspec(dllimport)
# endif
# else
# define XXH_PUBLIC_API /* do nothing */
# endif
#endif
#if defined (__GNUC__)
# define XXH_CONSTF __attribute__((__const__))
# define XXH_PUREF __attribute__((__pure__))
# define XXH_MALLOCF __attribute__((__malloc__))
#else
# define XXH_CONSTF /* disable */
# define XXH_PUREF
# define XXH_MALLOCF
#endif
/* *************************************
* Version
***************************************/
#define XXH_VERSION_MAJOR 0
#define XXH_VERSION_MINOR 8
#define XXH_VERSION_RELEASE 3
/*! @brief Version number, encoded as two digits each */
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
/*!
* @brief Obtains the xxHash version.
*
* This is mostly useful when xxHash is compiled as a shared library,
* since the returned value comes from the library, as opposed to header file.
*
* @return @ref XXH_VERSION_NUMBER of the invoked library.
*/
XXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void);
/* ****************************
* Common basic types
******************************/
#include /* size_t */
/*!
* @brief Exit code for the streaming API.
*/
typedef enum {
XXH_OK = 0, /*!< OK */
XXH_ERROR /*!< Error */
} XXH_errorcode;
/*-**********************************************************************
* 32-bit hash
************************************************************************/
#if defined(XXH_DOXYGEN) /* Don't show include */
/*!
* @brief An unsigned 32-bit integer.
*
* Not necessarily defined to `uint32_t` but functionally equivalent.
*/
typedef uint32_t XXH32_hash_t;
#elif !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# ifdef _AIX
# include
# else
# include
# endif
typedef uint32_t XXH32_hash_t;
#else
# include
# if UINT_MAX == 0xFFFFFFFFUL
typedef unsigned int XXH32_hash_t;
# elif ULONG_MAX == 0xFFFFFFFFUL
typedef unsigned long XXH32_hash_t;
# else
# error "unsupported platform: need a 32-bit type"
# endif
#endif
/*!
* @}
*
* @defgroup XXH32_family XXH32 family
* @ingroup public
* Contains functions used in the classic 32-bit xxHash algorithm.
*
* @note
* XXH32 is useful for older platforms, with no or poor 64-bit performance.
* Note that the @ref XXH3_family provides competitive speed for both 32-bit
* and 64-bit systems, and offers true 64/128 bit hash results.
*
* @see @ref XXH64_family, @ref XXH3_family : Other xxHash families
* @see @ref XXH32_impl for implementation details
* @{
*/
/*!
* @brief Calculates the 32-bit hash of @p input using xxHash32.
*
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
* @param seed The 32-bit seed to alter the hash's output predictably.
*
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return The calculated 32-bit xxHash32 value.
*
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed);
#ifndef XXH_NO_STREAM
/*!
* @typedef struct XXH32_state_s XXH32_state_t
* @brief The opaque state struct for the XXH32 streaming API.
*
* @see XXH32_state_s for details.
* @see @ref streaming_example "Streaming Example"
*/
typedef struct XXH32_state_s XXH32_state_t;
/*!
* @brief Allocates an @ref XXH32_state_t.
*
* @return An allocated pointer of @ref XXH32_state_t on success.
* @return `NULL` on failure.
*
* @note Must be freed with XXH32_freeState().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void);
/*!
* @brief Frees an @ref XXH32_state_t.
*
* @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState().
*
* @return @ref XXH_OK.
*
* @note @p statePtr must be allocated with XXH32_createState().
*
* @see @ref streaming_example "Streaming Example"
*
*/
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
/*!
* @brief Copies one @ref XXH32_state_t to another.
*
* @param dst_state The state to copy to.
* @param src_state The state to copy from.
* @pre
* @p dst_state and @p src_state must not be `NULL` and must not overlap.
*/
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
/*!
* @brief Resets an @ref XXH32_state_t to begin a new hash.
*
* @param statePtr The state struct to reset.
* @param seed The 32-bit seed to alter the hash result predictably.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note This function resets and seeds a state. Call it before @ref XXH32_update().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed);
/*!
* @brief Consumes a block of @p input to an @ref XXH32_state_t.
*
* @param statePtr The state struct to update.
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
*
* @pre
* @p statePtr must not be `NULL`.
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note Call this to incrementally consume blocks of data.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
/*!
* @brief Returns the calculated hash value from an @ref XXH32_state_t.
*
* @param statePtr The state struct to calculate the hash from.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return The calculated 32-bit xxHash32 value from that state.
*
* @note
* Calling XXH32_digest() will not affect @p statePtr, so you can update,
* digest, and update again.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
#endif /* !XXH_NO_STREAM */
/******* Canonical representation *******/
/*!
* @brief Canonical (big endian) representation of @ref XXH32_hash_t.
*/
typedef struct {
unsigned char digest[4]; /*!< Hash bytes, big endian */
} XXH32_canonical_t;
/*!
* @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t.
*
* @param dst The @ref XXH32_canonical_t pointer to be stored to.
* @param hash The @ref XXH32_hash_t to be converted.
*
* @pre
* @p dst must not be `NULL`.
*
* @see @ref canonical_representation_example "Canonical Representation Example"
*/
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
/*!
* @brief Converts an @ref XXH32_canonical_t to a native @ref XXH32_hash_t.
*
* @param src The @ref XXH32_canonical_t to convert.
*
* @pre
* @p src must not be `NULL`.
*
* @return The converted hash.
*
* @see @ref canonical_representation_example "Canonical Representation Example"
*/
XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
/*! @cond Doxygen ignores this part */
#ifdef __has_attribute
# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x)
#else
# define XXH_HAS_ATTRIBUTE(x) 0
#endif
/*! @endcond */
/*! @cond Doxygen ignores this part */
/*
* C23 __STDC_VERSION__ number hasn't been specified yet. For now
* leave as `201711L` (C17 + 1).
* TODO: Update to correct value when its been specified.
*/
#define XXH_C23_VN 201711L
/*! @endcond */
/*! @cond Doxygen ignores this part */
/* C-language Attributes are added in C23. */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute)
# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else
# define XXH_HAS_C_ATTRIBUTE(x) 0
#endif
/*! @endcond */
/*! @cond Doxygen ignores this part */
#if defined(__cplusplus) && defined(__has_cpp_attribute)
# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define XXH_HAS_CPP_ATTRIBUTE(x) 0
#endif
/*! @endcond */
/*! @cond Doxygen ignores this part */
/*
* Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute
* introduced in CPP17 and C23.
* CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough
* C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough
*/
#if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough)
# define XXH_FALLTHROUGH [[fallthrough]]
#elif XXH_HAS_ATTRIBUTE(__fallthrough__)
# define XXH_FALLTHROUGH __attribute__ ((__fallthrough__))
#else
# define XXH_FALLTHROUGH /* fallthrough */
#endif
/*! @endcond */
/*! @cond Doxygen ignores this part */
/*
* Define XXH_NOESCAPE for annotated pointers in public API.
* https://clang.llvm.org/docs/AttributeReference.html#noescape
* As of writing this, only supported by clang.
*/
#if XXH_HAS_ATTRIBUTE(noescape)
# define XXH_NOESCAPE __attribute__((__noescape__))
#else
# define XXH_NOESCAPE
#endif
/*! @endcond */
/*!
* @}
* @ingroup public
* @{
*/
#ifndef XXH_NO_LONG_LONG
/*-**********************************************************************
* 64-bit hash
************************************************************************/
#if defined(XXH_DOXYGEN) /* don't include */
/*!
* @brief An unsigned 64-bit integer.
*
* Not necessarily defined to `uint64_t` but functionally equivalent.
*/
typedef uint64_t XXH64_hash_t;
#elif !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# ifdef _AIX
# include
# else
# include
# endif
typedef uint64_t XXH64_hash_t;
#else
# include
# if defined(__LP64__) && ULONG_MAX == 0xFFFFFFFFFFFFFFFFULL
/* LP64 ABI says uint64_t is unsigned long */
typedef unsigned long XXH64_hash_t;
# else
/* the following type must have a width of 64-bit */
typedef unsigned long long XXH64_hash_t;
# endif
#endif
/*!
* @}
*
* @defgroup XXH64_family XXH64 family
* @ingroup public
* @{
* Contains functions used in the classic 64-bit xxHash algorithm.
*
* @note
* XXH3 provides competitive speed for both 32-bit and 64-bit systems,
* and offers true 64/128 bit hash results.
* It provides better speed for systems with vector processing capabilities.
*/
/*!
* @brief Calculates the 64-bit hash of @p input using xxHash64.
*
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
* @param seed The 64-bit seed to alter the hash's output predictably.
*
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return The calculated 64-bit xxHash64 value.
*
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed);
/******* Streaming *******/
#ifndef XXH_NO_STREAM
/*!
* @brief The opaque state struct for the XXH64 streaming API.
*
* @see XXH64_state_s for details.
* @see @ref streaming_example "Streaming Example"
*/
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
/*!
* @brief Allocates an @ref XXH64_state_t.
*
* @return An allocated pointer of @ref XXH64_state_t on success.
* @return `NULL` on failure.
*
* @note Must be freed with XXH64_freeState().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void);
/*!
* @brief Frees an @ref XXH64_state_t.
*
* @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState().
*
* @return @ref XXH_OK.
*
* @note @p statePtr must be allocated with XXH64_createState().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
/*!
* @brief Copies one @ref XXH64_state_t to another.
*
* @param dst_state The state to copy to.
* @param src_state The state to copy from.
* @pre
* @p dst_state and @p src_state must not be `NULL` and must not overlap.
*/
XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state);
/*!
* @brief Resets an @ref XXH64_state_t to begin a new hash.
*
* @param statePtr The state struct to reset.
* @param seed The 64-bit seed to alter the hash result predictably.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note This function resets and seeds a state. Call it before @ref XXH64_update().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed);
/*!
* @brief Consumes a block of @p input to an @ref XXH64_state_t.
*
* @param statePtr The state struct to update.
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
*
* @pre
* @p statePtr must not be `NULL`.
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note Call this to incrementally consume blocks of data.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);
/*!
* @brief Returns the calculated hash value from an @ref XXH64_state_t.
*
* @param statePtr The state struct to calculate the hash from.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return The calculated 64-bit xxHash64 value from that state.
*
* @note
* Calling XXH64_digest() will not affect @p statePtr, so you can update,
* digest, and update again.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr);
#endif /* !XXH_NO_STREAM */
/******* Canonical representation *******/
/*!
* @brief Canonical (big endian) representation of @ref XXH64_hash_t.
*/
typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t;
/*!
* @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t.
*
* @param dst The @ref XXH64_canonical_t pointer to be stored to.
* @param hash The @ref XXH64_hash_t to be converted.
*
* @pre
* @p dst must not be `NULL`.
*
* @see @ref canonical_representation_example "Canonical Representation Example"
*/
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash);
/*!
* @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t.
*
* @param src The @ref XXH64_canonical_t to convert.
*
* @pre
* @p src must not be `NULL`.
*
* @return The converted hash.
*
* @see @ref canonical_representation_example "Canonical Representation Example"
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src);
#ifndef XXH_NO_XXH3
/*!
* @}
* ************************************************************************
* @defgroup XXH3_family XXH3 family
* @ingroup public
* @{
*
* XXH3 is a more recent hash algorithm featuring:
* - Improved speed for both small and large inputs
* - True 64-bit and 128-bit outputs
* - SIMD acceleration
* - Improved 32-bit viability
*
* Speed analysis methodology is explained here:
*
* https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html
*
* Compared to XXH64, expect XXH3 to run approximately
* ~2x faster on large inputs and >3x faster on small ones,
* exact differences vary depending on platform.
*
* XXH3's speed benefits greatly from SIMD and 64-bit arithmetic,
* but does not require it.
* Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3
* at competitive speeds, even without vector support. Further details are
* explained in the implementation.
*
* XXH3 has a fast scalar implementation, but it also includes accelerated SIMD
* implementations for many common platforms:
* - AVX512
* - AVX2
* - SSE2
* - ARM NEON
* - WebAssembly SIMD128
* - POWER8 VSX
* - s390x ZVector
* This can be controlled via the @ref XXH_VECTOR macro, but it automatically
* selects the best version according to predefined macros. For the x86 family, an
* automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c.
*
* XXH3 implementation is portable:
* it has a generic C90 formulation that can be compiled on any platform,
* all implementations generate exactly the same hash value on all platforms.
* Starting from v0.8.0, it's also labelled "stable", meaning that
* any future version will also generate the same hash value.
*
* XXH3 offers 2 variants, _64bits and _128bits.
*
* When only 64 bits are needed, prefer invoking the _64bits variant, as it
* reduces the amount of mixing, resulting in faster speed on small inputs.
* It's also generally simpler to manipulate a scalar return type than a struct.
*
* The API supports one-shot hashing, streaming mode, and custom secrets.
*/
/*!
* @ingroup tuning
* @brief Possible values for @ref XXH_VECTOR.
*
* Unless set explicitly, determined automatically.
*/
# define XXH_SCALAR 0 /*!< Portable scalar version */
# define XXH_SSE2 1 /*!< SSE2 for Pentium 4, Opteron, all x86_64. */
# define XXH_AVX2 2 /*!< AVX2 for Haswell and Bulldozer */
# define XXH_AVX512 3 /*!< AVX512 for Skylake and Icelake */
# define XXH_NEON 4 /*!< NEON for most ARMv7-A, all AArch64, and WASM SIMD128 */
# define XXH_VSX 5 /*!< VSX and ZVector for POWER8/z13 (64-bit) */
# define XXH_SVE 6 /*!< SVE for some ARMv8-A and ARMv9-A */
# define XXH_LSX 7 /*!< LSX (128-bit SIMD) for LoongArch64 */
# define XXH_LASX 8 /*!< LASX (256-bit SIMD) for LoongArch64 */
/*-**********************************************************************
* XXH3 64-bit variant
************************************************************************/
/*!
* @brief Calculates 64-bit unseeded variant of XXH3 hash of @p input.
*
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
*
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return The calculated 64-bit XXH3 hash value.
*
* @note
* This is equivalent to @ref XXH3_64bits_withSeed() with a seed of `0`, however
* it may have slightly better performance due to constant propagation of the
* defaults.
*
* @see
* XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length);
/*!
* @brief Calculates 64-bit seeded variant of XXH3 hash of @p input.
*
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
* @param seed The 64-bit seed to alter the hash result predictably.
*
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return The calculated 64-bit XXH3 hash value.
*
* @note
* seed == 0 produces the same results as @ref XXH3_64bits().
*
* This variant generates a custom secret on the fly based on default secret
* altered using the @p seed value.
*
* While this operation is decently fast, note that it's not completely free.
*
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed);
/*!
* The bare minimum size for a custom secret.
*
* @see
* XXH3_64bits_withSecret(), XXH3_64bits_reset_withSecret(),
* XXH3_128bits_withSecret(), XXH3_128bits_reset_withSecret().
*/
#define XXH3_SECRET_SIZE_MIN 136
/*!
* @brief Calculates 64-bit variant of XXH3 with a custom "secret".
*
* @param data The block of data to be hashed, at least @p len bytes in size.
* @param len The length of @p data, in bytes.
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
*
* @return The calculated 64-bit XXH3 hash value.
*
* @pre
* The memory between @p data and @p data + @p len must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p data may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* It's possible to provide any blob of bytes as a "secret" to generate the hash.
* This makes it more difficult for an external actor to prepare an intentional collision.
* The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN).
* However, the quality of the secret impacts the dispersion of the hash algorithm.
* Therefore, the secret _must_ look like a bunch of random bytes.
* Avoid "trivial" or structured data such as repeated sequences or a text document.
* Whenever in doubt about the "randomness" of the blob of bytes,
* consider employing @ref XXH3_generateSecret() instead (see below).
* It will generate a proper high entropy secret derived from the blob of bytes.
* Another advantage of using XXH3_generateSecret() is that
* it guarantees that all bits within the initial blob of bytes
* will impact every bit of the output.
* This is not necessarily the case when using the blob of bytes directly
* because, when hashing _small_ inputs, only a portion of the secret is employed.
*
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize);
/******* Streaming *******/
#ifndef XXH_NO_STREAM
/*
* Streaming requires state maintenance.
* This operation costs memory and CPU.
* As a consequence, streaming is slower than one-shot hashing.
* For better performance, prefer one-shot functions whenever applicable.
*/
/*!
* @brief The opaque state struct for the XXH3 streaming API.
*
* @see XXH3_state_s for details.
* @see @ref streaming_example "Streaming Example"
*/
typedef struct XXH3_state_s XXH3_state_t;
XXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr);
/*!
* @brief Copies one @ref XXH3_state_t to another.
*
* @param dst_state The state to copy to.
* @param src_state The state to copy from.
* @pre
* @p dst_state and @p src_state must not be `NULL` and must not overlap.
*/
XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state);
/*!
* @brief Resets an @ref XXH3_state_t to begin a new hash.
*
* @param statePtr The state struct to reset.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note
* - This function resets `statePtr` and generate a secret with default parameters.
* - Call this function before @ref XXH3_64bits_update().
* - Digest will be equivalent to `XXH3_64bits()`.
*
* @see @ref streaming_example "Streaming Example"
*
*/
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);
/*!
* @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.
*
* @param statePtr The state struct to reset.
* @param seed The 64-bit seed to alter the hash result predictably.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note
* - This function resets `statePtr` and generate a secret from `seed`.
* - Call this function before @ref XXH3_64bits_update().
* - Digest will be equivalent to `XXH3_64bits_withSeed()`.
*
* @see @ref streaming_example "Streaming Example"
*
*/
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed);
/*!
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
*
* @param statePtr The state struct to reset.
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note
* `secret` is referenced, it _must outlive_ the hash streaming session.
*
* Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN,
* and the quality of produced hash values depends on secret's entropy
* (secret's content should look like a bunch of random bytes).
* When in doubt about the randomness of a candidate `secret`,
* consider employing `XXH3_generateSecret()` instead (see below).
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize);
/*!
* @brief Consumes a block of @p input to an @ref XXH3_state_t.
*
* @param statePtr The state struct to update.
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
*
* @pre
* @p statePtr must not be `NULL`.
* @pre
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note Call this to incrementally consume blocks of data.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);
/*!
* @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t.
*
* @param statePtr The state struct to calculate the hash from.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return The calculated XXH3 64-bit hash value from that state.
*
* @note
* Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update,
* digest, and update again.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr);
#endif /* !XXH_NO_STREAM */
/* note : canonical representation of XXH3 is the same as XXH64
* since they both produce XXH64_hash_t values */
/*-**********************************************************************
* XXH3 128-bit variant
************************************************************************/
/*!
* @brief The return value from 128-bit hashes.
*
* Stored in little endian order, although the fields themselves are in native
* endianness.
*/
typedef struct {
XXH64_hash_t low64; /*!< `value & 0xFFFFFFFFFFFFFFFF` */
XXH64_hash_t high64; /*!< `value >> 64` */
} XXH128_hash_t;
/*!
* @brief Calculates 128-bit unseeded variant of XXH3 of @p data.
*
* @param data The block of data to be hashed, at least @p length bytes in size.
* @param len The length of @p data, in bytes.
*
* @return The calculated 128-bit variant of XXH3 value.
*
* The 128-bit variant of XXH3 has more strength, but it has a bit of overhead
* for shorter inputs.
*
* This is equivalent to @ref XXH3_128bits_withSeed() with a seed of `0`, however
* it may have slightly better performance due to constant propagation of the
* defaults.
*
* @see XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len);
/*! @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.
*
* @param data The block of data to be hashed, at least @p length bytes in size.
* @param len The length of @p data, in bytes.
* @param seed The 64-bit seed to alter the hash result predictably.
*
* @return The calculated 128-bit variant of XXH3 value.
*
* @note
* seed == 0 produces the same results as @ref XXH3_64bits().
*
* This variant generates a custom secret on the fly based on default secret
* altered using the @p seed value.
*
* While this operation is decently fast, note that it's not completely free.
*
* @see XXH3_128bits(), XXH3_128bits_withSecret(): other seeding variants
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);
/*!
* @brief Calculates 128-bit variant of XXH3 with a custom "secret".
*
* @param data The block of data to be hashed, at least @p len bytes in size.
* @param len The length of @p data, in bytes.
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
*
* @return The calculated 128-bit variant of XXH3 value.
*
* It's possible to provide any blob of bytes as a "secret" to generate the hash.
* This makes it more difficult for an external actor to prepare an intentional collision.
* The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN).
* However, the quality of the secret impacts the dispersion of the hash algorithm.
* Therefore, the secret _must_ look like a bunch of random bytes.
* Avoid "trivial" or structured data such as repeated sequences or a text document.
* Whenever in doubt about the "randomness" of the blob of bytes,
* consider employing @ref XXH3_generateSecret() instead (see below).
* It will generate a proper high entropy secret derived from the blob of bytes.
* Another advantage of using XXH3_generateSecret() is that
* it guarantees that all bits within the initial blob of bytes
* will impact every bit of the output.
* This is not necessarily the case when using the blob of bytes directly
* because, when hashing _small_ inputs, only a portion of the secret is employed.
*
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize);
/******* Streaming *******/
#ifndef XXH_NO_STREAM
/*
* Streaming requires state maintenance.
* This operation costs memory and CPU.
* As a consequence, streaming is slower than one-shot hashing.
* For better performance, prefer one-shot functions whenever applicable.
*
* XXH3_128bits uses the same XXH3_state_t as XXH3_64bits().
* Use already declared XXH3_createState() and XXH3_freeState().
*
* All reset and streaming functions have same meaning as their 64-bit counterpart.
*/
/*!
* @brief Resets an @ref XXH3_state_t to begin a new hash.
*
* @param statePtr The state struct to reset.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note
* - This function resets `statePtr` and generate a secret with default parameters.
* - Call it before @ref XXH3_128bits_update().
* - Digest will be equivalent to `XXH3_128bits()`.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);
/*!
* @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.
*
* @param statePtr The state struct to reset.
* @param seed The 64-bit seed to alter the hash result predictably.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note
* - This function resets `statePtr` and generate a secret from `seed`.
* - Call it before @ref XXH3_128bits_update().
* - Digest will be equivalent to `XXH3_128bits_withSeed()`.
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed);
/*!
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
*
* @param statePtr The state struct to reset.
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* `secret` is referenced, it _must outlive_ the hash streaming session.
* Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN,
* and the quality of produced hash values depends on secret's entropy
* (secret's content should look like a bunch of random bytes).
* When in doubt about the randomness of a candidate `secret`,
* consider employing `XXH3_generateSecret()` instead (see below).
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize);
/*!
* @brief Consumes a block of @p input to an @ref XXH3_state_t.
*
* Call this to incrementally consume blocks of data.
*
* @param statePtr The state struct to update.
* @param input The block of data to be hashed, at least @p length bytes in size.
* @param length The length of @p input, in bytes.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @note
* The memory between @p input and @p input + @p length must be valid,
* readable, contiguous memory. However, if @p length is `0`, @p input may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
*/
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);
/*!
* @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t.
*
* @param statePtr The state struct to calculate the hash from.
*
* @pre
* @p statePtr must not be `NULL`.
*
* @return The calculated XXH3 128-bit hash value from that state.
*
* @note
* Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update,
* digest, and update again.
*
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr);
#endif /* !XXH_NO_STREAM */
/* Following helper functions make it possible to compare XXH128_hast_t values.
* Since XXH128_hash_t is a structure, this capability is not offered by the language.
* Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */
/*!
* @brief Check equality of two XXH128_hash_t values
*
* @param h1 The 128-bit hash value.
* @param h2 Another 128-bit hash value.
*
* @return `1` if `h1` and `h2` are equal.
* @return `0` if they are not.
*/
XXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2);
/*!
* @brief Compares two @ref XXH128_hash_t
*
* This comparator is compatible with stdlib's `qsort()`/`bsearch()`.
*
* @param h128_1 Left-hand side value
* @param h128_2 Right-hand side value
*
* @return >0 if @p h128_1 > @p h128_2
* @return =0 if @p h128_1 == @p h128_2
* @return <0 if @p h128_1 < @p h128_2
*/
XXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2);
/******* Canonical representation *******/
typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t;
/*!
* @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t.
*
* @param dst The @ref XXH128_canonical_t pointer to be stored to.
* @param hash The @ref XXH128_hash_t to be converted.
*
* @pre
* @p dst must not be `NULL`.
* @see @ref canonical_representation_example "Canonical Representation Example"
*/
XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash);
/*!
* @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t.
*
* @param src The @ref XXH128_canonical_t to convert.
*
* @pre
* @p src must not be `NULL`.
*
* @return The converted hash.
* @see @ref canonical_representation_example "Canonical Representation Example"
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src);
#endif /* !XXH_NO_XXH3 */
#endif /* XXH_NO_LONG_LONG */
/*!
* @}
*/
#endif /* XXHASH_H_5627135585666179 */
#if defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742)
#define XXHASH_H_STATIC_13879238742
/* ****************************************************************************
* This section contains declarations which are not guaranteed to remain stable.
* They may change in future versions, becoming incompatible with a different
* version of the library.
* These declarations should only be used with static linking.
* Never use them in association with dynamic linking!
***************************************************************************** */
/*
* These definitions are only present to allow static allocation
* of XXH states, on stack or in a struct, for example.
* Never **ever** access their members directly.
*/
/*!
* @internal
* @brief Structure for XXH32 streaming API.
*
* @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
* @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
* an opaque type. This allows fields to safely be changed.
*
* Typedef'd to @ref XXH32_state_t.
* Do not access the members of this struct directly.
* @see XXH64_state_s, XXH3_state_s
*/
struct XXH32_state_s {
XXH32_hash_t total_len_32; /*!< Total length hashed, modulo 2^32 */
XXH32_hash_t large_len; /*!< Whether the hash is >= 16 (handles @ref total_len_32 overflow) */
XXH32_hash_t acc[4]; /*!< Accumulator lanes */
unsigned char buffer[16]; /*!< Internal buffer for partial reads. */
XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */
XXH32_hash_t reserved; /*!< Reserved field. Do not read nor write to it. */
}; /* typedef'd to XXH32_state_t */
#ifndef XXH_NO_LONG_LONG /* defined when there is no 64-bit support */
/*!
* @internal
* @brief Structure for XXH64 streaming API.
*
* @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
* @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined. Otherwise it is
* an opaque type. This allows fields to safely be changed.
*
* Typedef'd to @ref XXH64_state_t.
* Do not access the members of this struct directly.
* @see XXH32_state_s, XXH3_state_s
*/
struct XXH64_state_s {
XXH64_hash_t total_len; /*!< Total length hashed. This is always 64-bit. */
XXH64_hash_t acc[4]; /*!< Accumulator lanes */
unsigned char buffer[32]; /*!< Internal buffer for partial reads.. */
XXH32_hash_t bufferedSize; /*!< Amount of data in @ref buffer */
XXH32_hash_t reserved32; /*!< Reserved field, needed for padding anyways*/
XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */
}; /* typedef'd to XXH64_state_t */
#ifndef XXH_NO_XXH3
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */
# define XXH_ALIGN(n) _Alignas(n)
#elif defined(__cplusplus) && (__cplusplus >= 201103L) /* >= C++11 */
/* In C++ alignas() is a keyword */
# define XXH_ALIGN(n) alignas(n)
#elif defined(__GNUC__)
# define XXH_ALIGN(n) __attribute__ ((aligned(n)))
#elif defined(_MSC_VER)
# define XXH_ALIGN(n) __declspec(align(n))
#else
# define XXH_ALIGN(n) /* disabled */
#endif
/* Old GCC versions only accept the attribute after the type in structures. */
#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \
&& ! (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 */ \
&& defined(__GNUC__)
# define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align)
#else
# define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type
#endif
/*!
* @internal
* @brief The size of the internal XXH3 buffer.
*
* This is the optimal update size for incremental hashing.
*
* @see XXH3_64b_update(), XXH3_128b_update().
*/
#define XXH3_INTERNALBUFFER_SIZE 256
/*!
* @def XXH3_SECRET_DEFAULT_SIZE
* @brief Default Secret's size
*
* This is the size of internal XXH3_kSecret
* and is needed by XXH3_generateSecret_fromSeed().
*
* Not to be confused with @ref XXH3_SECRET_SIZE_MIN.
*/
#define XXH3_SECRET_DEFAULT_SIZE 192
/*!
* @internal
* @brief Structure for XXH3 streaming API.
*
* @note This is only defined when @ref XXH_STATIC_LINKING_ONLY,
* @ref XXH_INLINE_ALL, or @ref XXH_IMPLEMENTATION is defined.
* Otherwise it is an opaque type.
* Never use this definition in combination with dynamic library.
* This allows fields to safely be changed in the future.
*
* @note ** This structure has a strict alignment requirement of 64 bytes!! **
* Do not allocate this with `malloc()` or `new`,
* it will not be sufficiently aligned.
* Use @ref XXH3_createState() and @ref XXH3_freeState(), or stack allocation.
*
* Typedef'd to @ref XXH3_state_t.
* Do never access the members of this struct directly.
*
* @see XXH3_INITSTATE() for stack initialization.
* @see XXH3_createState(), XXH3_freeState().
* @see XXH32_state_s, XXH64_state_s
*/
struct XXH3_state_s {
XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]);
/*!< The 8 accumulators. See @ref XXH32_state_s::acc and @ref XXH64_state_s::acc */
XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]);
/*!< Used to store a custom secret generated from a seed. */
XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]);
/*!< The internal buffer. @see XXH32_state_s::mem32 */
XXH32_hash_t bufferedSize;
/*!< The amount of memory in @ref buffer, @see XXH32_state_s::memsize */
XXH32_hash_t useSeed;
/*!< Reserved field. Needed for padding on 64-bit. */
size_t nbStripesSoFar;
/*!< Number or stripes processed. */
XXH64_hash_t totalLen;
/*!< Total length hashed. 64-bit even on 32-bit targets. */
size_t nbStripesPerBlock;
/*!< Number of stripes per block. */
size_t secretLimit;
/*!< Size of @ref customSecret or @ref extSecret */
XXH64_hash_t seed;
/*!< Seed for _withSeed variants. Must be zero otherwise, @see XXH3_INITSTATE() */
XXH64_hash_t reserved64;
/*!< Reserved field. */
const unsigned char* extSecret;
/*!< Reference to an external secret for the _withSecret variants, NULL
* for other variants. */
/* note: there may be some padding at the end due to alignment on 64 bytes */
}; /* typedef'd to XXH3_state_t */
#undef XXH_ALIGN_MEMBER
/*!
* @brief Initializes a stack-allocated `XXH3_state_s`.
*
* When the @ref XXH3_state_t structure is merely emplaced on stack,
* it should be initialized with XXH3_INITSTATE() or a memset()
* in case its first reset uses XXH3_NNbits_reset_withSeed().
* This init can be omitted if the first reset uses default or _withSecret mode.
* This operation isn't necessary when the state is created with XXH3_createState().
* Note that this doesn't prepare the state for a streaming operation,
* it's still necessary to use XXH3_NNbits_reset*() afterwards.
*/
#define XXH3_INITSTATE(XXH3_state_ptr) \
do { \
XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \
tmp_xxh3_state_ptr->seed = 0; \
tmp_xxh3_state_ptr->extSecret = NULL; \
} while(0)
/*!
* @brief Calculates the 128-bit hash of @p data using XXH3.
*
* @param data The block of data to be hashed, at least @p len bytes in size.
* @param len The length of @p data, in bytes.
* @param seed The 64-bit seed to alter the hash's output predictably.
*
* @pre
* The memory between @p data and @p data + @p len must be valid,
* readable, contiguous memory. However, if @p len is `0`, @p data may be
* `NULL`. In C++, this also must be *TriviallyCopyable*.
*
* @return The calculated 128-bit XXH3 value.
*
* @see @ref single_shot_example "Single Shot Example" for an example.
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);
/* === Experimental API === */
/* Symbols defined below must be considered tied to a specific library version. */
/*!
* @brief Derive a high-entropy secret from any user-defined content, named customSeed.
*
* @param secretBuffer A writable buffer for derived high-entropy secret data.
* @param secretSize Size of secretBuffer, in bytes. Must be >= XXH3_SECRET_SIZE_MIN.
* @param customSeed A user-defined content.
* @param customSeedSize Size of customSeed, in bytes.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* The generated secret can be used in combination with `*_withSecret()` functions.
* The `_withSecret()` variants are useful to provide a higher level of protection
* than 64-bit seed, as it becomes much more difficult for an external actor to
* guess how to impact the calculation logic.
*
* The function accepts as input a custom seed of any length and any content,
* and derives from it a high-entropy secret of length @p secretSize into an
* already allocated buffer @p secretBuffer.
*
* The generated secret can then be used with any `*_withSecret()` variant.
* The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(),
* @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret()
* are part of this list. They all accept a `secret` parameter
* which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN)
* _and_ feature very high entropy (consist of random-looking bytes).
* These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can
* be employed to ensure proper quality.
*
* @p customSeed can be anything. It can have any size, even small ones,
* and its content can be anything, even "poor entropy" sources such as a bunch
* of zeroes. The resulting `secret` will nonetheless provide all required qualities.
*
* @pre
* - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN
* - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior.
*
* Example code:
* @code{.c}
* #include
* #include
* #include
* #define XXH_STATIC_LINKING_ONLY // expose unstable API
* #include "xxhash.h"
* // Hashes argv[2] using the entropy from argv[1].
* int main(int argc, char* argv[])
* {
* char secret[XXH3_SECRET_SIZE_MIN];
* if (argv != 3) { return 1; }
* XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1]));
* XXH64_hash_t h = XXH3_64bits_withSecret(
* argv[2], strlen(argv[2]),
* secret, sizeof(secret)
* );
* printf("%016llx\n", (unsigned long long) h);
* }
* @endcode
*/
XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize);
/*!
* @brief Generate the same secret as the _withSeed() variants.
*
* @param secretBuffer A writable buffer of @ref XXH3_SECRET_DEFAULT_SIZE bytes
* @param seed The 64-bit seed to alter the hash result predictably.
*
* The generated secret can be used in combination with
*`*_withSecret()` and `_withSecretandSeed()` variants.
*
* Example C++ `std::string` hash class:
* @code{.cpp}
* #include
* #define XXH_STATIC_LINKING_ONLY // expose unstable API
* #include "xxhash.h"
* // Slow, seeds each time
* class HashSlow {
* XXH64_hash_t seed;
* public:
* HashSlow(XXH64_hash_t s) : seed{s} {}
* size_t operator()(const std::string& x) const {
* return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)};
* }
* };
* // Fast, caches the seeded secret for future uses.
* class HashFast {
* unsigned char secret[XXH3_SECRET_DEFAULT_SIZE];
* public:
* HashFast(XXH64_hash_t s) {
* XXH3_generateSecret_fromSeed(secret, seed);
* }
* size_t operator()(const std::string& x) const {
* return size_t{
* XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret))
* };
* }
* };
* @endcode
*/
XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed);
/*!
* @brief Maximum size of "short" key in bytes.
*/
#define XXH3_MIDSIZE_MAX 240
/*!
* @brief Calculates 64/128-bit seeded variant of XXH3 hash of @p data.
*
* @param data The block of data to be hashed, at least @p len bytes in size.
* @param len The length of @p data, in bytes.
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
* @param seed The 64-bit seed to alter the hash result predictably.
*
* These variants generate hash values using either:
* - @p seed for "short" keys (< @ref XXH3_MIDSIZE_MAX = 240 bytes)
* - @p secret for "large" keys (>= @ref XXH3_MIDSIZE_MAX).
*
* This generally benefits speed, compared to `_withSeed()` or `_withSecret()`.
* `_withSeed()` has to generate the secret on the fly for "large" keys.
* It's fast, but can be perceptible for "not so large" keys (< 1 KB).
* `_withSecret()` has to generate the masks on the fly for "small" keys,
* which requires more instructions than _withSeed() variants.
* Therefore, _withSecretandSeed variant combines the best of both worlds.
*
* When @p secret has been generated by XXH3_generateSecret_fromSeed(),
* this variant produces *exactly* the same results as `_withSeed()` variant,
* hence offering only a pure speed benefit on "large" input,
* by skipping the need to regenerate the secret for every large input.
*
* Another usage scenario is to hash the secret to a 64-bit hash value,
* for example with XXH3_64bits(), which then becomes the seed,
* and then employ both the seed and the secret in _withSecretandSeed().
* On top of speed, an added benefit is that each bit in the secret
* has a 50% chance to swap each bit in the output, via its impact to the seed.
*
* This is not guaranteed when using the secret directly in "small data" scenarios,
* because only portions of the secret are employed for small data.
*/
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t
XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len,
XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed);
/*!
* @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.
*
* @param input The memory segment to be hashed, at least @p len bytes in size.
* @param length The length of @p data, in bytes.
* @param secret The secret used to alter hash result predictably.
* @param secretSize The length of @p secret, in bytes (must be >= XXH3_SECRET_SIZE_MIN)
* @param seed64 The 64-bit seed to alter the hash result predictably.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @see XXH3_64bits_withSecretandSeed(): contract is the same.
*/
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t
XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length,
XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed64);
#ifndef XXH_NO_STREAM
/*!
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
*
* @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
* @param seed64 The 64-bit seed to alter the hash result predictably.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @see XXH3_64bits_withSecretandSeed(). Contract is identical.
*/
XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,
XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed64);
/*!
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
*
* @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().
* @param secret The secret data.
* @param secretSize The length of @p secret, in bytes.
* @param seed64 The 64-bit seed to alter the hash result predictably.
*
* @return @ref XXH_OK on success.
* @return @ref XXH_ERROR on failure.
*
* @see XXH3_64bits_withSecretandSeed(). Contract is identical.
*
* Note: there was a bug in an earlier version of this function (<= v0.8.2)
* that would make it generate an incorrect hash value
* when @p seed == 0 and @p length < XXH3_MIDSIZE_MAX
* and @p secret is different from XXH3_generateSecret_fromSeed().
* As stated in the contract, the correct hash result must be
* the same as XXH3_128bits_withSeed() when @p length <= XXH3_MIDSIZE_MAX.
* Results generated by this older version are wrong, hence not comparable.
*/
XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,
XXH_NOESCAPE const void* secret, size_t secretSize,
XXH64_hash_t seed64);
#endif /* !XXH_NO_STREAM */
#endif /* !XXH_NO_XXH3 */
#endif /* XXH_NO_LONG_LONG */
#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
# define XXH_IMPLEMENTATION
#endif
#endif /* defined(XXH_STATIC_LINKING_ONLY) && !defined(XXHASH_H_STATIC_13879238742) */
/* ======================================================================== */
/* ======================================================================== */
/* ======================================================================== */
/*-**********************************************************************
* xxHash implementation
*-**********************************************************************
* xxHash's implementation used to be hosted inside xxhash.c.
*
* However, inlining requires implementation to be visible to the compiler,
* hence be included alongside the header.
* Previously, implementation was hosted inside xxhash.c,
* which was then #included when inlining was activated.
* This construction created issues with a few build and install systems,
* as it required xxhash.c to be stored in /include directory.
*
* xxHash implementation is now directly integrated within xxhash.h.
* As a consequence, xxhash.c is no longer needed in /include.
*
* xxhash.c is still available and is still useful.
* In a "normal" setup, when xxhash is not inlined,
* xxhash.h only exposes the prototypes and public symbols,
* while xxhash.c can be built into an object file xxhash.o
* which can then be linked into the final binary.
************************************************************************/
#if ( defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) \
|| defined(XXH_IMPLEMENTATION) ) && !defined(XXH_IMPLEM_13a8737387)
# define XXH_IMPLEM_13a8737387
/* *************************************
* Tuning parameters
***************************************/
/*!
* @defgroup tuning Tuning parameters
* @{
*
* Various macros to control xxHash's behavior.
*/
#ifdef XXH_DOXYGEN
/*!
* @brief Define this to disable 64-bit code.
*
* Useful if only using the @ref XXH32_family and you have a strict C90 compiler.
*/
# define XXH_NO_LONG_LONG
# undef XXH_NO_LONG_LONG /* don't actually */
/*!
* @brief Controls how unaligned memory is accessed.
*
* By default, access to unaligned memory is controlled by `memcpy()`, which is
* safe and portable.
*
* Unfortunately, on some target/compiler combinations, the generated assembly
* is sub-optimal.
*
* The below switch allow selection of a different access method
* in the search for improved performance.
*
* @par Possible options:
*
* - `XXH_FORCE_MEMORY_ACCESS=0` (default): `memcpy`
* @par
* Use `memcpy()`. Safe and portable. Note that most modern compilers will
* eliminate the function call and treat it as an unaligned access.
*
* - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))`
* @par
* Depends on compiler extensions and is therefore not portable.
* This method is safe _if_ your compiler supports it,
* and *generally* as fast or faster than `memcpy`.
*
* - `XXH_FORCE_MEMORY_ACCESS=2`: Direct cast
* @par
* Casts directly and dereferences. This method doesn't depend on the
* compiler, but it violates the C standard as it directly dereferences an
* unaligned pointer. It can generate buggy code on targets which do not
* support unaligned memory accesses, but in some circumstances, it's the
* only known way to get the most performance.
*
* - `XXH_FORCE_MEMORY_ACCESS=3`: Byteshift
* @par
* Also portable. This can generate the best code on old compilers which don't
* inline small `memcpy()` calls, and it might also be faster on big-endian
* systems which lack a native byteswap instruction. However, some compilers
* will emit literal byteshifts even if the target supports unaligned access.
*
*
* @warning
* Methods 1 and 2 rely on implementation-defined behavior. Use these with
* care, as what works on one compiler/platform/optimization level may cause
* another to read garbage data or even crash.
*
* See https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html for details.
*
* Prefer these methods in priority order (0 > 3 > 1 > 2)
*/
# define XXH_FORCE_MEMORY_ACCESS 0
/*!
* @def XXH_SIZE_OPT
* @brief Controls how much xxHash optimizes for size.
*
* xxHash, when compiled, tends to result in a rather large binary size. This
* is mostly due to heavy usage to forced inlining and constant folding of the
* @ref XXH3_family to increase performance.
*
* However, some developers prefer size over speed. This option can
* significantly reduce the size of the generated code. When using the `-Os`
* or `-Oz` options on GCC or Clang, this is defined to 1 by default,
* otherwise it is defined to 0.
*
* Most of these size optimizations can be controlled manually.
*
* This is a number from 0-2.
* - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed
* comes first.
* - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more
* conservative and disables hacks that increase code size. It implies the
* options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0,
* and @ref XXH3_NEON_LANES == 8 if they are not already defined.
* - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible.
* Performance may cry. For example, the single shot functions just use the
* streaming API.
*/
# define XXH_SIZE_OPT 0
/*!
* @def XXH_FORCE_ALIGN_CHECK
* @brief If defined to non-zero, adds a special path for aligned inputs (XXH32()
* and XXH64() only).
*
* This is an important performance trick for architectures without decent
* unaligned memory access performance.
*
* It checks for input alignment, and when conditions are met, uses a "fast
* path" employing direct 32-bit/64-bit reads, resulting in _dramatically
* faster_ read speed.
*
* The check costs one initial branch per hash, which is generally negligible,
* but not zero.
*
* Moreover, it's not useful to generate an additional code path if memory
* access uses the same instruction for both aligned and unaligned
* addresses (e.g. x86 and aarch64).
*
* In these cases, the alignment check can be removed by setting this macro to 0.
* Then the code will always use unaligned memory access.
* Align check is automatically disabled on x86, x64, ARM64, and some ARM chips
* which are platforms known to offer good unaligned memory accesses performance.
*
* It is also disabled by default when @ref XXH_SIZE_OPT >= 1.
*
* This option does not affect XXH3 (only XXH32 and XXH64).
*/
# define XXH_FORCE_ALIGN_CHECK 0
/*!
* @def XXH_NO_INLINE_HINTS
* @brief When non-zero, sets all functions to `static`.
*
* By default, xxHash tries to force the compiler to inline almost all internal
* functions.
*
* This can usually improve performance due to reduced jumping and improved
* constant folding, but significantly increases the size of the binary which
* might not be favorable.
*
* Additionally, sometimes the forced inlining can be detrimental to performance,
* depending on the architecture.
*
* XXH_NO_INLINE_HINTS marks all internal functions as static, giving the
* compiler full control on whether to inline or not.
*
* When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if
* @ref XXH_SIZE_OPT >= 1, this will automatically be defined.
*/
# define XXH_NO_INLINE_HINTS 0
/*!
* @def XXH3_INLINE_SECRET
* @brief Determines whether to inline the XXH3 withSecret code.
*
* When the secret size is known, the compiler can improve the performance
* of XXH3_64bits_withSecret() and XXH3_128bits_withSecret().
*
* However, if the secret size is not known, it doesn't have any benefit. This
* happens when xxHash is compiled into a global symbol. Therefore, if
* @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0.
*
* Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers
* that are *sometimes* force inline on -Og, and it is impossible to automatically
* detect this optimization level.
*/
# define XXH3_INLINE_SECRET 0
/*!
* @def XXH32_ENDJMP
* @brief Whether to use a jump for `XXH32_finalize`.
*
* For performance, `XXH32_finalize` uses multiple branches in the finalizer.
* This is generally preferable for performance,
* but depending on exact architecture, a jmp may be preferable.
*
* This setting is only possibly making a difference for very small inputs.
*/
# define XXH32_ENDJMP 0
/*!
* @internal
* @brief Redefines old internal names.
*
* For compatibility with code that uses xxHash's internals before the names
* were changed to improve namespacing. There is no other reason to use this.
*/
# define XXH_OLD_NAMES
# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */
/*!
* @def XXH_NO_STREAM
* @brief Disables the streaming API.
*
* When xxHash is not inlined and the streaming functions are not used, disabling
* the streaming functions can improve code size significantly, especially with
* the @ref XXH3_family which tends to make constant folded copies of itself.
*/
# define XXH_NO_STREAM
# undef XXH_NO_STREAM /* don't actually */
#endif /* XXH_DOXYGEN */
/*!
* @}
*/
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
/* prefer __packed__ structures (method 1) for GCC
* < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy
* which for some reason does unaligned loads. */
# if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED))
# define XXH_FORCE_MEMORY_ACCESS 1
# endif
#endif
#ifndef XXH_SIZE_OPT
/* default to 1 for -Os or -Oz */
# if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__)
# define XXH_SIZE_OPT 1
# else
# define XXH_SIZE_OPT 0
# endif
#endif
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
/* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */
# if XXH_SIZE_OPT >= 1 || \
defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \
|| defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) /* visual */
# define XXH_FORCE_ALIGN_CHECK 0
# else
# define XXH_FORCE_ALIGN_CHECK 1
# endif
#endif
#ifndef XXH_NO_INLINE_HINTS
# if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */
# define XXH_NO_INLINE_HINTS 1
# else
# define XXH_NO_INLINE_HINTS 0
# endif
#endif
#ifndef XXH3_INLINE_SECRET
# if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \
|| !defined(XXH_INLINE_ALL)
# define XXH3_INLINE_SECRET 0
# else
# define XXH3_INLINE_SECRET 1
# endif
#endif
#ifndef XXH32_ENDJMP
/* generally preferable for performance */
# define XXH32_ENDJMP 0
#endif
/*!
* @defgroup impl Implementation
* @{
*/
/* *************************************
* Includes & Memory related functions
***************************************/
#if defined(XXH_NO_STREAM)
/* nothing */
#elif defined(XXH_NO_STDLIB)
/* When requesting to disable any mention of stdlib,
* the library loses the ability to invoked malloc / free.
* In practice, it means that functions like `XXH*_createState()`
* will always fail, and return NULL.
* This flag is useful in situations where
* xxhash.h is integrated into some kernel, embedded or limited environment
* without access to dynamic allocation.
*/
static XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; }
static void XXH_free(void* p) { (void)p; }
#else
/*
* Modify the local functions below should you wish to use
* different memory routines for malloc() and free()
*/
#include
/*!
* @internal
* @brief Modify this function to use a different routine than malloc().
*/
static XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); }
/*!
* @internal
* @brief Modify this function to use a different routine than free().
*/
static void XXH_free(void* p) { free(p); }
#endif /* XXH_NO_STDLIB */
#ifndef XXH_memcpy
/*!
* @internal
* @brief XXH_memcpy() macro can be redirected at compile time
*/
# include
# define XXH_memcpy memcpy
#endif
#ifndef XXH_memset
/*!
* @internal
* @brief XXH_memset() macro can be redirected at compile time
*/
# include
# define XXH_memset memset
#endif
#ifndef XXH_memcmp
/*!
* @internal
* @brief XXH_memcmp() macro can be redirected at compile time
* Note: only needed by XXH128.
*/
# include
# define XXH_memcmp memcmp
#endif
#include /* ULLONG_MAX */
/* *************************************
* Compiler Specific Options
***************************************/
#ifdef _MSC_VER /* Visual Studio warning fix */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
#endif
#if XXH_NO_INLINE_HINTS /* disable inlining hints */
# if defined(__GNUC__) || defined(__clang__)
# define XXH_FORCE_INLINE static __attribute__((__unused__))
# else
# define XXH_FORCE_INLINE static
# endif
# define XXH_NO_INLINE static
/* enable inlining hints */
#elif defined(__GNUC__) || defined(__clang__)
# define XXH_FORCE_INLINE static __inline__ __attribute__((__always_inline__, __unused__))
# define XXH_NO_INLINE static __attribute__((__noinline__))
#elif defined(_MSC_VER) /* Visual Studio */
# define XXH_FORCE_INLINE static __forceinline
# define XXH_NO_INLINE static __declspec(noinline)
#elif defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */
# define XXH_FORCE_INLINE static inline
# define XXH_NO_INLINE static
#else
# define XXH_FORCE_INLINE static
# define XXH_NO_INLINE static
#endif
#if defined(XXH_INLINE_ALL)
# define XXH_STATIC XXH_FORCE_INLINE
#else
# define XXH_STATIC static
#endif
#if XXH3_INLINE_SECRET
# define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE
#else
# define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE
#endif
#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */
# define XXH_RESTRICT /* disable */
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */
# define XXH_RESTRICT restrict
#elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \
|| (defined (__clang__)) \
|| (defined (_MSC_VER) && (_MSC_VER >= 1400)) \
|| (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300))
/*
* There are a LOT more compilers that recognize __restrict but this
* covers the major ones.
*/
# define XXH_RESTRICT __restrict
#else
# define XXH_RESTRICT /* disable */
#endif
/* *************************************
* Debug
***************************************/
/*!
* @ingroup tuning
* @def XXH_DEBUGLEVEL
* @brief Sets the debugging level.
*
* XXH_DEBUGLEVEL is expected to be defined externally, typically via the
* compiler's command line options. The value must be a number.
*/
#ifndef XXH_DEBUGLEVEL
# ifdef DEBUGLEVEL /* backwards compat */
# define XXH_DEBUGLEVEL DEBUGLEVEL
# else
# define XXH_DEBUGLEVEL 0
# endif
#endif
#if (XXH_DEBUGLEVEL>=1)
# include /* note: can still be disabled with NDEBUG */
# define XXH_ASSERT(c) assert(c)
#else
# if defined(__INTEL_COMPILER)
# define XXH_ASSERT(c) XXH_ASSUME((unsigned char) (c))
# else
# define XXH_ASSERT(c) XXH_ASSUME(c)
# endif
#endif
/* note: use after variable declarations */
#ifndef XXH_STATIC_ASSERT
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */
# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0)
# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */
# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0)
# else
# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { struct xxh_sa { char x[(c) ? 1 : -1]; }; } while(0)
# endif
# define XXH_STATIC_ASSERT(c) XXH_STATIC_ASSERT_WITH_MESSAGE((c),#c)
#endif
/*!
* @internal
* @def XXH_COMPILER_GUARD(var)
* @brief Used to prevent unwanted optimizations for @p var.
*
* It uses an empty GCC inline assembly statement with a register constraint
* which forces @p var into a general purpose register (eg eax, ebx, ecx
* on x86) and marks it as modified.
*
* This is used in a few places to avoid unwanted autovectorization (e.g.
* XXH32_round()). All vectorization we want is explicit via intrinsics,
* and _usually_ isn't wanted elsewhere.
*
* We also use it to prevent unwanted constant folding for AArch64 in
* XXH3_initCustomSecret_scalar().
*/
#if defined(__GNUC__) || defined(__clang__)
# define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var))
#else
# define XXH_COMPILER_GUARD(var) ((void)0)
#endif
/* Specifically for NEON vectors which use the "w" constraint, on
* Clang. */
#if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__)
# define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__("" : "+w" (var))
#else
# define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0)
#endif
/* *************************************
* Basic Types
***************************************/
#if !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# ifdef _AIX
# include
# else
# include
# endif
typedef uint8_t xxh_u8;
#else
typedef unsigned char xxh_u8;
#endif
typedef XXH32_hash_t xxh_u32;
#ifdef XXH_OLD_NAMES
# warning "XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly"
# define BYTE xxh_u8
# define U8 xxh_u8
# define U32 xxh_u32
#endif
/* *** Memory access *** */
/*!
* @internal
* @fn xxh_u32 XXH_read32(const void* ptr)
* @brief Reads an unaligned 32-bit integer from @p ptr in native endianness.
*
* Affected by @ref XXH_FORCE_MEMORY_ACCESS.
*
* @param ptr The pointer to read from.
* @return The 32-bit native endian integer from the bytes at @p ptr.
*/
/*!
* @internal
* @fn xxh_u32 XXH_readLE32(const void* ptr)
* @brief Reads an unaligned 32-bit little endian integer from @p ptr.
*
* Affected by @ref XXH_FORCE_MEMORY_ACCESS.
*
* @param ptr The pointer to read from.
* @return The 32-bit little endian integer from the bytes at @p ptr.
*/
/*!
* @internal
* @fn xxh_u32 XXH_readBE32(const void* ptr)
* @brief Reads an unaligned 32-bit big endian integer from @p ptr.
*
* Affected by @ref XXH_FORCE_MEMORY_ACCESS.
*
* @param ptr The pointer to read from.
* @return The 32-bit big endian integer from the bytes at @p ptr.
*/
/*!
* @internal
* @fn xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align)
* @brief Like @ref XXH_readLE32(), but has an option for aligned reads.
*
* Affected by @ref XXH_FORCE_MEMORY_ACCESS.
* Note that when @ref XXH_FORCE_ALIGN_CHECK == 0, the @p align parameter is
* always @ref XXH_alignment::XXH_unaligned.
*
* @param ptr The pointer to read from.
* @param align Whether @p ptr is aligned.
* @pre
* If @p align == @ref XXH_alignment::XXH_aligned, @p ptr must be 4 byte
* aligned.
* @return The 32-bit little endian integer from the bytes at @p ptr.
*/
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
/*
* Manual byteshift. Best for old compilers which don't inline memcpy.
* We actually directly use XXH_readLE32 and XXH_readBE32.
*/
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/*
* Force direct memory access. Only works on CPU which support unaligned memory
* access in hardware.
*/
static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/*
* __attribute__((aligned(1))) is supported by gcc and clang. Originally the
* documentation claimed that it only increased the alignment, but actually it
* can decrease it on gcc, clang, and icc:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,
* https://gcc.godbolt.org/z/xYez1j67Y.
*/
#ifdef XXH_OLD_NAMES
typedef union { xxh_u32 u32; } __attribute__((__packed__)) unalign;
#endif
static xxh_u32 XXH_read32(const void* ptr)
{
typedef __attribute__((__aligned__(1))) xxh_u32 xxh_unalign32;
return *((const xxh_unalign32*)ptr);
}
#else
/*
* Portable and safe solution. Generally efficient.
* see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html
*/
static xxh_u32 XXH_read32(const void* memPtr)
{
xxh_u32 val;
XXH_memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
/* *** Endianness *** */
/*!
* @ingroup tuning
* @def XXH_CPU_LITTLE_ENDIAN
* @brief Whether the target is little endian.
*
* Defined to 1 if the target is little endian, or 0 if it is big endian.
* It can be defined externally, for example on the compiler command line.
*
* If it is not defined,
* a runtime check (which is usually constant folded) is used instead.
*
* @note
* This is not necessarily defined to an integer constant.
*
* @see XXH_isLittleEndian() for the runtime check.
*/
#ifndef XXH_CPU_LITTLE_ENDIAN
/*
* Try to detect endianness automatically, to avoid the nonstandard behavior
* in `XXH_isLittleEndian()`
*/
# if defined(_WIN32) /* Windows is always little endian */ \
|| defined(__LITTLE_ENDIAN__) \
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
# define XXH_CPU_LITTLE_ENDIAN 1
# elif defined(__BIG_ENDIAN__) \
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
# define XXH_CPU_LITTLE_ENDIAN 0
# else
/*!
* @internal
* @brief Runtime check for @ref XXH_CPU_LITTLE_ENDIAN.
*
* Most compilers will constant fold this.
*/
static int XXH_isLittleEndian(void)
{
/*
* Portable and well-defined behavior.
* Don't use static: it is detrimental to performance.
*/
const union { xxh_u32 u; xxh_u8 c[4]; } one = { 1 };
return one.c[0];
}
# define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian()
# endif
#endif
/* ****************************************
* Compiler-specific Functions and Macros
******************************************/
#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#ifdef __has_builtin
# define XXH_HAS_BUILTIN(x) __has_builtin(x)
#else
# define XXH_HAS_BUILTIN(x) 0
#endif
/*
* C23 and future versions have standard "unreachable()".
* Once it has been implemented reliably we can add it as an
* additional case:
*
* ```
* #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN)
* # include
* # ifdef unreachable
* # define XXH_UNREACHABLE() unreachable()
* # endif
* #endif
* ```
*
* Note C++23 also has std::unreachable() which can be detected
* as follows:
* ```
* #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L)
* # include
* # define XXH_UNREACHABLE() std::unreachable()
* #endif
* ```
* NB: `__cpp_lib_unreachable` is defined in the `` header.
* We don't use that as including `` in `extern "C"` blocks
* doesn't work on GCC12
*/
#if XXH_HAS_BUILTIN(__builtin_unreachable)
# define XXH_UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
# define XXH_UNREACHABLE() __assume(0)
#else
# define XXH_UNREACHABLE()
#endif
#if XXH_HAS_BUILTIN(__builtin_assume)
# define XXH_ASSUME(c) __builtin_assume(c)
#else
# define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); }
#endif
/*!
* @internal
* @def XXH_rotl32(x,r)
* @brief 32-bit rotate left.
*
* @param x The 32-bit integer to be rotated.
* @param r The number of bits to rotate.
* @pre
* @p r > 0 && @p r < 32
* @note
* @p x and @p r may be evaluated multiple times.
* @return The rotated result.
*/
#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \
&& XXH_HAS_BUILTIN(__builtin_rotateleft64)
# define XXH_rotl32 __builtin_rotateleft32
# define XXH_rotl64 __builtin_rotateleft64
#elif XXH_HAS_BUILTIN(__builtin_stdc_rotate_left)
# define XXH_rotl32 __builtin_stdc_rotate_left
# define XXH_rotl64 __builtin_stdc_rotate_left
/* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */
#elif defined(_MSC_VER)
# define XXH_rotl32(x,r) _rotl(x,r)
# define XXH_rotl64(x,r) _rotl64(x,r)
#else
# define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
# define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r))))
#endif
/*!
* @internal
* @fn xxh_u32 XXH_swap32(xxh_u32 x)
* @brief A 32-bit byteswap.
*
* @param x The 32-bit integer to byteswap.
* @return @p x, byteswapped.
*/
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap32 _byteswap_ulong
#elif XXH_GCC_VERSION >= 403
# define XXH_swap32 __builtin_bswap32
#else
static xxh_u32 XXH_swap32 (xxh_u32 x)
{
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
((x >> 8) & 0x0000ff00 ) |
((x >> 24) & 0x000000ff );
}
#endif
/* ***************************
* Memory reads
*****************************/
/*!
* @internal
* @brief Enum to indicate whether a pointer is aligned.
*/
typedef enum {
XXH_aligned, /*!< Aligned */
XXH_unaligned /*!< Possibly unaligned */
} XXH_alignment;
/*
* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load.
*
* This is ideal for older compilers which don't inline memcpy.
*/
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr)
{
const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
return bytePtr[0]
| ((xxh_u32)bytePtr[1] << 8)
| ((xxh_u32)bytePtr[2] << 16)
| ((xxh_u32)bytePtr[3] << 24);
}
XXH_FORCE_INLINE xxh_u32 XXH_readBE32(const void* memPtr)
{
const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
return bytePtr[3]
| ((xxh_u32)bytePtr[2] << 8)
| ((xxh_u32)bytePtr[1] << 16)
| ((xxh_u32)bytePtr[0] << 24);
}
#else
XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
}
static xxh_u32 XXH_readBE32(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
}
#endif
XXH_FORCE_INLINE xxh_u32
XXH_readLE32_align(const void* ptr, XXH_alignment align)
{
if (align==XXH_unaligned) {
return XXH_readLE32(ptr);
} else {
return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr);
}
}
/* *************************************
* Misc
***************************************/
/*! @ingroup public */
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
/* *******************************************************************
* 32-bit hash functions
*********************************************************************/
/*!
* @}
* @defgroup XXH32_impl XXH32 implementation
* @ingroup impl
*
* Details on the XXH32 implementation.
* @{
*/
/* #define instead of static const, to be used as initializers */
#define XXH_PRIME32_1 0x9E3779B1U /*!< 0b10011110001101110111100110110001 */
#define XXH_PRIME32_2 0x85EBCA77U /*!< 0b10000101111010111100101001110111 */
#define XXH_PRIME32_3 0xC2B2AE3DU /*!< 0b11000010101100101010111000111101 */
#define XXH_PRIME32_4 0x27D4EB2FU /*!< 0b00100111110101001110101100101111 */
#define XXH_PRIME32_5 0x165667B1U /*!< 0b00010110010101100110011110110001 */
#ifdef XXH_OLD_NAMES
# define PRIME32_1 XXH_PRIME32_1
# define PRIME32_2 XXH_PRIME32_2
# define PRIME32_3 XXH_PRIME32_3
# define PRIME32_4 XXH_PRIME32_4
# define PRIME32_5 XXH_PRIME32_5
#endif
/*!
* @internal
* @brief Normal stripe processing routine.
*
* This shuffles the bits so that any bit from @p input impacts several bits in
* @p acc.
*
* @param acc The accumulator lane.
* @param input The stripe of input to mix.
* @return The mixed accumulator lane.
*/
static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input)
{
acc += input * XXH_PRIME32_2;
acc = XXH_rotl32(acc, 13);
acc *= XXH_PRIME32_1;
#if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE)
/*
* UGLY HACK:
* A compiler fence is used to prevent GCC and Clang from
* autovectorizing the XXH32 loop (pragmas and attributes don't work for some
* reason) without globally disabling SSE4.1.
*
* The reason we want to avoid vectorization is because despite working on
* 4 integers at a time, there are multiple factors slowing XXH32 down on
* SSE4:
* - There's a ridiculous amount of lag from pmulld (10 cycles of latency on
* newer chips!) making it slightly slower to multiply four integers at
* once compared to four integers independently. Even when pmulld was
* fastest, Sandy/Ivy Bridge, it is still not worth it to go into SSE
* just to multiply unless doing a long operation.
*
* - Four instructions are required to rotate,
* movqda tmp, v // not required with VEX encoding
* pslld tmp, 13 // tmp <<= 13
* psrld v, 19 // x >>= 19
* por v, tmp // x |= tmp
* compared to one for scalar:
* roll v, 13 // reliably fast across the board
* shldl v, v, 13 // Sandy Bridge and later prefer this for some reason
*
* - Instruction level parallelism is actually more beneficial here because
* the SIMD actually serializes this operation: While v1 is rotating, v2
* can load data, while v3 can multiply. SSE forces them to operate
* together.
*
* This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing
* the loop. NEON is only faster on the A53, and with the newer cores, it is less
* than half the speed.
*
* Additionally, this is used on WASM SIMD128 because it JITs to the same
* SIMD instructions and has the same issue.
*/
XXH_COMPILER_GUARD(acc);
#endif
return acc;
}
/*!
* @internal
* @brief Mixes all bits to finalize the hash.
*
* The final mix ensures that all input bits have a chance to impact any bit in
* the output digest, resulting in an unbiased distribution.
*
* @param hash The hash to avalanche.
* @return The avalanched hash.
*/
static xxh_u32 XXH32_avalanche(xxh_u32 hash)
{
hash ^= hash >> 15;
hash *= XXH_PRIME32_2;
hash ^= hash >> 13;
hash *= XXH_PRIME32_3;
hash ^= hash >> 16;
return hash;
}
#define XXH_get32bits(p) XXH_readLE32_align(p, align)
/*!
* @internal
* @brief Sets up the initial accumulator state for XXH32().
*/
XXH_FORCE_INLINE void
XXH32_initAccs(xxh_u32 *acc, xxh_u32 seed)
{
XXH_ASSERT(acc != NULL);
acc[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
acc[1] = seed + XXH_PRIME32_2;
acc[2] = seed + 0;
acc[3] = seed - XXH_PRIME32_1;
}
/*!
* @internal
* @brief Consumes a block of data for XXH32().
*
* @return the end input pointer.
*/
XXH_FORCE_INLINE const xxh_u8 *
XXH32_consumeLong(
xxh_u32 *XXH_RESTRICT acc,
xxh_u8 const *XXH_RESTRICT input,
size_t len,
XXH_alignment align
)
{
const xxh_u8* const bEnd = input + len;
const xxh_u8* const limit = bEnd - 15;
XXH_ASSERT(acc != NULL);
XXH_ASSERT(input != NULL);
XXH_ASSERT(len >= 16);
do {
acc[0] = XXH32_round(acc[0], XXH_get32bits(input)); input += 4;
acc[1] = XXH32_round(acc[1], XXH_get32bits(input)); input += 4;
acc[2] = XXH32_round(acc[2], XXH_get32bits(input)); input += 4;
acc[3] = XXH32_round(acc[3], XXH_get32bits(input)); input += 4;
} while (input < limit);
return input;
}
/*!
* @internal
* @brief Merges the accumulator lanes together for XXH32()
*/
XXH_FORCE_INLINE XXH_PUREF xxh_u32
XXH32_mergeAccs(const xxh_u32 *acc)
{
XXH_ASSERT(acc != NULL);
return XXH_rotl32(acc[0], 1) + XXH_rotl32(acc[1], 7)
+ XXH_rotl32(acc[2], 12) + XXH_rotl32(acc[3], 18);
}
/*!
* @internal
* @brief Processes the last 0-15 bytes of @p ptr.
*
* There may be up to 15 bytes remaining to consume from the input.
* This final stage will digest them to ensure that all input bytes are present
* in the final mix.
*
* @param hash The hash to finalize.
* @param ptr The pointer to the remaining input.
* @param len The remaining length, modulo 16.
* @param align Whether @p ptr is aligned.
* @return The finalized hash.
* @see XXH64_finalize().
*/
static XXH_PUREF xxh_u32
XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)
{
#define XXH_PROCESS1 do { \
hash += (*ptr++) * XXH_PRIME32_5; \
hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \
} while (0)
#define XXH_PROCESS4 do { \
hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \
ptr += 4; \
hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \
} while (0)
if (ptr==NULL) XXH_ASSERT(len == 0);
/* Compact rerolled version; generally faster */
if (!XXH32_ENDJMP) {
len &= 15;
while (len >= 4) {
XXH_PROCESS4;
len -= 4;
}
while (len > 0) {
XXH_PROCESS1;
--len;
}
return XXH32_avalanche(hash);
} else {
switch(len&15) /* or switch(bEnd - p) */ {
case 12: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 8: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 4: XXH_PROCESS4;
return XXH32_avalanche(hash);
case 13: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 9: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 5: XXH_PROCESS4;
XXH_PROCESS1;
return XXH32_avalanche(hash);
case 14: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 10: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 6: XXH_PROCESS4;
XXH_PROCESS1;
XXH_PROCESS1;
return XXH32_avalanche(hash);
case 15: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 11: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 7: XXH_PROCESS4;
XXH_FALLTHROUGH; /* fallthrough */
case 3: XXH_PROCESS1;
XXH_FALLTHROUGH; /* fallthrough */
case 2: XXH_PROCESS1;
XXH_FALLTHROUGH; /* fallthrough */
case 1: XXH_PROCESS1;
XXH_FALLTHROUGH; /* fallthrough */
case 0: return XXH32_avalanche(hash);
}
XXH_ASSERT(0);
return hash; /* reaching this point is deemed impossible */
}
}
#ifdef XXH_OLD_NAMES
# define PROCESS1 XXH_PROCESS1
# define PROCESS4 XXH_PROCESS4
#else
# undef XXH_PROCESS1
# undef XXH_PROCESS4
#endif
/*!
* @internal
* @brief The implementation for @ref XXH32().
*
* @param input , len , seed Directly passed from @ref XXH32().
* @param align Whether @p input is aligned.
* @return The calculated hash.
*/
XXH_FORCE_INLINE XXH_PUREF xxh_u32
XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)
{
xxh_u32 h32;
if (input==NULL) XXH_ASSERT(len == 0);
if (len>=16) {
xxh_u32 acc[4];
XXH32_initAccs(acc, seed);
input = XXH32_consumeLong(acc, input, len, align);
h32 = XXH32_mergeAccs(acc);
} else {
h32 = seed + XXH_PRIME32_5;
}
h32 += (xxh_u32)len;
return XXH32_finalize(h32, input, len&15, align);
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed)
{
#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH32_state_t state;
XXH32_reset(&state, seed);
XXH32_update(&state, (const xxh_u8*)input, len);
return XXH32_digest(&state);
#else
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_aligned);
} }
return XXH32_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned);
#endif
}
/******* Hash streaming *******/
#ifndef XXH_NO_STREAM
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
{
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
{
XXH_memcpy(dstState, srcState, sizeof(*dstState));
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed)
{
XXH_ASSERT(statePtr != NULL);
XXH_memset(statePtr, 0, sizeof(*statePtr));
XXH32_initAccs(statePtr->acc, seed);
return XXH_OK;
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH_errorcode
XXH32_update(XXH32_state_t* state, const void* input, size_t len)
{
if (input==NULL) {
XXH_ASSERT(len == 0);
return XXH_OK;
}
state->total_len_32 += (XXH32_hash_t)len;
state->large_len |= (XXH32_hash_t)((len>=16) | (state->total_len_32>=16));
XXH_ASSERT(state->bufferedSize < sizeof(state->buffer));
if (len < sizeof(state->buffer) - state->bufferedSize) { /* fill in tmp buffer */
XXH_memcpy(state->buffer + state->bufferedSize, input, len);
state->bufferedSize += (XXH32_hash_t)len;
return XXH_OK;
}
{ const xxh_u8* xinput = (const xxh_u8*)input;
const xxh_u8* const bEnd = xinput + len;
if (state->bufferedSize) { /* non-empty buffer: complete first */
XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize);
xinput += sizeof(state->buffer) - state->bufferedSize;
/* then process one round */
(void)XXH32_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned);
state->bufferedSize = 0;
}
XXH_ASSERT(xinput <= bEnd);
if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) {
/* Process the remaining data */
xinput = XXH32_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned);
}
if (xinput < bEnd) {
/* Copy the leftover to the tmp buffer */
XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput));
state->bufferedSize = (unsigned)(bEnd-xinput);
}
}
return XXH_OK;
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state)
{
xxh_u32 h32;
if (state->large_len) {
h32 = XXH32_mergeAccs(state->acc);
} else {
h32 = state->acc[2] /* == seed */ + XXH_PRIME32_5;
}
h32 += state->total_len_32;
return XXH32_finalize(h32, state->buffer, state->bufferedSize, XXH_aligned);
}
#endif /* !XXH_NO_STREAM */
/******* Canonical representation *******/
/*! @ingroup XXH32_family */
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
XXH_memcpy(dst, &hash, sizeof(*dst));
}
/*! @ingroup XXH32_family */
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
{
return XXH_readBE32(src);
}
#ifndef XXH_NO_LONG_LONG
/* *******************************************************************
* 64-bit hash functions
*********************************************************************/
/*!
* @}
* @ingroup impl
* @{
*/
/******* Memory access *******/
typedef XXH64_hash_t xxh_u64;
#ifdef XXH_OLD_NAMES
# define U64 xxh_u64
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
/*
* Manual byteshift. Best for old compilers which don't inline memcpy.
* We actually directly use XXH_readLE64 and XXH_readBE64.
*/
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static xxh_u64 XXH_read64(const void* memPtr)
{
return *(const xxh_u64*) memPtr;
}
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/*
* __attribute__((aligned(1))) is supported by gcc and clang. Originally the
* documentation claimed that it only increased the alignment, but actually it
* can decrease it on gcc, clang, and icc:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,
* https://gcc.godbolt.org/z/xYez1j67Y.
*/
#ifdef XXH_OLD_NAMES
typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((__packed__)) unalign64;
#endif
static xxh_u64 XXH_read64(const void* ptr)
{
typedef __attribute__((__aligned__(1))) xxh_u64 xxh_unalign64;
return *((const xxh_unalign64*)ptr);
}
#else
/*
* Portable and safe solution. Generally efficient.
* see: https://fastcompression.blogspot.com/2015/08/accessing-unaligned-memory.html
*/
static xxh_u64 XXH_read64(const void* memPtr)
{
xxh_u64 val;
XXH_memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap64 _byteswap_uint64
#elif XXH_GCC_VERSION >= 403
# define XXH_swap64 __builtin_bswap64
#else
static xxh_u64 XXH_swap64(xxh_u64 x)
{
return ((x << 56) & 0xff00000000000000ULL) |
((x << 40) & 0x00ff000000000000ULL) |
((x << 24) & 0x0000ff0000000000ULL) |
((x << 8) & 0x000000ff00000000ULL) |
((x >> 8) & 0x00000000ff000000ULL) |
((x >> 24) & 0x0000000000ff0000ULL) |
((x >> 40) & 0x000000000000ff00ULL) |
((x >> 56) & 0x00000000000000ffULL);
}
#endif
/* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))
XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr)
{
const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
return bytePtr[0]
| ((xxh_u64)bytePtr[1] << 8)
| ((xxh_u64)bytePtr[2] << 16)
| ((xxh_u64)bytePtr[3] << 24)
| ((xxh_u64)bytePtr[4] << 32)
| ((xxh_u64)bytePtr[5] << 40)
| ((xxh_u64)bytePtr[6] << 48)
| ((xxh_u64)bytePtr[7] << 56);
}
XXH_FORCE_INLINE xxh_u64 XXH_readBE64(const void* memPtr)
{
const xxh_u8* bytePtr = (const xxh_u8 *)memPtr;
return bytePtr[7]
| ((xxh_u64)bytePtr[6] << 8)
| ((xxh_u64)bytePtr[5] << 16)
| ((xxh_u64)bytePtr[4] << 24)
| ((xxh_u64)bytePtr[3] << 32)
| ((xxh_u64)bytePtr[2] << 40)
| ((xxh_u64)bytePtr[1] << 48)
| ((xxh_u64)bytePtr[0] << 56);
}
#else
XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
}
static xxh_u64 XXH_readBE64(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
}
#endif
XXH_FORCE_INLINE xxh_u64
XXH_readLE64_align(const void* ptr, XXH_alignment align)
{
if (align==XXH_unaligned)
return XXH_readLE64(ptr);
else
return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr);
}
/******* xxh64 *******/
/*!
* @}
* @defgroup XXH64_impl XXH64 implementation
* @ingroup impl
*
* Details on the XXH64 implementation.
* @{
*/
/* #define rather that static const, to be used as initializers */
#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL /*!< 0b1001111000110111011110011011000110000101111010111100101010000111 */
#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL /*!< 0b1100001010110010101011100011110100100111110101001110101101001111 */
#define XXH_PRIME64_3 0x165667B19E3779F9ULL /*!< 0b0001011001010110011001111011000110011110001101110111100111111001 */
#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL /*!< 0b1000010111101011110010100111011111000010101100101010111001100011 */
#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL /*!< 0b0010011111010100111010110010111100010110010101100110011111000101 */
#ifdef XXH_OLD_NAMES
# define PRIME64_1 XXH_PRIME64_1
# define PRIME64_2 XXH_PRIME64_2
# define PRIME64_3 XXH_PRIME64_3
# define PRIME64_4 XXH_PRIME64_4
# define PRIME64_5 XXH_PRIME64_5
#endif
/*! @copydoc XXH32_round */
static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input)
{
acc += input * XXH_PRIME64_2;
acc = XXH_rotl64(acc, 31);
acc *= XXH_PRIME64_1;
#if (defined(__AVX512F__)) && !defined(XXH_ENABLE_AUTOVECTORIZE)
/*
* DISABLE AUTOVECTORIZATION:
* A compiler fence is used to prevent GCC and Clang from
* autovectorizing the XXH64 loop (pragmas and attributes don't work for some
* reason) without globally disabling AVX512.
*
* Autovectorization of XXH64 tends to be detrimental,
* though the exact outcome may change depending on exact cpu and compiler version.
* For information, it has been reported as detrimental for Skylake-X,
* but possibly beneficial for Zen4.
*
* The default is to disable auto-vectorization,
* but you can select to enable it instead using `XXH_ENABLE_AUTOVECTORIZE` build variable.
*/
XXH_COMPILER_GUARD(acc);
#endif
return acc;
}
static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val)
{
val = XXH64_round(0, val);
acc ^= val;
acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4;
return acc;
}
/*! @copydoc XXH32_avalanche */
static xxh_u64 XXH64_avalanche(xxh_u64 hash)
{
hash ^= hash >> 33;
hash *= XXH_PRIME64_2;
hash ^= hash >> 29;
hash *= XXH_PRIME64_3;
hash ^= hash >> 32;
return hash;
}
#define XXH_get64bits(p) XXH_readLE64_align(p, align)
/*!
* @internal
* @brief Sets up the initial accumulator state for XXH64().
*/
XXH_FORCE_INLINE void
XXH64_initAccs(xxh_u64 *acc, xxh_u64 seed)
{
XXH_ASSERT(acc != NULL);
acc[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
acc[1] = seed + XXH_PRIME64_2;
acc[2] = seed + 0;
acc[3] = seed - XXH_PRIME64_1;
}
/*!
* @internal
* @brief Consumes a block of data for XXH64().
*
* @return the end input pointer.
*/
XXH_FORCE_INLINE const xxh_u8 *
XXH64_consumeLong(
xxh_u64 *XXH_RESTRICT acc,
xxh_u8 const *XXH_RESTRICT input,
size_t len,
XXH_alignment align
)
{
const xxh_u8* const bEnd = input + len;
const xxh_u8* const limit = bEnd - 31;
XXH_ASSERT(acc != NULL);
XXH_ASSERT(input != NULL);
XXH_ASSERT(len >= 32);
do {
/* reroll on 32-bit */
if (sizeof(void *) < sizeof(xxh_u64)) {
size_t i;
for (i = 0; i < 4; i++) {
acc[i] = XXH64_round(acc[i], XXH_get64bits(input));
input += 8;
}
} else {
acc[0] = XXH64_round(acc[0], XXH_get64bits(input)); input += 8;
acc[1] = XXH64_round(acc[1], XXH_get64bits(input)); input += 8;
acc[2] = XXH64_round(acc[2], XXH_get64bits(input)); input += 8;
acc[3] = XXH64_round(acc[3], XXH_get64bits(input)); input += 8;
}
} while (input < limit);
return input;
}
/*!
* @internal
* @brief Merges the accumulator lanes together for XXH64()
*/
XXH_FORCE_INLINE XXH_PUREF xxh_u64
XXH64_mergeAccs(const xxh_u64 *acc)
{
XXH_ASSERT(acc != NULL);
{
xxh_u64 h64 = XXH_rotl64(acc[0], 1) + XXH_rotl64(acc[1], 7)
+ XXH_rotl64(acc[2], 12) + XXH_rotl64(acc[3], 18);
/* reroll on 32-bit */
if (sizeof(void *) < sizeof(xxh_u64)) {
size_t i;
for (i = 0; i < 4; i++) {
h64 = XXH64_mergeRound(h64, acc[i]);
}
} else {
h64 = XXH64_mergeRound(h64, acc[0]);
h64 = XXH64_mergeRound(h64, acc[1]);
h64 = XXH64_mergeRound(h64, acc[2]);
h64 = XXH64_mergeRound(h64, acc[3]);
}
return h64;
}
}
/*!
* @internal
* @brief Processes the last 0-31 bytes of @p ptr.
*
* There may be up to 31 bytes remaining to consume from the input.
* This final stage will digest them to ensure that all input bytes are present
* in the final mix.
*
* @param hash The hash to finalize.
* @param ptr The pointer to the remaining input.
* @param len The remaining length, modulo 32.
* @param align Whether @p ptr is aligned.
* @return The finalized hash
* @see XXH32_finalize().
*/
XXH_STATIC XXH_PUREF xxh_u64
XXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)
{
if (ptr==NULL) XXH_ASSERT(len == 0);
len &= 31;
while (len >= 8) {
xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr));
ptr += 8;
hash ^= k1;
hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
len -= 8;
}
if (len >= 4) {
hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;
ptr += 4;
hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
len -= 4;
}
while (len > 0) {
hash ^= (*ptr++) * XXH_PRIME64_5;
hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1;
--len;
}
return XXH64_avalanche(hash);
}
#ifdef XXH_OLD_NAMES
# define PROCESS1_64 XXH_PROCESS1_64
# define PROCESS4_64 XXH_PROCESS4_64
# define PROCESS8_64 XXH_PROCESS8_64
#else
# undef XXH_PROCESS1_64
# undef XXH_PROCESS4_64
# undef XXH_PROCESS8_64
#endif
/*!
* @internal
* @brief The implementation for @ref XXH64().
*
* @param input , len , seed Directly passed from @ref XXH64().
* @param align Whether @p input is aligned.
* @return The calculated hash.
*/
XXH_FORCE_INLINE XXH_PUREF xxh_u64
XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)
{
xxh_u64 h64;
if (input==NULL) XXH_ASSERT(len == 0);
if (len>=32) { /* Process a large block of data */
xxh_u64 acc[4];
XXH64_initAccs(acc, seed);
input = XXH64_consumeLong(acc, input, len, align);
h64 = XXH64_mergeAccs(acc);
} else {
h64 = seed + XXH_PRIME64_5;
}
h64 += (xxh_u64) len;
return XXH64_finalize(h64, input, len, align);
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH64_hash_t XXH64 (XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)
{
#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH64_state_t state;
XXH64_reset(&state, seed);
XXH64_update(&state, (const xxh_u8*)input, len);
return XXH64_digest(&state);
#else
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_aligned);
} }
return XXH64_endian_align((const xxh_u8*)input, len, seed, XXH_unaligned);
#endif
}
/******* Hash Streaming *******/
#ifndef XXH_NO_STREAM
/*! @ingroup XXH64_family*/
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
{
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState)
{
XXH_memcpy(dstState, srcState, sizeof(*dstState));
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed)
{
XXH_ASSERT(statePtr != NULL);
XXH_memset(statePtr, 0, sizeof(*statePtr));
XXH64_initAccs(statePtr->acc, seed);
return XXH_OK;
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH_errorcode
XXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len)
{
if (input==NULL) {
XXH_ASSERT(len == 0);
return XXH_OK;
}
state->total_len += len;
XXH_ASSERT(state->bufferedSize <= sizeof(state->buffer));
if (len < sizeof(state->buffer) - state->bufferedSize) { /* fill in tmp buffer */
XXH_memcpy(state->buffer + state->bufferedSize, input, len);
state->bufferedSize += (XXH32_hash_t)len;
return XXH_OK;
}
{ const xxh_u8* xinput = (const xxh_u8*)input;
const xxh_u8* const bEnd = xinput + len;
if (state->bufferedSize) { /* non-empty buffer => complete first */
XXH_memcpy(state->buffer + state->bufferedSize, xinput, sizeof(state->buffer) - state->bufferedSize);
xinput += sizeof(state->buffer) - state->bufferedSize;
/* and process one round */
(void)XXH64_consumeLong(state->acc, state->buffer, sizeof(state->buffer), XXH_aligned);
state->bufferedSize = 0;
}
XXH_ASSERT(xinput <= bEnd);
if ((size_t)(bEnd - xinput) >= sizeof(state->buffer)) {
/* Process the remaining data */
xinput = XXH64_consumeLong(state->acc, xinput, (size_t)(bEnd - xinput), XXH_unaligned);
}
if (xinput < bEnd) {
/* Copy the leftover to the tmp buffer */
XXH_memcpy(state->buffer, xinput, (size_t)(bEnd-xinput));
state->bufferedSize = (unsigned)(bEnd-xinput);
}
}
return XXH_OK;
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state)
{
xxh_u64 h64;
if (state->total_len >= 32) {
h64 = XXH64_mergeAccs(state->acc);
} else {
h64 = state->acc[2] /*seed*/ + XXH_PRIME64_5;
}
h64 += (xxh_u64) state->total_len;
return XXH64_finalize(h64, state->buffer, (size_t)state->total_len, XXH_aligned);
}
#endif /* !XXH_NO_STREAM */
/******* Canonical representation *******/
/*! @ingroup XXH64_family */
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
XXH_memcpy(dst, &hash, sizeof(*dst));
}
/*! @ingroup XXH64_family */
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src)
{
return XXH_readBE64(src);
}
#ifndef XXH_NO_XXH3
/* *********************************************************************
* XXH3
* New generation hash designed for speed on small keys and vectorization
************************************************************************ */
/*!
* @}
* @defgroup XXH3_impl XXH3 implementation
* @ingroup impl
* @{
*/
/* === Compiler specifics === */
#if (defined(__GNUC__) && (__GNUC__ >= 3)) \
|| (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \
|| defined(__clang__)
# define XXH_likely(x) __builtin_expect(x, 1)
# define XXH_unlikely(x) __builtin_expect(x, 0)
#else
# define XXH_likely(x) (x)
# define XXH_unlikely(x) (x)
#endif
#ifndef XXH_HAS_INCLUDE
# ifdef __has_include
/*
* Not defined as XXH_HAS_INCLUDE(x) (function-like) because
* this causes segfaults in Apple Clang 4.2 (on Mac OS X 10.7 Lion)
*/
# define XXH_HAS_INCLUDE __has_include
# else
# define XXH_HAS_INCLUDE(x) 0
# endif
#endif
#if defined(__GNUC__) || defined(__clang__)
# if defined(__ARM_FEATURE_SVE)
# include
# endif
# if defined(__ARM_NEON__) || defined(__ARM_NEON) \
|| (defined(_M_ARM) && _M_ARM >= 7) \
|| defined(_M_ARM64) || defined(_M_ARM64EC) \
|| (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* WASM SIMD128 via SIMDe */
# define inline __inline__ /* circumvent a clang bug */
# include
# undef inline
# elif defined(__AVX2__)
# include
# elif defined(__SSE2__)
# include
# elif defined(__loongarch_asx)
# include
# include
# elif defined(__loongarch_sx)
# include
# endif
#endif
#if defined(_MSC_VER)
# include
#endif
/*
* One goal of XXH3 is to make it fast on both 32-bit and 64-bit, while
* remaining a true 64-bit/128-bit hash function.
*
* This is done by prioritizing a subset of 64-bit operations that can be
* emulated without too many steps on the average 32-bit machine.
*
* For example, these two lines seem similar, and run equally fast on 64-bit:
*
* xxh_u64 x;
* x ^= (x >> 47); // good
* x ^= (x >> 13); // bad
*
* However, to a 32-bit machine, there is a major difference.
*
* x ^= (x >> 47) looks like this:
*
* x.lo ^= (x.hi >> (47 - 32));
*
* while x ^= (x >> 13) looks like this:
*
* // note: funnel shifts are not usually cheap.
* x.lo ^= (x.lo >> 13) | (x.hi << (32 - 13));
* x.hi ^= (x.hi >> 13);
*
* The first one is significantly faster than the second, simply because the
* shift is larger than 32. This means:
* - All the bits we need are in the upper 32 bits, so we can ignore the lower
* 32 bits in the shift.
* - The shift result will always fit in the lower 32 bits, and therefore,
* we can ignore the upper 32 bits in the xor.
*
* Thanks to this optimization, XXH3 only requires these features to be efficient:
*
* - Usable unaligned access
* - A 32-bit or 64-bit ALU
* - If 32-bit, a decent ADC instruction
* - A 32 or 64-bit multiply with a 64-bit result
* - For the 128-bit variant, a decent byteswap helps short inputs.
*
* The first two are already required by XXH32, and almost all 32-bit and 64-bit
* platforms which can run XXH32 can run XXH3 efficiently.
*
* Thumb-1, the classic 16-bit only subset of ARM's instruction set, is one
* notable exception.
*
* First of all, Thumb-1 lacks support for the UMULL instruction which
* performs the important long multiply. This means numerous __aeabi_lmul
* calls.
*
* Second of all, the 8 functional registers are just not enough.
* Setup for __aeabi_lmul, byteshift loads, pointers, and all arithmetic need
* Lo registers, and this shuffling results in thousands more MOVs than A32.
*
* A32 and T32 don't have this limitation. They can access all 14 registers,
* do a 32->64 multiply with UMULL, and the flexible operand allowing free
* shifts is helpful, too.
*
* Therefore, we do a quick sanity check.
*
* If compiling Thumb-1 for a target which supports ARM instructions, we will
* emit a warning, as it is not a "sane" platform to compile for.
*
* Usually, if this happens, it is because of an accident and you probably need
* to specify -march, as you likely meant to compile for a newer architecture.
*
* Credit: large sections of the vectorial and asm source code paths
* have been contributed by @easyaspi314
*/
#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM)
# warning "XXH3 is highly inefficient without ARM or Thumb-2."
#endif
/* ==========================================
* Vectorization detection
* ========================================== */
#ifdef XXH_DOXYGEN
/*!
* @ingroup tuning
* @brief Overrides the vectorization implementation chosen for XXH3.
*
* Can be defined to 0 to disable SIMD,
* or any other authorized value of @ref XXH_VECTOR.
*
* If this is not defined, it uses predefined macros to determine the best
* implementation.
*/
# define XXH_VECTOR XXH_SCALAR
/*!
* @ingroup tuning
* @brief Selects the minimum alignment for XXH3's accumulators.
*
* When using SIMD, this should match the alignment required for said vector
* type, so, for example, 32 for AVX2.
*
* Default: Auto detected.
*/
# define XXH_ACC_ALIGN 8
#endif
/* Actual definition */
#ifndef XXH_DOXYGEN
#endif
#ifndef XXH_VECTOR /* can be defined on command line */
# if defined(__ARM_FEATURE_SVE)
# define XXH_VECTOR XXH_SVE
# elif ( \
defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \
|| defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \
|| (defined(__wasm_simd128__) && XXH_HAS_INCLUDE()) /* wasm simd128 via SIMDe */ \
) && ( \
defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
)
# define XXH_VECTOR XXH_NEON
# elif defined(__AVX512F__)
# define XXH_VECTOR XXH_AVX512
# elif defined(__AVX2__)
# define XXH_VECTOR XXH_AVX2
# elif defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2))
# define XXH_VECTOR XXH_SSE2
# elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \
|| (defined(__s390x__) && defined(__VEC__)) \
&& defined(__GNUC__) /* TODO: IBM XL */
# define XXH_VECTOR XXH_VSX
# elif defined(__loongarch_asx)
# define XXH_VECTOR XXH_LASX
# elif defined(__loongarch_sx)
# define XXH_VECTOR XXH_LSX
# else
# define XXH_VECTOR XXH_SCALAR
# endif
#endif
/* __ARM_FEATURE_SVE is only supported by GCC & Clang. */
#if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE)
# ifdef _MSC_VER
# pragma warning(once : 4606)
# else
# warning "__ARM_FEATURE_SVE isn't supported. Use SCALAR instead."
# endif
# undef XXH_VECTOR
# define XXH_VECTOR XXH_SCALAR
#endif
/*
* Controls the alignment of the accumulator,
* for compatibility with aligned vector loads, which are usually faster.
*/
#ifndef XXH_ACC_ALIGN
# if defined(XXH_X86DISPATCH)
# define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */
# elif XXH_VECTOR == XXH_SCALAR /* scalar */
# define XXH_ACC_ALIGN 8
# elif XXH_VECTOR == XXH_SSE2 /* sse2 */
# define XXH_ACC_ALIGN 16
# elif XXH_VECTOR == XXH_AVX2 /* avx2 */
# define XXH_ACC_ALIGN 32
# elif XXH_VECTOR == XXH_NEON /* neon */
# define XXH_ACC_ALIGN 16
# elif XXH_VECTOR == XXH_VSX /* vsx */
# define XXH_ACC_ALIGN 16
# elif XXH_VECTOR == XXH_AVX512 /* avx512 */
# define XXH_ACC_ALIGN 64
# elif XXH_VECTOR == XXH_SVE /* sve */
# define XXH_ACC_ALIGN 64
# elif XXH_VECTOR == XXH_LASX /* lasx */
# define XXH_ACC_ALIGN 64
# elif XXH_VECTOR == XXH_LSX /* lsx */
# define XXH_ACC_ALIGN 64
# endif
#endif
#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \
|| XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512
# define XXH_SEC_ALIGN XXH_ACC_ALIGN
#elif XXH_VECTOR == XXH_SVE
# define XXH_SEC_ALIGN XXH_ACC_ALIGN
#else
# define XXH_SEC_ALIGN 8
#endif
#if defined(__GNUC__) || defined(__clang__)
# define XXH_ALIASING __attribute__((__may_alias__))
#else
# define XXH_ALIASING /* nothing */
#endif
/*
* UGLY HACK:
* GCC usually generates the best code with -O3 for xxHash.
*
* However, when targeting AVX2, it is overzealous in its unrolling resulting
* in code roughly 3/4 the speed of Clang.
*
* There are other issues, such as GCC splitting _mm256_loadu_si256 into
* _mm_loadu_si128 + _mm256_inserti128_si256. This is an optimization which
* only applies to Sandy and Ivy Bridge... which don't even support AVX2.
*
* That is why when compiling the AVX2 version, it is recommended to use either
* -O2 -mavx2 -march=haswell
* or
* -O2 -mavx2 -mno-avx256-split-unaligned-load
* for decent performance, or to use Clang instead.
*
* Fortunately, we can control the first one with a pragma that forces GCC into
* -O2, but the other one we can't control without "failed to inline always
* inline function due to target mismatch" warnings.
*/
#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
&& defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
&& defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */
# pragma GCC push_options
# pragma GCC optimize("-O2")
#endif
#if XXH_VECTOR == XXH_NEON
/*
* UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3
* optimizes out the entire hashLong loop because of the aliasing violation.
*
* However, GCC is also inefficient at load-store optimization with vld1q/vst1q,
* so the only option is to mark it as aliasing.
*/
typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING;
/*!
* @internal
* @brief `vld1q_u64` but faster and alignment-safe.
*
* On AArch64, unaligned access is always safe, but on ARMv7-a, it is only
* *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86).
*
* GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it
* prohibits load-store optimizations. Therefore, a direct dereference is used.
*
* Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe
* unaligned load.
*/
#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__)
XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */
{
return *(xxh_aliasing_uint64x2_t const *)ptr;
}
#else
XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr)
{
return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr));
}
#endif
/*!
* @internal
* @brief `vmlal_u32` on low and high halves of a vector.
*
* This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with
* inline assembly and were therefore incapable of merging the `vget_{low, high}_u32`
* with `vmlal_u32`.
*/
#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11
XXH_FORCE_INLINE uint64x2_t
XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
{
/* Inline assembly is the only way */
__asm__("umlal %0.2d, %1.2s, %2.2s" : "+w" (acc) : "w" (lhs), "w" (rhs));
return acc;
}
XXH_FORCE_INLINE uint64x2_t
XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
{
/* This intrinsic works as expected */
return vmlal_high_u32(acc, lhs, rhs);
}
#else
/* Portable intrinsic versions */
XXH_FORCE_INLINE uint64x2_t
XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
{
return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs));
}
/*! @copydoc XXH_vmlal_low_u32
* Assume the compiler converts this to vmlal_high_u32 on aarch64 */
XXH_FORCE_INLINE uint64x2_t
XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
{
return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs));
}
#endif
/*!
* @ingroup tuning
* @brief Controls the NEON to scalar ratio for XXH3
*
* This can be set to 2, 4, 6, or 8.
*
* ARM Cortex CPUs are _very_ sensitive to how their pipelines are used.
*
* For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those
* can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU
* bandwidth.
*
* This is even more noticeable on the more advanced cores like the Cortex-A76 which
* can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once.
*
* Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes
* and 2 scalar lanes, which is chosen by default.
*
* This does not apply to Apple processors or 32-bit processors, which run better with
* full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes.
*
* This change benefits CPUs with large micro-op buffers without negatively affecting
* most other CPUs:
*
* | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. |
* |:----------------------|:--------------------|----------:|-----------:|------:|
* | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% |
* | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% |
* | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% |
* | Apple M1 | 4 NEON/8 micro-ops | 37.3 GB/s | 36.1 GB/s | ~-3% |
*
* It also seems to fix some bad codegen on GCC, making it almost as fast as clang.
*
* When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning
* it effectively becomes worse 4.
*
* @see XXH3_accumulate_512_neon()
*/
# ifndef XXH3_NEON_LANES
# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \
&& !defined(__APPLE__) && XXH_SIZE_OPT <= 0
# define XXH3_NEON_LANES 6
# else
# define XXH3_NEON_LANES XXH_ACC_NB
# endif
# endif
#endif /* XXH_VECTOR == XXH_NEON */
/*
* VSX and Z Vector helpers.
*
* This is very messy, and any pull requests to clean this up are welcome.
*
* There are a lot of problems with supporting VSX and s390x, due to
* inconsistent intrinsics, spotty coverage, and multiple endiannesses.
*/
#if XXH_VECTOR == XXH_VSX
/* Annoyingly, these headers _may_ define three macros: `bool`, `vector`,
* and `pixel`. This is a problem for obvious reasons.
*
* These keywords are unnecessary; the spec literally says they are
* equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd
* after including the header.
*
* We use pragma push_macro/pop_macro to keep the namespace clean. */
# pragma push_macro("bool")
# pragma push_macro("vector")
# pragma push_macro("pixel")
/* silence potential macro redefined warnings */
# undef bool
# undef vector
# undef pixel
# if defined(__s390x__)
# include
# else
# include
# endif
/* Restore the original macro values, if applicable. */
# pragma pop_macro("pixel")
# pragma pop_macro("vector")
# pragma pop_macro("bool")
typedef __vector unsigned long long xxh_u64x2;
typedef __vector unsigned char xxh_u8x16;
typedef __vector unsigned xxh_u32x4;
/*
* UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue.
*/
typedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING;
# ifndef XXH_VSX_BE
# if defined(__BIG_ENDIAN__) \
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
# define XXH_VSX_BE 1
# elif defined(__VEC_ELEMENT_REG_ORDER__) && __VEC_ELEMENT_REG_ORDER__ == __ORDER_BIG_ENDIAN__
# warning "-maltivec=be is not recommended. Please use native endianness."
# define XXH_VSX_BE 1
# else
# define XXH_VSX_BE 0
# endif
# endif /* !defined(XXH_VSX_BE) */
# if XXH_VSX_BE
# if defined(__POWER9_VECTOR__) || (defined(__clang__) && defined(__s390x__))
# define XXH_vec_revb vec_revb
# else
/*!
* A polyfill for POWER9's vec_revb().
*/
XXH_FORCE_INLINE xxh_u64x2 XXH_vec_revb(xxh_u64x2 val)
{
xxh_u8x16 const vByteSwap = { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08 };
return vec_perm(val, val, vByteSwap);
}
# endif
# endif /* XXH_VSX_BE */
/*!
* Performs an unaligned vector load and byte swaps it on big endian.
*/
XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr)
{
xxh_u64x2 ret;
XXH_memcpy(&ret, ptr, sizeof(xxh_u64x2));
# if XXH_VSX_BE
ret = XXH_vec_revb(ret);
# endif
return ret;
}
/*
* vec_mulo and vec_mule are very problematic intrinsics on PowerPC
*
* These intrinsics weren't added until GCC 8, despite existing for a while,
* and they are endian dependent. Also, their meaning swap depending on version.
* */
# if defined(__s390x__)
/* s390x is always big endian, no issue on this platform */
# define XXH_vec_mulo vec_mulo
# define XXH_vec_mule vec_mule
# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__)
/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */
/* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */
# define XXH_vec_mulo __builtin_altivec_vmulouw
# define XXH_vec_mule __builtin_altivec_vmuleuw
# else
/* gcc needs inline assembly */
/* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */
XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b)
{
xxh_u64x2 result;
__asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b));
return result;
}
XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b)
{
xxh_u64x2 result;
__asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b));
return result;
}
# endif /* XXH_vec_mulo, XXH_vec_mule */
#endif /* XXH_VECTOR == XXH_VSX */
#if XXH_VECTOR == XXH_SVE
#define ACCRND(acc, offset) \
do { \
svuint64_t input_vec = svld1_u64(mask, xinput + offset); \
svuint64_t secret_vec = svld1_u64(mask, xsecret + offset); \
svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec); \
svuint64_t swapped = svtbl_u64(input_vec, kSwap); \
svuint64_t mixed_lo = svextw_u64_x(mask, mixed); \
svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32); \
svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \
acc = svadd_u64_x(mask, acc, mul); \
} while (0)
#endif /* XXH_VECTOR == XXH_SVE */
/* prefetch
* can be disabled, by declaring XXH_NO_PREFETCH build macro */
#if defined(XXH_NO_PREFETCH)
# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */
#else
# if XXH_SIZE_OPT >= 1
# define XXH_PREFETCH(ptr) (void)(ptr)
# elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */
# include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
# define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
# else
# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */
# endif
#endif /* XXH_NO_PREFETCH */
/* ==========================================
* XXH3 default settings
* ========================================== */
#define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */
#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN)
# error "default keyset is not large enough"
#endif
/*!
* @internal
* @def XXH3_kSecret
* @brief Pseudorandom secret taken directly from FARSH. */
XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = {
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,
0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,
0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,
0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,
0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,
0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
};
static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */
static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */
#ifdef XXH_OLD_NAMES
# define kSecret XXH3_kSecret
#endif
#ifdef XXH_DOXYGEN
/*!
* @brief Calculates a 32-bit to 64-bit long multiply.
*
* Implemented as a macro.
*
* Wraps `__emulu` on MSVC x86 because it tends to call `__allmul` when it doesn't
* need to (but it shouldn't need to anyways, it is about 7 instructions to do
* a 64x64 multiply...). Since we know that this will _always_ emit `MULL`, we
* use that instead of the normal method.
*
* If you are compiling for platforms like Thumb-1 and don't have a better option,
* you may also want to write your own long multiply routine here.
*
* @param x, y Numbers to be multiplied
* @return 64-bit product of the low 32 bits of @p x and @p y.
*/
XXH_FORCE_INLINE xxh_u64
XXH_mult32to64(xxh_u64 x, xxh_u64 y)
{
return (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF);
}
#elif defined(_MSC_VER) && defined(_M_IX86)
# define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y))
#else
/*
* Downcast + upcast is usually better than masking on older compilers like
* GCC 4.2 (especially 32-bit ones), all without affecting newer compilers.
*
* The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands
* and perform a full 64x64 multiply -- entirely redundant on 32-bit.
*/
# define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y))
#endif
/*!
* @brief Calculates a 64->128-bit long multiply.
*
* Uses `__uint128_t` and `_umul128` if available, otherwise uses a scalar
* version.
*
* @param lhs , rhs The 64-bit integers to be multiplied
* @return The 128-bit result represented in an @ref XXH128_hash_t.
*/
static XXH128_hash_t
XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs)
{
/*
* GCC/Clang __uint128_t method.
*
* On most 64-bit targets, GCC and Clang define a __uint128_t type.
* This is usually the best way as it usually uses a native long 64-bit
* multiply, such as MULQ on x86_64 or MUL + UMULH on aarch64.
*
* Usually.
*
* Despite being a 32-bit platform, Clang (and emscripten) define this type
* despite not having the arithmetic for it. This results in a laggy
* compiler builtin call which calculates a full 128-bit multiply.
* In that case it is best to use the portable one.
* https://github.com/Cyan4973/xxHash/issues/211#issuecomment-515575677
*/
#if (defined(__GNUC__) || defined(__clang__)) && !defined(__wasm__) \
&& defined(__SIZEOF_INT128__) \
|| (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128)
__uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs;
XXH128_hash_t r128;
r128.low64 = (xxh_u64)(product);
r128.high64 = (xxh_u64)(product >> 64);
return r128;
/*
* MSVC for x64's _umul128 method.
*
* xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct);
*
* This compiles to single operand MUL on x64.
*/
#elif (defined(_M_X64) || defined(_M_IA64)) && !defined(_M_ARM64EC)
#ifndef _MSC_VER
# pragma intrinsic(_umul128)
#endif
xxh_u64 product_high;
xxh_u64 const product_low = _umul128(lhs, rhs, &product_high);
XXH128_hash_t r128;
r128.low64 = product_low;
r128.high64 = product_high;
return r128;
/*
* MSVC for ARM64's __umulh method.
*
* This compiles to the same MUL + UMULH as GCC/Clang's __uint128_t method.
*/
#elif defined(_M_ARM64) || defined(_M_ARM64EC)
#ifndef _MSC_VER
# pragma intrinsic(__umulh)
#endif
XXH128_hash_t r128;
r128.low64 = lhs * rhs;
r128.high64 = __umulh(lhs, rhs);
return r128;
#else
/*
* Portable scalar method. Optimized for 32-bit and 64-bit ALUs.
*
* This is a fast and simple grade school multiply, which is shown below
* with base 10 arithmetic instead of base 0x100000000.
*
* 9 3 // D2 lhs = 93
* x 7 5 // D2 rhs = 75
* ----------
* 1 5 // D2 lo_lo = (93 % 10) * (75 % 10) = 15
* 4 5 | // D2 hi_lo = (93 / 10) * (75 % 10) = 45
* 2 1 | // D2 lo_hi = (93 % 10) * (75 / 10) = 21
* + 6 3 | | // D2 hi_hi = (93 / 10) * (75 / 10) = 63
* ---------
* 2 7 | // D2 cross = (15 / 10) + (45 % 10) + 21 = 27
* + 6 7 | | // D2 upper = (27 / 10) + (45 / 10) + 63 = 67
* ---------
* 6 9 7 5 // D4 res = (27 * 10) + (15 % 10) + (67 * 100) = 6975
*
* The reasons for adding the products like this are:
* 1. It avoids manual carry tracking. Just like how
* (9 * 9) + 9 + 9 = 99, the same applies with this for UINT64_MAX.
* This avoids a lot of complexity.
*
* 2. It hints for, and on Clang, compiles to, the powerful UMAAL
* instruction available in ARM's Digital Signal Processing extension
* in 32-bit ARMv6 and later, which is shown below:
*
* void UMAAL(xxh_u32 *RdLo, xxh_u32 *RdHi, xxh_u32 Rn, xxh_u32 Rm)
* {
* xxh_u64 product = (xxh_u64)*RdLo * (xxh_u64)*RdHi + Rn + Rm;
* *RdLo = (xxh_u32)(product & 0xFFFFFFFF);
* *RdHi = (xxh_u32)(product >> 32);
* }
*
* This instruction was designed for efficient long multiplication, and
* allows this to be calculated in only 4 instructions at speeds
* comparable to some 64-bit ALUs.
*
* 3. It isn't terrible on other platforms. Usually this will be a couple
* of 32-bit ADD/ADCs.
*/
/* First calculate all of the cross products. */
xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF);
xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF);
xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32);
xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32);
/* Now add the products together. These will never overflow. */
xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi;
xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi;
xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF);
XXH128_hash_t r128;
r128.low64 = lower;
r128.high64 = upper;
return r128;
#endif
}
/*!
* @brief Calculates a 64-bit to 128-bit multiply, then XOR folds it.
*
* The reason for the separate function is to prevent passing too many structs
* around by value. This will hopefully inline the multiply, but we don't force it.
*
* @param lhs , rhs The 64-bit integers to multiply
* @return The low 64 bits of the product XOR'd by the high 64 bits.
* @see XXH_mult64to128()
*/
static xxh_u64
XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs)
{
XXH128_hash_t product = XXH_mult64to128(lhs, rhs);
return product.low64 ^ product.high64;
}
/*! Seems to produce slightly better code on GCC for some reason. */
XXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift)
{
XXH_ASSERT(0 <= shift && shift < 64);
return v64 ^ (v64 >> shift);
}
/*
* This is a fast avalanche stage,
* suitable when input bits are already partially mixed
*/
static XXH64_hash_t XXH3_avalanche(xxh_u64 h64)
{
h64 = XXH_xorshift64(h64, 37);
h64 *= PRIME_MX1;
h64 = XXH_xorshift64(h64, 32);
return h64;
}
/*
* This is a stronger avalanche,
* inspired by Pelle Evensen's rrmxmx
* preferable when input has not been previously mixed
*/
static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len)
{
/* this mix is inspired by Pelle Evensen's rrmxmx */
h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24);
h64 *= PRIME_MX2;
h64 ^= (h64 >> 35) + len ;
h64 *= PRIME_MX2;
return XXH_xorshift64(h64, 28);
}
/* ==========================================
* Short keys
* ==========================================
* One of the shortcomings of XXH32 and XXH64 was that their performance was
* sub-optimal on short lengths. It used an iterative algorithm which strongly
* favored lengths that were a multiple of 4 or 8.
*
* Instead of iterating over individual inputs, we use a set of single shot
* functions which piece together a range of lengths and operate in constant time.
*
* Additionally, the number of multiplies has been significantly reduced. This
* reduces latency, especially when emulating 64-bit multiplies on 32-bit.
*
* Depending on the platform, this may or may not be faster than XXH32, but it
* is almost guaranteed to be faster than XXH64.
*/
/*
* At very short lengths, there isn't enough input to fully hide secrets, or use
* the entire secret.
*
* There is also only a limited amount of mixing we can do before significantly
* impacting performance.
*
* Therefore, we use different sections of the secret and always mix two secret
* samples with an XOR. This should have no effect on performance on the
* seedless or withSeed variants because everything _should_ be constant folded
* by modern compilers.
*
* The XOR mixing hides individual parts of the secret and increases entropy.
*
* This adds an extra layer of strength for custom secrets.
*/
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(input != NULL);
XXH_ASSERT(1 <= len && len <= 3);
XXH_ASSERT(secret != NULL);
/*
* len = 1: combined = { input[0], 0x01, input[0], input[0] }
* len = 2: combined = { input[1], 0x02, input[0], input[1] }
* len = 3: combined = { input[2], 0x03, input[0], input[1] }
*/
{ xxh_u8 const c1 = input[0];
xxh_u8 const c2 = input[len >> 1];
xxh_u8 const c3 = input[len - 1];
xxh_u32 const combined = ((xxh_u32)c1 << 16) | ((xxh_u32)c2 << 24)
| ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8);
xxh_u64 const bitflip = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed;
xxh_u64 const keyed = (xxh_u64)combined ^ bitflip;
return XXH64_avalanche(keyed);
}
}
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(input != NULL);
XXH_ASSERT(secret != NULL);
XXH_ASSERT(4 <= len && len <= 8);
seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;
{ xxh_u32 const input1 = XXH_readLE32(input);
xxh_u32 const input2 = XXH_readLE32(input + len - 4);
xxh_u64 const bitflip = (XXH_readLE64(secret+8) ^ XXH_readLE64(secret+16)) - seed;
xxh_u64 const input64 = input2 + (((xxh_u64)input1) << 32);
xxh_u64 const keyed = input64 ^ bitflip;
return XXH3_rrmxmx(keyed, len);
}
}
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(input != NULL);
XXH_ASSERT(secret != NULL);
XXH_ASSERT(9 <= len && len <= 16);
{ xxh_u64 const bitflip1 = (XXH_readLE64(secret+24) ^ XXH_readLE64(secret+32)) + seed;
xxh_u64 const bitflip2 = (XXH_readLE64(secret+40) ^ XXH_readLE64(secret+48)) - seed;
xxh_u64 const input_lo = XXH_readLE64(input) ^ bitflip1;
xxh_u64 const input_hi = XXH_readLE64(input + len - 8) ^ bitflip2;
xxh_u64 const acc = len
+ XXH_swap64(input_lo) + input_hi
+ XXH3_mul128_fold64(input_lo, input_hi);
return XXH3_avalanche(acc);
}
}
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(len <= 16);
{ if (XXH_likely(len > 8)) return XXH3_len_9to16_64b(input, len, secret, seed);
if (XXH_likely(len >= 4)) return XXH3_len_4to8_64b(input, len, secret, seed);
if (len) return XXH3_len_1to3_64b(input, len, secret, seed);
return XXH64_avalanche(seed ^ (XXH_readLE64(secret+56) ^ XXH_readLE64(secret+64)));
}
}
/*
* DISCLAIMER: There are known *seed-dependent* multicollisions here due to
* multiplication by zero, affecting hashes of lengths 17 to 240.
*
* However, they are very unlikely.
*
* Keep this in mind when using the unseeded XXH3_64bits() variant: As with all
* unseeded non-cryptographic hashes, it does not attempt to defend itself
* against specially crafted inputs, only random inputs.
*
* Compared to classic UMAC where a 1 in 2^31 chance of 4 consecutive bytes
* cancelling out the secret is taken an arbitrary number of times (addressed
* in XXH3_accumulate_512), this collision is very unlikely with random inputs
* and/or proper seeding:
*
* This only has a 1 in 2^63 chance of 8 consecutive bytes cancelling out, in a
* function that is only called up to 16 times per hash with up to 240 bytes of
* input.
*
* This is not too bad for a non-cryptographic hash function, especially with
* only 64 bit outputs.
*
* The 128-bit variant (which trades some speed for strength) is NOT affected
* by this, although it is always a good idea to use a proper seed if you care
* about strength.
*/
XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input,
const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64)
{
#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
&& defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \
&& !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */
/*
* UGLY HACK:
* GCC for x86 tends to autovectorize the 128-bit multiply, resulting in
* slower code.
*
* By forcing seed64 into a register, we disrupt the cost model and
* cause it to scalarize. See `XXH32_round()`
*
* FIXME: Clang's output is still _much_ faster -- On an AMD Ryzen 3600,
* XXH3_64bits @ len=240 runs at 4.6 GB/s with Clang 9, but 3.3 GB/s on
* GCC 9.2, despite both emitting scalar code.
*
* GCC generates much better scalar code than Clang for the rest of XXH3,
* which is why finding a more optimal codepath is an interest.
*/
XXH_COMPILER_GUARD(seed64);
#endif
{ xxh_u64 const input_lo = XXH_readLE64(input);
xxh_u64 const input_hi = XXH_readLE64(input+8);
return XXH3_mul128_fold64(
input_lo ^ (XXH_readLE64(secret) + seed64),
input_hi ^ (XXH_readLE64(secret+8) - seed64)
);
}
}
/* For mid range keys, XXH3 uses a Mum-hash variant. */
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed)
{
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
XXH_ASSERT(16 < len && len <= 128);
{ xxh_u64 acc = len * XXH_PRIME64_1;
#if XXH_SIZE_OPT >= 1
/* Smaller and cleaner, but slightly slower. */
unsigned int i = (unsigned int)(len - 1) / 32;
do {
acc += XXH3_mix16B(input+16 * i, secret+32*i, seed);
acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed);
} while (i-- != 0);
#else
if (len > 32) {
if (len > 64) {
if (len > 96) {
acc += XXH3_mix16B(input+48, secret+96, seed);
acc += XXH3_mix16B(input+len-64, secret+112, seed);
}
acc += XXH3_mix16B(input+32, secret+64, seed);
acc += XXH3_mix16B(input+len-48, secret+80, seed);
}
acc += XXH3_mix16B(input+16, secret+32, seed);
acc += XXH3_mix16B(input+len-32, secret+48, seed);
}
acc += XXH3_mix16B(input+0, secret+0, seed);
acc += XXH3_mix16B(input+len-16, secret+16, seed);
#endif
return XXH3_avalanche(acc);
}
}
XXH_NO_INLINE XXH_PUREF XXH64_hash_t
XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed)
{
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
#define XXH3_MIDSIZE_STARTOFFSET 3
#define XXH3_MIDSIZE_LASTOFFSET 17
{ xxh_u64 acc = len * XXH_PRIME64_1;
xxh_u64 acc_end;
unsigned int const nbRounds = (unsigned int)len / 16;
unsigned int i;
XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
for (i=0; i<8; i++) {
acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed);
}
/* last bytes */
acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
XXH_ASSERT(nbRounds >= 8);
acc = XXH3_avalanche(acc);
#if defined(__clang__) /* Clang */ \
&& (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
&& !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */
/*
* UGLY HACK:
* Clang for ARMv7-A tries to vectorize this loop, similar to GCC x86.
* In everywhere else, it uses scalar code.
*
* For 64->128-bit multiplies, even if the NEON was 100% optimal, it
* would still be slower than UMAAL (see XXH_mult64to128).
*
* Unfortunately, Clang doesn't handle the long multiplies properly and
* converts them to the nonexistent "vmulq_u64" intrinsic, which is then
* scalarized into an ugly mess of VMOV.32 instructions.
*
* This mess is difficult to avoid without turning autovectorization
* off completely, but they are usually relatively minor and/or not
* worth it to fix.
*
* This loop is the easiest to fix, as unlike XXH32, this pragma
* _actually works_ because it is a loop vectorization instead of an
* SLP vectorization.
*/
#pragma clang loop vectorize(disable)
#endif
for (i=8 ; i < nbRounds; i++) {
/*
* Prevents clang for unrolling the acc loop and interleaving with this one.
*/
XXH_COMPILER_GUARD(acc);
acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed);
}
return XXH3_avalanche(acc + acc_end);
}
}
/* ======= Long Keys ======= */
#define XXH_STRIPE_LEN 64
#define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */
#define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64))
#ifdef XXH_OLD_NAMES
# define STRIPE_LEN XXH_STRIPE_LEN
# define ACC_NB XXH_ACC_NB
#endif
#ifndef XXH_PREFETCH_DIST
# ifdef __clang__
# define XXH_PREFETCH_DIST 320
# else
# if (XXH_VECTOR == XXH_AVX512)
# define XXH_PREFETCH_DIST 512
# else
# define XXH_PREFETCH_DIST 384
# endif
# endif /* __clang__ */
#endif /* XXH_PREFETCH_DIST */
/*
* These macros are to generate an XXH3_accumulate() function.
* The two arguments select the name suffix and target attribute.
*
* The name of this symbol is XXH3_accumulate_() and it calls
* XXH3_accumulate_512_().
*
* It may be useful to hand implement this function if the compiler fails to
* optimize the inline function.
*/
#define XXH3_ACCUMULATE_TEMPLATE(name) \
void \
XXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc, \
const xxh_u8* XXH_RESTRICT input, \
const xxh_u8* XXH_RESTRICT secret, \
size_t nbStripes) \
{ \
size_t n; \
for (n = 0; n < nbStripes; n++ ) { \
const xxh_u8* const in = input + n*XXH_STRIPE_LEN; \
XXH_PREFETCH(in + XXH_PREFETCH_DIST); \
XXH3_accumulate_512_##name( \
acc, \
in, \
secret + n*XXH_SECRET_CONSUME_RATE); \
} \
}
XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64)
{
if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64);
XXH_memcpy(dst, &v64, sizeof(v64));
}
/* Several intrinsic functions below are supposed to accept __int64 as argument,
* as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ .
* However, several environments do not define __int64 type,
* requiring a workaround.
*/
#if !defined (__VMS) \
&& (defined (__cplusplus) \
|| (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
typedef int64_t xxh_i64;
#else
/* the following type must have a width of 64-bit */
typedef long long xxh_i64;
#endif
/*
* XXH3_accumulate_512 is the tightest loop for long inputs, and it is the most optimized.
*
* It is a hardened version of UMAC, based off of FARSH's implementation.
*
* This was chosen because it adapts quite well to 32-bit, 64-bit, and SIMD
* implementations, and it is ridiculously fast.
*
* We harden it by mixing the original input to the accumulators as well as the product.
*
* This means that in the (relatively likely) case of a multiply by zero, the
* original input is preserved.
*
* On 128-bit inputs, we swap 64-bit pairs when we add the input to improve
* cross-pollination, as otherwise the upper and lower halves would be
* essentially independent.
*
* This doesn't matter on 64-bit hashes since they all get merged together in
* the end, so we skip the extra step.
*
* Both XXH3_64bits and XXH3_128bits use this subroutine.
*/
#if (XXH_VECTOR == XXH_AVX512) \
|| (defined(XXH_DISPATCH_AVX512) && XXH_DISPATCH_AVX512 != 0)
#ifndef XXH_TARGET_AVX512
# define XXH_TARGET_AVX512 /* disable attribute target */
#endif
XXH_FORCE_INLINE XXH_TARGET_AVX512 void
XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
__m512i* const xacc = (__m512i *) acc;
XXH_ASSERT((((size_t)acc) & 63) == 0);
XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));
{
/* data_vec = input[0]; */
__m512i const data_vec = _mm512_loadu_si512 (input);
/* key_vec = secret[0]; */
__m512i const key_vec = _mm512_loadu_si512 (secret);
/* data_key = data_vec ^ key_vec; */
__m512i const data_key = _mm512_xor_si512 (data_vec, key_vec);
/* data_key_lo = data_key >> 32; */
__m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32);
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m512i const product = _mm512_mul_epu32 (data_key, data_key_lo);
/* xacc[0] += swap(data_vec); */
__m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2));
__m512i const sum = _mm512_add_epi64(*xacc, data_swap);
/* xacc[0] += product; */
*xacc = _mm512_add_epi64(product, sum);
}
}
XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512)
/*
* XXH3_scrambleAcc: Scrambles the accumulators to improve mixing.
*
* Multiplication isn't perfect, as explained by Google in HighwayHash:
*
* // Multiplication mixes/scrambles bytes 0-7 of the 64-bit result to
* // varying degrees. In descending order of goodness, bytes
* // 3 4 2 5 1 6 0 7 have quality 228 224 164 160 100 96 36 32.
* // As expected, the upper and lower bytes are much worse.
*
* Source: https://github.com/google/highwayhash/blob/0aaf66b/highwayhash/hh_avx2.h#L291
*
* Since our algorithm uses a pseudorandom secret to add some variance into the
* mix, we don't need to (or want to) mix as often or as much as HighwayHash does.
*
* This isn't as tight as XXH3_accumulate, but still written in SIMD to avoid
* extraction.
*
* Both XXH3_64bits and XXH3_128bits use this subroutine.
*/
XXH_FORCE_INLINE XXH_TARGET_AVX512 void
XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 63) == 0);
XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i));
{ __m512i* const xacc = (__m512i*) acc;
const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1);
/* xacc[0] ^= (xacc[0] >> 47) */
__m512i const acc_vec = *xacc;
__m512i const shifted = _mm512_srli_epi64 (acc_vec, 47);
/* xacc[0] ^= secret; */
__m512i const key_vec = _mm512_loadu_si512 (secret);
__m512i const data_key = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */);
/* xacc[0] *= XXH_PRIME32_1; */
__m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32);
__m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32);
__m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32);
*xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32));
}
}
XXH_FORCE_INLINE XXH_TARGET_AVX512 void
XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
{
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0);
XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64);
XXH_ASSERT(((size_t)customSecret & 63) == 0);
(void)(&XXH_writeLE64);
{ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i);
__m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64);
__m512i const seed = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos);
const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret);
__m512i* const dest = ( __m512i*) customSecret;
int i;
XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */
XXH_ASSERT(((size_t)dest & 63) == 0);
for (i=0; i < nbRounds; ++i) {
dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed);
} }
}
#endif
#if (XXH_VECTOR == XXH_AVX2) \
|| (defined(XXH_DISPATCH_AVX2) && XXH_DISPATCH_AVX2 != 0)
#ifndef XXH_TARGET_AVX2
# define XXH_TARGET_AVX2 /* disable attribute target */
#endif
XXH_FORCE_INLINE XXH_TARGET_AVX2 void
XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 31) == 0);
{ __m256i* const xacc = (__m256i *) acc;
/* Unaligned. This is mainly for pointer arithmetic, and because
* _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
const __m256i* const xinput = (const __m256i *) input;
/* Unaligned. This is mainly for pointer arithmetic, and because
* _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
const __m256i* const xsecret = (const __m256i *) secret;
size_t i;
for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) {
/* data_vec = xinput[i]; */
__m256i const data_vec = _mm256_loadu_si256 (xinput+i);
/* key_vec = xsecret[i]; */
__m256i const key_vec = _mm256_loadu_si256 (xsecret+i);
/* data_key = data_vec ^ key_vec; */
__m256i const data_key = _mm256_xor_si256 (data_vec, key_vec);
/* data_key_lo = data_key >> 32; */
__m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32);
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m256i const product = _mm256_mul_epu32 (data_key, data_key_lo);
/* xacc[i] += swap(data_vec); */
__m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2));
__m256i const sum = _mm256_add_epi64(xacc[i], data_swap);
/* xacc[i] += product; */
xacc[i] = _mm256_add_epi64(product, sum);
} }
}
XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2)
XXH_FORCE_INLINE XXH_TARGET_AVX2 void
XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 31) == 0);
{ __m256i* const xacc = (__m256i*) acc;
/* Unaligned. This is mainly for pointer arithmetic, and because
* _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */
const __m256i* const xsecret = (const __m256i *) secret;
const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1);
size_t i;
for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) {
/* xacc[i] ^= (xacc[i] >> 47) */
__m256i const acc_vec = xacc[i];
__m256i const shifted = _mm256_srli_epi64 (acc_vec, 47);
__m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted);
/* xacc[i] ^= xsecret; */
__m256i const key_vec = _mm256_loadu_si256 (xsecret+i);
__m256i const data_key = _mm256_xor_si256 (data_vec, key_vec);
/* xacc[i] *= XXH_PRIME32_1; */
__m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32);
__m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32);
__m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32);
xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32));
}
}
}
XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
{
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0);
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6);
XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64);
(void)(&XXH_writeLE64);
XXH_PREFETCH(customSecret);
{ __m256i const seed = _mm256_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64, (xxh_i64)(0U - seed64), (xxh_i64)seed64);
const __m256i* const src = (const __m256i*) ((const void*) XXH3_kSecret);
__m256i* dest = ( __m256i*) customSecret;
# if defined(__GNUC__) || defined(__clang__)
/*
* On GCC & Clang, marking 'dest' as modified will cause the compiler:
* - do not extract the secret from sse registers in the internal loop
* - use less common registers, and avoid pushing these reg into stack
*/
XXH_COMPILER_GUARD(dest);
# endif
XXH_ASSERT(((size_t)src & 31) == 0); /* control alignment */
XXH_ASSERT(((size_t)dest & 31) == 0);
/* GCC -O2 need unroll loop manually */
dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed);
dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed);
dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed);
dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed);
dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed);
dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed);
}
}
#endif
/* x86dispatch always generates SSE2 */
#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH)
#ifndef XXH_TARGET_SSE2
# define XXH_TARGET_SSE2 /* disable attribute target */
#endif
XXH_FORCE_INLINE XXH_TARGET_SSE2 void
XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
/* SSE2 is just a half-scale version of the AVX2 version. */
XXH_ASSERT((((size_t)acc) & 15) == 0);
{ __m128i* const xacc = (__m128i *) acc;
/* Unaligned. This is mainly for pointer arithmetic, and because
* _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
const __m128i* const xinput = (const __m128i *) input;
/* Unaligned. This is mainly for pointer arithmetic, and because
* _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
const __m128i* const xsecret = (const __m128i *) secret;
size_t i;
for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {
/* data_vec = xinput[i]; */
__m128i const data_vec = _mm_loadu_si128 (xinput+i);
/* key_vec = xsecret[i]; */
__m128i const key_vec = _mm_loadu_si128 (xsecret+i);
/* data_key = data_vec ^ key_vec; */
__m128i const data_key = _mm_xor_si128 (data_vec, key_vec);
/* data_key_lo = data_key >> 32; */
__m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m128i const product = _mm_mul_epu32 (data_key, data_key_lo);
/* xacc[i] += swap(data_vec); */
__m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2));
__m128i const sum = _mm_add_epi64(xacc[i], data_swap);
/* xacc[i] += product; */
xacc[i] = _mm_add_epi64(product, sum);
} }
}
XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2)
XXH_FORCE_INLINE XXH_TARGET_SSE2 void
XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 15) == 0);
{ __m128i* const xacc = (__m128i*) acc;
/* Unaligned. This is mainly for pointer arithmetic, and because
* _mm_loadu_si128 requires a const __m128i * pointer for some reason. */
const __m128i* const xsecret = (const __m128i *) secret;
const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1);
size_t i;
for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) {
/* xacc[i] ^= (xacc[i] >> 47) */
__m128i const acc_vec = xacc[i];
__m128i const shifted = _mm_srli_epi64 (acc_vec, 47);
__m128i const data_vec = _mm_xor_si128 (acc_vec, shifted);
/* xacc[i] ^= xsecret[i]; */
__m128i const key_vec = _mm_loadu_si128 (xsecret+i);
__m128i const data_key = _mm_xor_si128 (data_vec, key_vec);
/* xacc[i] *= XXH_PRIME32_1; */
__m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
__m128i const prod_lo = _mm_mul_epu32 (data_key, prime32);
__m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32);
xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32));
}
}
}
XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
{
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
(void)(&XXH_writeLE64);
{ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i);
# if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900
/* MSVC 32bit mode does not support _mm_set_epi64x before 2015 */
XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, (xxh_i64)(0U - seed64) };
__m128i const seed = _mm_load_si128((__m128i const*)seed64x2);
# else
__m128i const seed = _mm_set_epi64x((xxh_i64)(0U - seed64), (xxh_i64)seed64);
# endif
int i;
const void* const src16 = XXH3_kSecret;
__m128i* dst16 = (__m128i*) customSecret;
# if defined(__GNUC__) || defined(__clang__)
/*
* On GCC & Clang, marking 'dest' as modified will cause the compiler:
* - do not extract the secret from sse registers in the internal loop
* - use less common registers, and avoid pushing these reg into stack
*/
XXH_COMPILER_GUARD(dst16);
# endif
XXH_ASSERT(((size_t)src16 & 15) == 0); /* control alignment */
XXH_ASSERT(((size_t)dst16 & 15) == 0);
for (i=0; i < nbRounds; ++i) {
dst16[i] = _mm_add_epi64(_mm_load_si128((const __m128i *)src16+i), seed);
} }
}
#endif
#if (XXH_VECTOR == XXH_NEON)
/* forward declarations for the scalar routines */
XXH_FORCE_INLINE void
XXH3_scalarRound(void* XXH_RESTRICT acc, void const* XXH_RESTRICT input,
void const* XXH_RESTRICT secret, size_t lane);
XXH_FORCE_INLINE void
XXH3_scalarScrambleRound(void* XXH_RESTRICT acc,
void const* XXH_RESTRICT secret, size_t lane);
/*!
* @internal
* @brief The bulk processing loop for NEON and WASM SIMD128.
*
* The NEON code path is actually partially scalar when running on AArch64. This
* is to optimize the pipelining and can have up to 15% speedup depending on the
* CPU, and it also mitigates some GCC codegen issues.
*
* @see XXH3_NEON_LANES for configuring this and details about this optimization.
*
* NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit
* integers instead of the other platforms which mask full 64-bit vectors,
* so the setup is more complicated than just shifting right.
*
* Additionally, there is an optimization for 4 lanes at once noted below.
*
* Since, as stated, the most optimal amount of lanes for Cortexes is 6,
* there needs to be *three* versions of the accumulate operation used
* for the remaining 2 lanes.
*
* WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap
* nearly perfectly.
*/
XXH_FORCE_INLINE void
XXH3_accumulate_512_neon( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 15) == 0);
XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0);
{ /* GCC for darwin arm64 does not like aliasing here */
xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc;
/* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */
uint8_t const* xinput = (const uint8_t *) input;
uint8_t const* xsecret = (const uint8_t *) secret;
size_t i;
#ifdef __wasm_simd128__
/*
* On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret
* is constant propagated, which results in it converting it to this
* inside the loop:
*
* a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0)
* b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0)
* ...
*
* This requires a full 32-bit address immediate (and therefore a 6 byte
* instruction) as well as an add for each offset.
*
* Putting an asm guard prevents it from folding (at the cost of losing
* the alignment hint), and uses the free offset in `v128.load` instead
* of adding secret_offset each time which overall reduces code size by
* about a kilobyte and improves performance.
*/
XXH_COMPILER_GUARD(xsecret);
#endif
/* Scalar lanes use the normal scalarRound routine */
for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {
XXH3_scalarRound(acc, input, secret, i);
}
i = 0;
/* 4 NEON lanes at a time. */
for (; i+1 < XXH3_NEON_LANES / 2; i+=2) {
/* data_vec = xinput[i]; */
uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput + (i * 16));
uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput + ((i+1) * 16));
/* key_vec = xsecret[i]; */
uint64x2_t key_vec_1 = XXH_vld1q_u64(xsecret + (i * 16));
uint64x2_t key_vec_2 = XXH_vld1q_u64(xsecret + ((i+1) * 16));
/* data_swap = swap(data_vec) */
uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1);
uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1);
/* data_key = data_vec ^ key_vec; */
uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1);
uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2);
/*
* If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a
* de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to
* get one vector with the low 32 bits of each lane, and one vector
* with the high 32 bits of each lane.
*
* The intrinsic returns a double vector because the original ARMv7-a
* instruction modified both arguments in place. AArch64 and SIMD128 emit
* two instructions from this intrinsic.
*
* [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ]
* [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ]
*/
uint32x4x2_t unzipped = vuzpq_u32(
vreinterpretq_u32_u64(data_key_1),
vreinterpretq_u32_u64(data_key_2)
);
/* data_key_lo = data_key & 0xFFFFFFFF */
uint32x4_t data_key_lo = unzipped.val[0];
/* data_key_hi = data_key >> 32 */
uint32x4_t data_key_hi = unzipped.val[1];
/*
* Then, we can split the vectors horizontally and multiply which, as for most
* widening intrinsics, have a variant that works on both high half vectors
* for free on AArch64. A similar instruction is available on SIMD128.
*
* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi
*/
uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi);
uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi);
/*
* Clang reorders
* a += b * c; // umlal swap.2d, dkl.2s, dkh.2s
* c += a; // add acc.2d, acc.2d, swap.2d
* to
* c += a; // add acc.2d, acc.2d, swap.2d
* c += b * c; // umlal acc.2d, dkl.2s, dkh.2s
*
* While it would make sense in theory since the addition is faster,
* for reasons likely related to umlal being limited to certain NEON
* pipelines, this is worse. A compiler guard fixes this.
*/
XXH_COMPILER_GUARD_CLANG_NEON(sum_1);
XXH_COMPILER_GUARD_CLANG_NEON(sum_2);
/* xacc[i] = acc_vec + sum; */
xacc[i] = vaddq_u64(xacc[i], sum_1);
xacc[i+1] = vaddq_u64(xacc[i+1], sum_2);
}
/* Operate on the remaining NEON lanes 2 at a time. */
for (; i < XXH3_NEON_LANES / 2; i++) {
/* data_vec = xinput[i]; */
uint64x2_t data_vec = XXH_vld1q_u64(xinput + (i * 16));
/* key_vec = xsecret[i]; */
uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16));
/* acc_vec_2 = swap(data_vec) */
uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1);
/* data_key = data_vec ^ key_vec; */
uint64x2_t data_key = veorq_u64(data_vec, key_vec);
/* For two lanes, just use VMOVN and VSHRN. */
/* data_key_lo = data_key & 0xFFFFFFFF; */
uint32x2_t data_key_lo = vmovn_u64(data_key);
/* data_key_hi = data_key >> 32; */
uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32);
/* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */
uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi);
/* Same Clang workaround as before */
XXH_COMPILER_GUARD_CLANG_NEON(sum);
/* xacc[i] = acc_vec + sum; */
xacc[i] = vaddq_u64 (xacc[i], sum);
}
}
}
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon)
XXH_FORCE_INLINE void
XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 15) == 0);
{ xxh_aliasing_uint64x2_t* xacc = (xxh_aliasing_uint64x2_t*) acc;
uint8_t const* xsecret = (uint8_t const*) secret;
size_t i;
/* WASM uses operator overloads and doesn't need these. */
#ifndef __wasm_simd128__
/* { prime32_1, prime32_1 } */
uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1);
/* { 0, prime32_1, 0, prime32_1 } */
uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32));
#endif
/* AArch64 uses both scalar and neon at the same time */
for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {
XXH3_scalarScrambleRound(acc, secret, i);
}
for (i=0; i < XXH3_NEON_LANES / 2; i++) {
/* xacc[i] ^= (xacc[i] >> 47); */
uint64x2_t acc_vec = xacc[i];
uint64x2_t shifted = vshrq_n_u64(acc_vec, 47);
uint64x2_t data_vec = veorq_u64(acc_vec, shifted);
/* xacc[i] ^= xsecret[i]; */
uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16));
uint64x2_t data_key = veorq_u64(data_vec, key_vec);
/* xacc[i] *= XXH_PRIME32_1 */
#ifdef __wasm_simd128__
/* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */
xacc[i] = data_key * XXH_PRIME32_1;
#else
/*
* Expanded version with portable NEON intrinsics
*
* lo(x) * lo(y) + (hi(x) * lo(y) << 32)
*
* prod_hi = hi(data_key) * lo(prime) << 32
*
* Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector
* as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits
* and avoid the shift.
*/
uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi);
/* Extract low bits for vmlal_u32 */
uint32x2_t data_key_lo = vmovn_u64(data_key);
/* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */
xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo);
#endif
}
}
}
#endif
#if (XXH_VECTOR == XXH_VSX)
XXH_FORCE_INLINE void
XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
/* presumed aligned */
xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;
xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */
xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */
xxh_u64x2 const v32 = { 32, 32 };
size_t i;
for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
/* data_vec = xinput[i]; */
xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i);
/* key_vec = xsecret[i]; */
xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i);
xxh_u64x2 const data_key = data_vec ^ key_vec;
/* shuffled = (data_key << 32) | (data_key >> 32); */
xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32);
/* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */
xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled);
/* acc_vec = xacc[i]; */
xxh_u64x2 acc_vec = xacc[i];
acc_vec += product;
/* swap high and low halves */
#ifdef __s390x__
acc_vec += vec_permi(data_vec, data_vec, 2);
#else
acc_vec += vec_xxpermdi(data_vec, data_vec, 2);
#endif
xacc[i] = acc_vec;
}
}
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx)
XXH_FORCE_INLINE void
XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 15) == 0);
{ xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;
const xxh_u8* const xsecret = (const xxh_u8*) secret;
/* constants */
xxh_u64x2 const v32 = { 32, 32 };
xxh_u64x2 const v47 = { 47, 47 };
xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 };
size_t i;
for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
/* xacc[i] ^= (xacc[i] >> 47); */
xxh_u64x2 const acc_vec = xacc[i];
xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47);
/* xacc[i] ^= xsecret[i]; */
xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i);
xxh_u64x2 const data_key = data_vec ^ key_vec;
/* xacc[i] *= XXH_PRIME32_1 */
/* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */
xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime);
/* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */
xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime);
xacc[i] = prod_odd + (prod_even << v32);
} }
}
#endif
#if (XXH_VECTOR == XXH_SVE)
XXH_FORCE_INLINE void
XXH3_accumulate_512_sve( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
uint64_t *xacc = (uint64_t *)acc;
const uint64_t *xinput = (const uint64_t *)(const void *)input;
const uint64_t *xsecret = (const uint64_t *)(const void *)secret;
svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1);
uint64_t element_count = svcntd();
if (element_count >= 8) {
svbool_t mask = svptrue_pat_b64(SV_VL8);
svuint64_t vacc = svld1_u64(mask, xacc);
ACCRND(vacc, 0);
svst1_u64(mask, xacc, vacc);
} else if (element_count == 2) { /* sve128 */
svbool_t mask = svptrue_pat_b64(SV_VL2);
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
svuint64_t acc1 = svld1_u64(mask, xacc + 2);
svuint64_t acc2 = svld1_u64(mask, xacc + 4);
svuint64_t acc3 = svld1_u64(mask, xacc + 6);
ACCRND(acc0, 0);
ACCRND(acc1, 2);
ACCRND(acc2, 4);
ACCRND(acc3, 6);
svst1_u64(mask, xacc + 0, acc0);
svst1_u64(mask, xacc + 2, acc1);
svst1_u64(mask, xacc + 4, acc2);
svst1_u64(mask, xacc + 6, acc3);
} else {
svbool_t mask = svptrue_pat_b64(SV_VL4);
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
svuint64_t acc1 = svld1_u64(mask, xacc + 4);
ACCRND(acc0, 0);
ACCRND(acc1, 4);
svst1_u64(mask, xacc + 0, acc0);
svst1_u64(mask, xacc + 4, acc1);
}
}
XXH_FORCE_INLINE void
XXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc,
const xxh_u8* XXH_RESTRICT input,
const xxh_u8* XXH_RESTRICT secret,
size_t nbStripes)
{
if (nbStripes != 0) {
uint64_t *xacc = (uint64_t *)acc;
const uint64_t *xinput = (const uint64_t *)(const void *)input;
const uint64_t *xsecret = (const uint64_t *)(const void *)secret;
svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1);
uint64_t element_count = svcntd();
if (element_count >= 8) {
svbool_t mask = svptrue_pat_b64(SV_VL8);
svuint64_t vacc = svld1_u64(mask, xacc + 0);
do {
/* svprfd(svbool_t, void *, enum svfprop); */
svprfd(mask, xinput + 128, SV_PLDL1STRM);
ACCRND(vacc, 0);
xinput += 8;
xsecret += 1;
nbStripes--;
} while (nbStripes != 0);
svst1_u64(mask, xacc + 0, vacc);
} else if (element_count == 2) { /* sve128 */
svbool_t mask = svptrue_pat_b64(SV_VL2);
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
svuint64_t acc1 = svld1_u64(mask, xacc + 2);
svuint64_t acc2 = svld1_u64(mask, xacc + 4);
svuint64_t acc3 = svld1_u64(mask, xacc + 6);
do {
svprfd(mask, xinput + 128, SV_PLDL1STRM);
ACCRND(acc0, 0);
ACCRND(acc1, 2);
ACCRND(acc2, 4);
ACCRND(acc3, 6);
xinput += 8;
xsecret += 1;
nbStripes--;
} while (nbStripes != 0);
svst1_u64(mask, xacc + 0, acc0);
svst1_u64(mask, xacc + 2, acc1);
svst1_u64(mask, xacc + 4, acc2);
svst1_u64(mask, xacc + 6, acc3);
} else {
svbool_t mask = svptrue_pat_b64(SV_VL4);
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
svuint64_t acc1 = svld1_u64(mask, xacc + 4);
do {
svprfd(mask, xinput + 128, SV_PLDL1STRM);
ACCRND(acc0, 0);
ACCRND(acc1, 4);
xinput += 8;
xsecret += 1;
nbStripes--;
} while (nbStripes != 0);
svst1_u64(mask, xacc + 0, acc0);
svst1_u64(mask, xacc + 4, acc1);
}
}
}
#endif
#if (XXH_VECTOR == XXH_LSX)
#define _LSX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
XXH_FORCE_INLINE void
XXH3_accumulate_512_lsx( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 15) == 0);
{
__m128i* const xacc = (__m128i *) acc;
const __m128i* const xinput = (const __m128i *) input;
const __m128i* const xsecret = (const __m128i *) secret;
for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) {
/* data_vec = xinput[i]; */
__m128i const data_vec = __lsx_vld(xinput + i, 0);
/* key_vec = xsecret[i]; */
__m128i const key_vec = __lsx_vld(xsecret + i, 0);
/* data_key = data_vec ^ key_vec; */
__m128i const data_key = __lsx_vxor_v(data_vec, key_vec);
/* data_key_lo = data_key >> 32; */
__m128i const data_key_lo = __lsx_vsrli_d(data_key, 32);
// __m128i const data_key_lo = __lsx_vsrli_d(data_key, 32);
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m128i const product = __lsx_vmulwev_d_wu(data_key, data_key_lo);
/* xacc[i] += swap(data_vec); */
__m128i const data_swap = __lsx_vshuf4i_w(data_vec, _LSX_SHUFFLE(1, 0, 3, 2));
__m128i const sum = __lsx_vadd_d(xacc[i], data_swap);
/* xacc[i] += product; */
xacc[i] = __lsx_vadd_d(product, sum);
}
}
}
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lsx)
XXH_FORCE_INLINE void
XXH3_scrambleAcc_lsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 15) == 0);
{
__m128i* const xacc = (__m128i*) acc;
const __m128i* const xsecret = (const __m128i *) secret;
const __m128i prime32 = __lsx_vreplgr2vr_d(XXH_PRIME32_1);
for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m128i); i++) {
/* xacc[i] ^= (xacc[i] >> 47) */
__m128i const acc_vec = xacc[i];
__m128i const shifted = __lsx_vsrli_d(acc_vec, 47);
__m128i const data_vec = __lsx_vxor_v(acc_vec, shifted);
/* xacc[i] ^= xsecret[i]; */
__m128i const key_vec = __lsx_vld(xsecret + i, 0);
__m128i const data_key = __lsx_vxor_v(data_vec, key_vec);
/* xacc[i] *= XXH_PRIME32_1; */
xacc[i] = __lsx_vmul_d(data_key, prime32);
}
}
}
#endif
#if (XXH_VECTOR == XXH_LASX)
#define _LASX_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
XXH_FORCE_INLINE void
XXH3_accumulate_512_lasx( void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 31) == 0);
{
__m256i* const xacc = (__m256i *) acc;
const __m256i* const xinput = (const __m256i *) input;
const __m256i* const xsecret = (const __m256i *) secret;
for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) {
/* data_vec = xinput[i]; */
__m256i const data_vec = __lasx_xvld(xinput + i, 0);
/* key_vec = xsecret[i]; */
__m256i const key_vec = __lasx_xvld(xsecret + i, 0);
/* data_key = data_vec ^ key_vec; */
__m256i const data_key = __lasx_xvxor_v(data_vec, key_vec);
/* data_key_lo = data_key >> 32; */
__m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32);
// __m256i const data_key_lo = __lasx_xvsrli_d(data_key, 32);
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
__m256i const product = __lasx_xvmulwev_d_wu(data_key, data_key_lo);
/* xacc[i] += swap(data_vec); */
__m256i const data_swap = __lasx_xvshuf4i_w(data_vec, _LASX_SHUFFLE(1, 0, 3, 2));
__m256i const sum = __lasx_xvadd_d(xacc[i], data_swap);
/* xacc[i] += product; */
xacc[i] = __lasx_xvadd_d(product, sum);
}
}
}
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(lasx)
XXH_FORCE_INLINE void
XXH3_scrambleAcc_lasx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
XXH_ASSERT((((size_t)acc) & 31) == 0);
{
__m256i* const xacc = (__m256i*) acc;
const __m256i* const xsecret = (const __m256i *) secret;
const __m256i prime32 = __lasx_xvreplgr2vr_d(XXH_PRIME32_1);
for (size_t i = 0; i < XXH_STRIPE_LEN / sizeof(__m256i); i++) {
/* xacc[i] ^= (xacc[i] >> 47) */
__m256i const acc_vec = xacc[i];
__m256i const shifted = __lasx_xvsrli_d(acc_vec, 47);
__m256i const data_vec = __lasx_xvxor_v(acc_vec, shifted);
/* xacc[i] ^= xsecret[i]; */
__m256i const key_vec = __lasx_xvld(xsecret + i, 0);
__m256i const data_key = __lasx_xvxor_v(data_vec, key_vec);
/* xacc[i] *= XXH_PRIME32_1; */
xacc[i] = __lasx_xvmul_d(data_key, prime32);
}
}
}
#endif
/* scalar variants - universal */
#if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__))
/*
* In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they
* emit an excess mask and a full 64-bit multiply-add (MADD X-form).
*
* While this might not seem like much, as AArch64 is a 64-bit architecture, only
* big Cortex designs have a full 64-bit multiplier.
*
* On the little cores, the smaller 32-bit multiplier is used, and full 64-bit
* multiplies expand to 2-3 multiplies in microcode. This has a major penalty
* of up to 4 latency cycles and 2 stall cycles in the multiply pipeline.
*
* Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does
* not have this penalty and does the mask automatically.
*/
XXH_FORCE_INLINE xxh_u64
XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc)
{
xxh_u64 ret;
/* note: %x = 64-bit register, %w = 32-bit register */
__asm__("umaddl %x0, %w1, %w2, %x3" : "=r" (ret) : "r" (lhs), "r" (rhs), "r" (acc));
return ret;
}
#else
XXH_FORCE_INLINE xxh_u64
XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc)
{
return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc;
}
#endif
/*!
* @internal
* @brief Scalar round for @ref XXH3_accumulate_512_scalar().
*
* This is extracted to its own function because the NEON path uses a combination
* of NEON and scalar.
*/
XXH_FORCE_INLINE void
XXH3_scalarRound(void* XXH_RESTRICT acc,
void const* XXH_RESTRICT input,
void const* XXH_RESTRICT secret,
size_t lane)
{
xxh_u64* xacc = (xxh_u64*) acc;
xxh_u8 const* xinput = (xxh_u8 const*) input;
xxh_u8 const* xsecret = (xxh_u8 const*) secret;
XXH_ASSERT(lane < XXH_ACC_NB);
XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0);
{
xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8);
xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8);
xacc[lane ^ 1] += data_val; /* swap adjacent lanes */
xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]);
}
}
/*!
* @internal
* @brief Processes a 64 byte block of data using the scalar path.
*/
XXH_FORCE_INLINE void
XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc,
const void* XXH_RESTRICT input,
const void* XXH_RESTRICT secret)
{
size_t i;
/* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */
#if defined(__GNUC__) && !defined(__clang__) \
&& (defined(__arm__) || defined(__thumb2__)) \
&& defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \
&& XXH_SIZE_OPT <= 0
# pragma GCC unroll 8
#endif
for (i=0; i < XXH_ACC_NB; i++) {
XXH3_scalarRound(acc, input, secret, i);
}
}
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar)
/*!
* @internal
* @brief Scalar scramble step for @ref XXH3_scrambleAcc_scalar().
*
* This is extracted to its own function because the NEON path uses a combination
* of NEON and scalar.
*/
XXH_FORCE_INLINE void
XXH3_scalarScrambleRound(void* XXH_RESTRICT acc,
void const* XXH_RESTRICT secret,
size_t lane)
{
xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */
const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */
XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0);
XXH_ASSERT(lane < XXH_ACC_NB);
{
xxh_u64 const key64 = XXH_readLE64(xsecret + lane * 8);
xxh_u64 acc64 = xacc[lane];
acc64 = XXH_xorshift64(acc64, 47);
acc64 ^= key64;
acc64 *= XXH_PRIME32_1;
xacc[lane] = acc64;
}
}
/*!
* @internal
* @brief Scrambles the accumulators after a large chunk has been read
*/
XXH_FORCE_INLINE void
XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
{
size_t i;
for (i=0; i < XXH_ACC_NB; i++) {
XXH3_scalarScrambleRound(acc, secret, i);
}
}
XXH_FORCE_INLINE void
XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
{
/*
* We need a separate pointer for the hack below,
* which requires a non-const pointer.
* Any decent compiler will optimize this out otherwise.
*/
const xxh_u8* kSecretPtr = XXH3_kSecret;
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
#if defined(__GNUC__) && defined(__aarch64__)
/*
* UGLY HACK:
* GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are
* placed sequentially, in order, at the top of the unrolled loop.
*
* While MOVK is great for generating constants (2 cycles for a 64-bit
* constant compared to 4 cycles for LDR), it fights for bandwidth with
* the arithmetic instructions.
*
* I L S
* MOVK
* MOVK
* MOVK
* MOVK
* ADD
* SUB STR
* STR
* By forcing loads from memory (as the asm line causes the compiler to assume
* that XXH3_kSecretPtr has been changed), the pipelines are used more
* efficiently:
* I L S
* LDR
* ADD LDR
* SUB STR
* STR
*
* See XXH3_NEON_LANES for details on the pipsline.
*
* XXH3_64bits_withSeed, len == 256, Snapdragon 835
* without hack: 2654.4 MB/s
* with hack: 3202.9 MB/s
*/
XXH_COMPILER_GUARD(kSecretPtr);
#endif
{ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16;
int i;
for (i=0; i < nbRounds; i++) {
/*
* The asm hack causes the compiler to assume that kSecretPtr aliases with
* customSecret, and on aarch64, this prevented LDP from merging two
* loads together for free. Putting the loads together before the stores
* properly generates LDP.
*/
xxh_u64 lo = XXH_readLE64(kSecretPtr + 16*i) + seed64;
xxh_u64 hi = XXH_readLE64(kSecretPtr + 16*i + 8) - seed64;
XXH_writeLE64((xxh_u8*)customSecret + 16*i, lo);
XXH_writeLE64((xxh_u8*)customSecret + 16*i + 8, hi);
} }
}
typedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t);
typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*);
typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64);
#if (XXH_VECTOR == XXH_AVX512)
#define XXH3_accumulate_512 XXH3_accumulate_512_avx512
#define XXH3_accumulate XXH3_accumulate_avx512
#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512
#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512
#elif (XXH_VECTOR == XXH_AVX2)
#define XXH3_accumulate_512 XXH3_accumulate_512_avx2
#define XXH3_accumulate XXH3_accumulate_avx2
#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2
#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2
#elif (XXH_VECTOR == XXH_SSE2)
#define XXH3_accumulate_512 XXH3_accumulate_512_sse2
#define XXH3_accumulate XXH3_accumulate_sse2
#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2
#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2
#elif (XXH_VECTOR == XXH_NEON)
#define XXH3_accumulate_512 XXH3_accumulate_512_neon
#define XXH3_accumulate XXH3_accumulate_neon
#define XXH3_scrambleAcc XXH3_scrambleAcc_neon
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#elif (XXH_VECTOR == XXH_VSX)
#define XXH3_accumulate_512 XXH3_accumulate_512_vsx
#define XXH3_accumulate XXH3_accumulate_vsx
#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#elif (XXH_VECTOR == XXH_SVE)
#define XXH3_accumulate_512 XXH3_accumulate_512_sve
#define XXH3_accumulate XXH3_accumulate_sve
#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#elif (XXH_VECTOR == XXH_LASX)
#define XXH3_accumulate_512 XXH3_accumulate_512_lasx
#define XXH3_accumulate XXH3_accumulate_lasx
#define XXH3_scrambleAcc XXH3_scrambleAcc_lasx
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#elif (XXH_VECTOR == XXH_LSX)
#define XXH3_accumulate_512 XXH3_accumulate_512_lsx
#define XXH3_accumulate XXH3_accumulate_lsx
#define XXH3_scrambleAcc XXH3_scrambleAcc_lsx
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#else /* scalar */
#define XXH3_accumulate_512 XXH3_accumulate_512_scalar
#define XXH3_accumulate XXH3_accumulate_scalar
#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#endif
#if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */
# undef XXH3_initCustomSecret
# define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
#endif
XXH_FORCE_INLINE void
XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,
const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble)
{
size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;
size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock;
size_t const nb_blocks = (len - 1) / block_len;
size_t n;
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
for (n = 0; n < nb_blocks; n++) {
f_acc(acc, input + n*block_len, secret, nbStripesPerBlock);
f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN);
}
/* last partial block */
XXH_ASSERT(len > XXH_STRIPE_LEN);
{ size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE));
f_acc(acc, input + nb_blocks*block_len, secret, nbStripes);
/* last stripe */
{ const xxh_u8* const p = input + len - XXH_STRIPE_LEN;
#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */
XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START);
} }
}
XXH_FORCE_INLINE xxh_u64
XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret)
{
return XXH3_mul128_fold64(
acc[0] ^ XXH_readLE64(secret),
acc[1] ^ XXH_readLE64(secret+8) );
}
static XXH_PUREF XXH64_hash_t
XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start)
{
xxh_u64 result64 = start;
size_t i = 0;
for (i = 0; i < 4; i++) {
result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i);
#if defined(__clang__) /* Clang */ \
&& (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \
&& (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
&& !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */
/*
* UGLY HACK:
* Prevent autovectorization on Clang ARMv7-a. Exact same problem as
* the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b.
* XXH3_64bits, len == 256, Snapdragon 835:
* without hack: 2063.7 MB/s
* with hack: 2560.7 MB/s
*/
XXH_COMPILER_GUARD(result64);
#endif
}
return XXH3_avalanche(result64);
}
/* do not align on 8, so that the secret is different from the accumulator */
#define XXH_SECRET_MERGEACCS_START 11
static XXH_PUREF XXH64_hash_t
XXH3_finalizeLong_64b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 len)
{
return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, len * XXH_PRIME64_1);
}
#define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \
XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 }
XXH_FORCE_INLINE XXH64_hash_t
XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,
const void* XXH_RESTRICT secret, size_t secretSize,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble)
{
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble);
/* converge into final hash */
XXH_STATIC_ASSERT(sizeof(acc) == 64);
XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
return XXH3_finalizeLong_64b(acc, (const xxh_u8*)secret, (xxh_u64)len);
}
/*
* It's important for performance to transmit secret's size (when it's static)
* so that the compiler can properly optimize the vectorized loop.
* This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set.
* When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE
* breaks -Og, this is XXH_NO_INLINE.
*/
XXH3_WITH_SECRET_INLINE XXH64_hash_t
XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
{
(void)seed64;
return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc);
}
/*
* It's preferable for performance that XXH3_hashLong is not inlined,
* as it results in a smaller function for small data, easier to the instruction cache.
* Note that inside this no_inline function, we do inline the internal loop,
* and provide a statically defined secret size to allow optimization of vector loop.
*/
XXH_NO_INLINE XXH_PUREF XXH64_hash_t
XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
{
(void)seed64; (void)secret; (void)secretLen;
return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc);
}
/*
* XXH3_hashLong_64b_withSeed():
* Generate a custom key based on alteration of default XXH3_kSecret with the seed,
* and then use this key for long mode hashing.
*
* This operation is decently fast but nonetheless costs a little bit of time.
* Try to avoid it whenever possible (typically when seed==0).
*
* It's important for performance that XXH3_hashLong is not inlined. Not sure
* why (uop cache maybe?), but the difference is large and easily measurable.
*/
XXH_FORCE_INLINE XXH64_hash_t
XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,
XXH64_hash_t seed,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble,
XXH3_f_initCustomSecret f_initSec)
{
#if XXH_SIZE_OPT <= 0
if (seed == 0)
return XXH3_hashLong_64b_internal(input, len,
XXH3_kSecret, sizeof(XXH3_kSecret),
f_acc, f_scramble);
#endif
{ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
f_initSec(secret, seed);
return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret),
f_acc, f_scramble);
}
}
/*
* It's important for performance that XXH3_hashLong is not inlined.
*/
XXH_NO_INLINE XXH64_hash_t
XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
{
(void)secret; (void)secretLen;
return XXH3_hashLong_64b_withSeed_internal(input, len, seed,
XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret);
}
typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t,
XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t);
XXH_FORCE_INLINE XXH64_hash_t
XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,
XXH3_hashLong64_f f_hashLong)
{
XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
/*
* If an action is to be taken if `secretLen` condition is not respected,
* it should be done here.
* For now, it's a contract pre-condition.
* Adding a check and a branch here would cost performance at every hash.
* Also, note that function signature doesn't offer room to return an error.
*/
if (len <= 16)
return XXH3_len_0to16_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);
if (len <= 128)
return XXH3_len_17to128_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
if (len <= XXH3_MIDSIZE_MAX)
return XXH3_len_129to240_64b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
return f_hashLong(input, len, seed64, (const xxh_u8*)secret, secretLen);
}
/* === Public entry point === */
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length)
{
return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH64_hash_t
XXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize)
{
return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH64_hash_t
XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed)
{
return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);
}
XXH_PUBLIC_API XXH64_hash_t
XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)
{
if (length <= XXH3_MIDSIZE_MAX)
return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize);
}
/* === XXH3 streaming === */
#ifndef XXH_NO_STREAM
/*
* Malloc's a pointer that is always aligned to @align.
*
* This must be freed with `XXH_alignedFree()`.
*
* malloc typically guarantees 16 byte alignment on 64-bit systems and 8 byte
* alignment on 32-bit. This isn't enough for the 32 byte aligned loads in AVX2
* or on 32-bit, the 16 byte aligned loads in SSE2 and NEON.
*
* This underalignment previously caused a rather obvious crash which went
* completely unnoticed due to XXH3_createState() not actually being tested.
* Credit to RedSpah for noticing this bug.
*
* The alignment is done manually: Functions like posix_memalign or _mm_malloc
* are avoided: To maintain portability, we would have to write a fallback
* like this anyways, and besides, testing for the existence of library
* functions without relying on external build tools is impossible.
*
* The method is simple: Overallocate, manually align, and store the offset
* to the original behind the returned pointer.
*
* Align must be a power of 2 and 8 <= align <= 128.
*/
static XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align)
{
XXH_ASSERT(align <= 128 && align >= 8); /* range check */
XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */
XXH_ASSERT(s != 0 && s < (s + align)); /* empty/overflow */
{ /* Overallocate to make room for manual realignment and an offset byte */
xxh_u8* base = (xxh_u8*)XXH_malloc(s + align);
if (base != NULL) {
/*
* Get the offset needed to align this pointer.
*
* Even if the returned pointer is aligned, there will always be
* at least one byte to store the offset to the original pointer.
*/
size_t offset = align - ((size_t)base & (align - 1)); /* base % align */
/* Add the offset for the now-aligned pointer */
xxh_u8* ptr = base + offset;
XXH_ASSERT((size_t)ptr % align == 0);
/* Store the offset immediately before the returned pointer. */
ptr[-1] = (xxh_u8)offset;
return ptr;
}
return NULL;
}
}
/*
* Frees an aligned pointer allocated by XXH_alignedMalloc(). Don't pass
* normal malloc'd pointers, XXH_alignedMalloc has a specific data layout.
*/
static void XXH_alignedFree(void* p)
{
if (p != NULL) {
xxh_u8* ptr = (xxh_u8*)p;
/* Get the offset byte we added in XXH_malloc. */
xxh_u8 offset = ptr[-1];
/* Free the original malloc'd pointer */
xxh_u8* base = ptr - offset;
XXH_free(base);
}
}
/*! @ingroup XXH3_family */
/*!
* @brief Allocate an @ref XXH3_state_t.
*
* @return An allocated pointer of @ref XXH3_state_t on success.
* @return `NULL` on failure.
*
* @note Must be freed with XXH3_freeState().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)
{
XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64);
if (state==NULL) return NULL;
XXH3_INITSTATE(state);
return state;
}
/*! @ingroup XXH3_family */
/*!
* @brief Frees an @ref XXH3_state_t.
*
* @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().
*
* @return @ref XXH_OK.
*
* @note Must be allocated with XXH3_createState().
*
* @see @ref streaming_example "Streaming Example"
*/
XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr)
{
XXH_alignedFree(statePtr);
return XXH_OK;
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API void
XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state)
{
XXH_memcpy(dst_state, src_state, sizeof(*dst_state));
}
static void
XXH3_reset_internal(XXH3_state_t* statePtr,
XXH64_hash_t seed,
const void* secret, size_t secretSize)
{
size_t const initStart = offsetof(XXH3_state_t, bufferedSize);
size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart;
XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart);
XXH_ASSERT(statePtr != NULL);
/* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */
XXH_memset((char*)statePtr + initStart, 0, initLength);
statePtr->acc[0] = XXH_PRIME32_3;
statePtr->acc[1] = XXH_PRIME64_1;
statePtr->acc[2] = XXH_PRIME64_2;
statePtr->acc[3] = XXH_PRIME64_3;
statePtr->acc[4] = XXH_PRIME64_4;
statePtr->acc[5] = XXH_PRIME32_2;
statePtr->acc[6] = XXH_PRIME64_5;
statePtr->acc[7] = XXH_PRIME32_1;
statePtr->seed = seed;
statePtr->useSeed = (seed != 0);
statePtr->extSecret = (const unsigned char*)secret;
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
statePtr->secretLimit = secretSize - XXH_STRIPE_LEN;
statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr)
{
if (statePtr == NULL) return XXH_ERROR;
XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
return XXH_OK;
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize)
{
if (statePtr == NULL) return XXH_ERROR;
XXH3_reset_internal(statePtr, 0, secret, secretSize);
if (secret == NULL) return XXH_ERROR;
if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
return XXH_OK;
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed)
{
if (statePtr == NULL) return XXH_ERROR;
if (seed==0) return XXH3_64bits_reset(statePtr);
if ((seed != statePtr->seed) || (statePtr->extSecret != NULL))
XXH3_initCustomSecret(statePtr->customSecret, seed);
XXH3_reset_internal(statePtr, seed, NULL, XXH_SECRET_DEFAULT_SIZE);
return XXH_OK;
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64)
{
if (statePtr == NULL) return XXH_ERROR;
if (secret == NULL) return XXH_ERROR;
if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
XXH3_reset_internal(statePtr, seed64, secret, secretSize);
statePtr->useSeed = 1; /* always, even if seed64==0 */
return XXH_OK;
}
/*!
* @internal
* @brief Processes a large input for XXH3_update() and XXH3_digest_long().
*
* Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block.
*
* @param acc Pointer to the 8 accumulator lanes
* @param nbStripesSoFarPtr In/out pointer to the number of leftover stripes in the block*
* @param nbStripesPerBlock Number of stripes in a block
* @param input Input pointer
* @param nbStripes Number of stripes to process
* @param secret Secret pointer
* @param secretLimit Offset of the last block in @p secret
* @param f_acc Pointer to an XXH3_accumulate implementation
* @param f_scramble Pointer to an XXH3_scrambleAcc implementation
* @return Pointer past the end of @p input after processing
*/
XXH_FORCE_INLINE const xxh_u8 *
XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock,
const xxh_u8* XXH_RESTRICT input, size_t nbStripes,
const xxh_u8* XXH_RESTRICT secret, size_t secretLimit,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble)
{
const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE;
/* Process full blocks */
if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) {
/* Process the initial partial block... */
size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr;
do {
/* Accumulate and scramble */
f_acc(acc, input, initialSecret, nbStripesThisIter);
f_scramble(acc, secret + secretLimit);
input += nbStripesThisIter * XXH_STRIPE_LEN;
nbStripes -= nbStripesThisIter;
/* Then continue the loop with the full block size */
nbStripesThisIter = nbStripesPerBlock;
initialSecret = secret;
} while (nbStripes >= nbStripesPerBlock);
*nbStripesSoFarPtr = 0;
}
/* Process a partial block */
if (nbStripes > 0) {
f_acc(acc, input, initialSecret, nbStripes);
input += nbStripes * XXH_STRIPE_LEN;
*nbStripesSoFarPtr += nbStripes;
}
/* Return end pointer */
return input;
}
#ifndef XXH3_STREAM_USE_STACK
# if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */
# define XXH3_STREAM_USE_STACK 1
# endif
#endif
/* This function accepts f_acc and f_scramble as function pointers,
* making it possible to implement multiple variants with different acc & scramble stages.
* This is notably useful to implement multiple vector variants with different intrinsics.
*/
XXH_FORCE_INLINE XXH_errorcode
XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
const xxh_u8* XXH_RESTRICT input, size_t len,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble)
{
if (input==NULL) {
XXH_ASSERT(len == 0);
return XXH_OK;
}
XXH_ASSERT(state != NULL);
{ const xxh_u8* const bEnd = input + len;
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1
/* For some reason, gcc and MSVC seem to suffer greatly
* when operating accumulators directly into state.
* Operating into stack space seems to enable proper optimization.
* clang, on the other hand, doesn't seem to need this trick */
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8];
XXH_memcpy(acc, state->acc, sizeof(acc));
#else
xxh_u64* XXH_RESTRICT const acc = state->acc;
#endif
state->totalLen += len;
XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);
/* small input : just fill in tmp buffer */
if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) {
XXH_memcpy(state->buffer + state->bufferedSize, input, len);
state->bufferedSize += (XXH32_hash_t)len;
return XXH_OK;
}
/* total input is now > XXH3_INTERNALBUFFER_SIZE */
#define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN)
XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */
/*
* Internal buffer is partially filled (always, except at beginning)
* Complete it, then consume it.
*/
if (state->bufferedSize) {
size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize;
XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize);
input += loadSize;
XXH3_consumeStripes(acc,
&state->nbStripesSoFar, state->nbStripesPerBlock,
state->buffer, XXH3_INTERNALBUFFER_STRIPES,
secret, state->secretLimit,
f_acc, f_scramble);
state->bufferedSize = 0;
}
XXH_ASSERT(input < bEnd);
if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {
size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN;
input = XXH3_consumeStripes(acc,
&state->nbStripesSoFar, state->nbStripesPerBlock,
input, nbStripes,
secret, state->secretLimit,
f_acc, f_scramble);
XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
}
/* Some remaining input (always) : buffer it */
XXH_ASSERT(input < bEnd);
XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE);
XXH_ASSERT(state->bufferedSize == 0);
XXH_memcpy(state->buffer, input, (size_t)(bEnd-input));
state->bufferedSize = (XXH32_hash_t)(bEnd-input);
#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1
/* save stack accumulators into state */
XXH_memcpy(state->acc, acc, sizeof(acc));
#endif
}
return XXH_OK;
}
/*
* Both XXH3_64bits_update and XXH3_128bits_update use this routine.
*/
XXH_NO_INLINE XXH_errorcode
XXH3_update_regular(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)
{
return XXH3_update(state, (const xxh_u8*)input, len,
XXH3_accumulate, XXH3_scrambleAcc);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)
{
return XXH3_update_regular(state, input, len);
}
XXH_FORCE_INLINE void
XXH3_digest_long (XXH64_hash_t* acc,
const XXH3_state_t* state,
const unsigned char* secret)
{
xxh_u8 lastStripe[XXH_STRIPE_LEN];
const xxh_u8* lastStripePtr;
/*
* Digest on a local copy. This way, the state remains unaltered, and it can
* continue ingesting more input afterwards.
*/
XXH_memcpy(acc, state->acc, sizeof(state->acc));
if (state->bufferedSize >= XXH_STRIPE_LEN) {
/* Consume remaining stripes then point to remaining data in buffer */
size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;
size_t nbStripesSoFar = state->nbStripesSoFar;
XXH3_consumeStripes(acc,
&nbStripesSoFar, state->nbStripesPerBlock,
state->buffer, nbStripes,
secret, state->secretLimit,
XXH3_accumulate, XXH3_scrambleAcc);
lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN;
} else { /* bufferedSize < XXH_STRIPE_LEN */
/* Copy to temp buffer */
size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;
XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */
XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize);
XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);
lastStripePtr = lastStripe;
}
/* Last stripe */
XXH3_accumulate_512(acc,
lastStripePtr,
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state)
{
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
if (state->totalLen > XXH3_MIDSIZE_MAX) {
XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
XXH3_digest_long(acc, state, secret);
return XXH3_finalizeLong_64b(acc, secret, (xxh_u64)state->totalLen);
}
/* totalLen <= XXH3_MIDSIZE_MAX: digesting a short input */
if (state->useSeed)
return XXH3_64bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);
return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),
secret, state->secretLimit + XXH_STRIPE_LEN);
}
#endif /* !XXH_NO_STREAM */
/* ==========================================
* XXH3 128 bits (a.k.a XXH128)
* ==========================================
* XXH3's 128-bit variant has better mixing and strength than the 64-bit variant,
* even without counting the significantly larger output size.
*
* For example, extra steps are taken to avoid the seed-dependent collisions
* in 17-240 byte inputs (See XXH3_mix16B and XXH128_mix32B).
*
* This strength naturally comes at the cost of some speed, especially on short
* lengths. Note that longer hashes are about as fast as the 64-bit version
* due to it using only a slight modification of the 64-bit loop.
*
* XXH128 is also more oriented towards 64-bit machines. It is still extremely
* fast for a _128-bit_ hash on 32-bit (it usually clears XXH64).
*/
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
/* A doubled version of 1to3_64b with different constants. */
XXH_ASSERT(input != NULL);
XXH_ASSERT(1 <= len && len <= 3);
XXH_ASSERT(secret != NULL);
/*
* len = 1: combinedl = { input[0], 0x01, input[0], input[0] }
* len = 2: combinedl = { input[1], 0x02, input[0], input[1] }
* len = 3: combinedl = { input[2], 0x03, input[0], input[1] }
*/
{ xxh_u8 const c1 = input[0];
xxh_u8 const c2 = input[len >> 1];
xxh_u8 const c3 = input[len - 1];
xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24)
| ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8);
xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13);
xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed;
xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed;
xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl;
xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph;
XXH128_hash_t h128;
h128.low64 = XXH64_avalanche(keyed_lo);
h128.high64 = XXH64_avalanche(keyed_hi);
return h128;
}
}
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(input != NULL);
XXH_ASSERT(secret != NULL);
XXH_ASSERT(4 <= len && len <= 8);
seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32;
{ xxh_u32 const input_lo = XXH_readLE32(input);
xxh_u32 const input_hi = XXH_readLE32(input + len - 4);
xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32);
xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed;
xxh_u64 const keyed = input_64 ^ bitflip;
/* Shift len to the left to ensure it is even, this avoids even multiplies. */
XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2));
m128.high64 += (m128.low64 << 1);
m128.low64 ^= (m128.high64 >> 3);
m128.low64 = XXH_xorshift64(m128.low64, 35);
m128.low64 *= PRIME_MX2;
m128.low64 = XXH_xorshift64(m128.low64, 28);
m128.high64 = XXH3_avalanche(m128.high64);
return m128;
}
}
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(input != NULL);
XXH_ASSERT(secret != NULL);
XXH_ASSERT(9 <= len && len <= 16);
{ xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed;
xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed;
xxh_u64 const input_lo = XXH_readLE64(input);
xxh_u64 input_hi = XXH_readLE64(input + len - 8);
XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1);
/*
* Put len in the middle of m128 to ensure that the length gets mixed to
* both the low and high bits in the 128x64 multiply below.
*/
m128.low64 += (xxh_u64)(len - 1) << 54;
input_hi ^= bitfliph;
/*
* Add the high 32 bits of input_hi to the high 32 bits of m128, then
* add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to
* the high 64 bits of m128.
*
* The best approach to this operation is different on 32-bit and 64-bit.
*/
if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */
/*
* 32-bit optimized version, which is more readable.
*
* On 32-bit, it removes an ADC and delays a dependency between the two
* halves of m128.high64, but it generates an extra mask on 64-bit.
*/
m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2);
} else {
/*
* 64-bit optimized (albeit more confusing) version.
*
* Uses some properties of addition and multiplication to remove the mask:
*
* Let:
* a = input_hi.lo = (input_hi & 0x00000000FFFFFFFF)
* b = input_hi.hi = (input_hi & 0xFFFFFFFF00000000)
* c = XXH_PRIME32_2
*
* a + (b * c)
* Inverse Property: x + y - x == y
* a + (b * (1 + c - 1))
* Distributive Property: x * (y + z) == (x * y) + (x * z)
* a + (b * 1) + (b * (c - 1))
* Identity Property: x * 1 == x
* a + b + (b * (c - 1))
*
* Substitute a, b, and c:
* input_hi.hi + input_hi.lo + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))
*
* Since input_hi.hi + input_hi.lo == input_hi, we get this:
* input_hi + ((xxh_u64)input_hi.lo * (XXH_PRIME32_2 - 1))
*/
m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1);
}
/* m128 ^= XXH_swap64(m128 >> 64); */
m128.low64 ^= XXH_swap64(m128.high64);
{ /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */
XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2);
h128.high64 += m128.high64 * XXH_PRIME64_2;
h128.low64 = XXH3_avalanche(h128.low64);
h128.high64 = XXH3_avalanche(h128.high64);
return h128;
} }
}
/*
* Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN
*/
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
{
XXH_ASSERT(len <= 16);
{ if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed);
if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed);
if (len) return XXH3_len_1to3_128b(input, len, secret, seed);
{ XXH128_hash_t h128;
xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72);
xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88);
h128.low64 = XXH64_avalanche(seed ^ bitflipl);
h128.high64 = XXH64_avalanche( seed ^ bitfliph);
return h128;
} }
}
/*
* A bit slower than XXH3_mix16B, but handles multiply by zero better.
*/
XXH_FORCE_INLINE XXH128_hash_t
XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2,
const xxh_u8* secret, XXH64_hash_t seed)
{
acc.low64 += XXH3_mix16B (input_1, secret+0, seed);
acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8);
acc.high64 += XXH3_mix16B (input_2, secret+16, seed);
acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8);
return acc;
}
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed)
{
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
XXH_ASSERT(16 < len && len <= 128);
{ XXH128_hash_t acc;
acc.low64 = len * XXH_PRIME64_1;
acc.high64 = 0;
#if XXH_SIZE_OPT >= 1
{
/* Smaller, but slightly slower. */
unsigned int i = (unsigned int)(len - 1) / 32;
do {
acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed);
} while (i-- != 0);
}
#else
if (len > 32) {
if (len > 64) {
if (len > 96) {
acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed);
}
acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed);
}
acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed);
}
acc = XXH128_mix32B(acc, input, input+len-16, secret, seed);
#endif
{ XXH128_hash_t h128;
h128.low64 = acc.low64 + acc.high64;
h128.high64 = (acc.low64 * XXH_PRIME64_1)
+ (acc.high64 * XXH_PRIME64_4)
+ ((len - seed) * XXH_PRIME64_2);
h128.low64 = XXH3_avalanche(h128.low64);
h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);
return h128;
}
}
}
XXH_NO_INLINE XXH_PUREF XXH128_hash_t
XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH64_hash_t seed)
{
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize;
XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
{ XXH128_hash_t acc;
unsigned i;
acc.low64 = len * XXH_PRIME64_1;
acc.high64 = 0;
/*
* We set as `i` as offset + 32. We do this so that unchanged
* `len` can be used as upper bound. This reaches a sweet spot
* where both x86 and aarch64 get simple agen and good codegen
* for the loop.
*/
for (i = 32; i < 160; i += 32) {
acc = XXH128_mix32B(acc,
input + i - 32,
input + i - 16,
secret + i - 32,
seed);
}
acc.low64 = XXH3_avalanche(acc.low64);
acc.high64 = XXH3_avalanche(acc.high64);
/*
* NB: `i <= len` will duplicate the last 32-bytes if
* len % 32 was zero. This is an unfortunate necessity to keep
* the hash result stable.
*/
for (i=160; i <= len; i += 32) {
acc = XXH128_mix32B(acc,
input + i - 32,
input + i - 16,
secret + XXH3_MIDSIZE_STARTOFFSET + i - 160,
seed);
}
/* last bytes */
acc = XXH128_mix32B(acc,
input + len - 16,
input + len - 32,
secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16,
(XXH64_hash_t)0 - seed);
{ XXH128_hash_t h128;
h128.low64 = acc.low64 + acc.high64;
h128.high64 = (acc.low64 * XXH_PRIME64_1)
+ (acc.high64 * XXH_PRIME64_4)
+ ((len - seed) * XXH_PRIME64_2);
h128.low64 = XXH3_avalanche(h128.low64);
h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64);
return h128;
}
}
}
static XXH_PUREF XXH128_hash_t
XXH3_finalizeLong_128b(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, xxh_u64 len)
{
XXH128_hash_t h128;
h128.low64 = XXH3_finalizeLong_64b(acc, secret, len);
h128.high64 = XXH3_mergeAccs(acc, secret + secretSize
- XXH_STRIPE_LEN - XXH_SECRET_MERGEACCS_START,
~(len * XXH_PRIME64_2));
return h128;
}
XXH_FORCE_INLINE XXH128_hash_t
XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len,
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble)
{
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble);
/* converge into final hash */
XXH_STATIC_ASSERT(sizeof(acc) == 64);
XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
return XXH3_finalizeLong_128b(acc, secret, secretSize, (xxh_u64)len);
}
/*
* It's important for performance that XXH3_hashLong() is not inlined.
*/
XXH_NO_INLINE XXH_PUREF XXH128_hash_t
XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64,
const void* XXH_RESTRICT secret, size_t secretLen)
{
(void)seed64; (void)secret; (void)secretLen;
return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret),
XXH3_accumulate, XXH3_scrambleAcc);
}
/*
* It's important for performance to pass @p secretLen (when it's static)
* to the compiler, so that it can properly optimize the vectorized loop.
*
* When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE
* breaks -Og, this is XXH_NO_INLINE.
*/
XXH3_WITH_SECRET_INLINE XXH128_hash_t
XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64,
const void* XXH_RESTRICT secret, size_t secretLen)
{
(void)seed64;
return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen,
XXH3_accumulate, XXH3_scrambleAcc);
}
XXH_FORCE_INLINE XXH128_hash_t
XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len,
XXH64_hash_t seed64,
XXH3_f_accumulate f_acc,
XXH3_f_scrambleAcc f_scramble,
XXH3_f_initCustomSecret f_initSec)
{
if (seed64 == 0)
return XXH3_hashLong_128b_internal(input, len,
XXH3_kSecret, sizeof(XXH3_kSecret),
f_acc, f_scramble);
{ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
f_initSec(secret, seed64);
return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret),
f_acc, f_scramble);
}
}
/*
* It's important for performance that XXH3_hashLong is not inlined.
*/
XXH_NO_INLINE XXH128_hash_t
XXH3_hashLong_128b_withSeed(const void* input, size_t len,
XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen)
{
(void)secret; (void)secretLen;
return XXH3_hashLong_128b_withSeed_internal(input, len, seed64,
XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret);
}
typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t,
XXH64_hash_t, const void* XXH_RESTRICT, size_t);
XXH_FORCE_INLINE XXH128_hash_t
XXH3_128bits_internal(const void* input, size_t len,
XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen,
XXH3_hashLong128_f f_hl128)
{
XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN);
/*
* If an action is to be taken if `secret` conditions are not respected,
* it should be done here.
* For now, it's a contract pre-condition.
* Adding a check and a branch here would cost performance at every hash.
*/
if (len <= 16)
return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64);
if (len <= 128)
return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
if (len <= XXH3_MIDSIZE_MAX)
return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64);
return f_hl128(input, len, seed64, secret, secretLen);
}
/* === Public XXH128 API === */
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len)
{
return XXH3_128bits_internal(input, len, 0,
XXH3_kSecret, sizeof(XXH3_kSecret),
XXH3_hashLong_128b_default);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t
XXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize)
{
return XXH3_128bits_internal(input, len, 0,
(const xxh_u8*)secret, secretSize,
XXH3_hashLong_128b_withSecret);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t
XXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)
{
return XXH3_128bits_internal(input, len, seed,
XXH3_kSecret, sizeof(XXH3_kSecret),
XXH3_hashLong_128b_withSeed);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t
XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)
{
if (len <= XXH3_MIDSIZE_MAX)
return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t
XXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)
{
return XXH3_128bits_withSeed(input, len, seed);
}
/* === XXH3 128-bit streaming === */
#ifndef XXH_NO_STREAM
/*
* All initialization and update functions are identical to 64-bit streaming variant.
* The only difference is the finalization routine.
*/
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr)
{
return XXH3_64bits_reset(statePtr);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize)
{
return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed)
{
return XXH3_64bits_reset_withSeed(statePtr, seed);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)
{
return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)
{
return XXH3_update_regular(state, input, len);
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state)
{
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
if (state->totalLen > XXH3_MIDSIZE_MAX) {
XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB];
XXH3_digest_long(acc, state, secret);
XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START);
return XXH3_finalizeLong_128b(acc, secret, state->secretLimit + XXH_STRIPE_LEN, (xxh_u64)state->totalLen);
}
/* len <= XXH3_MIDSIZE_MAX : short code */
if (state->useSeed)
return XXH3_128bits_withSeed(state->buffer, (size_t)state->totalLen, state->seed);
return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),
secret, state->secretLimit + XXH_STRIPE_LEN);
}
#endif /* !XXH_NO_STREAM */
/* 128-bit utility functions */
/* return : 1 is equal, 0 if different */
/*! @ingroup XXH3_family */
XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2)
{
/* note : XXH128_hash_t is compact, it has no padding byte */
return !(XXH_memcmp(&h1, &h2, sizeof(h1)));
}
/* This prototype is compatible with stdlib's qsort().
* @return : >0 if *h128_1 > *h128_2
* <0 if *h128_1 < *h128_2
* =0 if *h128_1 == *h128_2 */
/*! @ingroup XXH3_family */
XXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2)
{
XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1;
XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2;
int const hcmp = (h1.high64 > h2.high64) - (h2.high64 > h1.high64);
/* note : bets that, in most cases, hash values are different */
if (hcmp) return hcmp;
return (h1.low64 > h2.low64) - (h2.low64 > h1.low64);
}
/*====== Canonical representation ======*/
/*! @ingroup XXH3_family */
XXH_PUBLIC_API void
XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) {
hash.high64 = XXH_swap64(hash.high64);
hash.low64 = XXH_swap64(hash.low64);
}
XXH_memcpy(dst, &hash.high64, sizeof(hash.high64));
XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH128_hash_t
XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src)
{
XXH128_hash_t h;
h.high64 = XXH_readBE64(src);
h.low64 = XXH_readBE64(src->digest + 8);
return h;
}
/* ==========================================
* Secret generators
* ==========================================
*/
#define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x))
XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128)
{
XXH_writeLE64( dst, XXH_readLE64(dst) ^ h128.low64 );
XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 );
}
/*! @ingroup XXH3_family */
XXH_PUBLIC_API XXH_errorcode
XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize)
{
#if (XXH_DEBUGLEVEL >= 1)
XXH_ASSERT(secretBuffer != NULL);
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
#else
/* production mode, assert() are disabled */
if (secretBuffer == NULL) return XXH_ERROR;
if (secretSize < XXH3_SECRET_SIZE_MIN) return XXH_ERROR;
#endif
if (customSeedSize == 0) {
customSeed = XXH3_kSecret;
customSeedSize = XXH_SECRET_DEFAULT_SIZE;
}
#if (XXH_DEBUGLEVEL >= 1)
XXH_ASSERT(customSeed != NULL);
#else
if (customSeed == NULL) return XXH_ERROR;
#endif
/* Fill secretBuffer with a copy of customSeed - repeat as needed */
{ size_t pos = 0;
while (pos < secretSize) {
size_t const toCopy = XXH_MIN((secretSize - pos), customSeedSize);
XXH_memcpy((char*)secretBuffer + pos, customSeed, toCopy);
pos += toCopy;
} }
{ size_t const nbSeg16 = secretSize / 16;
size_t n;
XXH128_canonical_t scrambler;
XXH128_canonicalFromHash(&scrambler, XXH128(customSeed, customSeedSize, 0));
for (n=0; n/dev/null)
option "curses"
if test_nz "${ncurses_ldflags}"; then
add_cflags `pkg-config --cflags ${ncurses} 2>/dev/null`
add_ldflags "${ncurses_ldflags}"
else
add_links "curses"
fi
option_end
}
# the atomic option
# @note some systems need link atomic, e.g. raspberrypi
option "atomic"
add_links "atomic"
add_csnippets "
void test() {\n
int v;\n
__atomic_load(&v,&v,0);\n
}"
option_end
# the lua option
option "lua"
add_cfuncs "lua_pushstring"
add_cincludes "lua.h" "lualib.h" "lauxlib.h"
add_defines "LUA_COMPAT_5_1" "LUA_COMPAT_5_2" "LUA_COMPAT_5_3"
before_check "option_find_lua"
option_end
option_find_lua() {
local ldflags=""
local cflags=""
option "lua"
# detect lua5.4 on debian
cflags=`pkg-config --cflags lua5.4 2>/dev/null`
ldflags=`pkg-config --libs lua5.4 2>/dev/null`
# detect it on fedora
if test_z "${cflags}"; then
cflags=`pkg-config --cflags lua 2>/dev/null`
fi
if test_z "${ldflags}"; then
ldflags=`pkg-config --libs lua 2>/dev/null`
fi
if test_z "${cflags}"; then
cflags="-I/usr/include/lua5.4"
fi
if test_z "${ldflags}"; then
ldflags="-llua5.4"
fi
add_cflags "${cflags}"
add_ldflags "${ldflags}"
option_end
}
# the luajit option
option "luajit"
add_cfuncs "lua_pushstring"
add_cincludes "lua.h" "lualib.h" "lauxlib.h"
add_defines "USE_LUAJIT"
before_check "option_find_luajit"
option_end
option_find_luajit() {
local ldflags=""
local cflags=""
option "luajit"
cflags=`pkg-config --cflags luajit 2>/dev/null`
ldflags=`pkg-config --libs luajit 2>/dev/null`
if test_z "${cflags}"; then
cflags="-I/usr/include/luajit-2.1"
fi
if test_z "${ldflags}"; then
ldflags="-lluajit"
fi
add_cflags "${cflags}"
add_ldflags "${ldflags}"
option_end
}
# the lz4 option
option "lz4"
add_cfuncs "LZ4F_compressFrame"
add_cincludes "lz4.h" "lz4frame.h"
before_check "option_find_lz4"
option_end
option_find_lz4() {
local ldflags=""
local cflags=""
option "lz4"
cflags=`pkg-config --cflags liblz4 2>/dev/null`
ldflags=`pkg-config --libs liblz4 2>/dev/null`
if test_z "${cflags}"; then
cflags="-I/usr/include"
fi
if test_z "${ldflags}"; then
ldflags="-llz4"
fi
add_cflags "${cflags}"
add_ldflags "${ldflags}"
option_end
}
# the sv option
option "sv"
add_cfuncs "semver_tryn"
add_cincludes "semver.h"
add_links "sv"
before_check "option_find_sv"
option_end
option_find_sv() {
local ldflags=""
local cflags=""
option "sv"
cflags=`pkg-config --cflags libsv 2>/dev/null`
ldflags=`pkg-config --libs libsv 2>/dev/null`
if test_z "${cflags}"; then
cflags="-I/usr/include"
fi
if test_z "${ldflags}"; then
ldflags="-lsv"
fi
add_cflags "${cflags}"
add_ldflags "${ldflags}"
option_end
}
# the tbox option
option "tbox"
add_cfuncs "tb_exit" "tb_md5_init" "tb_charset_conv_data"
add_cincludes "tbox/tbox.h"
add_links "tbox"
before_check "option_find_tbox"
option_end
option_find_tbox() {
local ldflags=""
local cflags=""
option "tbox"
cflags=`pkg-config --cflags libtbox 2>/dev/null`
ldflags=`pkg-config --libs libtbox 2>/dev/null`
if test_z "${cflags}"; then
cflags="-I/usr/include"
fi
if test_z "${ldflags}"; then
ldflags="-ltbox"
fi
add_cflags "${cflags}"
add_ldflags "${ldflags}"
# ubuntu armv7/armel maybe need it
if is_plat "linux" && is_arch "armv7" "arm"; then
add_ldflags "-latomic"
fi
option_end
}
# add projects
if ! has_config "external"; then
if is_config "runtime" "luajit"; then
includes "src/luajit"
else
includes "src/lua"
fi
includes "src/lua-cjson"
includes "src/lz4"
includes "src/sv"
includes "src/tbox"
fi
includes "src/xmake"
includes "src/cli"
================================================
FILE: core/xpack.lua
================================================
xpack("xmake")
set_homepage("https://xmake.io")
set_title("Xmake build utility ($(arch))")
set_description("A cross-platform build utility based on Lua.")
set_copyright("Copyright (C) 2015-present, Xmake Open Source Community")
set_author("ruki ")
set_licensefile("../LICENSE.md")
set_formats("nsis", "wix", "zip")
add_targets("cli")
set_bindir(".")
set_iconfile("src/cli/xmake.ico")
add_components("LongPath")
on_load(function (package)
local arch = package:arch()
if package:is_plat("windows") then
if arch == "x64" then
arch = "win64"
elseif arch == "x86" then
arch = "win32"
end
end
package:set("basename", "xmake-v$(version)." .. arch)
local format = package:format()
if format == "zip" then
package:set("prefixdir", "xmake")
end
end)
before_package(function (package)
import("net.http")
import("utils.archive")
import("core.base.global")
local format = package:format()
if package:is_plat("windows") and (format == "nsis" or format == "wix" or format == "zip") then
local winenv = path.join(os.programdir(), "winenv")
if false then -- os.isdir(winenv) then
package:add("installfiles", path.join(winenv, "**"), {rootdir = path.directory(winenv)})
else
local arch = package:arch()
local url_7z = "https://github.com/xmake-mirror/7zip/releases/download/24.08/7z24.08-" .. arch .. ".zip"
local curl_version = "8.11.0_4"
local url_curl = "https://curl.se/windows/dl-" .. curl_version .. "/curl-" .. curl_version
if package:is_arch("x64", "x86_64") then
url_curl = url_curl .. "-win64-mingw.zip"
elseif package:is_arch("arm64") then
url_curl = url_curl .. "-win64a-mingw.zip"
else
url_curl = url_curl .. "-win32-mingw.zip"
end
local archive_7z = path.join(package:builddir(), "7z.zip")
local archive_curl = path.join(package:builddir(), "curl.zip")
local tmpdir_7z = path.join(package:builddir(), "7z")
local tmpdir_curl = path.join(package:builddir(), "curl")
local winenv_bindir = path.join(package:builddir(), "winenv", "bin")
os.mkdir(winenv_bindir)
http.download(url_7z, archive_7z, {insecure = global.get("insecure-ssl")})
archive.extract(archive_7z, tmpdir_7z)
os.cp(path.join(tmpdir_7z, "*"), winenv_bindir)
http.download(url_curl, archive_curl, {insecure = global.get("insecure-ssl")})
archive.extract(archive_curl, tmpdir_curl)
os.cp(path.join(tmpdir_curl, "*", "bin", "*.exe"), winenv_bindir)
os.cp(path.join(tmpdir_curl, "*", "bin", "*.crt"), winenv_bindir)
winenv = path.directory(winenv_bindir)
package:add("installfiles", path.join(winenv, "**"), {rootdir = path.directory(winenv)})
end
end
end)
xpack_component("LongPath")
set_title("Enable Long Path")
set_description("Increases the maximum path length limit, up to 32,767 characters (before 256).")
on_installcmd(function (component, batchcmds)
batchcmds:rawcmd("nsis", [[
${If} $NoAdmin == "false"
; Enable long path
WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1
${EndIf}]])
batchcmds:rawcmd("wix", [[
]])
end)
xpack("xmakesrc")
set_homepage("https://xmake.io")
set_title("Xmake build utility ($(arch))")
set_description("A cross-platform build utility based on Lua.")
set_copyright("Copyright (C) 2015-present, Xmake Open Source Community")
set_author("ruki ")
set_formats("srczip", "srctargz", "runself", "srpm", "deb")
set_basename("xmake-v$(version)")
set_prefixdir("xmake-$(version)")
set_license("Apache-2.0")
before_package(function (package)
import("devel.git")
local rootdir = path.join(os.tmpfile(package:basename() .. "_" .. package:format()) .. ".dir", "repo")
if not os.isdir(rootdir) then
os.tryrm(rootdir)
os.cp(path.directory(os.projectdir()), rootdir)
git.clean({repodir = rootdir, force = true, all = true})
git.reset({repodir = rootdir, hard = true})
if os.isfile(path.join(rootdir, ".gitmodules")) then
git.submodule.clean({repodir = rootdir, force = true, all = true})
git.submodule.reset({repodir = rootdir, hard = true})
end
end
local extraconf = {rootdir = rootdir}
package:add("sourcefiles", path.join(rootdir, "core/**|src/pdcurses/**|src/luajit/**|src/tbox/tbox/src/demo/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "xmake/**|scripts/vsxmake/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "*.md"), extraconf)
package:add("sourcefiles", path.join(rootdir, "configure"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/*.sh"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/man/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/debian/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/msys/**"), extraconf)
end)
on_buildcmd(function (package, batchcmds)
local format = package:format()
if format == "srpm" or format == "deb" then
batchcmds:runv("./configure")
batchcmds:runv("make", {"-j4"})
end
end)
on_installcmd(function (package, batchcmds)
local format = package:format()
if format == "runself" then
batchcmds:runv("./scripts/get.sh", {"__local__"})
elseif format == "srpm" or format == "deb" then
batchcmds:runv("make", {"install", path(package:install_rootdir(), function (p) return "PREFIX=" .. p end)})
end
end)
================================================
FILE: scripts/debian/README.Debian
================================================
xmake for Debian
---------------
-- ruki Thu, 06 Apr 2017 21:22:12 +0800
================================================
FILE: scripts/debian/README.source
================================================
xmake for Debian
---------------
-- ruki Thu, 06 Apr 2017 21:22:12 +0800
================================================
FILE: scripts/debian/changelog
================================================
xmake (2.3.6+2) xenial; urgency=medium
* update 2.3.6
-- ruki Thu, 05 Aug 2020 21:22:12 +0800
================================================
FILE: scripts/debian/compat
================================================
9
================================================
FILE: scripts/debian/control
================================================
Source: xmake
Section: contrib/devel
Priority: optional
Maintainer: ruki
Build-Depends: debhelper (>=9)
Standards-Version: 3.9.7
Homepage: http://xmake.io
#Vcs-Git: git@github.com:xmake-io/xmake.git
#Vcs-Browser: https://github.com/xmake-io/xmake.git
Package: xmake
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: A cross-platform build utility based on Lua
xmake is a lightweight cross-platform build utility based on Lua.
It uses xmake.lua to maintain project builds. Compared with makefile/CMakeLists.txt,
the configuration syntax is more concise and intuitive.
It is very friendly to novices and can quickly get started in a short time.
Let users focus more on actual project development.
================================================
FILE: scripts/debian/copyright
================================================
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: xmake
Source: https://github.com/xmake-io/xmake
Files: *
Copyright: 2015-present ruki
License: Apache-2.0
.
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
# Please avoid picking licenses with terms that are more restrictive than the
# packaged work, as it may make Debian's contributions unacceptable upstream.
================================================
FILE: scripts/debian/init.d.ex
================================================
#!/bin/sh
# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then
set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
fi
### BEGIN INIT INFO
# Provides: xmake
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description:
# Description:
# <...>
# <...>
### END INIT INFO
# Author: ruki
DESC="xmake"
DAEMON=/usr/bin/xmake
# This is an example to start a single forking daemon capable of writing
# a pid file. To get other behaviors, implement do_start(), do_stop() or
# other functions to override the defaults in /lib/init/init-d-script.
# See also init-d-script(5)
================================================
FILE: scripts/debian/manpage.1.ex
================================================
.\" Hey, EMACS: -*- nroff -*-
.\" (C) Copyright 2017 ruki ,
.\"
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH Xmake SECTION "April 6 2017"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
xmake \- program to do something
.SH SYNOPSIS
.B xmake
.RI [ options ] " files" ...
.br
.B bar
.RI [ options ] " files" ...
.SH DESCRIPTION
This manual page documents briefly the
.B xmake
and
.B bar
commands.
.PP
.\" TeX users may be more comfortable with the \fB\fP and
.\" \fI\fP escape sequences to invode bold face and italics,
.\" respectively.
\fBxmake\fP is a program that...
.SH OPTIONS
These programs follow the usual GNU command line syntax, with long
options starting with two dashes (`-').
A summary of options is included below.
For a complete description, see the Info files.
.TP
.B \-h, \-\-help
Show summary of options.
.TP
.B \-v, \-\-version
Show version of program.
.SH SEE ALSO
.BR bar (1),
.BR baz (1).
.br
The programs are documented fully by
.IR "The Rise and Fall of a Fooish Bar" ,
available via the Info system.
================================================
FILE: scripts/debian/manpage.sgml.ex
================================================
manpage.1'. You may view
the manual page with: `docbook-to-man manpage.sgml | nroff -man |
less'. A typical entry in a Makefile or Makefile.am is:
manpage.1: manpage.sgml
docbook-to-man $< > $@
The docbook-to-man binary is found in the docbook-to-man package.
Please remember that if you create the nroff version in one of the
debian/rules file targets (such as build), you will need to include
docbook-to-man in your Build-Depends control field.
-->
FIRSTNAME">
SURNAME">
April 6 2017">
SECTION">
waruqi@gmail.com">
Xmake">
Debian">
GNU">
GPL">
]>
&dhemail;
&dhfirstname;
&dhsurname;
2003&dhusername;
&dhdate;
&dhucpackage;
&dhsection;
&dhpackage;program to do something&dhpackage;DESCRIPTIONThis manual page documents briefly the
&dhpackage; and bar
commands.This manual page was written for the &debian; distribution
because the original program does not have a manual page.
Instead, it has documentation in the &gnu;
Info format; see below.&dhpackage; is a program that...OPTIONSThese programs follow the usual &gnu; command line syntax,
with long options starting with two dashes (`-'). A summary of
options is included below. For a complete description, see the
Info files.Show summary of options.Show version of program.SEE ALSObar (1), baz (1).The programs are documented fully by The Rise and
Fall of a Fooish Bar available via the
Info system.AUTHORThis manual page was written by &dhusername; &dhemail; for
the &debian; system (and may be used by others). Permission is
granted to copy, distribute and/or modify this document under
the terms of the &gnu; General Public License, Version 2 any
later version published by the Free Software Foundation.
On Debian systems, the complete text of the GNU General Public
License can be found in /usr/share/common-licenses/GPL.
================================================
FILE: scripts/debian/manpage.xml.ex
================================================
. will be generated. You may view the
manual page with: nroff -man . | less'. A typical entry
in a Makefile or Makefile.am is:
DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl
XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0"
manpage.1: manpage.xml
$(XP) $(DB2MAN) $<
The xsltproc binary is found in the xsltproc package. The XSL files are in
docbook-xsl. A description of the parameters you can use can be found in the
docbook-xsl-doc-* packages. Please remember that if you create the nroff
version in one of the debian/rules file targets (such as build), you will need
to include xsltproc and docbook-xsl in your Build-Depends control field.
Alternatively use the xmlto command/package. That will also automatically
pull in xsltproc and docbook-xsl.
Notes for using docbook2x: docbook2x-man does not automatically create the
AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as
... .
To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections
read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be
found in the docbook-xsl-doc-html package.
Validation can be done using: `xmllint -''-noout -''-valid manpage.xml`
General documentation about man-pages and man-page-formatting:
man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
-->
]>
&dhtitle;&dhpackage;&dhfirstname;&dhsurname;Wrote this manpage for the Debian system.&dhemail;2007&dhusername;This manual page was written for the Debian system
(and may be used by others).Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU General Public License,
Version 2 or (at your option) any later version published by
the Free Software Foundation.On Debian systems, the complete text of the GNU General Public
License can be found in
/usr/share/common-licenses/GPL.&dhucpackage;&dhsection;&dhpackage;program to do something&dhpackage;thisthisthat&dhpackage;DESCRIPTIONThis manual page documents briefly the
&dhpackage; and bar
commands.This manual page was written for the Debian distribution
because the original program does not have a manual page.
Instead, it has documentation in the GNU info1 format; see below.&dhpackage; is a program that...OPTIONSThe program follows the usual GNU command line syntax,
with long options starting with two dashes (`-'). A summary of
options is included below. For a complete description, see the
info1 files.Does this and that.Show summary of options.Show version of program.FILES/etc/foo.confThe system-wide configuration file to control the
behaviour of &dhpackage;. See
foo.conf5 for further details.${HOME}/.foo.confThe per-user configuration file to control the
behaviour of &dhpackage;. See
foo.conf5 for further details.ENVIRONMENTFOO_CONFIf used, the defined file is used as configuration
file (see also ).DIAGNOSTICSThe following diagnostics may be issued
on stderr:Bad configuration file. Exiting.The configuration file seems to contain a broken configuration
line. Use the option, to get more info.
&dhpackage; provides some return codes, that can
be used in scripts:CodeDiagnostic0Program exited successfully.1The configuration file seems to be broken.BUGSThe program is currently limited to only work
with the foobar library.The upstreams BTS can be found
at .SEE ALSObar1, baz1, foo.conf5The programs are documented fully by The Rise and
Fall of a Fooish Bar available via the info1 system.
================================================
FILE: scripts/debian/menu.ex
================================================
?package(xmake):needs="X11|text|vc|wm" section="Applications/see-menu-manual"\
title="xmake" command="/usr/bin/xmake"
================================================
FILE: scripts/debian/postinst.ex
================================================
#!/bin/sh
# postinst script for xmake
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * `configure'
# * `abort-upgrade'
# * `abort-remove' `in-favour'
#
# * `abort-remove'
# * `abort-deconfigure' `in-favour'
# `removing'
#
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0
================================================
FILE: scripts/debian/postrm.ex
================================================
#!/bin/sh
# postrm script for xmake
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * `remove'
# * `purge'
# * `upgrade'
# * `failed-upgrade'
# * `abort-install'
# * `abort-install'
# * `abort-upgrade'
# * `disappear'
#
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0
================================================
FILE: scripts/debian/preinst.ex
================================================
#!/bin/sh
# preinst script for xmake
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * `install'
# * `install'
# * `upgrade'
# * `abort-upgrade'
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
install|upgrade)
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0
================================================
FILE: scripts/debian/prerm.ex
================================================
#!/bin/sh
# prerm script for xmake
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * `remove'
# * `upgrade'
# * `failed-upgrade'
# * `remove' `in-favour'
# * `deconfigure' `in-favour'
# `removing'
#
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0
================================================
FILE: scripts/debian/rules
================================================
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# prefix
prefix=$(CURDIR)/debian/xmake/usr
configure: configure-stamp
configure-stamp:
dh_testdir
touch configure-stamp
build: build-stamp
build-stamp: configure-stamp
dh_testdir
./configure
make
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
mkdir -p $(prefix)/bin
mkdir -p $(prefix)/share
cp -r $(CURDIR)/xmake $(prefix)/share
cp -p $(CURDIR)/build/xmake $(prefix)/bin/xmake
chmod 755 $(prefix)/bin/xmake
cp -p $(CURDIR)/scripts/xrepo.sh $(prefix)/bin/xrepo
chmod 755 $(prefix)/bin/xrepo
distclean: clean
uninstall:
if [ -f /usr/bin/xmake ]; then rm /usr/bin/xmake; fi
if [ -f /usr/bin/xrepo ]; then rm /usr/bin/xrepo; fi
if [ -d /usr/share/xmake ]; then rm -rf /usr/share/xmake; fi
binary-indep: build install
# We have nothing to do by default.
# # Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs $(CURDIR)/CHANGELOG.md
dh_installdocs
dh_installexamples
dh_installman
dh_link
dh_strip
dh_compress
dh_fixperms
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install uninstall configure
================================================
FILE: scripts/debian/source/format
================================================
3.0 (quilt)
================================================
FILE: scripts/debian/watch.ex
================================================
# Example watch control file for uscan
# Rename this file to "watch" and then you can run the "uscan" command
# to check for upstream updates and more.
# See uscan(1) for format
# Compulsory line, this is a version 4 file
version=4
# PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig
#opts="pgpsigurlmangle=s%$%.sig%"
# HTTP site (basic)
#http://example.com/downloads.html \
# files/xmake-([\d\.]+)\.tar\.gz debian uupdate
# Uncommment to examine a FTP server
#ftp://ftp.example.com/pub/xmake-(.*)\.tar\.gz debian uupdate
# SourceForge hosted projects
# http://sf.net/xmake/ xmake-(.*)\.tar\.gz debian uupdate
# GitHub hosted projects
#opts="filenamemangle="s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \
# https://github.com//xmake/tags \
# (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate
# PyPI
# https://pypi.python.org/packages/source//xmake/ \
# xmake-(.+)\.tar\.gz debian uupdate
# Direct Git
# opts="mode=git" http://git.example.com/xmake.git \
# refs/tags/v([\d\.]+) debian uupdate
# Uncomment to find new files on GooglePages
# http://example.googlepages.com/foo.html xmake-(.*)\.tar\.gz
================================================
FILE: scripts/debian/xmake-docs.docs
================================================
README.source
README.Debian
================================================
FILE: scripts/debian/xmake.cron.d.ex
================================================
#
# Regular cron jobs for the xmake package
#
0 4 * * * root [ -x /usr/bin/xmake_maintenance ] && /usr/bin/xmake_maintenance
================================================
FILE: scripts/debian/xmake.default.ex
================================================
# Defaults for xmake initscript
# sourced by /etc/init.d/xmake
# installed at /etc/default/xmake by the maintainer scripts
#
# This is a POSIX shell fragment
#
# Additional options that are passed to the Daemon.
DAEMON_OPTS=""
================================================
FILE: scripts/debian/xmake.doc-base.EX
================================================
Document: xmake
Title: Debian xmake Manual
Author:
Abstract: This manual describes what xmake is
and how it can be used to
manage online manuals on Debian systems.
Section: unknown
Format: debiandoc-sgml
Files: /usr/share/doc/xmake/xmake.sgml.gz
Format: postscript
Files: /usr/share/doc/xmake/xmake.ps.gz
Format: text
Files: /usr/share/doc/xmake/xmake.text.gz
Format: HTML
Index: /usr/share/doc/xmake/html/index.html
Files: /usr/share/doc/xmake/html/*.html
================================================
FILE: scripts/get.ps1
================================================
#!/usr/bin/env pwsh
#Requires -version 5
# xmake getter
# usage: (in powershell)
# Invoke-Expression (Invoke-Webrequest -UseBasicParsing).Content
param (
[string]$version = "master",
[string]$installdir = ""
)
& {
$LastRelease = "v3.0.7"
$ErrorActionPreference = 'Stop'
function writeErrorTip($msg) {
Write-Host $msg -BackgroundColor Red -ForegroundColor White
}
if (-not $env:CI) {
$logo = @(
' _ '
' __ ___ __ __ __ _| | ______ '
' \ \/ / | \/ |/ _ | |/ / __ \ '
' > < | \__/ | /_| | < ___/ '
' /_/\_\_|_| |_|\__ \|_|\_\____| getter '
' '
' ')
Write-Host $([string]::Join("`n", $logo)) -ForegroundColor Green
}
if ($IsLinux -or $IsMacOS) {
writeErrorTip 'Install on *nix is not supported, try '
writeErrorTip '(Use curl) "curl -fsSL https://xmake.io/shget.text | bash"'
writeErrorTip 'or'
writeErrorTip '(Use wget) "wget https://xmake.io/shget.text -O - | bash"'
throw 'Unsupported platform'
}
$temppath = ([System.IO.Path]::GetTempPath(), $env:TMP, $env:TEMP, "$(Get-Location)" -ne $null)[0]
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
if ($null -eq $installdir -or $installdir -match '^\s*$') {
$installdir = & {
# Install to old xmake path
$oldXmake = Get-Command xmake -CommandType Application -ErrorAction SilentlyContinue
if ($oldXmake) {
return Split-Path $oldXmake.Path -Parent
}
if ($HOME) {
return Join-Path $HOME 'xmake'
}
if ($env:APPDATA) {
return Join-Path $env:APPDATA 'xmake'
}
if ($env:ProgramFiles) {
return Join-Path $env:ProgramFiles 'xmake'
}
return 'C:\xmake'
}
}
$installdir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($installdir)
if ($null -eq $version -or $version -match '^\s*$') {
$v = 'master'
} else {
$v = $version.Trim()
if ($v.Contains('.')) {
$v = [version]::Parse($version)
$v = New-Object -TypeName version -ArgumentList $v.Major, $v.Minor, $v.Build
}
}
function checkTempAccess {
$outfile = Join-Path $temppath "$pid.tmp"
try {
Write-Output $pid | Out-File -FilePath $outfile
Remove-Item $outfile
} catch {
writeErrorTip 'Cannot write to temp path'
writeErrorTip 'Please set environment var "TMP" to another path'
throw
}
}
function xmakeInstall {
$outfile = Join-Path $temppath "$pid-xmake-installer.exe"
$x64arch = @('AMD64', 'IA64')
$arch = if ($env:PROCESSOR_ARCHITECTURE -in $x64arch -or $env:PROCESSOR_ARCHITEW6432 -in $x64arch) { 'x64' } else { 'x86' }
$winarch = if ($env:PROCESSOR_ARCHITECTURE -in $x64arch -or $env:PROCESSOR_ARCHITEW6432 -in $x64arch) { 'win64' } else { 'win32' }
if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') {
Write-Host "Unsupported host architecture detected: ARM64."
}
$url = if ($v -is [version]) {
"https://github.com/xmake-io/xmake/releases/download/v$v/xmake-v$v.$winarch.exe"
} else {
"https://github.com/xmake-io/xmake/releases/download/$LastRelease/xmake-$v.$winarch.exe"
}
Write-Host "Start downloading $url .."
try {
Invoke-Webrequest $url -OutFile $outfile -UseBasicParsing
} catch {
writeErrorTip 'Download failed!'
writeErrorTip 'Check your network or... the news of S3 break'
throw
}
Write-Host 'Start installation... Hope your antivirus doesn''t trouble'
Write-Host "Install to $installdir"
try {
$adminflag = "/NOADMIN "
try {
$tempfolder = New-Item "$installdir-$PID-temp" -ItemType Directory
Remove-Item $tempfolder.FullName
} catch {
$adminflag = ""
}
Start-Process -FilePath $outfile -ArgumentList "$adminflag/S /D=$installdir" -Wait
} catch {
writeErrorTip 'Install failed!'
writeErrorTip 'Close your antivirus then try again'
throw
} finally {
Remove-Item $outfile -ErrorAction SilentlyContinue
}
Write-Host 'Adding to PATH... almost done'
$env:Path += ";$installdir"
try {
xmake --version
} catch {
writeErrorTip 'Everything is showing installation has finished'
writeErrorTip 'But xmake could not run... Why?'
throw
}
}
function registerTabCompletion {
# TODO: add --global --user choice
Write-Host "Tab completion service"
try {
xmake update --integrate
} catch {
writeErrorTip "Failed to register tab completion!"
writeErrorTip 'Please try "xmake update --integrate" to register manually.'
return
}
Write-Host "Tab completion installed"
}
checkTempAccess
xmakeInstall
if (-not $env:CI) {
registerTabCompletion
} else {
Write-Host "Tab completion registration has been skipped for CI"
}
}
================================================
FILE: scripts/get.sh
================================================
#!/usr/bin/env bash
# xmake getter
# usage: bash <(curl -s ) [branch|__local__|__run__] [commit/__install_only__]
set -o pipefail
#-----------------------------------------------------------------------------
# some helper functions
#
raise() {
echo "$@" 1>&2 ; exit 1
}
test_z() {
if test "x${1}" = "x"; then
return 0
fi
return 1
}
test_nz() {
if test "x${1}" != "x"; then
return 0
fi
return 1
}
test_eq() {
if test "x${1}" = "x${2}"; then
return 0
fi
return 1
}
test_nq() {
if test "x${1}" != "x${2}"; then
return 0
fi
return 1
}
#-----------------------------------------------------------------------------
# prepare
#
# print a LOGO!
echo 'xmake, A cross-platform build utility based on Lua. '
echo 'Copyright (C) 2015-present Ruki Wang, https://xmake.io'
echo ' _ '
echo ' __ ___ __ __ __ _| | ______ '
echo ' \ \/ / | \/ |/ _ | |/ / __ \ '
echo ' > < | \__/ | /_| | < ___/ '
echo ' /_/\_\_|_| |_|\__ \|_|\_\____| '
echo ' by ruki, xmake.io '
echo ' '
echo ' 👉 Manual: https://xmake.io/guide/quick-start '
echo ' 🙏 Donate: https://xmake.io/about/sponsor '
echo ' '
# has sudo?
if [ 0 -ne "$(id -u)" ]; then
if sudo --version >/dev/null 2>&1
then
sudoprefix=sudo
else
sudoprefix=
fi
else
export XMAKE_ROOT=y
sudoprefix=
fi
# make tmpdir
if [ -z "$TMPDIR" ]; then
tmpdir=/tmp/.xmake_getter$$
else
tmpdir=$TMPDIR/.xmake_getter$$
fi
if [ -d $tmpdir ]; then
rm -rf $tmpdir
fi
# get make
if gmake --version >/dev/null 2>&1
then
make=gmake
else
make=make
fi
remote_get_content() {
if curl --version >/dev/null 2>&1
then
curl -fSL "$1"
elif wget --version >/dev/null 2>&1 || wget --help >/dev/null 2>&1
then
wget "$1" -O -
fi
}
get_host_speed() {
if [ `uname` == "Darwin" ]; then
ping -c 1 -t 1 $1 2>/dev/null | egrep -o 'time=\d+' | egrep -o "\d+" || echo "65535"
else
ping -c 1 -W 1 $1 2>/dev/null | grep -E -o 'time=[0-9]+' | grep -E -o "[0-9]+" || echo "65535"
fi
}
get_fast_host() {
if test_eq "$GITHUB_ACTIONS" "true" || test_eq "$GITHUB_ACTIONS" "1"; then
echo "github.com"
else
speed_gitee=$(get_host_speed "gitee.com")
speed_github=$(get_host_speed "github.com")
if [ $speed_gitee -le $speed_github ]; then
echo "gitee.com"
else
echo "github.com"
fi
fi
}
# get branch
branch=__run__
if test_nz "$1"; then
brancharr=($1)
if [ ${#brancharr[@]} -eq 1 ]
then
branch=${brancharr[0]}
fi
echo "Branch: $branch"
fi
# get fasthost and git repository
if test_nq "$branch" "__local__"; then
fasthost=$(get_fast_host)
if test_eq "$fasthost" "gitee.com"; then
gitrepo="https://gitee.com/tboox/xmake.git"
gitrepo_raw="https://gitee.com/tboox/xmake/raw/master"
else
gitrepo="https://github.com/xmake-io/xmake.git"
#gitrepo_raw="https://github.com/xmake-io/xmake/raw/master"
gitrepo_raw="https://fastly.jsdelivr.net/gh/xmake-io/xmake@master"
fi
fi
#-----------------------------------------------------------------------------
# install tools
#
test_tools() {
prog='#include \nint main(){return 0;}'
{
git --version &&
$make --version &&
{
echo -e "$prog" | cc -xc - -o /dev/null ||
echo -e "$prog" | gcc -xc - -o /dev/null ||
echo -e "$prog" | clang -xc - -o /dev/null ||
echo -e "$prog" | cc -xc -c - -o /dev/null -I/usr/include -I/usr/local/include ||
echo -e "$prog" | gcc -xc -c - -o /dev/null -I/usr/include -I/usr/local/include ||
echo -e "$prog" | clang -xc -c - -o /dev/null -I/usr/include -I/usr/local/include
}
} >/dev/null 2>&1
}
install_tools() {
{ apt --version >/dev/null 2>&1 && $sudoprefix apt install -y git build-essential libreadline-dev; } ||
{ dnf --version >/dev/null 2>&1 && $sudoprefix dnf install -y git readline-devel bzip2 @development-tools; } ||
{ yum --version >/dev/null 2>&1 && $sudoprefix yum install -y git readline-devel bzip2 && $sudoprefix yum groupinstall -y 'Development Tools'; } ||
{ zypper --version >/dev/null 2>&1 && $sudoprefix zypper --non-interactive install git readline-devel && $sudoprefix zypper --non-interactive install -t pattern devel_C_C++; } ||
{ pacman -V >/dev/null 2>&1 && $sudoprefix pacman -S --noconfirm --needed git base-devel ncurses readline; } ||
{ emerge -V >/dev/null 2>&1 && $sudoprefix emerge -atv dev-vcs/git; } ||
{ pkg list-installed >/dev/null 2>&1 && $sudoprefix pkg install -y git getconf build-essential readline; } || # termux
{ pkg help >/dev/null 2>&1 && $sudoprefix pkg install -y git readline ncurses; } || # freebsd
{ nix-env --version >/dev/null 2>&1 && nix-env -i git gcc readline ncurses; } || # nixos
{ apk --version >/dev/null 2>&1 && $sudoprefix apk add git gcc g++ make readline-dev ncurses-dev libc-dev linux-headers; } ||
{ xbps-install --version >/dev/null 2>&1 && $sudoprefix xbps-install -Sy git base-devel; } #void
}
test_tools || { install_tools && test_tools; } || raise "$(echo -e 'Dependencies Installation Fail\nThe getter currently only support these package managers\n\t* apt\n\t* dnf\n\t* yum\n\t* zypper\n\t* pacman\n\t* portage\n\t* xbps\n Please install following dependencies manually:\n\t* git\n\t* build essential like `make`, `gcc`, etc\n\t* libreadline-dev (readline-devel)')" 1
#-----------------------------------------------------------------------------
# install xmake
#
projectdir=$tmpdir
if test_eq "$branch" "__local__"; then
if [ -d '.git' ]; then
git submodule update --init --recursive
fi
cp -r . $projectdir
elif test_eq "$branch" "__run__"; then
version=$(git ls-remote --tags "$gitrepo" | tail -c7)
pack=gz
mkdir -p $projectdir
runfile_url="https://fastly.jsdelivr.net/gh/xmake-mirror/xmake-releases@$version/xmake-$version.$pack.run"
echo "downloading $runfile_url .."
remote_get_content "$runfile_url" > $projectdir/xmake.run
if [[ $? != 0 ]]; then
runfile_url="https://github.com/xmake-io/xmake/releases/download/$version/xmake-$version.$pack.run"
echo "downloading $runfile_url .."
remote_get_content "$runfile_url" > $projectdir/xmake.run
fi
sh $projectdir/xmake.run --noexec --quiet --target $projectdir
else
echo "cloning $gitrepo $branch .."
if test_nz "$2"; then
git clone --filter=tree:0 --no-checkout -b "$branch" "$gitrepo" --recurse-submodules $projectdir || raise "clone failed, check your network or branch name"
cd $projectdir || raise 'chdir failed!'
git checkout -qf "$2"
cd - || raise 'chdir failed!'
else
git clone --depth=1 -b "$branch" "$gitrepo" --recurse-submodules $projectdir || raise "clone failed, check your network or branch name"
fi
fi
# do build
if test_nq "$2" "__install_only__"; then
if [ -f "$projectdir/configure" ]; then
cd $projectdir || raise 'chdir failed!'
./configure || raise "configure failed!"
cd - || raise 'chdir failed!'
fi
$make -C $projectdir --no-print-directory -j4 || raise "make failed!"
fi
# do install
if test_z "$prefix"; then
prefix=~/.local
fi
if test_nz "$prefix"; then
$make -C $projectdir --no-print-directory install PREFIX="$prefix" || raise "install failed!"
else
$sudoprefix $make -C $projectdir --no-print-directory install || raise "install failed!"
fi
#-----------------------------------------------------------------------------
# install profile
#
install_profile() {
export XMAKE_ROOTDIR="$prefix/bin"
[[ "$PATH" =~ (^|:)"$XMAKE_ROOTDIR"(:|$) ]] || export PATH="$XMAKE_ROOTDIR:$PATH"
xmake --version
xmake update --integrate
}
install_profile
================================================
FILE: scripts/makeppa
================================================
#!/usr/bin/env bash
# check
if [ $# -lt 1 ]; then
echo "Usage: ./scripts/makeppa [serie] [patch]"
exit
fi
# workdir
workdir=./xmake-ppa
if [ ! -d $workdir ]; then
mkdir $workdir
fi
# version
version=`cat ./core/xmake.lua | grep -E "^set_version" | grep -oE "[0-9]*\.[0-9]*\.[0-9]*"`
# serie, e.g. groovy, focal, bionic, xenial, trusty, precise
serie="$1"
if [ -z $serie ]; then
serie=xenial
fi
# patch number
patch="$2"
if [ -z $patch ]; then
patch=1
fi
# tarball
basename=xmake-$version+$patch$serie
tarball=$workdir/$basename.tar.gz
if [ ! -f $tarball ]; then
cd core
xmake pack --autobuild=n -y --formats=srctargz --basename=xmake -o ../artifacts xmakesrc || exit -1
cd ..
cp ./artifacts/xmake.tar.gz $tarball
fi
# extract tarball
cd $workdir
if [ -d xmakesrc ]; then
rm -rf xmakesrc
fi
if [ ! -d $basename ]; then
mkdir xmakesrc
tar -xvf $basename.tar.gz -C xmakesrc
mv xmakesrc/xmake-$version $basename
fi
# enter project directory
cd $basename
# make template
echo "making template .."
if [ -d debian ]; then
rm -rf debian
fi
export USER=`id -u -n`
dh_make -e waruqi@gmail.com -c apache -y -s -f ../$basename.tar.gz
# copy debian
echo "instaling debian .."
if [ -d debian ]; then
rm -rf debian
fi
cp -r ../../scripts/debian .
# update changelog
rm debian/changelog
dch -v $version+$patch$serie "update $version" -D $serie --create --package xmake -M $USER
cat debian/changelog
# build package
echo "building package .."
debuild -S -k02713554FA2CE4AADA20AB23167A22F22C0C68C9
# check package
echo "checking package .."
lintian ../xmake_$version+$patch$serie.dsc
# upload package
echo "uploading package .."
source=xmake_$version+"$patch$serie"_source
if [ -f ../$source.ppa.upload ]; then
rm ../$source.ppa.upload
fi
dput ppa:xmake-io/xmake ../$source.changes
# remove workdir
cd ../..
rm -rf xmake-ppa
# install dh-make and gpg
# sudo apt install dh-make rng-tools
#
# @see https://help.ubuntu.com/community/GnuPrivacyGuardHowto
#
# generate key
# gpg --gen-key
#
# save public/private key
# gpg -a --export 2C0C68C9 > /mnt/xmake_ppa_pgp.pub
# gpg -a --export-secret-keys 2C0C68C9 > /mnt/xmake_ppa_pgp.sec
#
# submit to keykserver and import this key to launchpad.net
# @see https://launchpad.net/+help-registry/import-pgp-key.html
# gpg --send-keys --keyserver keyserver.ubuntu.com 2C0C68C9
#
# recv email and validate this gpg key
# gpg --decrypt file.txt
# goto link
#
# show gpg
# gpg --fingerprint
# pub 2048R/2C0C68C9 2020-09-08
# Key fingerprint = 0271 3554 FA2C E4AA DA20 AB23 167A 22F2 2C0C 68C9
#
# build package and upload ppa to launchpad.net
# https://launchpad.net/~xmake-io/+archive/ubuntu/xmake
#
# recv and import key on ubuntu
# gpg --keyserver keyserver.ubuntu.com --recv 2C0C68C9
# gpg --export --armor 2C0C68C9 | sudo apt-key add -
#
# show long key
# gpg --keyid-format long --list-keys waruqi@gmail.com
#
================================================
FILE: scripts/man/xmake.1
================================================
.TH "xmake" "1"
.SH NAME
xmake \- cross-platform build utility based on Lua
.SH SYNOPSIS
.B xmake
.RI [ task "] [" options "] [" target ]
.SH DESCRIPTION
.B xmake
is a lightweight cross-platform build utility based on Lua. It uses
.I xmake.lua
to maintain project builds. Compared with
.IR makefile / CMakeLists.txt ,
the configuration syntax is more concise and intuitive. It is very friendly to
novices and can quickly get started in a short time. Let users focus more on
actual project development.
.SH ACTIONS
.TP
.B b, build
Build targets if no given tasks.
.TP
.B u, uninstall
Uninstall the project binary files.
.TP
.B p, package
Package target.
.TP
.B r, run
Run the project target.
.TP
.B g, global
Configure the global options for xmake.
.TP
.B i, install
Package and install the target binary files.
.TP
.B c, clean
Remove all binary and temporary files.
.TP
.B create
Create a new project.
.TP
.B q, require
Install and update required packages.
.TP
.B update
Update and uninstall the xmake program.
.TP
.B f, config
Configure the project.
.SH PLUGINS
.TP
.B plugin
Manage plugins of xmake.
.TP
.B m, macro
Run the given macro.
.TP
.B doxygen
Generate the doxygen document.
.TP
.B l, lua
Run the lua script.
.TP
.B repo
Manage package repositories.
.TP
.B service
Start service for remote or distributed compilation and etc. (Experimental, still in development)
.TP
.B project
Generate the project file.
.TP
.B show
Show the given project information.
.SH OPTIONS
.TP
.B \-q, \-\-quiet
Quiet operation.
.TP
.B \-y, \-\-yes
Input yes by default if need user confirm.
.TP
.BR \-\-confirm =\fICONFIRM
Input the given result if need user confirm.
\- yes
\- no
\- def
.TP
.B \-v, \-\-verbose
Print lots of verbose information for users.
.TP
.B \-\-root
Allow one to run xmake as root.
.TP
.B \-D, \-\-diagnosis
Print lots of diagnosis information (backtrace, check info ..) only for developers.
And we can append \fB\-v\fR to get more whole information.
e.g. $ xmake \-vD
.TP
.B \-\-version
Print the version number and exit.
.TP
.B \-h, \-\-help
Print this help message and exit.
.TP
.BI \-F " FILE" ", \-\-file\fR=" FILE
Read a given
.B xmake.lua
file.
.TP
.BI \-P " PROJECT" ", \-\-project\fR=" PROJECT
Change to the given project directory.
Search priority:
1. The Given Command Argument
2. The Environment Variable: \fBXMAKE_PROJECT_DIR\fR
3. The Current Directory
.SH BUILD OPTIONS
.TP
.B \-b, \-\-build
Build target. This is default building mode and optional.
.TP
.B \-r, \-\-rebuild
Rebuild the target.
.TP
.B \-a, \-\-all
Build all targets.
.TP
.B \-\-dry\-run
Dry run to build target.
.TP
.BI \-j " JOBS" ", \-\-jobs\fR=" JOBS
Specifies the number of jobs to build simultaneously. (default: 6)
.TP
.B \-w, \-\-warning
Enable the warnings output.
.TP
.BI \-\-files= FILES
Build the given source files.
e.g.
.RS
.EX
\- xmake \-\-files=src/main.c
\- xmake \-\-files='src/*.c' [target]
\- xmake \-\-files='src/**c|excluded_file.c'
\- xmake \-\-files='src/main.c:src/test.c'
.EE
.RE
.TP
.B target
The target name. It will build all default targets if this parameter is not specified.
.SH AUTHOR
.B xmake
is written by
.MT waruqi@\:gmail.com
ruki
.ME .
This manual page was written by
.MT mmyangfl@\:gmail.com
Yangfl
.ME
for the Debian Project (and may be used by others).
================================================
FILE: scripts/man/xrepo.1
================================================
.TH "xrepo" "1"
.SH NAME
xrepo \- cross-platform build utility based on Lua
.SH SYNOPSIS
.B xrepo
.RI [ action "] [" options ]
.SH DESCRIPTION
.B xrepo
is a lightweight cross-platform build utility based on Lua. It uses
.I xrepo.lua
to maintain project builds. Compared with
.IR makefile / CMakeLists.txt ,
the configuration syntax is more concise and intuitive. It is very friendly to
novices and can quickly get started in a short time. Let users focus more on
actual project development.
.SH ACTIONS
.TP
.B clean
Clear all package caches and remove all not\-referenced packages.
.TP
.B env
Set environment and execute command, or print environment.
.TP
.B export
Export the given packages.
.TP
.B fetch
Fetch library information of the given installed packages.
.TP
.B import
Import the given packages.
.TP
.B info
Show information of the given packages.
.TP
.B install
Install the given packages.
.TP
.B remove
Remove the given packages.
.TP
.B scan
Scan the given or all installed packages.
.TP
.B search
Search the given packages.
.TP
.B add\-repo
Add the given remote repository url.
.TP
.B list\-repo
List all remote repositories.
.TP
.B rm\-repo
Remove the given remote repository.
.TP
.B update\-repo
Update all local repositories from remote.
.SH OPTIONS
.TP
.B \-q, \-\-quiet
Quiet operation.
.TP
.B \-y, \-\-yes
Input yes by default if need user confirm.
.TP
.B \-\-root
Allow one to run xrepo as root.
.TP
.B \-v, \-\-verbose
Print lots of verbose information for users.
.TP
.B \-D, \-\-diagnosis
Print lots of diagnosis information.
.TP
.B \-\-version
Print the version number and exit.
.TP
.B \-h, \-\-help
Print this help message and exit.
.SH AUTHOR
.B xrepo
is written by
.MT waruqi@\:gmail.com
ruki
.ME .
This manual page was written by
.MT mmyangfl@\:gmail.com
Yangfl
.ME
for the Debian Project (and may be used by others).
================================================
FILE: scripts/msys/xmake.cmd
================================================
@echo off
setlocal
set BASEDIR=%~dp0
if exist "%BASEDIR%..\share\xmake\xmake.exe" (
"%BASEDIR%..\share\xmake\xmake.exe" %*
)
endlocal
================================================
FILE: scripts/msys/xmake.ps1
================================================
$BASEDIR = Split-Path -Parent $MyInvocation.MyCommand.Definition
if (Test-Path "$BASEDIR\..\share\xmake\xmake.exe") {
& "$BASEDIR\..\share\xmake\xmake.exe" @args
}
================================================
FILE: scripts/msys/xmake.sh
================================================
#!/usr/bin/env bash
BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$BASEDIR/../share/xmake/xmake.exe" ]; then
$BASEDIR/../share/xmake/xmake.exe "$@"
fi
================================================
FILE: scripts/rpmbuild/0001-use-static-libsv-and-tbox.patch
================================================
diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh
index dc45ecbca..d0e0d0069 100755
--- a/core/src/xmake/xmake.sh
+++ b/core/src/xmake/xmake.sh
@@ -6,6 +6,8 @@ target "xmake"
# add deps
if has_config "external"; then
+ add_deps "sv"
+ add_deps "tbox"
local libs="lz4 sv tbox"
for lib in $libs; do
if has_config "$lib"; then
diff --git a/core/xmake.sh b/core/xmake.sh
index 2ae2e686b..6ea8c1b69 100755
--- a/core/xmake.sh
+++ b/core/xmake.sh
@@ -214,6 +214,9 @@ if ! has_config "external"; then
includes "src/lz4"
includes "src/sv"
includes "src/tbox"
+else
+ includes "src/sv"
+ includes "src/tbox"
fi
includes "src/xmake"
includes "src/cli"
================================================
FILE: scripts/rpmbuild/xmake.spec
================================================
%global debug_package %{nil}
%define use_luajit 0
%undefine __brp_mangle_shebangs
Name: xmake
Version: 3.0.7
Release: 1%{?dist}
Summary: A cross-platform build utility based on Lua
# Application and 3rd-party modules licensing:
# * xmake - Apache-2.0 -- Main tarball;
# * libsv - Public Domain -- static dependency;
# * tbox - Apache-2.0 -- static dependency;
# * xxHash - BSD -- static dependency;
License: Apache-2.0 AND LicenseRef-Fedora-Public-Domain AND BSD
URL: https://xmake.io
Source0: https://github.com/xmake-io/xmake/releases/download/v%{version}/%{name}-v%{version}.tar.gz
Patch0: 0001-use-static-libsv-and-tbox.patch
BuildRequires: pkgconfig(ncurses)
BuildRequires: pkgconfig(liblz4)
%if %{use_luajit}
BuildRequires: pkgconfig(luajit)
%else
BuildRequires: pkgconfig(lua) >= 5.4
%endif
BuildRequires: gcc
BuildRequires: gcc-c++
# Virtual provides for bundled libraries
Provides: bundled(libsv) = 0.0.1
Provides: bundled(libtbox) = 1.7.3
%description
xmake is a lightweight cross-platform build utility based on Lua.
It uses xmake.lua to maintain project builds. Compared with makefile/CMakeLists.txt,
the configuration syntax is more concise and intuitive.
It is very friendly to novices and can quickly get started in a short time.
Let users focus more on actual project development.
It can compile the project directly like Make/Ninja, or
generate project files like CMake/Meson, and it also has a built-in package management
system to help users solve the integrated use of C/C++ dependent libraries.
%prep
%autosetup -n %{name}-%{version} -p1
# Cleanup bundled deps
rm -rf core/src/{lua,luajit,lua-cjson,lz4,pdcurses}/*/
%build
%set_build_flags
%if %{use_luajit}
%configure --external=y --runtime=luajit
%else
%configure --external=y --runtime=lua
%endif
%make_build
%install
mkdir -p %{buildroot}%{_mandir}/man1/
install -Dpm0755 build/xmake \
%{buildroot}%{_bindir}/%{name}
install -Dpm0755 scripts/xrepo.sh \
%{buildroot}%{_bindir}/xrepo
install -Dpm0644 scripts/man/*1 \
%{buildroot}%{_mandir}/man1/
install -Dpm0644 xmake/scripts/completions/register-completions.bash \
%{buildroot}%{_datadir}/bash-completion/completions/xmake
install -Dpm0644 xmake/scripts/completions/register-completions.fish \
%{buildroot}%{_datadir}/fish/vendor_completions.d/xmake.fish
install -Dpm0644 xmake/scripts/completions/register-completions.zsh \
%{buildroot}%{_datadir}/zsh/site-functions/xmake
cp -rp xmake \
%{buildroot}%{_datadir}/xmake
%check
%{buildroot}%{_bindir}/%{name} --version
%{buildroot}%{_bindir}/xrepo --version
%files
%doc README.md CHANGELOG.md
%license LICENSE.md NOTICE.md
%{_bindir}/%{name}
%{_bindir}/xrepo
%{_datadir}/%{name}
%{_datadir}/bash-completion/completions/xmake
%{_datadir}/zsh/site-functions/xmake
%{_datadir}/fish/vendor_completions.d/xmake.fish
%{_mandir}/man1/*.1*
%changelog
* Tue Jul 11 2023 Zephyr Lykos - 2.8.1-1
- Update to 2.8.1
* Sun Jun 04 2023 Zephyr Lykos - 2.7.9-1
- Switch to release tarball
- Use system provided libs if possible
- Fix docs & manpage installation
- Install shell completions
* Sun Oct 18 2020 Ruki Wang - 2.3.8-1
- v2.3.8 released
* Mon Sep 14 2020 Ruki Wang - 2.3.7-1
- Initial Commit
================================================
FILE: scripts/srcenv.bat
================================================
@echo off
setlocal
set script_dir=%~dp0
set PATH=%script_dir%..\core\build;%cd%;%PATH%
set XMAKE_PROGRAM_DIR=%script_dir%..\xmake
set XMAKE_PROGRAM_FILE=%script_dir%..\core\build\xmake.exe
start cmd /k cd %script_dir%..\
endlocal
================================================
FILE: scripts/srcenv.profile
================================================
# cd projectdir
xmake_binaries=(
"build/xmake"
"build/xmake.exe"
"core/build/xmake"
"core/build/xmake.exe"
)
export XMAKE_PROGRAM_DIR=`pwd`/xmake
xmake_found=0
for xmake_binary in "${xmake_binaries[@]}"; do
if [[ -x "$xmake_binary" ]] && ("$xmake_binary" --version); then
xmake_found=1
break
fi
done
if [ $xmake_found -eq 0 ]; then
unset xmake_binaries xmake_binary xmake_found
echo "Error: Cannot find a working xmake executable"
return 1
fi
alias xmake=`pwd`/$xmake_binary
export XMAKE_PROGRAM_FILE=`pwd`/$xmake_binary
alias xrepo=`pwd`/scripts/xrepo.sh
unset xmake_binaries xmake_binary xmake_found
xmake l xmake.programdir
xmake l xmake.programfile
================================================
FILE: scripts/srcenv.ps1
================================================
$xmake_root = (Split-Path $PSScriptRoot -Parent)
$env:PATH = "$xmake_root\core\build;$pwd;$env:PATH"
$env:XMAKE_PROGRAM_FILE = "$xmake_root\core\build\xmake.exe"
$env:XMAKE_PROGRAM_DIR = "$xmake_root\xmake"
Set-Location "$xmake_root"
Start-Process powershell
================================================
FILE: scripts/xrepo.bat
================================================
@set "XMAKE_ROOTDIR=%~dp0"
@if not defined XMAKE_PROGRAM_FILE (
@set "XMAKE_PROGRAM_FILE=%XMAKE_ROOTDIR%xmake.exe"
)
@if [%1]==[env] (
if [%2]==[quit] (
if defined XMAKE_PROMPT_BACKUP (
call %XMAKE_ENV_BACKUP%
setlocal EnableDelayedExpansion
if !errorlevel! neq 0 exit /B !errorlevel!
endlocal
set "PROMPT=%XMAKE_PROMPT_BACKUP%"
set XMAKE_ENV_BACKUP=
set XMAKE_PROMPT_BACKUP=
)
goto :ENDXREPO
)
if [%2]==[shell] (
if defined XMAKE_PROMPT_BACKUP (
call %XMAKE_ENV_BACKUP%
setlocal EnableDelayedExpansion
if !errorlevel! neq 0 exit /B !errorlevel!
"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info config
if !errorlevel! neq 0 (
exit /B !errorlevel!
)
@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info prompt 1>nul
if !errorlevel! neq 0 (
echo error: xmake.lua not found^^!
exit /B !errorlevel!
)
endlocal
set "PROMPT=%XMAKE_PROMPT_BACKUP%"
set XMAKE_ENV_BACKUP=
set XMAKE_PROMPT_BACKUP=
echo Please rerun `xrepo env shell` to enter the environment.
exit /B 1
) else (
setlocal EnableDelayedExpansion
"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info config
if !errorlevel! neq 0 (
exit /B !errorlevel!
)
@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env | findstr . && (
echo error: corrupt xmake.lua detected in the current directory^^!
exit /B 1
)
@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info prompt 1>nul
if !errorlevel! neq 0 (
echo error: xmake.lua not found^^!
exit /B !errorlevel!
)
endlocal
for /f %%i in ('@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info prompt') do @(
@set "PROMPT=%%i %PROMPT%"
)
@set "XMAKE_PROMPT_BACKUP=%PROMPT%"
)
for /f %%i in ('@"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info envfile') do @(
@set "XMAKE_ENV_BACKUP=%%i.bat"
@"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info backup.cmd 1>"%%i.bat"
)
for /f %%i in ('@"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info envfile') do @(
@"%XMAKE_PROGRAM_FILE%" lua private.xrepo.action.env.info script.cmd 1>"%%i.bat"
call "%%i.bat"
)
goto :ENDXREPO
)
set XREPO_BIND_FLAG=
if [%2]==[-b] if [%4]==[shell] (
set XREPO_BIND_FLAG=1
)
if [%2]==[--bind] if [%4]==[shell] (
set XREPO_BIND_FLAG=1
)
if defined XREPO_BIND_FLAG (
set XREPO_BIND_FLAG=
if defined XMAKE_PROMPT_BACKUP (
call %XMAKE_ENV_BACKUP%
setlocal EnableDelayedExpansion
if !errorlevel! neq 0 exit /B !errorlevel!
endlocal
set "PROMPT=%XMAKE_PROMPT_BACKUP%"
set XMAKE_ENV_BACKUP=
set XMAKE_PROMPT_BACKUP=
echo Please rerun `xrepo env %2 %3 shell` to enter the environment.
exit /B 1
) else (
pushd %XMAKE_ROOTDIR%
setlocal EnableDelayedExpansion
%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info config %3
if !errorlevel! neq 0 (
popd
exit /B !errorlevel!
)
@%XMAKE_PROGRAM_FILE% lua --quiet private.xrepo.action.env.info prompt %3 1>nul
if !errorlevel! neq 0 (
popd
echo error: environment not found^^!
exit /B !errorlevel!
)
endlocal
for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua --quiet private.xrepo.action.env.info prompt %3') do @(
@set "PROMPT=%%i %PROMPT%"
)
@set "XMAKE_PROMPT_BACKUP=%PROMPT%"
)
for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info envfile %3') do @(
@set "XMAKE_ENV_BACKUP=%%i.bat"
@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info backup.cmd %3 1>"%%i.bat"
)
for /f %%i in ('@%XMAKE_PROGRAM_FILE% lua private.xrepo.action.env.info envfile %3') do @(
@"%XMAKE_PROGRAM_FILE%" lua --quiet private.xrepo.action.env.info script.cmd %3 1>"%%i.bat"
call "%%i.bat"
)
popd
goto :ENDXREPO
)
)
@call "%XMAKE_PROGRAM_FILE%" lua private.xrepo %*
:ENDXREPO
================================================
FILE: scripts/xrepo.ps1
================================================
$script:SCRIPT_PATH = $myinvocation.mycommand.path
$script:BASE_DIR = Split-Path $SCRIPT_PATH -Parent
$Env:XMAKE_PROGRAM_FILE = Join-Path $BASE_DIR xmake.exe
if ($Args.Count -eq 0) {
# No args, just call the underlying xmake executable.
& $Env:XMAKE_PROGRAM_FILE lua private.xrepo;
} else {
$Command = $Args[0];
if (($Command -eq "env") -and ($Args.Count -ge 2)) {
switch ($Args[1]) {
"shell" {
if (-not (Test-Path 'Env:XMAKE_ROOTDIR')) {
$Env:XMAKE_ROOTDIR = $BASE_DIR;
Import-Module "$Env:XMAKE_ROOTDIR\scripts\xrepo-hook.psm1";
Add-XrepoEnvironmentToPrompt;
}
if ((Test-Path 'Env:XMAKE_PROMPT_MODIFIER') -and ($Env:XMAKE_PROMPT_MODIFIER -ne "")) {
Exit-XrepoEnvironment;
}
Enter-XrepoEnvironment $Null;
return;
}
"quit" {
Exit-XrepoEnvironment;
return;
}
{$_ -in "-b", "--bind"} {
if (($Args.Count -ge 4) -and ($Args[3] -eq "shell")) {
if (-not (Test-Path 'Env:XMAKE_ROOTDIR')) {
$Env:XMAKE_ROOTDIR = $BASE_DIR;
Import-Module "$Env:XMAKE_ROOTDIR\scripts\xrepo-hook.psm1";
Add-XrepoEnvironmentToPrompt;
}
if ((Test-Path 'Env:XMAKE_PROMPT_MODIFIER') -and ($Env:XMAKE_PROMPT_MODIFIER -ne "")) {
Exit-XrepoEnvironment;
}
Enter-XrepoEnvironment $Args[2];
return;
}
}
}
}
& $Env:XMAKE_PROGRAM_FILE lua private.xrepo $Args;
}
================================================
FILE: scripts/xrepo.sh
================================================
#!/usr/bin/env bash
BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -f "$BASEDIR/xmake" ]; then
$BASEDIR/xmake lua private.xrepo "$@"
else
xmake lua private.xrepo "$@"
fi
================================================
FILE: tests/actions/config/.gitignore
================================================
test
================================================
FILE: tests/actions/config/test.lua
================================================
function test_workdir(t)
os.tryrm("test")
os.tryrm("build")
os.tryrm("build2")
os.tryrm(".xmake")
os.exec("xmake create test")
os.exec("xmake config -P test")
os.exec("xmake")
t:require(os.isdir("build"))
t:require(os.isdir(".xmake"))
t:require_not(os.isdir("test/build"))
t:require_not(os.isdir("test/.xmake"))
os.exec("xmake config -o build2")
os.exec("xmake")
t:require(os.isdir("build2"))
os.tryrm("build")
os.tryrm("build2")
os.tryrm(".xmake")
os.cd("test")
os.exec("xmake create -P subtest")
os.cd("subtest")
os.exec("xmake config -P .")
os.exec("xmake")
t:require(os.isdir("build"))
t:require(os.isdir(".xmake"))
t:require_not(os.isdir("../build"))
t:require_not(os.isdir("../.xmake"))
t:require_not(os.isdir("../../build"))
t:require_not(os.isdir("../../.xmake"))
end
================================================
FILE: tests/actions/install/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/actions/install/src/foo.cpp
================================================
#include "foo.h"
int add(int a, int b) {
return a + b;
}
================================================
FILE: tests/actions/install/src/foo.h
================================================
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32)
# define __export __declspec(dllexport)
#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
# define __export __attribute__((visibility("default")))
#else
# define __export
#endif
__export int add(int a, int b);
#ifdef __cplusplus
}
#endif
================================================
FILE: tests/actions/install/src/foo.txt
================================================
================================================
FILE: tests/actions/install/src/main.cpp
================================================
#include "foo.h"
#include
int main(int argc, char** argv) {
std::cout << "add(1, 2) = " << add(1, 2) << std::endl;
return 0;
}
================================================
FILE: tests/actions/install/test.lua
================================================
function main(t)
if is_host("windows", "linux", "macosx") and os.arch():startswith("x") then
os.vrun("xmake -y")
os.vrun("xmake run app")
os.vrun("xmake install -o build/usr")
if not is_host("linux") then -- TODO, change rpath has been not supported yet on linux.
os.vrun("./build/usr/app/bin/app" .. (is_host("windows") and ".exe" or ""))
end
end
end
================================================
FILE: tests/actions/install/xmake.lua
================================================
add_rules("mode.debug", "mode.release")
set_version("1.0.1", {soname = true})
add_requires("libzip", {system = false, configs = {shared = true}})
target("foo")
set_kind("shared")
add_files("src/foo.cpp")
add_packages("libzip", {public = true})
add_headerfiles("src/foo.h", {public = true})
add_installfiles("src/foo.txt", {prefixdir = "assets", public = true})
set_prefixdir("/", {libdir = "foo_lib"})
target("app")
set_kind("binary")
add_deps("foo")
add_files("src/main.cpp")
set_prefixdir("app", {libdir = "app_lib"})
add_rpathdirs("@loader_path/../app_lib", {installonly = true})
includes("@builtin/xpack")
xpack("test")
add_targets("app")
set_formats("zip")
================================================
FILE: tests/actions/package/localpkg/bar/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/actions/package/localpkg/bar/src/main.cpp
================================================
#include "foo.h"
#include
using namespace std;
int main(int argc, char** argv)
{
cout << "foo(1, 2) = " << foo(1, 2) << endl;
return 0;
}
================================================
FILE: tests/actions/package/localpkg/bar/xmake.lua
================================================
add_rules("mode.debug", "mode.release")
add_repositories("local-repo build")
add_requires("foo")
target("bar")
set_kind("binary")
add_files("src/*.cpp")
add_packages("foo")
================================================
FILE: tests/actions/package/localpkg/libfoo/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/actions/package/localpkg/libfoo/src/add.cpp
================================================
#include "add.h"
int add(int a, int b)
{
return a + b;
}
================================================
FILE: tests/actions/package/localpkg/libfoo/src/add.h
================================================
#ifdef __cplusplus
extern "C" {
#endif
/*! calculate add(a, b)
*
* @param a the first argument
* @param b the second argument
*
* @return the result
*/
int add(int a, int b);
#ifdef __cplusplus
}
#endif
================================================
FILE: tests/actions/package/localpkg/libfoo/src/foo.cpp
================================================
#include "add.h"
#include "sub.h"
#include "foo.h"
int foo(int a, int b)
{
return add(sub(a, b), sub(b, a));
}
================================================
FILE: tests/actions/package/localpkg/libfoo/src/foo.h
================================================
#ifdef __cplusplus
extern "C" {
#endif
/*! calculate foo(a, b)
*
* @param a the first argument
* @param b the second argument
*
* @return the result
*/
int foo(int a, int b);
#ifdef __cplusplus
}
#endif
================================================
FILE: tests/actions/package/localpkg/libfoo/src/sub.cpp
================================================
#include "sub.h"
int sub(int a, int b)
{
return a - b;
}
================================================
FILE: tests/actions/package/localpkg/libfoo/src/sub.h
================================================
#ifdef __cplusplus
extern "C" {
#endif
/*! calculate sub(a, b)
*
* @param a the first argument
* @param b the second argument
*
* @return the result
*/
int sub(int a, int b);
#ifdef __cplusplus
}
#endif
================================================
FILE: tests/actions/package/localpkg/libfoo/xmake.lua
================================================
add_rules("mode.debug", "mode.release")
set_license("Apache-2.0")
target("sub")
set_kind("static")
add_files("src/sub.cpp")
add_headerfiles("src/sub.h")
target("add")
set_kind("static")
add_files("src/add.cpp")
add_headerfiles("src/add.h")
target("foo")
add_deps("add", "sub")
set_kind("static")
add_files("src/foo.cpp")
add_headerfiles("src/foo.h")
================================================
FILE: tests/actions/package/localpkg/test.lua
================================================
function main(t)
if (os.subarch():startswith("x") or os.subarch() == "i386") and not is_host("bsd", "solaris", "haiku") then
os.cd("libfoo")
os.exec("xmake package -D -o ../bar/build")
os.cd("../bar")
os.exec("xmake f -c -D")
os.exec("xmake -D")
os.exec("xmake run")
end
end
================================================
FILE: tests/actions/test/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/actions/test/outputs/fail_hello_xmake.txt
================================================
hello xmake
================================================
FILE: tests/actions/test/outputs/pass_hello_foo.txt
================================================
hello foo
================================================
FILE: tests/actions/test/src/compile_1.cpp
================================================
#include
int main(int argc, char** argv) {
static_assert(0, "error");
return 0;
}
================================================
FILE: tests/actions/test/src/compile_2.cpp
================================================
#include
int main(int argc, char** argv) {
static_assert(0, "error");
return 0;
}
================================================
FILE: tests/actions/test/src/run_timeout.cpp
================================================
#ifdef _MSC_VER
# include
#else
# include
#endif
int main(int argc, char** argv) {
#ifdef _MSC_VER
Sleep(10 * 1000);
#else
usleep(10 * 100 * 1000);
#endif
return 0;
}
================================================
FILE: tests/actions/test/src/test_1.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_2.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_3.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_4.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_5.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello2 " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_6.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_7.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return -1;
}
================================================
FILE: tests/actions/test/src/test_8.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
cout << "hello xmake" << endl;
return 0;
}
================================================
FILE: tests/actions/test/src/test_9.cpp
================================================
#include
using namespace std;
int main(int argc, char** argv)
{
char const* arg = argc > 1? argv[1] : "xmake";
cout << "hello " << arg << endl;
return 0;
}
================================================
FILE: tests/actions/test/test.lua
================================================
function main(t)
os.exec("xmake test")
end
================================================
FILE: tests/actions/test/tests/stub_1.cpp
================================================
#ifndef STUB_1
#error
#endif
================================================
FILE: tests/actions/test/tests/stub_2.cpp
================================================
#ifndef STUB_2
#error
#endif
================================================
FILE: tests/actions/test/tests/stub_n1.cpp
================================================
#ifndef STUB_N
#error
#endif
================================================
FILE: tests/actions/test/tests/stub_n2.cpp
================================================
#ifndef STUB_N
#error
#endif
================================================
FILE: tests/actions/test/xmake.lua
================================================
add_rules("mode.debug", "mode.release")
set_policy("test.return_zero_on_failure", true)
for _, file in ipairs(os.files("src/test_*.cpp")) do
local 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
target("test_output_files")
set_kind("binary")
set_default(false)
add_files("src/test_1.cpp")
add_tests("pass_output_file", {trim_output = true, runargs = "foo", pass_output_files = "outputs/pass_hello_foo.txt"})
add_tests("fail_output_file", {trim_output = true, should_fail = true, fail_output_files = "outputs/fail_hello_xmake.txt"})
target("test_10")
set_kind("binary")
set_default(false)
add_files("src/compile_1.cpp")
add_tests("compile_fail", {build_should_fail = true})
target("test_11")
set_kind("binary")
set_default(false)
add_files("src/compile_2.cpp")
add_tests("compile_pass", {build_should_pass = true})
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", {realtime_output = true, files = "tests/stub_n*.cpp", defines = "STUB_N"})
target("test_timeout")
set_kind("binary")
set_default(false)
add_files("src/run_timeout.cpp")
add_tests("run_timeout", {run_timeout = 1000})
================================================
FILE: tests/apis/add_allowedxxx/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/apis/add_allowedxxx/src/main.cpp
================================================
#include
using namespace std;
int main(int argc, char **argv) {
cout << "hello world!" << endl;
return 0;
}
================================================
FILE: tests/apis/add_allowedxxx/xmake.lua
================================================
add_rules("mode.debug", "mode.release")
set_defaultmode("releasedbg")
set_defaultplat("linux")
set_defaultarchs("macosx|arm64", "linux|i386", "armv7")
set_allowedmodes("releasedbg", "debug")
set_allowedplats("windows", "linux", "macosx")
set_allowedarchs("macosx|arm64", "macosx|x86_64", "linux|i386", "linux|x86_64")
target("test")
set_kind("binary")
add_files("src/*.cpp")
================================================
FILE: tests/apis/add_configfiles/config.h.in
================================================
#define HAVE_${module}_H
#define HELLO "${hello} ${ARCH} ${PLAT}"
${define FOO_ENABLE}
${define FOO_ENABLE2}
${define FOO_STRING}
${define FOO_DEFINE}
${define FOO2_ENABLE}
${define FOO2_ENABLE2}
${define FOO2_STRING}
${define_export MYLIB}
${define_custom FOO_STRING arg1 arg2}
#define HAVE_SSE2 ${default HAVE_SSE2 0}
================================================
FILE: tests/apis/add_configfiles/config2.h.in
================================================
#define HAVE_@module@_H
#define HELLO2 "@hello@ @ARCH@ @PLAT@"
@define FOO_ENABLE@
@define FOO_ENABLE2@
@define FOO_STRING@
@define FOO2_ENABLE@
@define FOO2_ENABLE2@
@define FOO2_STRING@
#define DEFAULT_TEST @default default_test 0@
================================================
FILE: tests/apis/add_configfiles/hello.man
================================================
${module} ${ARCH}
================================================
FILE: tests/apis/add_configfiles/main.c
================================================
#include
#include
#include "config.h"
int main(int argc, char **argv) {
printf("hello %s\n", HELLO);
return 0;
}
================================================
FILE: tests/apis/add_configfiles/main2.c
================================================
#include
#include
#include "config2.h"
int main(int argc, char **argv) {
printf("hello2 %s\n", HELLO2);
return 0;
}
================================================
FILE: tests/apis/add_configfiles/test.c.in
================================================
int test()
{
return 0;
}
================================================
FILE: tests/apis/add_configfiles/test.lua
================================================
function main()
os.exec("xmake")
end
================================================
FILE: tests/apis/add_configfiles/xmake.lua
================================================
option("foo")
set_default("foo")
set_description("The Foo Info")
option_end()
if has_config("foo") then
set_configvar("FOO_ENABLE", 1)
set_configvar("FOO_ENABLE2", false)
set_configvar("FOO_STRING", get_config("foo"))
set_configvar("FOO_DEFINE", get_config("foo"), {quote = false})
end
option("foo2")
set_default(true)
set_description("Enable Foo2")
set_configvar("FOO2_ENABLE", true)
set_configvar("FOO2_STRING", "foo")
option_end()
target("test")
set_kind("binary")
add_files("main.c")
set_configvar("module", "test")
set_configdir("$(builddir)/config")
add_configfiles("test.c.in", {filename = "mytest.c"})
add_configfiles("config.h.in", {variables = {hello = "xmake"}, prefixdir = "header",
preprocessor = function (preprocessor_name, name, value, opt)
if preprocessor_name == "define_custom" then
return string.format("#define CUSTOM_%s %s", name, value)
end
end})
add_configfiles("*.man", {onlycopy = true, prefixdir = "man"})
add_includedirs("$(builddir)/config/header")
target("test2")
set_kind("binary")
add_files("main2.c")
set_configvar("module", "test2")
set_configdir("$(builddir)/config2")
add_configfiles("test.c.in", {filename = "mytest.c"})
add_configfiles("config2.h.in", {variables = {hello = "xmake2"}, pattern = "@([^\n]-)@", prefixdir = "header"})
add_configfiles("*.man", {onlycopy = true, prefixdir = "man"})
add_includedirs("$(builddir)/config2/header")
add_options("foo2")
================================================
FILE: tests/apis/add_defines/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/apis/add_defines/src/main.cpp
================================================
#include
using namespace std;
int main(int argc, char **argv) {
cout << TEST1 << endl;
cout << TEST2 << endl;
cout << TEST3 << endl;
cout << TEST4 << endl;
cout << TEST5 << endl;
cout << TEST6 << endl;
return 0;
}
================================================
FILE: tests/apis/add_defines/test.lua
================================================
function main()
os.exec("xmake")
end
================================================
FILE: tests/apis/add_defines/xmake.lua
================================================
add_rules("mode.debug", "mode.release")
target("test")
set_kind("binary")
add_files("src/*.cpp")
add_defines("TEST1=\"hello\"")
add_defines("TEST2=\"hello xmake\"")
add_defines("TEST3=3")
add_cxflags("-DTEST4=\"hello\"")
add_cxflags("-DTEST5=\"hello xmake\" -DTEST6=3")
================================================
FILE: tests/apis/add_deps/inc1/stub.h
================================================
================================================
FILE: tests/apis/add_deps/inc2/stub.h
================================================
================================================
FILE: tests/apis/add_deps/inc3/stub.h
================================================
================================================
FILE: tests/apis/add_deps/inc4/stub.h
================================================
================================================
FILE: tests/apis/add_deps/src/interface.c
================================================
#include "interface.h"
int add(int a, int b) {
return a + b;
}
================================================
FILE: tests/apis/add_deps/src/interface.h
================================================
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN32)
#define __export __declspec(dllexport)
#elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
#define __export __attribute__((visibility("default")))
#else
#define __export
#endif
/*! calculate add(a, b)
*
* @param a the first argument
* @param b the second argument
*
* @return the result
*/
__export int add(int a, int b);
#ifdef __cplusplus
}
#endif
================================================
FILE: tests/apis/add_deps/src/main.c
================================================
#include
int main(int argc, char **argv) {
printf("hello world!\n");
return 0;
}
================================================
FILE: tests/apis/add_deps/test.lua
================================================
function main()
os.exec("xmake")
end
================================================
FILE: tests/apis/add_deps/xmake.lua
================================================
target("dep1")
set_kind("static")
add_files("src/*.c")
add_cflags("-DFLAG1")
add_cflags("-DFLAG2", {interface = true})
add_includedirs("inc1", {public = true})
add_defines("TEST1", {public = true})
target("dep2")
set_kind("shared")
add_deps("dep1")
add_files("src/*.c")
add_includedirs("inc2", {interface = true})
add_defines("TEST2", {interface = true})
on_load(function (target)
print(target:extraconf("includedirs"))
print(target:extraconf("defines", "TEST2"))
print(target:extraconf("defines", "TEST2", "interface"))
print(target:get("files"))
print(target:get("files", {private = true}))
print(target:get("files", {public = true}))
print(target:get("files", {interface = true}))
print(target:get("defines"))
print(target:get("defines", {private = true}))
print(target:get("defines", {public = true}))
print(target:get("defines", {interface = true}))
end)
target("dep3")
set_kind("static")
add_files("src/*.c")
add_includedirs("inc3")
target("dep4")
set_kind("static")
add_files("src/*.c")
add_includedirs("inc4", {public = true})
add_defines("TEST4", {public = true})
target("demo")
set_kind("binary")
add_deps("dep2", "dep3")
add_deps("dep4", {inherit = false})
add_files("src/*.c")
================================================
FILE: tests/apis/add_imports/test.lua
================================================
function main()
os.exec("xmake")
end
================================================
FILE: tests/apis/add_imports/xmake.lua
================================================
target("test")
add_imports("core.base.option", "core.base.task")
before_build(function (target)
assert(option)
assert(task)
end)
on_build(function (target)
assert(option)
assert(task)
end)
after_build(function (target)
assert(option)
assert(task)
end)
================================================
FILE: tests/apis/add_xxx/test.lua
================================================
function main()
os.exec("xmake")
end
================================================
FILE: tests/apis/add_xxx/xmake.lua
================================================
add_defines("TEST1")
target("test")
add_defines("TEST2")
on_build(function (target)
local defines = table.concat(target:get("defines"), " ")
assert(defines:find("TEST1", 1, true))
assert(defines:find("TEST2", 1, true))
end)
================================================
FILE: tests/apis/check_xxx/config.h.in
================================================
${define HAS_STRING_H}
${define HAS_STRING_AND_STDIO_H}
${define HAS_WCHAR_AND_FLOAT}
${define HAS_PTHREAD}
${define HAS_STATIC_ASSERT}
${define HAS_SETJMP}
${define HAS_CONSTEXPR}
${define HAS_CONSEXPR_AND_STATIC_ASSERT}
${define HAS_SSE2}
${define HAS_LONG_8}
${define HAS_CXX_STD_98}
${define HAS_CXX_STD_11}
${define HAS_CXX_STD_14}
${define HAS_CXX_STD_17}
${define HAS_CXX_STD_20}
${define HAS_C_STD_89}
${define HAS_C_STD_99}
${define HAS_C_STD_11}
${define HAS_C_STD_17}
${define HAS_GCC}
${define HAS_CXX20}
${define IS_BIG_ENDIAN}
${define NO_GCC}
${define PTR_SIZE}
${define HAVE_VISIBILITY}
${define CUSTOM_ASSERT}
#define HAS_WCHAR ${default HAS_WCHAR 0}
================================================
FILE: tests/apis/check_xxx/foo.c
================================================
#include "config.h"
int foo() {
return 0;
}
================================================
FILE: tests/apis/check_xxx/main.c
================================================
int main(int argc, char **argv) {
return 0;
}
================================================
FILE: tests/apis/check_xxx/test.lua
================================================
function main()
os.exec("xmake")
end
================================================
FILE: tests/apis/check_xxx/xmake.lua
================================================
includes("@builtin/check")
target("foo")
set_kind("static")
add_files("foo.c")
add_includedirs("$(builddir)")
add_configfiles("config.h.in")
check_bigendian("IS_BIG_ENDIAN")
check_ctypes("HAS_WCHAR", "wchar_t")
check_cincludes("HAS_STRING_H", "string.h")
check_csnippets("HAS_INT_4", "return (sizeof(int) == 4)? 0 : -1;", {tryrun = true})
check_csnippets("HAS_INT_4_IN_MAIN", [[
int test() {
return (sizeof(int) == 4)? 0 : -1;
}
int main(int argc, char** argv)
{
return test();
}]], {tryrun = true})
check_csnippets("INT_SIZE", 'printf("%d", sizeof(int)); return 0;', {output = true, number = true})
check_sizeof("LONG_SIZE", "long")
check_sizeof("STRING_SIZE", "std::string", {includes = "string"})
configvar_check_bigendian("IS_BIG_ENDIAN")
configvar_check_cincludes("HAS_STRING_AND_STDIO_H", {"string.h", "stdio.h"})
configvar_check_ctypes("HAS_WCHAR_AND_FLOAT", {"wchar_t", "float"})
configvar_check_links("HAS_PTHREAD", {"pthread", "m", "dl"})
configvar_check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");")
configvar_check_cfuncs("HAS_SETJMP", "setjmp", {includes = {"signal.h", "setjmp.h"}})
configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr", {languages = "c++11"})
configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})
configvar_check_features("HAS_CXX_STD_98", "cxx_std_98")
configvar_check_features("HAS_CXX_STD_11", "cxx_std_11", {languages = "c++11"})
configvar_check_features("HAS_CXX_STD_14", "cxx_std_14", {languages = "c++14"})
configvar_check_features("HAS_CXX_STD_17", "cxx_std_17", {languages = "c++17"})
configvar_check_features("HAS_CXX_STD_20", "cxx_std_20", {languages = "c++20"})
configvar_check_features("HAS_C_STD_89", "c_std_89")
configvar_check_features("HAS_C_STD_99", "c_std_99")
configvar_check_features("HAS_C_STD_11", "c_std_11", {languages = "c11"})
configvar_check_features("HAS_C_STD_17", "c_std_17", {languages = "c17"})
configvar_check_cflags("HAS_SSE2", "-msse2")
configvar_check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0 : -1;", {tryrun = true})
configvar_check_csnippets("PTR_SIZE", 'printf("%d", sizeof(void*)); return 0;', {output = true, number = true})
configvar_check_csnippets("HAVE_VISIBILITY", 'extern __attribute__((__visibility__("hidden"))) int hiddenvar;', {default = 0})
configvar_check_csnippets("CUSTOM_ASSERT=assert", 'assert(1);', {default = "", quote = false})
configvar_check_macros("HAS_GCC", "__GNUC__")
configvar_check_macros("NO_GCC", "__GNUC__", {defined = false})
configvar_check_macros("HAS_CXX20", "__cplusplus >= 202002L", {languages = "c++20"})
local features_cxx17 = {
"cxx_aggregate_bases",
"cxx_aligned_new",
"cxx_capture_star_this",
"cxx_constexpr",
"cxx_deduction_guides",
"cxx_enumerator_attributes",
"cxx_fold_expressions",
"cxx_guaranteed_copy_elision",
"cxx_hex_float",
"cxx_if_constexpr",
"cxx_inheriting_constructors",
"cxx_inline_variables",
"cxx_namespace_attributes",
"cxx_noexcept_function_type",
"cxx_nontype_template_args",
"cxx_nontype_template_parameter_auto",
"cxx_range_based_for",
"cxx_static_assert",
"cxx_structured_bindings",
"cxx_template_template_args",
"cxx_variadic_using"}
for _, feature in ipairs(features_cxx17) do
check_features("HAS_17_" .. feature:upper(), feature, {languages = "c++17"})
end
local features_cxx20 = {
"cxx_aggregate_paren_init",
"cxx_char8_t",
"cxx_concepts",
"cxx_conditional_explicit",
"cxx_consteval",
"cxx_constexpr",
"cxx_constexpr_dynamic_alloc",
"cxx_constexpr_in_decltype",
"cxx_constinit",
"cxx_deduction_guides",
"cxx_designated_initializers",
"cxx_generic_lambdas",
"cxx_impl_coroutine",
"cxx_impl_destroying_delete",
"cxx_impl_three_way_comparison",
"cxx_init_captures",
"cxx_modules",
"cxx_nontype_template_args",
"cxx_using_enum"}
for _, feature in ipairs(features_cxx20) do
check_features("HAS_20_" .. feature:upper(), feature, {languages = "c++20"})
end
target("test")
add_deps("foo")
set_kind("binary")
add_files("main.c")
================================================
FILE: tests/apis/clone_target/src/main.cpp
================================================
#include
using namespace std;
int main(int argc, char **argv) {
cout << "hello world!" << endl;
return 0;
}
================================================
FILE: tests/apis/clone_target/test.lua
================================================
function main()
os.exec("xmake -vD")
end
================================================
FILE: tests/apis/clone_target/xmake.lua
================================================
target("test")
set_kind("binary")
add_files("src/*.cpp")
add_defines("TEST")
after_load(function (target)
import("core.project.project")
local t = target:clone()
t:name_set("test2")
t:add("deps", "test")
t:add("defines", "TEST2")
t:set("link_before", function (target)
print("link1", target:name())
assert(target:dep("test"):data("linked"))
end)
project.target_add(t)
end)
before_link(function (target)
print("link2", target:name())
target:data_set("linked", true)
end)
================================================
FILE: tests/apis/custom_scopeapis/.gitignore
================================================
# Xmake cache
.xmake/
build/
# MacOS Cache
.DS_Store
================================================
FILE: tests/apis/custom_scopeapis/src/main.cpp
================================================
#include