| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- -- 自动生成 compile_commands.json,方便 VSCode/Clangd 做代码补全与跳转
- add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
- -- 从环境变量读取布尔宏值,支持: true/false, 1/0, on/off(大小写不敏感)
- local function getBooleanEnvDefineValue(envKey, defaultValue)
- local rawValue = os.getenv(envKey)
- if nil == rawValue or "" == rawValue then
- return defaultValue
- end
- local lowerValue = rawValue:lower()
- if "true" == lowerValue or "1" == lowerValue or "on" == lowerValue then
- return "true"
- end
- if "false" == lowerValue or "0" == lowerValue or "off" == lowerValue then
- return "false"
- end
- print("warning: invalid " .. envKey .. "=" .. rawValue .. ", fallback to " .. defaultValue)
- return defaultValue
- end
- -- 从环境变量读取非负整数宏;不合法则打印 warning 并忽略。
- local function tryAddNumericEnvDefine(envKey, defineKey, minValue)
- local rawValue = os.getenv(envKey)
- if nil == rawValue or "" == rawValue then
- return
- end
- local numericValue = tonumber(rawValue)
- if nil == numericValue then
- print("warning: invalid " .. envKey .. "=" .. rawValue .. ", ignored")
- return
- end
- numericValue = math.floor(numericValue)
- if numericValue < minValue then
- print("warning: invalid " .. envKey .. "=" .. rawValue .. ", expected >= " .. tostring(minValue) .. ", ignored")
- return
- end
- add_defines(defineKey .. "=" .. tostring(numericValue))
- end
- -- 单测主线固定为 linux-freertos + heap_4
- -- 把 yyjson 单独编译为静态库,避免每次业务宏变化都重编译其大体积源码
- -- 说明:
- -- 1) yyjson 基本不依赖 RyanJson 的业务宏,拆分后可显著减少重复编译。
- -- 2) binary 目标通过 add_deps("yyjsonStatic") 链接该静态库。
- target("yyjsonStatic", function()
- set_kind("static")
- set_default(false)
- set_toolchains("clang")
- set_plat("linux")
- set_arch("x86")
- set_languages("gnu99")
- set_optimize("fastest")
- add_includedirs('./test/externalModule/yyjson', {public = true})
- add_files('./test/externalModule/yyjson/*.c', {public = true}, {cxflags = "-w"})
- end)
- -- 统一构建配置:两个 target 共享同一套流程,仅通过 isFuzz 切换差异
- local function setupRyanJsonTarget(isFuzz)
- set_kind("binary")
- -- 编译工具链与平台配置
- set_toolchains("clang")
- set_plat("linux")
- set_arch("x86")
- set_languages("gnu99")
- -- 编译优化策略
- set_policy("build.ccache", false)
- set_optimize("fastest")
- -- 警告设置:启用所有警告(Clang 下相当于 -Weverything)
- set_warnings("everything")
- -- 三个核心配置宏支持由环境变量覆盖:
- -- RYANJSON_STRICT_OBJECT_KEY_CHECK
- -- RYANJSON_DEFAULT_ADD_AT_HEAD
- -- RYANJSON_SNPRINTF_SUPPORT_SCIENTIFIC
- local strictObjectKeyCheck = getBooleanEnvDefineValue("RYANJSON_STRICT_OBJECT_KEY_CHECK", "false")
- local defaultAddAtHead = getBooleanEnvDefineValue("RYANJSON_DEFAULT_ADD_AT_HEAD", "false")
- local snprintfSupportScientific = getBooleanEnvDefineValue("RYANJSON_SNPRINTF_SUPPORT_SCIENTIFIC", "false")
- add_defines("RyanJsonStrictObjectKeyCheck=" .. strictObjectKeyCheck)
- add_defines("RyanJsonDefaultAddAtHead=" .. defaultAddAtHead)
- -- 声明 snprintf 支持科学计数法,影响 double 序列化策略
- add_defines("RyanJsonSnprintfSupportScientific=" .. snprintfSupportScientific)
- -- 启用 Linux 测试环境分支(用于主机侧测试/兼容代码路径)
- add_defines("RyanJsonLinuxTestEnv")
- add_defines("RyanJsonTestPlatformLinuxFreeRtos")
- add_defines("RyanJsonFreeRtosHeap4")
- -- 向代码注入项目根目录,供测试与样例定位资源
- add_defines("RyanJsonProjectRootPath=\"$(projectdir)\"")
- -- 让 Unity 使用项目自定义配置头
- add_defines("UNITY_INCLUDE_CONFIG_H")
- -- 测试分配模拟参数(可选):用于评估不同 malloc 头部与对齐策略的影响。
- tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_HEADER_SIZE", "RyanJsonTestAllocHeaderSize", 0)
- tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_ALIGN_SIZE", "RyanJsonTestAllocAlignSize", 1)
- -- add_defines("RyanJsonEnableAssert")
- -- fuzz 专用差异:启用 libFuzzer 宏与链接参数(会注入 main)
- if isFuzz then
- add_defines("isEnableFuzzer")
- -- 编译期启用 libFuzzer 插桩
- add_cxflags("-fsanitize=fuzzer", {force = true})
- -- 链接期注入 libFuzzer runtime(包含 fuzz main)
- add_ldflags("-fsanitize=fuzzer", {force = true})
- end
- -- 覆盖率相关
- add_cxflags(
- "-fprofile-instr-generate", -- 生成原始 profile 数据
- "-fcoverage-mapping", -- 生成源码到覆盖率映射
- {force = true}
- )
- add_ldflags(
- "-fprofile-instr-generate", -- 链接覆盖率 runtime
- "-fcoverage-mapping", -- 链接覆盖率映射支持
- {force = true}
- )
- -- 链接器安全硬化与优化选项
- add_ldflags(
- "-flto", -- 链接时优化(跨文件优化)
- "-fPIE", -- 生成位置无关可执行代码
- "-pie", -- 启用 PIE 可执行文件
- "-fno-omit-frame-pointer", -- 保留栈帧,便于回溯定位
- "-fstack-clash-protection",-- 栈碰撞防护
- "-Wl,-z,relro", -- 重定位表只读保护
- "-Wl,-z,now", -- 启动时完成符号绑定
- "-Wl,-z,noexecstack", -- 栈不可执行
- "-Wl,-z,separate-code", -- 代码段与数据段分离
- {force = true}
- )
- add_syslinks("pthread")
- -- 主机侧统一开启 Sanitizer
- add_cxflags(
- "-fsanitize=alignment", -- 检测未对齐内存访问
- "-fno-sanitize-recover=undefined", -- UB 触发后立即终止
- {force = true}
- )
- add_ldflags(
- "-fsanitize=alignment", -- 未对齐访问检查
- "-fno-sanitize-recover=undefined", -- UB 触发后立即终止
- "-fsanitize=address", -- 越界/UAF 等内存错误
- "-fsanitize=leak", -- 泄漏检测
- "-fsanitize=undefined", -- 常见未定义行为检测
- "-fsanitize=pointer-compare", -- 非法指针比较
- "-fsanitize=pointer-subtract", -- 非法指针相减
- "-fsanitize=bounds", -- 数组/边界检查
- "-fsanitize=float-divide-by-zero", -- 浮点除零检查
- "-fsanitize=float-cast-overflow", -- 浮点转整型溢出检查
- {force = true}
- )
- -- 编译器警告与静态分析
- add_cxflags(
- -- 调试与标准一致性
- "-g3", -- 生成详细调试信息
- "-pedantic", -- 严格遵循标准
- -- 基础与强化告警
- "-Wall", -- 常用告警集合
- "-Wextra", -- 额外告警
- "-Wconversion", -- 隐式类型转换
- "-Wsign-conversion", -- 有/无符号转换
- "-Wdouble-promotion", -- float 隐式提升为 double
- "-Wstrict-prototypes", -- 函数声明原型检查
- "-Wold-style-definition", -- 旧式函数定义检查
- "-Wimplicit-fallthrough", -- switch 穿透检查
- "-Wshadow", -- 变量遮蔽检查
- "-Wcast-align", -- 潜在未对齐转换
- "-Wpointer-arith", -- 指针算术风险
- "-Warray-bounds", -- 数组越界检查
- "-Wshift-overflow", -- 位移溢出检查
- "-Wformat-truncation", -- 格式化截断检查
- "-Walloc-size", -- 分配大小异常
- "-Wnull-dereference", -- 空指针解引用
- "-Wtautological-compare", -- 恒真/恒假比较
- "-Wstrict-overflow", -- 有符号溢出假设
- "-Wmissing-prototypes", -- 缺少原型声明
- "-Wmissing-declarations", -- 缺少对外声明
- "-Wredundant-decls", -- 冗余声明
- "-Wunreachable-code", -- 不可达代码
- "-Wtype-limits", -- 类型边界恒真比较
- "-Wshift-negative-value", -- 负值位移检查
- "-Wdiv-by-zero", -- 除零检查
- "-Wformat-security", -- 格式化安全检查
- "-Wdisabled-optimization",-- 被禁用优化提示
- "-Wreturn-local-addr", -- 返回局部地址检查
- "-Wdeprecated", -- 弃用 API 提示
- "-Wuninitialized", -- 未初始化变量检查
- -- 代码生成与安全策略
- "-fstack-protector-strong", -- 强栈保护
- "-Wmissing-include-dirs", -- 头文件目录缺失
- "-Wcast-qual", -- 丢失 const/volatile 限定
- "-Wconditional-uninitialized", -- 条件分支未初始化
- "-Wcovered-switch-default", -- switch default 覆盖提示
- "-Wformat-nonliteral", -- 非字面量格式串
- "-Wformat-signedness", -- 格式化符号位不匹配
- "-Wvla", -- 可变长数组检查
- "-fno-common", -- 禁止旧式多重定义
- "-fno-strict-aliasing", -- 放宽别名优化,减少 UB 风险
- "-Wdocumentation", -- 文档注释检查
- "-Wparentheses-equality", -- 可疑括号比较
- -- 针对当前仓库的降噪项(避免第三方/历史代码噪声淹没关键告警)
- "-Wno-documentation",
- "-Wno-extra-semi-stmt",
- "-Wno-unsafe-buffer-usage",
- "-Wno-declaration-after-statement",
- "-Wno-padded",
- "-Wno-switch-default",
- "-Wno-unused-macros",
- {force = true}
- )
- -- 头文件
- add_includedirs('./RyanJson', {public = true})
- add_includedirs('./example', {public = true})
- add_includedirs('./test/fuzzer/include', {public = true})
- add_includedirs('./test/unityTest/runner', {public = true})
- add_includedirs('./test/unityTest/common', {public = true})
- add_includedirs('./test/unityTest/include', {public = true})
- add_includedirs('./test/unityTest/cases/core', {public = true})
- add_includedirs('./test/unityTest/cases/equality', {public = true})
- add_includedirs('./test/unityTest/cases/utils', {public = true})
- add_includedirs('./test/externalModule/valloc', {public = true})
- add_includedirs('./test/externalModule/tlsf', {public = true})
- add_includedirs('./test/externalModule/cJSON', {public = true})
- add_includedirs('./test/externalModule/unity/src', {public = true})
- add_includedirs('./test/unityTest/cases/RFC8259', {public = true})
- -- 头文件仍由主目标暴露,源码改为依赖静态库 yyjsonStatic
- add_includedirs('./test/externalModule/yyjson', {public = true})
- -- 依赖第三方静态库(减少重复编译)
- add_deps("yyjsonStatic")
- add_includedirs('./test/externalModule/FreeRTOS-Kernel/include', {public = true})
- add_includedirs('./test/externalModule/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix', {public = true})
- -- 源文件
- add_files('./RyanJson/*.c', {public = true})
- add_files('./example/*.c', {public = true})
- add_files('./test/unityTest/**.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/list.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/queue.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/tasks.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/timers.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/event_groups.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/stream_buffer.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/port.c',
- {public = true},
- {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/utils/wait_for_event.c',
- {public = true},
- {cxflags = "-w"})
- add_files('./test/externalModule/FreeRTOS-Kernel/portable/MemMang/heap_4.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/valloc/*.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/tlsf/*.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/cJSON/*.c', {public = true}, {cxflags = "-w"})
- add_files('./test/externalModule/unity/src/*.c', {public = true}, {cxflags = "-w"})
- if isFuzz then
- -- fuzz 目标:编入全部 fuzz case
- add_files('./test/fuzzer/**.c', {public = true})
- else
- -- unit 目标:仅补最小 fuzzer runtime 依赖,避免注入 libFuzzer main。
- -- 原因:RyanJsonPrint.c 在 RyanJsonLinuxTestEnv 下会引用 RyanJsonFuzzerShouldFail。
- add_files('./test/fuzzer/utils/fuzzerDriver.c', {public = true}, {cxflags = "-w"})
- add_files('./test/fuzzer/utils/fuzzerMemory.c', {public = true}, {cxflags = "-w"})
- end
- end
- target("RyanJson", function()
- -- 默认目标:Unit 测试路径(不注入 libFuzzer main)
- setupRyanJsonTarget(false)
- end)
- target("RyanJsonFuzz", function()
- -- 专用 fuzz 目标:默认不参与普通 xmake 构建
- set_default(false)
- setupRyanJsonTarget(true)
- end)
- -- QEMU Cortex-M 目标:用于硬件语义校验(含非对齐访问 fault)
- local function setupRyanJsonQemuTarget(options)
- local cpu = options.cpu
- local freertosPort = options.freertosPort
- local isCm4f = options.isCm4f
- set_kind("binary")
- set_default(false)
- set_extension(".elf")
- set_toolchains("gcc")
- set_plat("cross")
- set_arch("arm")
- set_languages("gnu99")
- set_optimize("fastest")
- set_symbols("debug")
- set_toolset("cc", "arm-none-eabi-gcc")
- set_toolset("as", "arm-none-eabi-gcc")
- set_toolset("ld", "arm-none-eabi-gcc")
- set_toolset("ar", "arm-none-eabi-ar")
- local strictObjectKeyCheck = getBooleanEnvDefineValue("RYANJSON_STRICT_OBJECT_KEY_CHECK", "false")
- local defaultAddAtHead = getBooleanEnvDefineValue("RYANJSON_DEFAULT_ADD_AT_HEAD", "false")
- local snprintfSupportScientific = getBooleanEnvDefineValue("RYANJSON_SNPRINTF_SUPPORT_SCIENTIFIC", "true")
- add_defines("RyanJsonStrictObjectKeyCheck=" .. strictObjectKeyCheck)
- add_defines("RyanJsonDefaultAddAtHead=" .. defaultAddAtHead)
- add_defines("RyanJsonSnprintfSupportScientific=" .. snprintfSupportScientific)
- add_defines("RyanJsonTestPlatformQemu")
- add_defines("RyanJsonFreeRtosHeap4")
- add_defines("RyanJsonProjectRootPath=\"$(projectdir)\"")
- add_defines("UNITY_INCLUDE_CONFIG_H")
- add_defines("YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS=1")
- -- 测试分配模拟参数(可选):用于评估不同 malloc 头部与对齐策略的影响。
- tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_HEADER_SIZE", "RyanJsonTestAllocHeaderSize", 0)
- tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_ALIGN_SIZE", "RyanJsonTestAllocAlignSize", 1)
- add_cxflags(
- "-mcpu=" .. cpu,
- "-mthumb",
- "-ffunction-sections",
- "-fdata-sections",
- "-fno-common",
- "-fno-strict-aliasing",
- "-Wall",
- "-Wextra",
- "-Wno-unused-parameter",
- {force = true}
- )
- if isCm4f then
- add_cxflags(
- "-mfpu=fpv4-sp-d16",
- "-mfloat-abi=hard",
- {force = true}
- )
- end
- add_asflags(
- "-mcpu=" .. cpu,
- "-mthumb",
- {force = true}
- )
- if isCm4f then
- add_asflags(
- "-mfpu=fpv4-sp-d16",
- "-mfloat-abi=hard",
- {force = true}
- )
- end
- add_ldflags(
- "-mcpu=" .. cpu,
- "-mthumb",
- "-Ttest/qemu/platform/linkerMps2An386.ld",
- "-Wl,--gc-sections",
- "-Wl,--print-memory-usage",
- "--specs=nosys.specs",
- "-nostartfiles",
- {force = true}
- )
- if isCm4f then
- add_ldflags(
- "-mfpu=fpv4-sp-d16",
- "-mfloat-abi=hard",
- {force = true}
- )
- end
- add_syslinks("c", "m", "gcc")
- add_includedirs("./RyanJson", {public = true})
- add_includedirs("./test/qemu/platform", {public = true})
- add_includedirs("./test/qemu/common", {public = true})
- add_includedirs("./example", {public = true})
- add_includedirs("./test/unityTest/runner", {public = true})
- add_includedirs("./test/unityTest/common", {public = true})
- add_includedirs("./test/unityTest/include", {public = true})
- add_includedirs("./test/unityTest/cases/core", {public = true})
- add_includedirs("./test/unityTest/cases/equality", {public = true})
- add_includedirs("./test/unityTest/cases/utils", {public = true})
- add_includedirs("./test/unityTest/cases/RFC8259", {public = true})
- add_includedirs("./test/unityTest/cases/performance", {public = true})
- add_includedirs("./test/externalModule/valloc", {public = true})
- add_includedirs("./test/externalModule/tlsf", {public = true})
- add_includedirs("./test/externalModule/cJSON", {public = true})
- add_includedirs("./test/externalModule/unity/src", {public = true})
- add_includedirs("./test/externalModule/yyjson", {public = true})
- add_includedirs("./test/externalModule/FreeRTOS-Kernel/include", {public = true})
- add_includedirs("./test/externalModule/FreeRTOS-Kernel/portable/GCC/" .. freertosPort, {public = true})
- add_files("./RyanJson/*.c", {public = true})
- add_files("./example/*.c", {public = true})
- add_files("./test/qemu/platform/qemuPlatform.c", {public = true})
- add_files("./test/qemu/platform/qemuStartup.c", {public = true})
- add_files("./test/qemu/platform/qemuFault.c", {public = true})
- add_files("./test/qemu/platform/qemuSyscalls.c", {public = true})
- add_files("./test/qemu/platform/qemuFreertosHeap.c", {public = true})
- add_files("./test/unityTest/**.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/valloc/*.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/tlsf/*.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/cJSON/*.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/unity/src/*.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/yyjson/*.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/list.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/queue.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/tasks.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/timers.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/event_groups.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/stream_buffer.c", {public = true}, {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/portable/GCC/" .. freertosPort .. "/port.c",
- {public = true},
- {cxflags = "-w"})
- add_files("./test/externalModule/FreeRTOS-Kernel/portable/MemMang/heap_4.c", {public = true}, {cxflags = "-w"})
- after_build(function(target)
- local elfFile = target:targetfile()
- local outDir = path.directory(elfFile)
- local baseName = path.basename(elfFile)
- local binFile = path.join(outDir, baseName .. ".bin")
- local hexFile = path.join(outDir, baseName .. ".hex")
- os.execv("arm-none-eabi-objcopy", {"-O", "binary", elfFile, binFile})
- os.execv("arm-none-eabi-objcopy", {"-O", "ihex", elfFile, hexFile})
- end)
- end
- target("RyanJsonQemu", function()
- setupRyanJsonQemuTarget({
- cpu = "cortex-m4",
- freertosPort = "ARM_CM4F",
- isCm4f = true,
- })
- end)
- target("RyanJsonQemuCm3", function()
- setupRyanJsonQemuTarget({
- cpu = "cortex-m3",
- freertosPort = "ARM_CM3",
- isCm4f = false,
- })
- add_defines("RyanJsonQemuSoftUnalignedTrap")
- end)
|