xmake.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. -- 自动生成 compile_commands.json,方便 VSCode/Clangd 做代码补全与跳转
  2. add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
  3. -- 从环境变量读取布尔宏值,支持: true/false, 1/0, on/off(大小写不敏感)
  4. local function getBooleanEnvDefineValue(envKey, defaultValue)
  5. local rawValue = os.getenv(envKey)
  6. if nil == rawValue or "" == rawValue then
  7. return defaultValue
  8. end
  9. local lowerValue = rawValue:lower()
  10. if "true" == lowerValue or "1" == lowerValue or "on" == lowerValue then
  11. return "true"
  12. end
  13. if "false" == lowerValue or "0" == lowerValue or "off" == lowerValue then
  14. return "false"
  15. end
  16. print("warning: invalid " .. envKey .. "=" .. rawValue .. ", fallback to " .. defaultValue)
  17. return defaultValue
  18. end
  19. -- 从环境变量读取非负整数宏;不合法则打印 warning 并忽略。
  20. local function tryAddNumericEnvDefine(envKey, defineKey, minValue)
  21. local rawValue = os.getenv(envKey)
  22. if nil == rawValue or "" == rawValue then
  23. return
  24. end
  25. local numericValue = tonumber(rawValue)
  26. if nil == numericValue then
  27. print("warning: invalid " .. envKey .. "=" .. rawValue .. ", ignored")
  28. return
  29. end
  30. numericValue = math.floor(numericValue)
  31. if numericValue < minValue then
  32. print("warning: invalid " .. envKey .. "=" .. rawValue .. ", expected >= " .. tostring(minValue) .. ", ignored")
  33. return
  34. end
  35. add_defines(defineKey .. "=" .. tostring(numericValue))
  36. end
  37. -- 单测主线固定为 linux-freertos + heap_4
  38. -- 把 yyjson 单独编译为静态库,避免每次业务宏变化都重编译其大体积源码
  39. -- 说明:
  40. -- 1) yyjson 基本不依赖 RyanJson 的业务宏,拆分后可显著减少重复编译。
  41. -- 2) binary 目标通过 add_deps("yyjsonStatic") 链接该静态库。
  42. target("yyjsonStatic", function()
  43. set_kind("static")
  44. set_default(false)
  45. set_toolchains("clang")
  46. set_plat("linux")
  47. set_arch("x86")
  48. set_languages("gnu99")
  49. set_optimize("fastest")
  50. add_includedirs('./test/externalModule/yyjson', {public = true})
  51. add_files('./test/externalModule/yyjson/*.c', {public = true}, {cxflags = "-w"})
  52. end)
  53. -- 统一构建配置:两个 target 共享同一套流程,仅通过 isFuzz 切换差异
  54. local function setupRyanJsonTarget(isFuzz)
  55. set_kind("binary")
  56. -- 编译工具链与平台配置
  57. set_toolchains("clang")
  58. set_plat("linux")
  59. set_arch("x86")
  60. set_languages("gnu99")
  61. -- 编译优化策略
  62. set_policy("build.ccache", false)
  63. set_optimize("fastest")
  64. -- 警告设置:启用所有警告(Clang 下相当于 -Weverything)
  65. set_warnings("everything")
  66. -- 三个核心配置宏支持由环境变量覆盖:
  67. -- RYANJSON_STRICT_OBJECT_KEY_CHECK
  68. -- RYANJSON_DEFAULT_ADD_AT_HEAD
  69. -- RYANJSON_SNPRINTF_SUPPORT_SCIENTIFIC
  70. local strictObjectKeyCheck = getBooleanEnvDefineValue("RYANJSON_STRICT_OBJECT_KEY_CHECK", "false")
  71. local defaultAddAtHead = getBooleanEnvDefineValue("RYANJSON_DEFAULT_ADD_AT_HEAD", "false")
  72. local snprintfSupportScientific = getBooleanEnvDefineValue("RYANJSON_SNPRINTF_SUPPORT_SCIENTIFIC", "false")
  73. add_defines("RyanJsonStrictObjectKeyCheck=" .. strictObjectKeyCheck)
  74. add_defines("RyanJsonDefaultAddAtHead=" .. defaultAddAtHead)
  75. -- 声明 snprintf 支持科学计数法,影响 double 序列化策略
  76. add_defines("RyanJsonSnprintfSupportScientific=" .. snprintfSupportScientific)
  77. -- 启用 Linux 测试环境分支(用于主机侧测试/兼容代码路径)
  78. add_defines("RyanJsonLinuxTestEnv")
  79. add_defines("RyanJsonTestPlatformLinuxFreeRtos")
  80. add_defines("RyanJsonFreeRtosHeap4")
  81. -- 向代码注入项目根目录,供测试与样例定位资源
  82. add_defines("RyanJsonProjectRootPath=\"$(projectdir)\"")
  83. -- 让 Unity 使用项目自定义配置头
  84. add_defines("UNITY_INCLUDE_CONFIG_H")
  85. -- 测试分配模拟参数(可选):用于评估不同 malloc 头部与对齐策略的影响。
  86. tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_HEADER_SIZE", "RyanJsonTestAllocHeaderSize", 0)
  87. tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_ALIGN_SIZE", "RyanJsonTestAllocAlignSize", 1)
  88. -- add_defines("RyanJsonEnableAssert")
  89. -- fuzz 专用差异:启用 libFuzzer 宏与链接参数(会注入 main)
  90. if isFuzz then
  91. add_defines("isEnableFuzzer")
  92. -- 编译期启用 libFuzzer 插桩
  93. add_cxflags("-fsanitize=fuzzer", {force = true})
  94. -- 链接期注入 libFuzzer runtime(包含 fuzz main)
  95. add_ldflags("-fsanitize=fuzzer", {force = true})
  96. end
  97. -- 覆盖率相关
  98. add_cxflags(
  99. "-fprofile-instr-generate", -- 生成原始 profile 数据
  100. "-fcoverage-mapping", -- 生成源码到覆盖率映射
  101. {force = true}
  102. )
  103. add_ldflags(
  104. "-fprofile-instr-generate", -- 链接覆盖率 runtime
  105. "-fcoverage-mapping", -- 链接覆盖率映射支持
  106. {force = true}
  107. )
  108. -- 链接器安全硬化与优化选项
  109. add_ldflags(
  110. "-flto", -- 链接时优化(跨文件优化)
  111. "-fPIE", -- 生成位置无关可执行代码
  112. "-pie", -- 启用 PIE 可执行文件
  113. "-fno-omit-frame-pointer", -- 保留栈帧,便于回溯定位
  114. "-fstack-clash-protection",-- 栈碰撞防护
  115. "-Wl,-z,relro", -- 重定位表只读保护
  116. "-Wl,-z,now", -- 启动时完成符号绑定
  117. "-Wl,-z,noexecstack", -- 栈不可执行
  118. "-Wl,-z,separate-code", -- 代码段与数据段分离
  119. {force = true}
  120. )
  121. add_syslinks("pthread")
  122. -- 主机侧统一开启 Sanitizer
  123. add_cxflags(
  124. "-fsanitize=alignment", -- 检测未对齐内存访问
  125. "-fno-sanitize-recover=undefined", -- UB 触发后立即终止
  126. {force = true}
  127. )
  128. add_ldflags(
  129. "-fsanitize=alignment", -- 未对齐访问检查
  130. "-fno-sanitize-recover=undefined", -- UB 触发后立即终止
  131. "-fsanitize=address", -- 越界/UAF 等内存错误
  132. "-fsanitize=leak", -- 泄漏检测
  133. "-fsanitize=undefined", -- 常见未定义行为检测
  134. "-fsanitize=pointer-compare", -- 非法指针比较
  135. "-fsanitize=pointer-subtract", -- 非法指针相减
  136. "-fsanitize=bounds", -- 数组/边界检查
  137. "-fsanitize=float-divide-by-zero", -- 浮点除零检查
  138. "-fsanitize=float-cast-overflow", -- 浮点转整型溢出检查
  139. {force = true}
  140. )
  141. -- 编译器警告与静态分析
  142. add_cxflags(
  143. -- 调试与标准一致性
  144. "-g3", -- 生成详细调试信息
  145. "-pedantic", -- 严格遵循标准
  146. -- 基础与强化告警
  147. "-Wall", -- 常用告警集合
  148. "-Wextra", -- 额外告警
  149. "-Wconversion", -- 隐式类型转换
  150. "-Wsign-conversion", -- 有/无符号转换
  151. "-Wdouble-promotion", -- float 隐式提升为 double
  152. "-Wstrict-prototypes", -- 函数声明原型检查
  153. "-Wold-style-definition", -- 旧式函数定义检查
  154. "-Wimplicit-fallthrough", -- switch 穿透检查
  155. "-Wshadow", -- 变量遮蔽检查
  156. "-Wcast-align", -- 潜在未对齐转换
  157. "-Wpointer-arith", -- 指针算术风险
  158. "-Warray-bounds", -- 数组越界检查
  159. "-Wshift-overflow", -- 位移溢出检查
  160. "-Wformat-truncation", -- 格式化截断检查
  161. "-Walloc-size", -- 分配大小异常
  162. "-Wnull-dereference", -- 空指针解引用
  163. "-Wtautological-compare", -- 恒真/恒假比较
  164. "-Wstrict-overflow", -- 有符号溢出假设
  165. "-Wmissing-prototypes", -- 缺少原型声明
  166. "-Wmissing-declarations", -- 缺少对外声明
  167. "-Wredundant-decls", -- 冗余声明
  168. "-Wunreachable-code", -- 不可达代码
  169. "-Wtype-limits", -- 类型边界恒真比较
  170. "-Wshift-negative-value", -- 负值位移检查
  171. "-Wdiv-by-zero", -- 除零检查
  172. "-Wformat-security", -- 格式化安全检查
  173. "-Wdisabled-optimization",-- 被禁用优化提示
  174. "-Wreturn-local-addr", -- 返回局部地址检查
  175. "-Wdeprecated", -- 弃用 API 提示
  176. "-Wuninitialized", -- 未初始化变量检查
  177. -- 代码生成与安全策略
  178. "-fstack-protector-strong", -- 强栈保护
  179. "-Wmissing-include-dirs", -- 头文件目录缺失
  180. "-Wcast-qual", -- 丢失 const/volatile 限定
  181. "-Wconditional-uninitialized", -- 条件分支未初始化
  182. "-Wcovered-switch-default", -- switch default 覆盖提示
  183. "-Wformat-nonliteral", -- 非字面量格式串
  184. "-Wformat-signedness", -- 格式化符号位不匹配
  185. "-Wvla", -- 可变长数组检查
  186. "-fno-common", -- 禁止旧式多重定义
  187. "-fno-strict-aliasing", -- 放宽别名优化,减少 UB 风险
  188. "-Wdocumentation", -- 文档注释检查
  189. "-Wparentheses-equality", -- 可疑括号比较
  190. -- 针对当前仓库的降噪项(避免第三方/历史代码噪声淹没关键告警)
  191. "-Wno-documentation",
  192. "-Wno-extra-semi-stmt",
  193. "-Wno-unsafe-buffer-usage",
  194. "-Wno-declaration-after-statement",
  195. "-Wno-padded",
  196. "-Wno-switch-default",
  197. "-Wno-unused-macros",
  198. {force = true}
  199. )
  200. -- 头文件
  201. add_includedirs('./RyanJson', {public = true})
  202. add_includedirs('./example', {public = true})
  203. add_includedirs('./test/fuzzer/include', {public = true})
  204. add_includedirs('./test/unityTest/runner', {public = true})
  205. add_includedirs('./test/unityTest/common', {public = true})
  206. add_includedirs('./test/unityTest/include', {public = true})
  207. add_includedirs('./test/unityTest/cases/core', {public = true})
  208. add_includedirs('./test/unityTest/cases/equality', {public = true})
  209. add_includedirs('./test/unityTest/cases/utils', {public = true})
  210. add_includedirs('./test/externalModule/valloc', {public = true})
  211. add_includedirs('./test/externalModule/tlsf', {public = true})
  212. add_includedirs('./test/externalModule/cJSON', {public = true})
  213. add_includedirs('./test/externalModule/unity/src', {public = true})
  214. add_includedirs('./test/unityTest/cases/RFC8259', {public = true})
  215. -- 头文件仍由主目标暴露,源码改为依赖静态库 yyjsonStatic
  216. add_includedirs('./test/externalModule/yyjson', {public = true})
  217. -- 依赖第三方静态库(减少重复编译)
  218. add_deps("yyjsonStatic")
  219. add_includedirs('./test/externalModule/FreeRTOS-Kernel/include', {public = true})
  220. add_includedirs('./test/externalModule/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix', {public = true})
  221. -- 源文件
  222. add_files('./RyanJson/*.c', {public = true})
  223. add_files('./example/*.c', {public = true})
  224. add_files('./test/unityTest/**.c', {public = true}, {cxflags = "-w"})
  225. add_files('./test/externalModule/FreeRTOS-Kernel/list.c', {public = true}, {cxflags = "-w"})
  226. add_files('./test/externalModule/FreeRTOS-Kernel/queue.c', {public = true}, {cxflags = "-w"})
  227. add_files('./test/externalModule/FreeRTOS-Kernel/tasks.c', {public = true}, {cxflags = "-w"})
  228. add_files('./test/externalModule/FreeRTOS-Kernel/timers.c', {public = true}, {cxflags = "-w"})
  229. add_files('./test/externalModule/FreeRTOS-Kernel/event_groups.c', {public = true}, {cxflags = "-w"})
  230. add_files('./test/externalModule/FreeRTOS-Kernel/stream_buffer.c', {public = true}, {cxflags = "-w"})
  231. add_files('./test/externalModule/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/port.c',
  232. {public = true},
  233. {cxflags = "-w"})
  234. add_files('./test/externalModule/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/utils/wait_for_event.c',
  235. {public = true},
  236. {cxflags = "-w"})
  237. add_files('./test/externalModule/FreeRTOS-Kernel/portable/MemMang/heap_4.c', {public = true}, {cxflags = "-w"})
  238. add_files('./test/externalModule/valloc/*.c', {public = true}, {cxflags = "-w"})
  239. add_files('./test/externalModule/tlsf/*.c', {public = true}, {cxflags = "-w"})
  240. add_files('./test/externalModule/cJSON/*.c', {public = true}, {cxflags = "-w"})
  241. add_files('./test/externalModule/unity/src/*.c', {public = true}, {cxflags = "-w"})
  242. if isFuzz then
  243. -- fuzz 目标:编入全部 fuzz case
  244. add_files('./test/fuzzer/**.c', {public = true})
  245. else
  246. -- unit 目标:仅补最小 fuzzer runtime 依赖,避免注入 libFuzzer main。
  247. -- 原因:RyanJsonPrint.c 在 RyanJsonLinuxTestEnv 下会引用 RyanJsonFuzzerShouldFail。
  248. add_files('./test/fuzzer/utils/fuzzerDriver.c', {public = true}, {cxflags = "-w"})
  249. add_files('./test/fuzzer/utils/fuzzerMemory.c', {public = true}, {cxflags = "-w"})
  250. end
  251. end
  252. target("RyanJson", function()
  253. -- 默认目标:Unit 测试路径(不注入 libFuzzer main)
  254. setupRyanJsonTarget(false)
  255. end)
  256. target("RyanJsonFuzz", function()
  257. -- 专用 fuzz 目标:默认不参与普通 xmake 构建
  258. set_default(false)
  259. setupRyanJsonTarget(true)
  260. end)
  261. -- QEMU Cortex-M 目标:用于硬件语义校验(含非对齐访问 fault)
  262. local function setupRyanJsonQemuTarget(options)
  263. local cpu = options.cpu
  264. local freertosPort = options.freertosPort
  265. local isCm4f = options.isCm4f
  266. set_kind("binary")
  267. set_default(false)
  268. set_extension(".elf")
  269. set_toolchains("gcc")
  270. set_plat("cross")
  271. set_arch("arm")
  272. set_languages("gnu99")
  273. set_optimize("fastest")
  274. set_symbols("debug")
  275. set_toolset("cc", "arm-none-eabi-gcc")
  276. set_toolset("as", "arm-none-eabi-gcc")
  277. set_toolset("ld", "arm-none-eabi-gcc")
  278. set_toolset("ar", "arm-none-eabi-ar")
  279. local strictObjectKeyCheck = getBooleanEnvDefineValue("RYANJSON_STRICT_OBJECT_KEY_CHECK", "false")
  280. local defaultAddAtHead = getBooleanEnvDefineValue("RYANJSON_DEFAULT_ADD_AT_HEAD", "false")
  281. local snprintfSupportScientific = getBooleanEnvDefineValue("RYANJSON_SNPRINTF_SUPPORT_SCIENTIFIC", "true")
  282. add_defines("RyanJsonStrictObjectKeyCheck=" .. strictObjectKeyCheck)
  283. add_defines("RyanJsonDefaultAddAtHead=" .. defaultAddAtHead)
  284. add_defines("RyanJsonSnprintfSupportScientific=" .. snprintfSupportScientific)
  285. add_defines("RyanJsonTestPlatformQemu")
  286. add_defines("RyanJsonFreeRtosHeap4")
  287. add_defines("RyanJsonProjectRootPath=\"$(projectdir)\"")
  288. add_defines("UNITY_INCLUDE_CONFIG_H")
  289. add_defines("YYJSON_DISABLE_UNALIGNED_MEMORY_ACCESS=1")
  290. -- 测试分配模拟参数(可选):用于评估不同 malloc 头部与对齐策略的影响。
  291. tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_HEADER_SIZE", "RyanJsonTestAllocHeaderSize", 0)
  292. tryAddNumericEnvDefine("RYANJSON_TEST_ALLOC_ALIGN_SIZE", "RyanJsonTestAllocAlignSize", 1)
  293. add_cxflags(
  294. "-mcpu=" .. cpu,
  295. "-mthumb",
  296. "-ffunction-sections",
  297. "-fdata-sections",
  298. "-fno-common",
  299. "-fno-strict-aliasing",
  300. "-Wall",
  301. "-Wextra",
  302. "-Wno-unused-parameter",
  303. {force = true}
  304. )
  305. if isCm4f then
  306. add_cxflags(
  307. "-mfpu=fpv4-sp-d16",
  308. "-mfloat-abi=hard",
  309. {force = true}
  310. )
  311. end
  312. add_asflags(
  313. "-mcpu=" .. cpu,
  314. "-mthumb",
  315. {force = true}
  316. )
  317. if isCm4f then
  318. add_asflags(
  319. "-mfpu=fpv4-sp-d16",
  320. "-mfloat-abi=hard",
  321. {force = true}
  322. )
  323. end
  324. add_ldflags(
  325. "-mcpu=" .. cpu,
  326. "-mthumb",
  327. "-Ttest/qemu/platform/linkerMps2An386.ld",
  328. "-Wl,--gc-sections",
  329. "-Wl,--print-memory-usage",
  330. "--specs=nosys.specs",
  331. "-nostartfiles",
  332. {force = true}
  333. )
  334. if isCm4f then
  335. add_ldflags(
  336. "-mfpu=fpv4-sp-d16",
  337. "-mfloat-abi=hard",
  338. {force = true}
  339. )
  340. end
  341. add_syslinks("c", "m", "gcc")
  342. add_includedirs("./RyanJson", {public = true})
  343. add_includedirs("./test/qemu/platform", {public = true})
  344. add_includedirs("./test/qemu/common", {public = true})
  345. add_includedirs("./example", {public = true})
  346. add_includedirs("./test/unityTest/runner", {public = true})
  347. add_includedirs("./test/unityTest/common", {public = true})
  348. add_includedirs("./test/unityTest/include", {public = true})
  349. add_includedirs("./test/unityTest/cases/core", {public = true})
  350. add_includedirs("./test/unityTest/cases/equality", {public = true})
  351. add_includedirs("./test/unityTest/cases/utils", {public = true})
  352. add_includedirs("./test/unityTest/cases/RFC8259", {public = true})
  353. add_includedirs("./test/unityTest/cases/performance", {public = true})
  354. add_includedirs("./test/externalModule/valloc", {public = true})
  355. add_includedirs("./test/externalModule/tlsf", {public = true})
  356. add_includedirs("./test/externalModule/cJSON", {public = true})
  357. add_includedirs("./test/externalModule/unity/src", {public = true})
  358. add_includedirs("./test/externalModule/yyjson", {public = true})
  359. add_includedirs("./test/externalModule/FreeRTOS-Kernel/include", {public = true})
  360. add_includedirs("./test/externalModule/FreeRTOS-Kernel/portable/GCC/" .. freertosPort, {public = true})
  361. add_files("./RyanJson/*.c", {public = true})
  362. add_files("./example/*.c", {public = true})
  363. add_files("./test/qemu/platform/qemuPlatform.c", {public = true})
  364. add_files("./test/qemu/platform/qemuStartup.c", {public = true})
  365. add_files("./test/qemu/platform/qemuFault.c", {public = true})
  366. add_files("./test/qemu/platform/qemuSyscalls.c", {public = true})
  367. add_files("./test/qemu/platform/qemuFreertosHeap.c", {public = true})
  368. add_files("./test/unityTest/**.c", {public = true}, {cxflags = "-w"})
  369. add_files("./test/externalModule/valloc/*.c", {public = true}, {cxflags = "-w"})
  370. add_files("./test/externalModule/tlsf/*.c", {public = true}, {cxflags = "-w"})
  371. add_files("./test/externalModule/cJSON/*.c", {public = true}, {cxflags = "-w"})
  372. add_files("./test/externalModule/unity/src/*.c", {public = true}, {cxflags = "-w"})
  373. add_files("./test/externalModule/yyjson/*.c", {public = true}, {cxflags = "-w"})
  374. add_files("./test/externalModule/FreeRTOS-Kernel/list.c", {public = true}, {cxflags = "-w"})
  375. add_files("./test/externalModule/FreeRTOS-Kernel/queue.c", {public = true}, {cxflags = "-w"})
  376. add_files("./test/externalModule/FreeRTOS-Kernel/tasks.c", {public = true}, {cxflags = "-w"})
  377. add_files("./test/externalModule/FreeRTOS-Kernel/timers.c", {public = true}, {cxflags = "-w"})
  378. add_files("./test/externalModule/FreeRTOS-Kernel/event_groups.c", {public = true}, {cxflags = "-w"})
  379. add_files("./test/externalModule/FreeRTOS-Kernel/stream_buffer.c", {public = true}, {cxflags = "-w"})
  380. add_files("./test/externalModule/FreeRTOS-Kernel/portable/GCC/" .. freertosPort .. "/port.c",
  381. {public = true},
  382. {cxflags = "-w"})
  383. add_files("./test/externalModule/FreeRTOS-Kernel/portable/MemMang/heap_4.c", {public = true}, {cxflags = "-w"})
  384. after_build(function(target)
  385. local elfFile = target:targetfile()
  386. local outDir = path.directory(elfFile)
  387. local baseName = path.basename(elfFile)
  388. local binFile = path.join(outDir, baseName .. ".bin")
  389. local hexFile = path.join(outDir, baseName .. ".hex")
  390. os.execv("arm-none-eabi-objcopy", {"-O", "binary", elfFile, binFile})
  391. os.execv("arm-none-eabi-objcopy", {"-O", "ihex", elfFile, hexFile})
  392. end)
  393. end
  394. target("RyanJsonQemu", function()
  395. setupRyanJsonQemuTarget({
  396. cpu = "cortex-m4",
  397. freertosPort = "ARM_CM4F",
  398. isCm4f = true,
  399. })
  400. end)
  401. target("RyanJsonQemuCm3", function()
  402. setupRyanJsonQemuTarget({
  403. cpu = "cortex-m3",
  404. freertosPort = "ARM_CM3",
  405. isCm4f = false,
  406. })
  407. add_defines("RyanJsonQemuSoftUnalignedTrap")
  408. end)