尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Keil MDK 静态 LIB 库生成、接入与交付实战

发布时间:2026/9/29 3:22:16

资讯中心
01
ARTICLE

Keil MDK 静态 LIB 库生成、接入与交付实战

Keil MDK 静态 LIB 库生成、接入与交付实战
前阵子帮朋友收拾一个交付项目的烂摊子。他们做的是工业采集仪表算法部分滤波、标定、非线性补偿本来是自己的核心资产前期为了赶进度直接把 .c 源码连带头文件打包给了客户。半年后客户那边三个工程师各自改了一版同一套算法分叉成四个分支出了问题回头找他们连原始版本都对不上号。后来我建议他们把算法层剥离出来用 Keil MDK 编译成静态 LIB 库再交付源码只留在自己手里客户拿到的是 .lib 加一套公开的头文件接口。整个过程踩的坑比想象中多——浮点设置不一致导致链接报错、MicroLIB 和标准库混用导致串口输出乱码、库里注册的回调被链接器当成垃圾代码裁掉这些都不是看两页帮助文档能解决的。这篇文章就把 Keil MDK 生成 LIB 库以及使用 LIB 库的完整用法讲透怎么把工程改造成一个只能编译成库的工程、Output 页里那几个勾选框到底动了什么、库文件怎么挂进调用方工程、头文件该怎么写才不给自己挖坑、编译器版本和 FPU 配置为什么必须严格对齐、以及一堆只有真正交付过库的人才会知道的细节。不管你是刚接触 Keil 的新手还是已经在做模块化交付的老手下面的内容都能直接拿去用。1. 先想清楚什么时候该用 LIB什么时候别用1.1 三种最典型的落地场景第一种是知识产权保护与交付边界控制。你写了一套算法、一套协议栈、一套驱动不想让下游拿到源码但又必须让对方能在自己的工程里调用。LIB 库在这里的作用不是加密而是划边界它把实现细节锁在二进制里把接口留给头文件。这里要说清楚一个认知静态库并不是绝对安全的用反汇编工具照样能把机器码还原成汇编只是还原不出可读性好的 C 代码。所以如果你的目标是绝对防破解静态库做不到它只适合防顺手改一改和防源码四处扩散。第二种是编译时间与工程整洁度优化。我手上有个 STM32 项目图形库加文件系统加协议栈全量编译一次要六分多钟改一行 UI 代码也要等六分钟。把不常动的中间层LVGL 的移植层、FatFs 的底层适配、协议编解码打成 LIB 之后日常编译降到四十秒左右。原因很直接链接器不需要再重新编译这些 .c 文件直接从归档里抽取目标文件拼进最终镜像。对于每天要编译几十次的开发节奏这个收益非常实在。第三种是多人协作下的接口冻结。一个人负责底层驱动另一个人负责业务逻辑两个人约定好头文件之后驱动方把库发过来业务方就不再依赖驱动的具体实现。哪怕驱动内部重构了三遍只要头文件不变业务代码一行都不用动。这种做法在团队里推行的前提是头文件必须当成正式交付物来管理不能今天加个参数明天删个宏否则比直接给源码还乱。1.2 库交付的隐性成本先算清楚再决定用库不是没有代价的我看到过不少团队在这一点上吃亏。首先是调试难度上升。客户现场出了异常单步调试进去只能看到反汇编看不到源码行号除非你交付带调试信息的库但那又等于把符号表给出去了。所以交付库的时候一定要给客户留一个带调试信息版本用于内部定位问题同时约定这个版本不对外流转。其次是编译器耦合变强。Keil MDK 从 ARM Compiler 5armcc切换到 ARM Compiler 6armclang之后目标文件格式和 ABI 都有变化AC5 编出来的库和 AC6 编出来的库不建议混着链接官方也不保证兼容。这意味着一旦你交付了一个 AC5 编译的库客户升级到新版 MDK 时可能就得回来找你要新库。这个连锁反应要在交付前就跟客户讲明白别等到出事再解释。最后是配置漂移。库的代码编译时用了一套宏观配置比如HSE_VALUE是 8MHz 还是 25MHz、USE_HAL_DRIVER有没有定义调用方工程里如果定义成了另一套轻则功能不对重则链接报错。解决办法是把所有必须一致的配置写进头文件里用#error做编译期拦截具体怎么做在第 3 节展开。2. Keil MDK 生成 LIB 库的完整实操流程2.1 工程改造先把库工程清洗干净拿到一个能跑的工程不要上来就勾 Create Library先把不该进库的东西剔掉。我一般按这个顺序处理。排除启动文件和 main 函数。启动文件startup_stm32f1xx.s之类定义了中断向量表这是调用方工程的职责库里面绝不能带。做法是在 Project 窗口里右键该文件 → Options for File → 勾上 Exclude from build或者直接在文件属性里把它从当前 Target 移除。main.c同理库不需要 main。有人图省事留着 main.c 不排除结果生成库的时候报Symbol main multiply defined或者更隐蔽地出现库里的 main 抢了调用方的 main排查起来非常费时间。把对外接口和内部实现分开。建议目录结构做成三个文件夹inc放对外头文件src放实现private放只给内部用的头文件和辅助函数。只把inc目录加进 C/C 选项卡的 Include Pathsprivate目录不要加进去——因为库一旦生成Include Paths 这个设置对调用方是不生效的调用方只会拿你交付的inc。这个动作的本质是强迫自己想清楚哪些东西我愿意暴露。把所有内部函数加上 static。这是个大坑新手特别容易忽略。库里的非 static 全局函数会全部成为对外符号如果调用方工程里恰好有个同名的函数比如都叫delay_ms、get_tick链接器会直接报符号重复定义。我见过最惨的一次是两个模块都定义了SystemInit链接报错报了三屏。养成习惯只要这个函数不打算给别人用一律加static如果因为跨文件调用没法加 static至少加个模块前缀比如algo_filter_init而不是filter_init。处理全局变量。库里的全局变量在链接时会被分配进.bss或.data段。如果这个变量只在本模块用加static如果确实要暴露给调用方在头文件里用extern声明并且要想清楚一个前提——这个变量的地址在两边的编译单元里必须一致所以绝不能出现库里定义了一份、调用方又定义了一份的情况。2.2 Output 选项卡里那几个勾选框逐个说清楚工程清洗完之后打开 Options for Target → Output 标签页。这个页面看着简单但几个选项之间的相互影响很大。选项建议设置说明与影响Select Folder for Objects固定为.\Objects生成的 .lib 会放在这个目录下路径别带中文和空格Name of Executable改成库名如AlgoCore生成的库文件名会跟随最终得到AlgoCore.libCreate Library勾选关键开关勾上后产物从 .axf 变成 .libDebug Information勾选保留调试信息方便自己定位问题对外交付版本可关掉Create HEX File取消库没有可执行镜像勾了也没用还可能干扰判断Browse Information按需主要影响 IDE 内的跳转和符号浏览不影响库本身关于Create Library这个选项不同 MDK 版本的界面位置略有差异有时它在 Output 页的下半部分有时和 Create HEX File 并排但名字是一致的。勾上它之后你会注意到 Create HEX File 自动变灰——因为没有可执行文件可转换这是正常现象。再说Debug Information。这个选项决定了编译出来的目标文件里是否保留调试信息段。保留的好处是你自己拿着库和源码还能调试缺点是库体积变大并且符号信息会暴露函数名和变量名。我通常做两套内部调试版勾上 Debug Information对外交付版取消勾选同时在 C/C 选项卡的 Misc Controls 里加--no_debug_macros减少宏信息的泄露。还有一点常被忽略C/C 选项卡下的 Optimization 等级。库编译时的优化等级会固化进机器码。你如果用-O0编出来的库调用方工程就算设成-O2库里那部分代码也不会变快。我一般对交付库用-O2或-Os空间优先并且在 C/C 选项卡里勾上 One ELF Section per Function。这个选项让每个函数独立成段链接器就能把库里没被引用的函数逐个丢掉——不做这一步库里的代码会整块整块被拉进最终镜像Flash 占用会很难看。2.3 编译并确认产物设置好之后按 F7 全量编译建议先 Rebuild避免残留的旧 .o 混进归档。编译输出窗口最后几行应该能看到类似这样的信息linking... Program Size: Code4820 RO-data380 RW-data24 ZI-data1120 .\Objects\AlgoCore.lib - 0 Error(s), 0 Warning(s).注意最后一行产物是.lib而不是.axf说明库生成成功。如果你看到的还是AlgoCore.axf说明 Create Library 没勾上或者被别的设置覆盖了。编译完之后去Objects目录下确认一下除了AlgoCore.lib还会有一堆同名的.o文件每个 .c 对应一个和.d依赖文件。.o文件是中间产物如果你想手工重打包库这些文件是原料。我习惯把Objects目录整体清一遍再重新 Rebuild因为增量编译有个陷阱你删掉了某个 .c 文件但对应的 .o 还留在目录里重新生成库的时候这个旧 .o 可能还在归档里导致库里有个已经删除的函数。这种问题排查起来极其恶心所以生成库之前一律 Rebuild。2.4 顺带说说命令行生成库的做法IDE 图形界面适合手工操作但如果你要接入自动化构建命令行更靠谱。ARM 工具链自带的归档工具叫armar用法和 Linux 下的 ar 基本一致# 从若干目标文件创建库 armar --create AlgoCore.lib filter.o calib.o interp.o # 往已有库里追加目标文件 armar -r AlgoCore.lib crc.o # 列出库里的成员 armar -t AlgoCore.lib # 删除某个成员 armar -d AlgoCore.lib filter.o配合 Keil 安装目录下的armcc或 AC6 的armclang先把 .c 编译成 .o再用 armar 归档就能在 CI 里全自动出库。命令行的好处是参数全部显式可见谁改了什么配置一目了然不会像 IDE 那样出现某个人本地改了设置但没提交的情况。这里提醒一句armar的参数在不同工具链版本下略有差异动手前先跑一遍armar --help确认。还有个小工具值得记住fromelf。它除了能反汇编 .axf也能对 .lib 做处理用来检查库里到底有哪些函数、每个函数多大fromelf --text -c AlgoCore.lib拿到库之后先跑一下这个命令确认该进去的函数都在、不该进去的没混进来比在 IDE 里瞎猜快得多。3. 把 LIB 接进目标工程头文件、挂载与首次验证3.1 头文件才是真正的接口契约库本身只是机器码调用方看不到里面的东西所有的约定都写在头文件里。写头文件有几个必须守的规矩。第一用extern C包起来。只要你的库是 C 编的或者调用方可能是 C 工程就必须加#ifndef ALGOCORE_H #define ALGOCORE_H #ifdef __cplusplus extern C { #endif int algo_filter_init(void); int algo_filter_process(const short *in, short *out, unsigned int len); #ifdef __cplusplus } #endif #endif不加这段C 编译器的名字改编name mangling会把algo_filter_init变成_Z16algo_filter_initv这种符号而库是 C 编的两边对不上链接直接报未定义符号。第二参数类型只用固定宽度类型。int在 ARM 上是 32 位但在别的平台上可能是 16 位。头文件里一律用int32_t、uint16_t这类标准类型避免移植时出现库和调用方对同一个参数的理解不一样。同理结构体里如果有 padding要显式写出来别指望两边的编译器对齐规则完全一致。第三配置项用#error做编译期拦截。如果库的行为依赖某个宏比如浮点精度或者缓冲区大小在头文件里加一段检查#ifndef ALGO_BUF_LEN #error ALGO_BUF_LEN must be defined before including algocore.h #endif #if (ALGO_BUF_LEN 64) || (ALGO_BUF_LEN 4096) #error ALGO_BUF_LEN out of supported range (64~4096) #endif这样调用方配置错了编译阶段就报出来不用等到跑起来发现数据错乱再去查。这个技巧我用过很多次能省掉大量现场调试时间。第四头文件里不要放实现。有些人喜欢把小的工具函数写成static inline放在头文件里觉得这样调用方便。问题是这段代码是在调用方工程里编译的用的是调用方的优化等级和编译选项行为可能和你库里的不一致更麻烦的是如果调用方工程开了更严格的告警等级你的头文件可能直接触发 warning 甚至 error。要暴露小函数就在库里实现并在头文件里声明别用 inline 绕过边界。3.2 在 Keil 中挂载 LIB 文件这一步的界面操作不复杂但有两个细节容易出错。推荐的做法是在 Project 窗口里建一个独立的组比如叫Library右键这个组 → Add Existing Files to Group弹出文件对话框时把右下角的文件类型下拉框改成Library file (*.lib)。默认类型是 C 源文件不改这个下拉框你会发现在目录里看不到任何 .lib 文件会误以为文件不存在。这个小坑我见过太多人踩。挂载完之后右键这个 .lib 文件 → Options for File确认它被正确识别为库文件。理论上不需要额外设置但有一种特殊情况要处理如果你同时挂载了库和库的源码调试阶段会这么干必须把源码那一组排除出编译否则链接器既从库里抽符号又从源码里生成符号直接报重复定义。另一个细节是库的搜索路径。如果你的 .lib 放在工程目录之外比如放在公共的3rdparty/lib/目录下Keil 里挂载时用的是相对路径或绝对路径。团队协作时绝对路径是灾难别人机器上根本没有这个目录。统一用相对于 .uvprojx 文件的相对路径并且把这个 lib 目录纳入版本管理。3.3 写一个最小验证工程别急着集成到主工程库挂进去之后先别急着在主工程里调用。新建一个空的最小工程只做一件事调用库里的一个函数然后通过串口或者 GPIO 把结果打出来。这样做的好处是出问题时范围很小不用在几千行代码里找原因。最小验证的代码大概长这样#include algocore.h static short in_buf[ALGO_BUF_LEN]; static short out_buf[ALGO_BUF_LEN]; int main(void) { uart_init(115200); int ret algo_filter_init(); printf(algo_filter_init ret %d\r\n, ret); for (int i 0; i ALGO_BUF_LEN; i) { in_buf[i] (short)(i * 4); } algo_filter_process(in_buf, out_buf, ALGO_BUF_LEN); printf(out[0]%d out[%d]%d\r\n, out_buf[0], ALGO_BUF_LEN - 1, out_buf[ALGO_BUF_LEN - 1]); while (1) { } }验证通过的标准有三个编译零错误零警告、链接能找到所有库函数、运行结果和你在库工程里跑出来的一致。第三个标准最关键前两个过了但结果不对说明两边的编译配置有差异往下看第 4 节。顺便说链接完之后看一眼 Map 文件在 Linker 选项卡勾上--map搜索你的库函数名确认它确实是从 .lib 里抽取出来的而不是被别的东西替代了。Map 文件里会明确写出来源是AlgoCore.lib(filter.o)这个信息在排查符号冲突时非常有用。4. 编译器和运行时配置必须对齐的四个关键项4.1 编译器版本与工具链一致性这是最容易埋雷的一项。ARM Compiler 5 和 ARM Compiler 6 是两套完全不同的后端一个基于自家的 armcc一个基于 LLVM 的 armclang生成的目标文件格式、异常处理模型、库函数实现都有差异。用 AC5 编的库丢进一个 AC6 的工程里链接运气好能过运气不好会报一堆莫名其妙的符号未定义或者段属性冲突。在 Keil 里Options for Target → Target 标签页的 ARM Compiler 下拉框决定了用哪套编译器。生成库和调用库时这个选择必须一致。同样一致的还有 C/C 选项卡下的语言标准C99 / C11 / gnu11以及 Misc Controls 里手工加的各种--参数。我的做法是在交付包里放一个build_info.txt写清楚编译器版本号、语言标准、优化等级、关键宏定义。厂里的人拿到库之后照着配一遍比来回问快得多。编译器版本可以在编译输出窗口顶部看到类似Toolchain: MDK-ARM Professional Version 5.38, ARM Compiler 6.19。4.2 浮点 ABI 和 FPU 设置这一条单独拎出来讲因为它引发的故障最隐蔽。Target 标签页里的 Floating Point Hardware 选项决定了两件事代码里浮点运算怎么编软浮点模拟还是硬件 FPU 指令、函数调用时浮点参数怎么传寄存器还是栈。这两件事都直接影响 ABI。如果库是用 Single Precision开启单精度 FPU编的而调用方工程设置成 Not Used会出现两类问题链接阶段可能报__aeabi_fadd、__aeabi_fmul这类符号未定义因为库没有引用这些软浮点运行时函数或者更麻烦的——链接过了但运行时浮点结果完全不对。我遇到过最诡异的一次是滤波系数算出来差了三个数量级查了两天最后发现是 FPU 设置不一致。处理原则很简单库和调用方的 FPU 设置必须逐字一致。把这个要求写进交付文档并且在头文件里加一道编译期检查#if defined(__SOFTFP__) defined(ALGO_REQUIRE_HARD_FPU) #error This library requires hardware FPU. Enable FPU in Target settings. #endif__SOFTFP__这个宏在软浮点编译时会被定义用它做判断比较可靠。类似的还有字节序相关的__BIG_ENDIAN虽然 Cortex-M 基本都是小端但养成检查的习惯没坏处。4.3 MicroLIB、printf 重定向与 semihosting库内部只要用到了printf、malloc、memcpy这类标准库函数就会牵扯到运行时库的选择。Keil 的 Target 页有个 Use MicroLIB 复选框勾上用的是 ARM 精简版 C 库不勾用的是标准 C 库。这两套库的函数实现不一样混用会出问题。典型症状是库用 MicroLIB 编的调用方工程没勾 MicroLIB链接时报__use_no_semihosting was requested, but _ttywrch was referenced之类的错误。反过来也一样。解决方式有两个一是两边统一设置二是在库这一侧彻底不用标准库的重型功能只保留memcpy/memset这类几乎无依赖的函数。再说 semihosting。库如果调用了printf而调用方没有重定向输出链接器会去找 semihosting 相关的符号这些符号需要调试器支持脱离仿真器跑的时候会直接卡死在某个 BKPT 指令上。正确的做法是让调用方实现输出重定向MicroLIB 下只需实现fputc标准库下还需要_sys_write、_sys_exit等一组函数。库这边最好把printf从对外接口里拿掉改成注册日志回调的形式typedef void (*algo_log_fn)(const char *msg); void algo_set_log_handler(algo_log_fn fn);这样一来库里不直接依赖任何输出设备谁调用谁负责提供打印函数链接期完全干净。这个设计模式我强烈推荐用到所有对外交付的库里能省掉大量跟运行时库纠缠的时间。4.4 优化等级、内联与调试体验前面提过优化等级会固化进库的机器码这里补充一个相关的坑如果你在库的源文件里用了__inline或者依赖编译器自动内联那么函数的机器码可能被内联进调用者也可能根本不存在独立的函数实体。这会造成两个后果一是 Map 文件里看不到这个函数让你误以为库没生成对二是设置断点时压根断不进去。我的处理原则是所有出现在头文件里的对外接口必须禁止内联。可以加__attribute__((noinline))或者在函数定义前加static之外的关键字修饰。同时对外接口不要写成宏宏会在调用方展开你把接口改成宏等于把实现细节又漏出去了。另外一个实际经验库里的代码如果用-O2编译单步调试时会出现跳来跳去、变量显示 optimized out的情况。所以我在内部保留一个-O0的调试版库专门用来定位问题跟交付版分开管理别混在一起。5. 常见报错与排查速查5.1 链接期报错速查表这些报错我基本都踩过一遍整理成表方便对着查报错信息大概率原因处理方式Undefined symbol xxx (referred from main.o)库里有这个符号但没被抽取或函数命名不一致用 fromelf 检查库内符号确认头文件声明和库实现的名字、参数完全一致Symbol xxx multiply defined库和源码同时挂载或库内非 static 函数与调用方重名排除源码组把库内部函数加 static 或统一加前缀__aeabi_fadd undefined库用了硬浮点调用方没开 FPU两边 Floating Point Hardware 设置统一__use_no_semihosting was requested...库引用了 semihosting 相关输出库改为回调式日志或两边统一运行时库设置L6915E: Library reports error类提示库的运行时配置和调用方冲突检查 MicroLIB 勾选状态、C 库版本是否一致No space in execution regions库太大被整块拉进镜像库编译时勾 One ELF Section per Function让链接器能裁剪未用函数关于第一行Undefined symbol有个细节值得展开。静态库的链接机制是按需抽取——链接器扫一遍所有未解析符号只有某个 .o 里包含这些符号时才把它从库里抽出来。这意味着如果库里的 A.o 调用了 B.o 里的函数而调用方只直接调用了 A.o 里的接口链接器在处理 A.o 时会发现 B.o 里的符号也没解析然后再去抽 B.o这个过程是迭代的一般能自动收敛。但如果你的库里有只在启动时自动执行的东西比如 C 全局对象的构造函数、__attribute__((constructor))修饰的函数它们没有任何符号被外部引用链接器就会认为这个 .o 是垃圾直接丢掉导致功能静默失效。这种情况的解决办法是用--whole-archive强制把整个库都拉进来--whole-archive AlgoCore.lib --no_whole_archive加在 Linker 选项卡的 Misc Controls 里。代价是 Flash 占用变大因为库里所有函数都进来了所以只在确实需要时才用。5.2 运行期异常的排查思路链接过了但跑起来不对排查顺序我一般是这样第一步确认符号来源。打开 Map 文件搜库函数名看它是不是真的来自 .lib。如果来自一个你没预期的 .o那说明还存在一份源码或者另一个同名库在起作用。第二步确认配置宏。库在编译时用的宏和调用方在编译时定义的宏是不是一套。最容易出问题的是缓冲区长度、采样率、通道数这类两边都要知道的参数。这类参数如果只能靠人工同步早晚会出错所以能放到运行期初始化的就放运行期通过 init 函数的参数传进去。第三步确认内存布局。库里的全局数组、大缓冲区会占用 .bss 段如果调用方工程的 RAM 本来就紧张可能出现栈溢出或者堆冲突。库的设计上大块内存尽量让调用方通过指针传入库本身只保留状态变量这样内存归属清晰。第四步上示波器或者逻辑分析仪。这一步听起来原始但很多库有问题的结论最后都被证明是时序或者硬件问题。我印象很深的一次客户说库里的 SPI 驱动时序不对最后发现是他们的板子上拉电阻焊错了。先排除外围再怀疑代码。5.3 我踩过的几个坑直接抄作业第一个坑生成的库文件名跟预期不一样。原因是 Name of Executable 那一栏没改生成的还是工程的默认名字结果Objects目录下出现一个奇怪名字的 .lib另外还有个旧的 .axf 混在里面一度以为库没生成成功。后来我养成了习惯生成库之后一定先armar -t看一眼成员列表确认内容对。第二个坑库里的回调函数指针被清零。库里定义了一个static algo_callback_t cb;通过接口函数赋值。这个变量在 .bss 段启动时被清零但如果在 main 之前就触发了中断中断里用到这个回调就会跳到一个空指针。这类问题的根源是库和调用方的初始化顺序不明确解决办法是把库的初始化显式化绝不在库内部搞自动初始化。第三个坑头文件里用到了库内部的头文件。交付时只给了algocore.h但这个头文件里#include algo_internal.h导致调用方编译直接报找不到文件。后来我定了个规矩对外头文件必须自包含self-contained只依赖标准库头文件任何内部头文件都不允许出现在里面。这条规矩看起来简单执行起来需要点自律。第四个坑库的版本没记录。交付了三个版本的库客户当时用的是最新版结果半个月后回来反馈问题谁也不知道板子上跑的是哪个版本。现在的做法是在库的头文件里加两个宏一个是版本号一个是编译时间戳同时在库的初始化函数里返回版本号调用方可以把版本打出来#define ALGOCORE_VERSION_MAJOR 1 #define ALGOCORE_VERSION_MINOR 3 #define ALGOCORE_VERSION_PATCH 2 #define ALGOCORE_VERSION_STRING 1.3.2 uint32_t algo_get_version(void);这个函数几乎零成本但在实际支持过程中价值极高。6. 库的版本管理与交付清单6.1 每次交付必须归档的东西库交付最容易乱的地方不是技术是管理。我给团队定的规矩是每次交付建一个独立目录命名格式是AlgoCore_v1.3.2_20240315里面必须包含五样东西.lib文件、对外头文件整个 inc 目录、一份配置说明编译器版本、优化等级、FPU 设置、必须定义的宏、一个最小示例工程能直接打开编译运行的那种、以及一个变更记录。缺任何一样这一版就不算交付完成。最小示例工程这一项最容易被省但它恰恰是回报最高的。客户拿到库之后的第一件事就是能不能跑起来你给一个能直接打开的示例工程他们十分钟就能验证完不用来回问。我做过对比有示例工程的交付后续的技术支持邮件量能少一半以上。6.2 库的命名与目录约定命名上我建议库名全部用大驼峰加上明确的功能前缀不要用lib开头因为文件扩展名已经是 .lib 了再加 lib 前缀会变成libAlgoCore.lib看起来冗余。文件名里不要出现版本号版本号通过归档目录和头文件宏体现这样调用方工程的配置不用每次升级都改路径。目录结构上一个可复用的第三方库目录大概长这样3rdparty/ AlgoCore/ inc/ algocore.h algocore_types.h lib/ AlgoCore.lib AlgoCore_debug.lib doc/ release_notes.md build_info.txt example/ AlgoCoreDemo.uvprojxinc目录里只放两份头文件是有意为之一份是主接口一份是公共类型定义。头文件数量越少调用方理解成本越低。有些库把内部类型也暴露出去最后变成改一个内部结构体就要重新交付一次头文件完全失去了库的意义。6.3 交付说明里必须写清楚的几件事写交付文档的时候我会固定写这几条逐条对应最容易出问题的环节。第一是本库由 MDK-ARM 5.38 ARM Compiler 6.19 编译请使用相同或兼容版本把版本号钉死。第二是Target 设置中 Floating Point Hardware 必须为 Single Precision配合头文件里的编译期检查双保险。第三是Use MicroLIB 状态必须与库一致本库为未勾选。第四是本库不依赖任何输出设备日志通过 algo_set_log_handler 注册回调。第五是库内所有对外符号均以 algo_ 开头如与你的工程冲突请及时反馈。这几条看着啰嗦但都是被现实教育出来的。尤其是第三条MicroLIB 的勾选状态不一致导致的链接错误占了我们对接问题里相当大的比例。与其每次重新解释一遍不如写进文档里谁都能查到。另外说个实际体会库的调试版本带调试信息的那个不要随手发给客户哪怕是为了帮他们排查问题。正确的做法是让客户提供复现路径和现象你在自己的调试环境里复现。库的意义就是把实现锁住一旦调试版流出去这个边界就没了。真有必须联合调试的场景用远程协助的方式别发文件。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。