CCS编译报错“Target ‘all‘ not remade”排查指南:从gmake原理到实践
发布时间:2026/9/28 13:15:48 锦皓数字建站

刚接触CCS的朋友十有八九都会撞上这个报错控制台里刷出一大堆编译日志拉到最底下赫然一行大红的“gmake: Target all not remade because of errors”。说句实话我第一次看到这行字的时候也懵了一小会儿——它看起来像是整个编译系统在摊手“我不干了你自己看去吧。”但实际上这句提示本身并不是错误的真正原因它只是一个终止通知gmake在构建过程中碰到了某个错误导致最终目标“all”没有生成。这篇文章我会从这个报错的开排查逻辑讲起结合我在CCSCode Composer StudioTI官方集成开发环境上做的几个DSP项目的实际经验把这句报错背后的构建机制、高频根因、排查步骤、修复方法一次性讲透。不管你是被这道报错卡了一上午的新手还是想系统性了解CCS编译过程的老人这篇文章都应该能帮你省下不少时间。1. 从报错信息本身说起这句话到底在说什么很多人一看到“Target all not remade because of errors”就慌了觉得是工程废了或者是自己装的CCS有问题。其实真要理解这句话得分两层来看一层是“gmake”是什么另一层是“Target all”又是什么。1.1 报错信息的字面含义拆解先拆词。gmake是 GNU Make 在 Windows/Linux 环境下的一种叫法CCS 从很老的版本开始就把它作为底层的构建驱动。Make 这类工具做的事情本质上就是“按依赖关系依次执行命令”——它读一个 Makefile里面描述了编译哪个源文件、生成哪个目标文件、最后怎么链接成最终的可执行文件。那Target all又是什么在 Makefile 体系里“all”是一个非常约定俗成的总目标你可以把它理解成“工程的全部产出”。当你在 CCS 里点了锤子按钮触发编译时gmake 会默认去构建这个叫“all”的目标而“all”又依赖于你工程里所有源文件编译出来的目标文件、库文件和最终的输出文件。“not remade”的意思就更直白了gmake 发现有些依赖项没搞定所以干脆不执行“all”的最终生成动作。因为 Make 的基本原则是“如果一个目标的依赖没构建成功那这个目标本身也不能构建”。这是一条保护链防止你拿着残缺的半成品去烧录或者仿真。你看整句话拼起来的信息量其实就是“编译流程中有环节失败了所以我中止了最终输出。”真正值得关注的是这条报错上方那些带着error字样的具体日志。与其盯着这行“总告警”发愁不如顺着日志往上找。1.2 为什么CCS会用gmake而不是其他构建工具这里我补一个背景知识理解了它你在排错时思路会清晰很多。CCS 早期基于 Eclipse 框架Eclipse 生态里的 C/C 开发环境CDT默认就使用 Make 体系来管理构建。TI 在此基础上套了自己的编译工具链如 ti-cgt、cl2000、armcl 等于是整体构建流程就变成了“Eclipse 生成 Makefile → gmake 执行 Makefile → 调用 TI 编译器编译链接”。所以本质上你在 CCS 里看到的编译输出并不是“IDE 在编译”而是IDE 在后台替你调用 gmake 编译器在编译。这条链路意味着两件事第一Makefile 的生成是动态的。你在 CCS 图形界面上改的编译选项、包含路径、预定义宏最终都会转换成 Makefile 里的变量和规则。如果图形界面配置和实际代码有冲突gmake 执行时就会报出五花八门的错误。第二gmake 的错误提示风格非常“Unix 化”。它只告诉你“哪个目标没完成”并不会帮你做智能诊断。这和 Visual Studio 那种“双击错误就能跳到代码行”的体验完全不同。所以我们在 CCS 里排错一定要养成看完整日志的习惯。2. 排查总路线不要在错误信息上死磕清楚了上面这些原理你就会明白排查这个问题的正确姿势是绕过“总告警”直接抓“首因错误”。我这几年的经验是绝大多数情况下真正的错误一定在这行“Target all not remade”之前若干行的编译日志里。2.1 第一步打开完整编译日志别让报错被吞掉如果你在 CCS 的 Console 面板里只看到很少的输出连error细节都被折叠了那多半是因为构建输出级别设置得不够详细。这个时候就得先把“案发现场”完整还原出来。具体操作在工程上右键 → Properties → C/C Build → Build Output把输出级别从默认的“Detailed”或者“No Console Output”改成“Full”或“Detailed”。有些版本里这个选项在“Console”相关的配置项下。改完之后重新触发编译你会看到 Console 面板刷出的日志多了很多每一条编译命令的前后细节都能看到。还有一个我常用的方法在 Console 面板里右键选择“Copy Selected”或者直接全选复制把完整日志粘贴到文本编辑器里然后用搜索功能定位。这比在 IDE 里滚动翻找高效得多。2.2 第二步定位第一个真正的错误拿到了完整日志下一步就是搜索。建议直接搜error关键字注意不要光搜小写的error因为不同编译器的日志格式不一样有时候是: error:有时候是#errorTI 的编译器有时会用 ERROR这种标记。如果在日志中搜索到了多个error请务必以第一个为准。为什么要以第一个为准因为 gmake 在遇到编译错误后通常会继续尝试其他不相关的编译任务或者因为某个头文件缺失导致几十个源文件连环报错。这就造成了一种“错误的瀑布效应”——你如果只关注最后一个报错很可能会被牵着鼻子走。反过来第一个报错往往是不依赖其他错误的最底层原因。把第一个修好了后面一半以上的报错可能自动消失。2.3 第三步分类处理逐个击破定位到第一个错误之后先把它归个类。我实际排查下来这类报错背后的真正错误基本逃不出三大类错误类别典型报错特征处理思路编译类错误fatal error #1965: cannot open source file xxx.h、unrecognized token、expected a ;检查代码语法、头文件包含路径、宏定义链接类错误undefined symbol、multiple definition、cannot find -lxxx检查文件是否加入工程、库路径、链接器配置构建环境类错误Permission denied、File not found、gmake: *** No rule to make target检查文件系统权限、工程路径、外部进程干扰三大类的处理重点完全不同。编译类错误重点查代码和头文件路径链接类错误重点查工程文件列表和库配置构建环境类错误重点查你的工程路径、操作系统权限和后台进程。下面我挑几个最高频的场景结合实操展开讲讲。3. 高频根因专项排查与实战修复这一节我会把“真正导致编译失败”的具体问题拆开来讲。每个场景我都尽量还原真实的报错现场和处理过程这样你以后遇到相似情况可以少走弯路。3.1 头文件路径配置最常见也最容易被忽略先看一个非常典型的报错场景 ERROR: fatal error #1965: cannot open source file DSP2833x_Device.h gmake: *** [main.obj] Error 1 gmake: Target all not remade because of errors这种情况下真正的错误是编译器找不到DSP2833x_Device.h后续的Target all not remade只是“顺带通知”而已。为什么找不到头文件据我观察常见原因有三类第一类include 路径压根没加进工程。有些头文件放在工程的/include子目录下但工程配置里没有把这个目录加到“Include Options”里。编译器在#include DSP2833x_Device.h时只会默认搜索源文件所在目录、编译器自带 include 目录以及你在编译选项里指定的目录。如果你没指定对应路径自然就找不到了。解决方法很简单右键工程 → Properties → C/C General → Paths and Symbols → Includes 标签页把存放头文件的目录加进去。注意这里要选对语言GNU C / GNU C并且要用Add...添加目录路径。添加完毕后一定要点右下角的“Apply”和“OK”很多朋友改完配置忘了应用结果编译还是报错白白折腾半天。第二类路径写错或者符号用错。Windows 下路径分隔符是反斜杠\但 gmake 和编译器在解析时对反斜杠的处理很微妙。我踩过的坑是在 include 路径里写了类似..\include\DSP2833x\common这种反斜杠混合相对路径结果编译器在某个环节把转义字符解析错了报了一堆莫名其妙的错误。后来我全部改成正斜杠/——../include/DSP2833x/common问题就消失了。这里建议你养成习惯在 CCS 的路径配置里一律用正斜杠/这是最保险的写法。第三类相对路径的“相对基准”错了。这是 gmake 机制下最坑的一个点。你在图形界面写../common/include这个相对路径是相对于“哪个目录”解析的答案是相对于 Makefile 文件所在目录也就是工程目录下某个 build 子目录。如果你的工程目录层级比较深比如work/project_v2/software/dsp/main.c而头文件放在work/project_v2/shared/inc那你单纯写../shared/inc可能完全对不上。因为编译器编译main.c时相对路径基准是工程根目录而不是 main.c 所在的目录。我个人的习惯是如果头文件路径涉及多层上级目录优先用“工程名相对路径”的方式即把工程根目录先加进 include 路径然后代码里写#include shared/inc/xxx.h。这样不管目录挪到哪里只要工程整体路径不拆散编译都能正常找到。3.2 链接阶段错误undefined symbol 与 multiple definition编译过程都通过了结果在链接阶段报了一堆错误最后也以“Target all not remade because of errors”收尾。这种情况也非常常见。undefined symbol的含义是某个函数或变量被声明、被调用了但定义找不到。常见原因有函数声明了但没实现也就是 .c 文件里没有对应函数体源文件压根没加入工程。比如你在某个 .c 文件里定义了void InitSystem(void)但该文件没有通过“Add Files”加入工程链接器根本不知道它的存在被调用的函数在一个静态库 (.lib/.a) 里但链接器的库搜索路径里没包含这个库。排查方法我推荐用“链接器命令行”来核对。在 CCS 的工程属性 → Build → Linker或者直接看完整编译日志里最后那几行链接命令把命令行中出现的所有 .c/.obj/.lib 列出来然后对照你的工程里实际存在的文件看是否有遗漏。模糊归模糊但多数时候一眼就能看出少加了哪个文件。multiple definition的意思更直白同一个符号被定义了多次。常见原因有三种一是多个源文件里都定义了一个同名的全局变量比如Uint16 flag;写在头文件里又被多个 .c 文件包含二是同一个 .c 文件被重复添加到了工程里三是静态库和源文件里各定义了一个同名函数。解决multiple definition的教训是头文件里只声明不要定义。如果需要共享全局变量用extern在头文件里声明在某个 .c 文件里定义。这么写虽然看上去多了一行代码但能避免的麻烦远不止一次编译报错——当工程规模变大、参与的人变多时这个习惯能让你少加无数个夜班。3.3 工程路径与文件名中文、空格等“隐形杀手”第三种高频场景和代码本身没关系纯粹是“路径问题”。gmake 这个工具虽然能跑在 Windows 上但它骨子里带着 Unix 的脾气对路径里的空格、中文、括号等特殊字符容忍度很低。有一次我帮朋友排查问题他的工程放在E:\开发板例程\DSP28335\新建文件夹 (3)\LED_Blink编译时报了一堆cannot open source file和No such file or directory最后也是“Target all not remade”。我看了一眼路径就明白问题出在哪儿了路径里有中文、有空格还有括号。gmake 在执行 Makefile 里的命令时会把整条命令交给系统 shell 去跑而路径里的空格会被当成多个参数括号在某些 shell 规则里也有特殊含义。解决办法很简单也很无奈把工程整个复制到一个全英文、无空格、无特殊字符的路径下比如C:\ti_workspace\led_blink。复制完成后在 CCS 里重新导入工程或切换工作区到新路径再次编译通常问题就消失了。你别觉得这是“绕路”。在嵌入式开发领域很多工具链都是根深蒂固的 Linux/Unix 血统它们对路径格式的要求就是苛刻。与其跟工具斗智斗勇不如一开始就保持路径干净。我现在每开一个新项目第一件事就是在C:\workspace下建一个纯英文的工程文件夹所有代码、脚本都在这个目录之下。4. 编译环境层面的“隐形杀手”这一节聊点更隐藏的问题。有时候你的代码没问题、路径没问题、配置也没问题但编译就是反复出“Target all not remade because of errors”的幺蛾子。这时候就要往“编译环境”层面想了。4.1 外部环境干扰杀毒软件、索引器与文件占用我遇到过好几次“邪门”问题编译日志里显示某个 .obj 文件Permission denied或者是gmake: *** fopen: Permission denied。一开始我还以为是工程只读属性折腾了半天最后发现是杀毒软件在实时扫描编译生成的临时文件把文件锁住了。CCS 在编译时会不断在 Debug 或 Release 目录下生成 .obj、.out、.d 等文件杀毒软件的实时防护如果介入很可能会导致 gmake 无法正常写入。排查方法在编译时留意日志中是否出现Permission denied、Access is denied、Sharing violation之类的字样。如果有直接把工程目录加入杀毒软件白名单或者临时关闭实时防护后再编译一次。如果你用的电脑上装了公司统一部署的安全软件没法关那就尽量避免把工程放在被重点监控的目录底下比如“文档”、“桌面”往往都是重点防护区。另一个外部干扰是“文件被其他程序占用”。最常见的坑是你用某个编辑器打开了工程里的某个源文件然后又启动了另一套构建脚本——Windows 下如果文件被锁定gmake 无法更新对应的 .obj 文件就会报错。这时候可以先重启一下 CCS把其他占用文件的程序关掉再重新编译。4.2 CCS版本与编译器版本不匹配还有一类问题感觉上“哪哪都没错”但编译就是失败。后来我留意到和CCS 版本与编译器CGT版本不匹配有很大关系。比如老工程是用 CCS 6 配 TI v16.9 编译器写的你换上 CCS 12 后工程默认编译器版本被自动替换成 v20.2某些老代码在新编译器下会报出一些新的编译错误——比如语法检查更严格了、某些隐含的类型转换被升级为 error最后也以“Target all not remade because of errors”收尾。处理办法有两个方向一是升级代码把新编译器抱怨的地方改掉这也是长期最佳方案二是在工程属性里把编译器版本改回老版本如果 CCS 里还保留着老版本编译器的话。具体操作右键工程 → Properties → General → Toolchain / Compiler version下拉选择你原本的编译器版本。顺带提一句工作区索引缓存Indexer也可能会捣乱。如果你发现代码里明明已经修正了错误但重新编译时错误依旧可以试试 Project → Clean把工程清干净再重建。如果还不行重启 CCS再不行把工作区里的.metadata文件夹备份后删掉重新在工作区导入工程。这个方法有点暴力但对付各种 IDE “神经病”问题往往有奇效。5. 常见问题速查与排查技巧实录学完了原理和专项场景最后我用一个速查表帮你把整个排查思路沉淀下来。以后遇到编译报错可以直接对着这个表一步步走。5.1 高频问题速查表报错现象日志中的关键字根因方向首选排查动作解决参考fatal error #1965: cannot open source file xxx.h头文件路径未配置 / 路径格式错误检查 include 路径用正斜杠重写添加 include 路径统一/分隔符undefined symbol缺少函数定义文件未加入工程核对链接命令行中的文件/库列表添加源文件或库路径multiple definition全局变量/函数重复定义用extern改头文件声明头文件只声明源文件里定义cannot open file xxx.obj/No such file.obj 文件丢失工程里引用了不存在的源文件检查工程文件列表Project → Clean从工程移除引用重新构建Permission denied/Sharing violation杀毒软件 / 文件占用检查是否被其他程序锁定加入白名单 / 关闭占用程序gmake: *** No rule to make target xxx工程里引用的文件已移动或删除定位引用位置更新路径修改文件引用或还原文件日志中路径出现中文/空格gmake 对特殊字符敏感检查工程存放路径复制到全英文路径下5.2 一次完整排错过程的现场复盘最后我给你还原一次我最近处理的实际案例重点展示排查的完整顺序。当时一个电机控制项目同事在 CCS 里点编译日志刷了不到 1 秒就停了最后一行就是“Target all not remade because of errors”。日志上面有几行#1965 cannot open source file F2837xD_GlobalPrototypes.h后面还跟着十几个cannot open的头文件错误。我第一反应不是去一个个补路径而是先看这个头文件在工程里的物理位置。查了一下这个头文件确实存在于工程的include目录下但问题的关键是工程属性里 include 路径配置写的是../include而工程实际路径是D:\work\MotorCtrl_A01\software\cpu1头文件在D:\work\MotorCtrl_A01\software\include。也就是说../include在 Makefile 的执行目录里被解析成D:\work\MotorCtrl_A01\software\cpu1\../include这本来也没错但 gmake 把整条编译命令交给 shell 之后路径里的反斜杠在传递时有一部分变成了\i这种转义形式导致编译器找不到。我没去纠结反斜杠转义的问题直接把工程属性里的 include 路径从../include改成绝对路径D:/work/MotorCtrl_A01/software/include并顺手把所有其他 include 路径里的反斜杠全部替换成了正斜杠。重新编译报错立刻少了一半——说明大多数头文件找不到都是由路径格式问题连带触发的。剩下的一半里有一个undefined symbol是因为同事新写了一个PID_Update函数但对应的 .c 文件没有加入工程还有一个multiple definition是某个全局配置结构体在头文件里定义了被两个源文件包含后重复定义。把这三个问题依次处理完编译顺利通过最后生成了.out文件。“Target all not remade”这句报错再也没出现。6. 写在最后的几点实操心得我的经验是CCS 里这个“gmake: Target all not remade because of errors”本质上是个“闹钟”不是“判决书”。它提醒你去看编译日志中更早的信息而真正要解决的问题十有八九就藏在上面几行到几十行之间。遇到它先深呼吸然后往上翻日志找第一个 error大部分问题就解决了七八成。另外分享一个小技巧在 CCS 的 Console 面板里双击带error关键字的日志行IDE 通常会尝试帮你跳到对应的源文件或工程配置项。虽然不是每次都能准确跳转但在某些版本里确实能快速定位到出错的那一行代码。如果双击没反应就用外部文本编辑器打开完整日志用搜索定位然后手动去代码里找。最后再给新接触 CCS 的朋友一个建议每次新建工程第一件事就是把工程目录放到全英文路径下并在工程属性里把 include 路径统一改成正斜杠写法。这个习惯坚持下来你会发现编译报错的频率比身边同事低不少。虽然这个报错本身不难解决但能省下的调试时间放到代码功能调试上收益要大得多。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。