<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>http://localhost:3000/blog</id>
    <title>个人空间 Blog</title>
    <updated>2026-07-16T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="http://localhost:3000/blog"/>
    <subtitle>个人空间 Blog</subtitle>
    <icon>http://localhost:3000/img/favicon.svg</icon>
    <entry>
        <title type="html"><![CDATA[个人空间开始建设]]></title>
        <id>http://localhost:3000/blog/site-start</id>
        <link href="http://localhost:3000/blog/site-start"/>
        <updated>2026-07-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[记录这个个人内容中心的目标与第一阶段范围。]]></summary>
        <content type="html"><![CDATA[<p>这个网站用于统一整理博客、长期文档、个人项目和履历信息。</p>
<!-- -->
<p>第一阶段选择 Docusaurus 和 TypeScript，先完成稳定的内容结构、测试基线与本地构建。部署方式、复杂主题切换和私人内容系统暂不纳入范围。</p>]]></content>
        <author>
            <name>个人站作者</name>
        </author>
        <category label="建站" term="建站"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[macOS "应用已损坏" 完全指南]]></title>
        <id>http://localhost:3000/blog/macos-app-damaged-guide</id>
        <link href="http://localhost:3000/blog/macos-app-damaged-guide"/>
        <updated>2025-12-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[这是一个集原理讲解、场景复现和解决方案于一体的完整指南。通过本项目提供的工具，你可以亲手复现 macOS Gatekeeper 的拦截行为，并彻底理解 “应用已损坏” (App Damaged) 背后的技术真相。]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p>这是一个集<strong>原理讲解</strong>、<strong>场景复现</strong>和<strong>解决方案</strong>于一体的完整指南。通过本项目提供的工具，你可以亲手复现 macOS Gatekeeper 的拦截行为，并彻底理解 “应用已损坏” (App Damaged) 背后的技术真相。</p>
</blockquote>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-现象描述">1. 现象描述<a href="http://localhost:3000/blog/macos-app-damaged-guide#1-%E7%8E%B0%E8%B1%A1%E6%8F%8F%E8%BF%B0" class="hash-link" aria-label="1. 现象描述的直接链接" title="1. 现象描述的直接链接" translate="no">​</a></h2>
<p>在 macOS 上安装或启动应用时，可能会遇到以下提示：</p>
<blockquote>
<p>“xxx.app 已损坏，无法打开。你应该将它移到废纸篓。”
(English: "xxx.app is damaged and can't be opened. You should move it to the Trash.")</p>
</blockquote>
<p><strong>核心事实</strong>：
大多数情况下，<strong>文件并没有物理损坏</strong>。这通常是 macOS 的 <strong>Gatekeeper 安全机制</strong>在发现应用“来路不明”（如带有隔离属性且无有效签名）时，为了安全起见直接拒绝运行的通用错误提示。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-核心原理两道防线">2. 核心原理：两道防线<a href="http://localhost:3000/blog/macos-app-damaged-guide#2-%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86%E4%B8%A4%E9%81%93%E9%98%B2%E7%BA%BF" class="hash-link" aria-label="2. 核心原理：两道防线的直接链接" title="2. 核心原理：两道防线的直接链接" translate="no">​</a></h2>
<p>macOS 的应用启动检查可以看作是两道防线：</p>
<ol>
<li class="">
<p><strong>第一道防线：内核 (Kernel) —— 强制代码签名</strong></p>
<ul>
<li class=""><strong>机制</strong>：在 M1/M2/M3 (Apple Silicon) 芯片上，<strong>所有可执行代码必须拥有签名</strong>（哪怕是 Ad-hoc 签名）。</li>
<li class=""><strong>拦截表现</strong>：如果完全无签名，内核直接拒绝加载，进程崩溃（<code>Killed</code>）。</li>
<li class=""><strong>豁免</strong>：本地编译生成的文件会有临时的 AMFI 豁免，但一旦文件离开本机（异地），豁免失效，必须有签名才能活。</li>
</ul>
</li>
<li class="">
<p><strong>第二道防线：Gatekeeper —— 信任策略检查</strong></p>
<ul>
<li class=""><strong>触发开关</strong>：<strong>隔离属性 (Quarantine)</strong>。当文件来自非本地来源（如下载、AirDrop）时，系统会自动添加此属性。<strong>一旦检测到此属性</strong>，Gatekeeper 即会介入。</li>
<li class=""><strong>检查内容</strong>：<!-- -->
<ul>
<li class=""><strong>是不是正经开发者？</strong> (是否有 Apple Developer ID)。</li>
<li class=""><strong>有没有恶意软件？</strong> (是否经过公证 Notarized)。</li>
<li class=""><strong>文件改没改过？</strong> (哈希校验)。</li>
</ul>
</li>
<li class=""><strong>拦截表现</strong>：提示“无法验证开发者”或“<strong>应用已损坏</strong>”。</li>
</ul>
</li>
</ol>
<p><strong>总结</strong>：</p>
<ul>
<li class=""><strong>无签名</strong> -&gt; 死在第一道防线（内核）。</li>
<li class=""><strong>Ad-hoc + 隔离</strong> -&gt; 死在第二道防线（Gatekeeper）。</li>
<li class=""><strong>文件篡改</strong> -&gt; 死在哈希校验（Gatekeeper）。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-验证实验室亲自复现与验证">3. 验证实验室：亲自复现与验证<a href="http://localhost:3000/blog/macos-app-damaged-guide#3-%E9%AA%8C%E8%AF%81%E5%AE%9E%E9%AA%8C%E5%AE%A4%E4%BA%B2%E8%87%AA%E5%A4%8D%E7%8E%B0%E4%B8%8E%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="3. 验证实验室：亲自复现与验证的直接链接" title="3. 验证实验室：亲自复现与验证的直接链接" translate="no">​</a></h2>
<p>为了验证上述原理，我们编写了一个简单的验证工具包。这里包含了 6 个核心实验，覆盖了 macOS 下应用运行的所有关键场景。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实验概览表">实验概览表<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C%E6%A6%82%E8%A7%88%E8%A1%A8" class="hash-link" aria-label="实验概览表的直接链接" title="实验概览表的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">ID</th><th style="text-align:left">场景描述</th><th style="text-align:left">状态配置</th><th style="text-align:left">预期结果 (Apple Silicon)</th><th style="text-align:left">核心原理</th></tr></thead><tbody><tr><td style="text-align:left"><strong>1</strong></td><td style="text-align:left"><strong>本地无签名</strong></td><td style="text-align:left">无签名 + 无隔离</td><td style="text-align:left">✅ <strong>运行成功</strong></td><td style="text-align:left">本地编译豁免 / 内核信任</td></tr><tr><td style="text-align:left"><strong>2</strong></td><td style="text-align:left"><strong>模拟异地无签名</strong></td><td style="text-align:left">无签名 + 无隔离</td><td style="text-align:left">❌ <strong>拒绝 (Killed)</strong></td><td style="text-align:left">必死。一旦离机 AMFI 豁免失效，内核强制要求签名</td></tr><tr><td style="text-align:left"><strong>3</strong></td><td style="text-align:left"><strong>模拟异地 Ad-hoc</strong></td><td style="text-align:left">Ad-hoc + 无隔离</td><td style="text-align:left">✅ <strong>运行成功</strong></td><td style="text-align:left"><strong>唯一活路</strong>。Ad-hoc 满足内核，无隔离绕过 Gatekeeper</td></tr><tr><td style="text-align:left"><strong>4</strong></td><td style="text-align:left"><strong>模拟异地 Ad-hoc</strong></td><td style="text-align:left">Ad-hoc + 有隔离</td><td style="text-align:left">⚠️ <strong>拦截/损坏</strong></td><td style="text-align:left">签名未被信任 (无 Developer ID)</td></tr><tr><td style="text-align:left"><strong>5</strong></td><td style="text-align:left"><strong>自动隔离机制</strong></td><td style="text-align:left">浏览器下载</td><td style="text-align:left">ℹ️ <strong>属性自动添加</strong></td><td style="text-align:left">Launch Services 自动标记下载文件</td></tr><tr><td style="text-align:left"><strong>6</strong></td><td style="text-align:left"><strong>签名完整性验证</strong></td><td style="text-align:left">Linker vs Codesign</td><td style="text-align:left">⚠️ <strong>结果迥异</strong></td><td style="text-align:left"><strong>资源密封 (Sealed Resources)</strong> 决定是硬拦截还是软拦截</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="项目结构">项目结构<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84" class="hash-link" aria-label="项目结构的直接链接" title="项目结构的直接链接" translate="no">​</a></h3>
<blockquote>
<p>📦 <strong>完整项目代码</strong>：<a href="https://github.com/fengyueran/macos-gatekeeper-guide" target="_blank" rel="noopener noreferrer" class="">macos-gatekeeper-guide</a></p>
</blockquote>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">macos-gatekeeper-guide/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── build_test_app.sh # 构建脚本（支持多种签名模式）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── src/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│ └── main.swift # 测试应用源码（SwiftUI）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── build/ # 构建产物目录（自动生成）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── \*.app # 生成的测试应用</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p><strong>核心文件说明</strong>：</p>
<ul>
<li class=""><strong><code>build_test_app.sh</code></strong>：一键构建工具，支持 <code>--unsigned</code>、<code>--linker-signed</code>、<code>--name</code> 等参数</li>
<li class=""><strong><code>src/main.swift</code></strong>：极简 SwiftUI 应用，用于验证签名和 Gatekeeper 行为</li>
</ul>
<p><strong>使用前提</strong>：确保在项目根目录下执行所有命令。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实验-1本地无签名基准对照">实验 1：本地无签名（基准对照）<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C-1%E6%9C%AC%E5%9C%B0%E6%97%A0%E7%AD%BE%E5%90%8D%E5%9F%BA%E5%87%86%E5%AF%B9%E7%85%A7" class="hash-link" aria-label="实验 1：本地无签名（基准对照）的直接链接" title="实验 1：本地无签名（基准对照）的直接链接" translate="no">​</a></h3>
<p>验证 macOS 对“本机生产”文件的信任机制。</p>
<ol>
<li class=""><strong>构建无签名应用</strong>：<!-- -->
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">./build_test_app.sh --unsigned --name "App_Exp1"</span><br></div></code></pre></div></div>
<em>(说明：此处的 <code>--unsigned</code> 会显式移除所有签名，包括 Linker-Signed（编辑器自动添加的签名）。)</em></li>
<li class=""><strong>运行</strong>：双击 <code>build/App_Exp1.app</code>。</li>
</ol>
<p><strong>结果</strong>：✅ <strong>成功打开</strong>。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp1_success.webp" alt="实验1：本地无签名成功运行" class="img_gjoA"></p>
<blockquote>
<p><strong>原理</strong>：本机编译的文件享有 AMFI 临时豁免，即使完全无签名也能运行。</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实验-2异地无签名--移除隔离模拟尝试绕过">实验 2：异地无签名 + 移除隔离（模拟尝试绕过）<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C-2%E5%BC%82%E5%9C%B0%E6%97%A0%E7%AD%BE%E5%90%8D--%E7%A7%BB%E9%99%A4%E9%9A%94%E7%A6%BB%E6%A8%A1%E6%8B%9F%E5%B0%9D%E8%AF%95%E7%BB%95%E8%BF%87" class="hash-link" aria-label="实验 2：异地无签名 + 移除隔离（模拟尝试绕过）的直接链接" title="实验 2：异地无签名 + 移除隔离（模拟尝试绕过）的直接链接" translate="no">​</a></h3>
<p>验证如果用户手动移除了隔离属性，<strong>完全无签名</strong>的应用在异地是否能运行。</p>
<ol>
<li class=""><strong>构建无签名应用</strong>：<!-- -->
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">./build_test_app.sh --unsigned --name "App_Exp2"</span><br></div></code></pre></div></div>
</li>
<li class=""><strong>通过 AirDrop 传输到另一台 Mac</strong>。</li>
<li class=""><strong>在接收机器上移除隔离属性</strong>：<!-- -->
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">xattr -d com.apple.quarantine /path/to/App_Exp2.app</span><br></div></code></pre></div></div>
</li>
<li class=""><strong>运行</strong>：双击 <code>App_Exp2.app</code>。</li>
</ol>
<p><strong>结果</strong>：❌ <strong>无法打开 / 闪退</strong>。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp2_killed.webp" alt="实验2：异地无签名被杀" class="img_gjoA"></p>
<ul>
<li class=""><strong>注意</strong>：此时在“隐私与安全性”中<strong>不会出现</strong>“仍要打开”的按钮。</li>
<li class=""><strong>原理</strong>：因为隔离属性已被移除，Gatekeeper 没有介入，是<strong>内核直接查杀</strong>了进程。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实验-3异地完整-ad-hoc--无隔离成功绕过方案">实验 3：异地完整 Ad-hoc + 无隔离（成功绕过方案）<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C-3%E5%BC%82%E5%9C%B0%E5%AE%8C%E6%95%B4-ad-hoc--%E6%97%A0%E9%9A%94%E7%A6%BB%E6%88%90%E5%8A%9F%E7%BB%95%E8%BF%87%E6%96%B9%E6%A1%88" class="hash-link" aria-label="实验 3：异地完整 Ad-hoc + 无隔离（成功绕过方案）的直接链接" title="实验 3：异地完整 Ad-hoc + 无隔离（成功绕过方案）的直接链接" translate="no">​</a></h3>
<p>验证 <strong>Ad-hoc 签名</strong>在移除隔离属性后的行为。</p>
<ol>
<li class=""><strong>构建完整 Ad-hoc 应用</strong>：<!-- -->
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">./build_test_app.sh --name "App_Exp3"</span><br></div></code></pre></div></div>
</li>
<li class=""><strong>通过 AirDrop 传输到另一台 Mac</strong>。</li>
<li class=""><strong>在接收机器上移除隔离属性</strong>：<!-- -->
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">xattr -d com.apple.quarantine /path/to/App_Exp3.app</span><br></div></code></pre></div></div>
</li>
<li class=""><strong>运行</strong>：双击 <code>App_Exp3.app</code>。</li>
</ol>
<p><strong>结果</strong>：✅ <strong>成功打开</strong>。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp3_success.webp" alt="实验3：Ad-hoc签名成功运行" class="img_gjoA"></p>
<blockquote>
<p><strong>结论</strong>：<strong>完整 Ad-hoc + 移除隔离 = 可行</strong>。
内核只要求“有签名”，Gatekeeper 只要求“有隔离才查”。只要移除了隔离，Gatekeeper 不上班，内核看到有签名就放行。</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实验-4异地-ad-hoc--有隔离标准拦截">实验 4：异地 Ad-hoc + 有隔离（标准拦截）<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C-4%E5%BC%82%E5%9C%B0-ad-hoc--%E6%9C%89%E9%9A%94%E7%A6%BB%E6%A0%87%E5%87%86%E6%8B%A6%E6%88%AA" class="hash-link" aria-label="实验 4：异地 Ad-hoc + 有隔离（标准拦截）的直接链接" title="实验 4：异地 Ad-hoc + 有隔离（标准拦截）的直接链接" translate="no">​</a></h3>
<p>这是最真实的默认场景：你写了个 App（未购买证书），直接分发给他人使用。</p>
<ol>
<li class=""><strong>构建</strong>：<!-- -->
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">./build_test_app.sh --name "App_Exp4"</span><br></div></code></pre></div></div>
</li>
<li class=""><strong>通过 AirDrop 传输到另一台 Mac（自动添加隔离属性）</strong>。</li>
<li class=""><strong>运行</strong>：双击 <code>build/App_Exp4.app</code>。</li>
</ol>
<p><strong>结果</strong>：⚠️ <strong>被拦截 / 提示无法验证开发者</strong>。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp4_blocked.webp" alt="实验4：被Gatekeeper拦截" class="img_gjoA"></p>
<ul>
<li class=""><strong>关键点</strong>：由于我们的构建脚本使用了规范的 <code>codesign</code>，签名结构完整。因此，在“隐私与安全性”设置中，<strong>会出现“仍要打开”按钮</strong>，允许用户手动放行。</li>
</ul>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp4_open_anyway.webp" alt="实验4：隐私与安全性中的&quot;仍要打开&quot;按钮" class="img_gjoA"></p>
<p>点击仍要打开，打开成功</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp4_success.webp" alt="实验4：点击&quot;仍要打开&quot;后成功运行" class="img_gjoA"></p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="实验-5自动隔离机制演示">实验 5：自动隔离机制演示<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C-5%E8%87%AA%E5%8A%A8%E9%9A%94%E7%A6%BB%E6%9C%BA%E5%88%B6%E6%BC%94%E7%A4%BA" class="hash-link" aria-label="实验 5：自动隔离机制演示的直接链接" title="实验 5：自动隔离机制演示的直接链接" translate="no">​</a></h2>
<p>验证到底什么操作会给文件贴上“隔离”标签。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="验证步骤">验证步骤<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E9%AA%8C%E8%AF%81%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="验证步骤的直接链接" title="验证步骤的直接链接" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>使用 curl 下载</strong>（纯命令行）：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">curl -o google.png https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">xattr -l google.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 结果：(无输出，表示无属性)</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>使用 Safari/Chrome 下载</strong>同一张图：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">xattr -l ~/Downloads/googlelogo_color_272x92dp.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 输出示例：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># com.apple.quarantine: 0081;693a85a3;Chrome;632447E8-28E3-443B-B2D8-FA423C6B2384</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>使用 AirDrop 接收</strong>文件。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">xattr -l ~/Downloads/googlelogo_color_272x92dp.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 输出示例：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># com.apple.quarantine: 0081;655...;sharingd;...</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>微信传输</strong>：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">xattr -l ~/Downloads/googlelogo_color_272x92dp.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 输出示例：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># com.apple.quarantine:0082;693a8446;WeChat;</span><br></div></code></pre></div></div>
</li>
</ol>
<blockquote>
<p><strong>原理</strong>：</p>
<ul>
<li class="">隔离属性由 macOS 的 <strong>Launch Services</strong> 框架自动添加</li>
<li class="">当应用（如浏览器、AirDrop、微信）通过特定 API 下载或接收文件时，会触发 Launch Services 标记</li>
<li class="">命令行工具（curl、wget）直接写入文件系统，不经过这些 API，因此不会触发标记</li>
<li class="">隔离属性包含来源信息（下载工具名称、时间戳、URL 等），用于追溯文件来源</li>
</ul>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实验-6签名完整性实验解密仍要打开消失之谜">实验 6：签名完整性实验（解密“仍要打开”消失之谜）<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E5%AE%9E%E9%AA%8C-6%E7%AD%BE%E5%90%8D%E5%AE%8C%E6%95%B4%E6%80%A7%E5%AE%9E%E9%AA%8C%E8%A7%A3%E5%AF%86%E4%BB%8D%E8%A6%81%E6%89%93%E5%BC%80%E6%B6%88%E5%A4%B1%E4%B9%8B%E8%B0%9C" class="hash-link" aria-label="实验 6：签名完整性实验（解密“仍要打开”消失之谜）的直接链接" title="实验 6：签名完整性实验（解密“仍要打开”消失之谜）的直接链接" translate="no">​</a></h3>
<p>能够解释为什么同样的 Ad-hoc 签名，有的能点“仍要打开”，有的直接报“已损坏”。</p>
<ol>
<li class="">
<p><strong>第一阶段：构建“残血版” (硬拦截)</strong>
使用 <code>--linker-signed</code> 参数，构建一个仅包含 Linker 签名但没有资源密封（Sealed Resources）的应用。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">./build_test_app.sh --linker-signed --name "App_Exp6_Bad"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 手动添加隔离属性（模拟下载）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">xattr -w com.apple.quarantine "0081;632447E8;Chrome;" build/App_Exp6_Bad.app</span><br></div></code></pre></div></div>
<p><strong>结果</strong>：双击运行 -&gt; ❌ <strong>“应用已损坏”</strong> (无按钮)。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp6_damaged.webp" alt="实验6：硬拦截 - 应用已损坏" class="img_gjoA"></p>
</li>
<li class="">
<p><strong>第二阶段：修复为“满血版” (软拦截)</strong>
对同一个 App 进行规范签名。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">codesign --code --force --deep --sign - --verbose=4 build/App_Exp6_Bad.app</span><br></div></code></pre></div></div>
<p><strong>结果</strong>：双击运行 -&gt; ⚠️ <strong>“无法验证开发者”</strong> -&gt; 设置中出现 <strong>【仍要打开】</strong> 按钮。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp6_blocked.webp" alt="实验6：软拦截 - 无法验证开发者" class="img_gjoA"></p>
<p>点击 OK（确定），弹出 Open Anyway(仍要打开)
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp6_open_anyway.webp" alt="实验6：&quot;仍要打开&quot;按钮" class="img_gjoA"></p>
<p>点击仍要打开，打开成功
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/exp6_success.webp" alt="实验6：点击&quot;仍要打开&quot;后成功运行" class="img_gjoA"></p>
</li>
</ol>
<blockquote>
<p><strong>结论</strong>：<strong>签名结构完整性</strong>决定了是“硬拦截（已损坏）”还是“软拦截（无法验证）”。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-深度辨析硬拦截-vs-软拦截">4. 深度辨析：硬拦截 vs 软拦截<a href="http://localhost:3000/blog/macos-app-damaged-guide#4-%E6%B7%B1%E5%BA%A6%E8%BE%A8%E6%9E%90%E7%A1%AC%E6%8B%A6%E6%88%AA-vs-%E8%BD%AF%E6%8B%A6%E6%88%AA" class="hash-link" aria-label="4. 深度辨析：硬拦截 vs 软拦截的直接链接" title="4. 深度辨析：硬拦截 vs 软拦截的直接链接" translate="no">​</a></h2>
<p>通过实验 6，我们知道了签名结构的重要性。那么如何查看应用的签名状态呢？</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="查看签名信息">查看签名信息<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E6%9F%A5%E7%9C%8B%E7%AD%BE%E5%90%8D%E4%BF%A1%E6%81%AF" class="hash-link" aria-label="查看签名信息的直接链接" title="查看签名信息的直接链接" translate="no">​</a></h3>
<p>使用 <code>codesign</code> 命令可以查看应用的详细签名信息：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看签名详情</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">codesign -dvvv /path/to/Your.app</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 关键输出示例：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Linker-Signed（残缺）:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#   Sealed Resources=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 完整 Ad-hoc:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#   Sealed Resources=version 2 rule count=13 nested=0</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="硬拦截-vs-软拦截对比">硬拦截 vs 软拦截对比<a href="http://localhost:3000/blog/macos-app-damaged-guide#%E7%A1%AC%E6%8B%A6%E6%88%AA-vs-%E8%BD%AF%E6%8B%A6%E6%88%AA%E5%AF%B9%E6%AF%94" class="hash-link" aria-label="硬拦截 vs 软拦截对比的直接链接" title="硬拦截 vs 软拦截对比的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">拦截类型</th><th style="text-align:left">签名状态</th><th style="text-align:left">典型特征 (codesign -dvvv)</th><th style="text-align:left">用户界面</th><th style="text-align:left">原因说明</th></tr></thead><tbody><tr><td style="text-align:left"><strong>🔴 硬拦截</strong></td><td style="text-align:left"><strong>Linker-Signed</strong><br>(编译器自动签)</td><td style="text-align:left"><code>Sealed Resources=none</code></td><td style="text-align:left">❌ <strong>已损坏</strong><br>(无按钮)</td><td style="text-align:left">签名结构残缺，Gatekeeper 认为包损坏</td></tr><tr><td style="text-align:left"><strong>🟡 软拦截</strong></td><td style="text-align:left"><strong>完整 Ad-hoc</strong><br>(手动 codesign)</td><td style="text-align:left"><code>Sealed Resources=version 2...</code></td><td style="text-align:left">⚠️ <strong>无法验证</strong><br>(<strong>有按钮</strong>)</td><td style="text-align:left">签名完整但无开发者身份，允许手动放行</td></tr><tr><td style="text-align:left"><strong>🟢 通过</strong></td><td style="text-align:left"><strong>正式证书</strong></td><td style="text-align:left"><code>Authority=Apple Developer...</code></td><td style="text-align:left">✅ <strong>直接打开</strong></td><td style="text-align:left">有效的开发者签名，正常流程</td></tr></tbody></table>
<p><strong>如何确诊？</strong>
使用日志查看确切错误：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">log stream --predicate 'process == "syspolicyd"' --info</span><br></div></code></pre></div></div>
<ul>
<li class=""><strong>硬拦截 (-67062)</strong>：签名结构无法满足要求（如 Linker-Signed 加了隔离）。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-12-06-macOS%E5%BA%94%E7%94%A8%E5%B7%B2%E6%8D%9F%E5%9D%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/log_hard_intercept.webp" alt="系统日志显示硬拦截错误" class="img_gjoA"></li>
<li class=""><strong>软拦截</strong>: 系统尝试获取授权，允许用户手动批准。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-用户端解决方案按推荐程度排序">5. 用户端解决方案（按推荐程度排序）<a href="http://localhost:3000/blog/macos-app-damaged-guide#5-%E7%94%A8%E6%88%B7%E7%AB%AF%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E6%8C%89%E6%8E%A8%E8%8D%90%E7%A8%8B%E5%BA%A6%E6%8E%92%E5%BA%8F" class="hash-link" aria-label="5. 用户端解决方案（按推荐程度排序）的直接链接" title="5. 用户端解决方案（按推荐程度排序）的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="-方案-a终端命令解除隔离">✅ 方案 A：终端命令解除隔离<a href="http://localhost:3000/blog/macos-app-damaged-guide#-%E6%96%B9%E6%A1%88-a%E7%BB%88%E7%AB%AF%E5%91%BD%E4%BB%A4%E8%A7%A3%E9%99%A4%E9%9A%94%E7%A6%BB" class="hash-link" aria-label="✅ 方案 A：终端命令解除隔离的直接链接" title="✅ 方案 A：终端命令解除隔离的直接链接" translate="no">​</a></h3>
<p>这是根治“已损坏”且适用性最广的方法（前提：App 有起码的签名）。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 递归删除隔离属性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">xattr -r -d com.apple.quarantine /path/to/Your.app</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="️-方案-b仍要打开">⚠️ 方案 B：“仍要打开”<a href="http://localhost:3000/blog/macos-app-damaged-guide#%EF%B8%8F-%E6%96%B9%E6%A1%88-b%E4%BB%8D%E8%A6%81%E6%89%93%E5%BC%80" class="hash-link" aria-label="⚠️ 方案 B：“仍要打开”的直接链接" title="⚠️ 方案 B：“仍要打开”的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>适用</strong>：签名完整但无 Developer ID 的应用。</li>
<li class=""><strong>操作</strong>：系统设置 -&gt; 隐私与安全性 -&gt; 点击【仍要打开】。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="-方案-c开启任何来源">🚫 方案 C：开启“任何来源”<a href="http://localhost:3000/blog/macos-app-damaged-guide#-%E6%96%B9%E6%A1%88-c%E5%BC%80%E5%90%AF%E4%BB%BB%E4%BD%95%E6%9D%A5%E6%BA%90" class="hash-link" aria-label="🚫 方案 C：开启“任何来源”的直接链接" title="🚫 方案 C：开启“任何来源”的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo spctl --master-disable</span><br></div></code></pre></div></div>
<p><em>(这无法解决内核级的签名缺失问题，不推荐)</em></p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-开发者根治方案">6. 开发者根治方案<a href="http://localhost:3000/blog/macos-app-damaged-guide#6-%E5%BC%80%E5%8F%91%E8%80%85%E6%A0%B9%E6%B2%BB%E6%96%B9%E6%A1%88" class="hash-link" aria-label="6. 开发者根治方案的直接链接" title="6. 开发者根治方案的直接链接" translate="no">​</a></h2>
<p>如果您是开发者，想要分发应用且确保用户<strong>100% 不遇到</strong>此问题：</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="-唯一正道签名--公证">🔑 唯一正道：签名 + 公证<a href="http://localhost:3000/blog/macos-app-damaged-guide#-%E5%94%AF%E4%B8%80%E6%AD%A3%E9%81%93%E7%AD%BE%E5%90%8D--%E5%85%AC%E8%AF%81" class="hash-link" aria-label="🔑 唯一正道：签名 + 公证的直接链接" title="🔑 唯一正道：签名 + 公证的直接链接" translate="no">​</a></h3>
<ol>
<li class=""><strong>购买</strong>：<a href="https://developer.apple.com/programs/" target="_blank" rel="noopener noreferrer" class="">Apple Developer Program</a> ($99/年)。</li>
<li class=""><strong>签名</strong>：使用 <code>Developer ID Application</code> 证书签名。</li>
<li class=""><strong>公证 (Notarize)</strong>：提交给 Apple 服务器进行恶意软件扫描，并获取 Ticket。</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="-分发建议">📦 分发建议<a href="http://localhost:3000/blog/macos-app-damaged-guide#-%E5%88%86%E5%8F%91%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="📦 分发建议的直接链接" title="📦 分发建议的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>推荐 DMG</strong>：虽然也会带有 Quarantine，但由于是只读镜像，它能确保文件权限和结构<strong>绝对完整</strong>。只要用户通过上述方案绕过 Quarantine，App 是一定能跑的。</li>
<li class=""><strong>慎用 Zip</strong>：如果用户解压工具不当，可能会丢失可执行权限或破坏 Bundle，导致“真·损坏”。</li>
</ul>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="macOS" term="macOS"/>
        <category label="安全" term="安全"/>
        <category label="教程" term="教程"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[C++ 指针详解：传统指针与智能指针]]></title>
        <id>http://localhost:3000/blog/cpp-pointers-guide</id>
        <link href="http://localhost:3000/blog/cpp-pointers-guide"/>
        <updated>2025-12-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[指针是 C++ 的核心特性。本文精简介绍了传统指针与智能指针（C++11+）的用法与最佳实践。]]></summary>
        <content type="html"><![CDATA[<p>指针是 C++ 的核心特性。本文精简介绍了传统指针与智能指针（C++11+）的用法与最佳实践。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="一传统指针基础">一、传统指针基础<a href="http://localhost:3000/blog/cpp-pointers-guide#%E4%B8%80%E4%BC%A0%E7%BB%9F%E6%8C%87%E9%92%88%E5%9F%BA%E7%A1%80" class="hash-link" aria-label="一、传统指针基础的直接链接" title="一、传统指针基础的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="基本概念">基本概念<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5" class="hash-link" aria-label="基本概念的直接链接" title="基本概念的直接链接" translate="no">​</a></h3>
<p>指针存储内存地址，通过 <code>*</code> 解引用，<code>&amp;</code> 取地址。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> val </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ptr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">           </span><span class="token comment" style="color:#999988;font-style:italic">// ptr 存储 val 的地址</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">*</span><span class="token plain">ptr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 通过指针修改 val 的值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 指针的 const 修饰</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> c_ptr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic">// 指向常量:不能通过指针修改值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> ptr_c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic">// 常量指针:指针本身不能改变指向</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="动态内存管理">动态内存管理<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%8A%A8%E6%80%81%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86" class="hash-link" aria-label="动态内存管理的直接链接" title="动态内存管理的直接链接" translate="no">​</a></h3>
<p>使用 <code>new</code>/<code>delete</code> 在堆上分配和释放内存,<strong>必须成对使用</strong>。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">dynamicMemory</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> obj </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 分配单个对象</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">int</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> arr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">{</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 分配数组</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 使用完毕后释放</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">delete</span><span class="token plain"> obj</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   obj </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">nullptr</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">delete</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> arr</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> arr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">nullptr</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 数组必须用 delete[]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="常见陷阱">常见陷阱<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%B8%B8%E8%A7%81%E9%99%B7%E9%98%B1" class="hash-link" aria-label="常见陷阱的直接链接" title="常见陷阱的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">问题</th><th style="text-align:left">错误示例</th><th style="text-align:left">正确做法</th></tr></thead><tbody><tr><td style="text-align:left"><strong>内存泄漏</strong></td><td style="text-align:left"><code>int* p = new int;</code> (忘记释放)</td><td style="text-align:left">用完后 <code>delete p;</code></td></tr><tr><td style="text-align:left"><strong>悬空指针</strong></td><td style="text-align:left"><code>delete p; *p = 1;</code></td><td style="text-align:left"><code>delete p; p = nullptr;</code></td></tr><tr><td style="text-align:left"><strong>重复释放</strong></td><td style="text-align:left"><code>delete p; delete p;</code></td><td style="text-align:left">删除后立即设为 <code>nullptr</code></td></tr><tr><td style="text-align:left"><strong>数组释放</strong></td><td style="text-align:left"><code>int* arr = new int[5]; delete arr;</code></td><td style="text-align:left">必须用 <code>delete[] arr;</code></td></tr></tbody></table>
<p><strong>传统指针的问题</strong></p>
<p>手动管理内存容易出错,异常安全性差。现代 C++ 推荐使用智能指针自动管理生命周期。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="二智能指针自动内存管理">二、智能指针:自动内存管理<a href="http://localhost:3000/blog/cpp-pointers-guide#%E4%BA%8C%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E8%87%AA%E5%8A%A8%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86" class="hash-link" aria-label="二、智能指针:自动内存管理的直接链接" title="二、智能指针:自动内存管理的直接链接" translate="no">​</a></h2>
<p>C++11 引入 <code>&lt;memory&gt;</code> 头文件,提供三种智能指针,利用 RAII 机制自动管理资源。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="stdunique_ptr---独占所有权"><code>std::unique_ptr</code> - 独占所有权<a href="http://localhost:3000/blog/cpp-pointers-guide#stdunique_ptr---%E7%8B%AC%E5%8D%A0%E6%89%80%E6%9C%89%E6%9D%83" class="hash-link" aria-label="stdunique_ptr---独占所有权的直接链接" title="stdunique_ptr---独占所有权的直接链接" translate="no">​</a></h3>
<p><strong>最常用的智能指针</strong>,零开销,确保资源只有一个拥有者。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;memory&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">uniquePtrDemo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 推荐使用 make_unique 创建</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> ptr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_unique</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name keyword" style="color:#00009f">int</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 独占特性:不可复制,只能移动</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// auto p2 = ptr;           // ❌ 编译错误</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> p2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">move</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ptr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 转移所有权,ptr 变为 nullptr</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 数组支持</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> arr </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_unique</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name keyword" style="color:#00009f">int</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">[</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">]</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 自定义删除器(如关闭文件句柄)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> file </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">unique_ptr</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">FILE</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">,</span><span class="token generic-function generic class-name"> </span><span class="token generic-function generic class-name keyword" style="color:#00009f">decltype</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">(</span><span class="token generic-function generic class-name operator" style="color:#393A34">&amp;</span><span class="token generic-function generic class-name">fclose</span><span class="token generic-function generic class-name punctuation" style="color:#393A34">)</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">fopen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"test.txt"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"w"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">fclose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 离开作用域自动释放</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="stdshared_ptr---共享所有权"><code>std::shared_ptr</code> - 共享所有权<a href="http://localhost:3000/blog/cpp-pointers-guide#stdshared_ptr---%E5%85%B1%E4%BA%AB%E6%89%80%E6%9C%89%E6%9D%83" class="hash-link" aria-label="stdshared_ptr---共享所有权的直接链接" title="stdshared_ptr---共享所有权的直接链接" translate="no">​</a></h3>
<p>使用引用计数,允许多个指针共享同一资源,最后一个持有者销毁时释放资源。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">sharedPtrDemo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> p1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_shared</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name keyword" style="color:#00009f">int</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 引用计数 = 1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> p2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> p1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// 引用计数 = 2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">p2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// p2 销毁,引用计数 = 1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// p1 依然有效</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// p1 销毁,引用计数 = 0,资源释放</span><br></div></code></pre></div></div>
<p>为什么用 make_shared?
<code>make_shared</code> 只分配一次内存(对象 + 控制块),而 <code>shared_ptr(new T)</code> 需要两次分配,效率更低。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="stdweak_ptr---弱引用"><code>std::weak_ptr</code> - 弱引用<a href="http://localhost:3000/blog/cpp-pointers-guide#stdweak_ptr---%E5%BC%B1%E5%BC%95%E7%94%A8" class="hash-link" aria-label="stdweak_ptr---弱引用的直接链接" title="stdweak_ptr---弱引用的直接链接" translate="no">​</a></h3>
<p>不增加引用计数,用于打破循环引用或实现观察者模式。</p>
<p><strong>解决循环引用:</strong></p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token class-name">Node</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">shared_ptr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Node</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> next</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">weak_ptr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Node</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> prev</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 用 weak_ptr 打破循环</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">~</span><span class="token function" style="color:#d73a49">Node</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Node 析构\n"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">noCycle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> n1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_shared</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Node</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> n2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_shared</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">Node</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    n1</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> n2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    n2</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain">prev </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> n1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 如果 prev 是 shared_ptr,会导致循环引用</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 正常析构</span><br></div></code></pre></div></div>
<p><strong>安全访问:</strong></p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">weak_ptr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">int</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> wp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> sp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_shared</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name keyword" style="color:#00009f">int</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">42</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    wp </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> locked </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> wp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">lock</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 尝试升级为 shared_ptr</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">cout </span><span class="token operator" style="color:#393A34">&lt;&lt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">locked</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// 对象存在,可以访问</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// sp 销毁后,wp.lock() 返回 nullptr</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="三实战成员变量设计">三、实战:成员变量设计<a href="http://localhost:3000/blog/cpp-pointers-guide#%E4%B8%89%E5%AE%9E%E6%88%98%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="三、实战:成员变量设计的直接链接" title="三、实战:成员变量设计的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="默认选择直接实例">默认选择:直接实例<a href="http://localhost:3000/blog/cpp-pointers-guide#%E9%BB%98%E8%AE%A4%E9%80%89%E6%8B%A9%E7%9B%B4%E6%8E%A5%E5%AE%9E%E4%BE%8B" class="hash-link" aria-label="默认选择:直接实例的直接链接" title="默认选择:直接实例的直接链接" translate="no">​</a></h3>
<p><strong>原则</strong>:能用值类型就用值类型,简单可靠。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Car</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Engine engine</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 推荐:生命周期自动绑定</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Car</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">engine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2.0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 初始化列表构造</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p><strong>优点</strong>:</p>
<ul>
<li class="">内存连续,缓存友好</li>
<li class="">生命周期自动管理</li>
<li class="">无空指针风险</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="何时使用指针">何时使用指针?<a href="http://localhost:3000/blog/cpp-pointers-guide#%E4%BD%95%E6%97%B6%E4%BD%BF%E7%94%A8%E6%8C%87%E9%92%88" class="hash-link" aria-label="何时使用指针?的直接链接" title="何时使用指针?的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">场景</th><th style="text-align:left">推荐类型</th><th style="text-align:left">原因</th></tr></thead><tbody><tr><td style="text-align:left"><strong>多态</strong></td><td style="text-align:left"><code>unique_ptr&lt;Base&gt;</code></td><td style="text-align:left">基类指针指向不同派生类对象</td></tr><tr><td style="text-align:left"><strong>可选成员</strong></td><td style="text-align:left"><code>unique_ptr&lt;T&gt;</code> / <code>optional&lt;T&gt;</code></td><td style="text-align:left">成员可能不存在</td></tr><tr><td style="text-align:left"><strong>延迟初始化</strong></td><td style="text-align:left"><code>unique_ptr&lt;T&gt;</code></td><td style="text-align:left">构造时不创建,稍后按需创建</td></tr><tr><td style="text-align:left"><strong>共享成员</strong></td><td style="text-align:left"><code>shared_ptr&lt;T&gt;</code></td><td style="text-align:left">多个对象共享同一实例</td></tr><tr><td style="text-align:left"><strong>PIMPL 模式</strong></td><td style="text-align:left"><code>unique_ptr&lt;Impl&gt;</code></td><td style="text-align:left">隐藏实现,减少编译依赖</td></tr><tr><td style="text-align:left"><strong>循环依赖</strong></td><td style="text-align:left"><code>weak_ptr&lt;T&gt;</code></td><td style="text-align:left">打破循环引用</td></tr><tr><td style="text-align:left"><strong>Qt 对象</strong></td><td style="text-align:left"><code>T*</code> (原始指针)</td><td style="text-align:left">Qt 父子机制自动管理,不要用智能指针</td></tr></tbody></table>
<p><strong>示例:多态容器</strong></p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Zoo</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">vector</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">unique_ptr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Animal</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> animals</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">unique_ptr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Animal</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> animal</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        animals</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">push_back</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">move</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">animal</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="四高级混用场景与陷阱">四、高级:混用场景与陷阱<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%9B%9B%E9%AB%98%E7%BA%A7%E6%B7%B7%E7%94%A8%E5%9C%BA%E6%99%AF%E4%B8%8E%E9%99%B7%E9%98%B1" class="hash-link" aria-label="四、高级:混用场景与陷阱的直接链接" title="四、高级:混用场景与陷阱的直接链接" translate="no">​</a></h2>
<p>在实际项目中,常遇到原始指针、智能指针、Qt 对象混用,这是最容易出错的地方。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="核心原则">核心原则<a href="http://localhost:3000/blog/cpp-pointers-guide#%E6%A0%B8%E5%BF%83%E5%8E%9F%E5%88%99" class="hash-link" aria-label="核心原则的直接链接" title="核心原则的直接链接" translate="no">​</a></h3>
<p><strong>谁创建谁拥有,谁拥有谁删除</strong>。一个资源只能有一个"主人"。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="场景-1标准-c---智能指针与原始指针">场景 1:标准 C++ - 智能指针与原始指针<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%9C%BA%E6%99%AF-1%E6%A0%87%E5%87%86-c---%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E4%B8%8E%E5%8E%9F%E5%A7%8B%E6%8C%87%E9%92%88" class="hash-link" aria-label="场景 1:标准 C++ - 智能指针与原始指针的直接链接" title="场景 1:标准 C++ - 智能指针与原始指针的直接链接" translate="no">​</a></h3>
<p><strong>规则</strong>:智能指针拥有所有权,原始指针仅用于观察。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">MyClass</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> ptr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 接收原始指针</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ptr</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> ptr</span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token function" style="color:#d73a49">doSomething</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ❌ 绝对不要 delete ptr</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">caller</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> owner </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_unique</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">MyClass</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">owner</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 借用给函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// owner 离开作用域,自动释放</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="场景-2-父子对象机制">场景 2<!-- -->:Qt<!-- --> 父子对象机制<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%9C%BA%E6%99%AF-2-%E7%88%B6%E5%AD%90%E5%AF%B9%E8%B1%A1%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="场景-2-父子对象机制的直接链接" title="场景-2-父子对象机制的直接链接" translate="no">​</a></h3>
<p>Qt 使用对象树自动管理 <code>QObject</code> 及其派生类的内存。</p>
<p><strong>规则</strong>:</p>
<ul>
<li class="">有 <code>parent</code> 的对象由 parent 负责释放</li>
<li class="">使用原始指针,<strong>不要</strong> <code>delete</code>,<strong>不要</strong>用智能指针</li>
</ul>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createWidget</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    QWidget</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> parent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">QWidget</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    QPushButton</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> btn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">QPushButton</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Click"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> parent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 指定 parent</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 不需要 delete btn,parent 析构时会自动释放</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="场景-3纯-c-对象在-qt-项目中">场景 3:纯 C++ 对象在 Qt 项目中<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%9C%BA%E6%99%AF-3%E7%BA%AF-c-%E5%AF%B9%E8%B1%A1%E5%9C%A8-qt-%E9%A1%B9%E7%9B%AE%E4%B8%AD" class="hash-link" aria-label="场景 3:纯 C++ 对象在 Qt 项目中的直接链接" title="场景 3:纯 C++ 对象在 Qt 项目中的直接链接" translate="no">​</a></h3>
<p><strong>不继承 <code>QObject</code> 的类不享受 Qt 内存管理</strong>,必须手动管理。</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyData</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/* 普通 C++ 类 */</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">qtFunction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ❌ 错误:内存泄漏!</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    MyData</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">MyData</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ✅ 正确:使用智能指针</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">auto</span><span class="token plain"> safeData </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token generic-function function" style="color:#d73a49">make_unique</span><span class="token generic-function generic class-name operator" style="color:#393A34">&lt;</span><span class="token generic-function generic class-name">MyData</span><span class="token generic-function generic class-name operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="场景-4-与-c-混合开发">场景 4<!-- -->:QML<!-- --> 与 C++ 混合开发<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%9C%BA%E6%99%AF-4-%E4%B8%8E-c-%E6%B7%B7%E5%90%88%E5%BC%80%E5%8F%91" class="hash-link" aria-label="场景-4-与-c-混合开发的直接链接" title="场景-4-与-c-混合开发的直接链接" translate="no">​</a></h3>
<p>所有权取决于对象的创建方式:</p>
<table><thead><tr><th style="text-align:left">创建方式</th><th style="text-align:left">所有权归属</th><th style="text-align:left">生命周期管理</th></tr></thead><tbody><tr><td style="text-align:left">QML 声明式创建</td><td style="text-align:left">QML 引擎</td><td style="text-align:left">QML 自动管理</td></tr><tr><td style="text-align:left">C++ 创建并传递给 QML</td><td style="text-align:left">C++</td><td style="text-align:left">C++ 负责释放</td></tr><tr><td style="text-align:left">QML 动态创建 (createObject)</td><td style="text-align:left">QML 引擎</td><td style="text-align:left">QML 垃圾回收</td></tr></tbody></table>
<p><strong>示例<!-- -->:QML<!-- --> 声明式创建</strong></p>
<div class="language-qml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-qml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">Rectangle {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CircuitPainter { // C++ 注册的类</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        id: painter</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CircuitPainter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token base-clause keyword" style="color:#00009f">public</span><span class="token base-clause"> </span><span class="token base-clause class-name">QQuickPaintedItem</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    QVector</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">Wire</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> m_wires</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Wire 对象没有 parent</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">~</span><span class="token function" style="color:#d73a49">CircuitPainter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// CircuitPainter 自身由 QML 管理（有父对象 Rectangle）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// 但 m_wires 里的 Wire* 对象没有 parent，必须手动清理</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">qDeleteAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">m_wires</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>:::tip 关键区分</p>
<ul>
<li class=""><strong>CircuitPainter 自身</strong>：由 QML 父对象（Rectangle）管理，QML 会自动释放</li>
<li class=""><strong>m_wires 成员</strong>：里面的 <code>Wire*</code> 对象没有指定 parent，必须在析构函数中手动清理
:::</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="致命陷阱-与智能指针混用">致命陷阱<!-- -->:Qt<!-- --> 与智能指针混用<a href="http://localhost:3000/blog/cpp-pointers-guide#%E8%87%B4%E5%91%BD%E9%99%B7%E9%98%B1-%E4%B8%8E%E6%99%BA%E8%83%BD%E6%8C%87%E9%92%88%E6%B7%B7%E7%94%A8" class="hash-link" aria-label="致命陷阱-与智能指针混用的直接链接" title="致命陷阱-与智能指针混用的直接链接" translate="no">​</a></h3>
<p><strong>❌ 错误:智能指针管理 Qt 子对象</strong></p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    QWidget</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> parent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">QWidget</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 错误!unique_ptr 和 parent 都会尝试 delete btn</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    std</span><span class="token double-colon punctuation" style="color:#393A34">::</span><span class="token plain">unique_ptr</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain">QPushButton</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">btn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">QPushButton</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// CRASH! Double Free</span><br></div></code></pre></div></div>
<p><strong>✅ 正确做法:</strong></p>
<ol>
<li class=""><strong>有 parent 的 QObject</strong>:用原始指针,交给 Qt 管理</li>
<li class=""><strong>无 parent 的 QObject</strong>:可用 <code>std::unique_ptr</code> 或 <code>QScopedPointer</code></li>
<li class=""><strong>非 QObject 类</strong>:优先用 <code>std::unique_ptr</code> / <code>std::shared_ptr</code></li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="五指针选择速查表">五、指针选择速查表<a href="http://localhost:3000/blog/cpp-pointers-guide#%E4%BA%94%E6%8C%87%E9%92%88%E9%80%89%E6%8B%A9%E9%80%9F%E6%9F%A5%E8%A1%A8" class="hash-link" aria-label="五、指针选择速查表的直接链接" title="五、指针选择速查表的直接链接" translate="no">​</a></h2>
<table><thead><tr><th style="text-align:left">场景</th><th style="text-align:left">推荐类型</th><th style="text-align:left">理由</th></tr></thead><tbody><tr><td style="text-align:left"><strong>标准 C++</strong></td><td style="text-align:left"><code>std::unique_ptr</code></td><td style="text-align:left">默认首选,安全高效</td></tr><tr><td style="text-align:left"><strong>多处共享</strong></td><td style="text-align:left"><code>std::shared_ptr</code></td><td style="text-align:left">真正需要共享所有权时使用</td></tr><tr><td style="text-align:left"><strong>观察者模式</strong></td><td style="text-align:left"><code>std::weak_ptr</code></td><td style="text-align:left">不影响生命周期的弱引用</td></tr><tr><td style="text-align:left"><strong>Qt 有 parent</strong></td><td style="text-align:left"><code>T*</code> (原始指针)</td><td style="text-align:left">Qt 自动管理,不要干扰</td></tr><tr><td style="text-align:left"><strong>Qt 无 parent</strong></td><td style="text-align:left"><code>QScopedPointer</code> / <code>unique_ptr</code></td><td style="text-align:left">防止忘记释放</td></tr><tr><td style="text-align:left"><strong>Qt 弱引用</strong></td><td style="text-align:left"><code>QPointer&lt;T&gt;</code></td><td style="text-align:left">自动检测 Qt 对象是否被销毁</td></tr><tr><td style="text-align:left"><strong>函数参数</strong></td><td style="text-align:left"><code>T&amp;</code> / <code>T*</code></td><td style="text-align:left">不转移所有权,仅观察</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="六最佳实践">六、最佳实践<a href="http://localhost:3000/blog/cpp-pointers-guide#%E5%85%AD%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="六、最佳实践的直接链接" title="六、最佳实践的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><strong>优先使用 <code>make_unique</code> / <code>make_shared</code></strong>:更安全、更高效</li>
<li class=""><strong>原始指针仅用于观察</strong>:不拥有所有权,不负责 <code>delete</code></li>
<li class=""><strong>明确所有权语义</strong>:<!-- -->
<ul>
<li class="">函数参数用引用 (<code>T&amp;</code>) 或原始指针 (<code>T*</code>)</li>
<li class="">需要转移所有权时用 <code>unique_ptr</code></li>
<li class="">需要共享所有权时用 <code>shared_ptr</code></li>
</ul>
</li>
<li class=""><strong>Qt 开发特例</strong>:有 parent 的 <code>QObject</code> 只用原始指针</li>
<li class=""><strong>初始化原始指针</strong>:务必初始化为 <code>nullptr</code></li>
</ol>
<p>现代 C++ 原则
除非别无选择,否则<strong>不要手动调用 <code>delete</code></strong>。</p>
<p>在 Qt 中,<strong>相信 Parent 机制</strong>。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="C++" term="C++"/>
        <category label="Programming" term="Programming"/>
        <category label="教程" term="教程"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[VSCode配置详解：Launch、Settings与Tasks]]></title>
        <id>http://localhost:3000/blog/2024/12/04/VSCode配置详解：Launch、Settings与Tasks</id>
        <link href="http://localhost:3000/blog/2024/12/04/VSCode配置详解：Launch、Settings与Tasks"/>
        <updated>2025-12-04T14:16:00.000Z</updated>
        <summary type="html"><![CDATA[VS Code 的强大离不开 .vscode 目录下的三个核心配置文件：settings.json、tasks.json 和 launch.json。这些配置仅对当前项目生效，且Cursor 编辑器也能完美兼容。本文通过精简的示例介绍它们的作用及协作方式。]]></summary>
        <content type="html"><![CDATA[<p>VS Code 的强大离不开 <code>.vscode</code> 目录下的三个核心配置文件：<code>settings.json</code>、<code>tasks.json</code> 和 <code>launch.json</code>。这些配置<strong>仅对当前项目生效</strong>，且<strong>Cursor 编辑器也能完美兼容</strong>。本文通过精简的示例介绍它们的作用及协作方式。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-settingsjson编辑器配置">1. settings.json：编辑器配置<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#1-settingsjson%E7%BC%96%E8%BE%91%E5%99%A8%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="1. settings.json：编辑器配置的直接链接" title="1. settings.json：编辑器配置的直接链接" translate="no">​</a></h2>
<p><strong>作用</strong>：控制编辑器行为（当前工作区级别，优先级高于全局设置）。</p>
<p><strong>示例</strong>：</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// .vscode/settings.json</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"editor.formatOnSave"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 保存时自动格式化</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"editor.tabSize"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 缩进大小</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"files.exclude"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 隐藏特定文件</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"**/.git"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"**/.DS_Store"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"search.exclude"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 搜索时排除</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"**/node_modules"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-tasksjson任务自动化">2. tasks.json：任务自动化<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#2-tasksjson%E4%BB%BB%E5%8A%A1%E8%87%AA%E5%8A%A8%E5%8C%96" class="hash-link" aria-label="2. tasks.json：任务自动化的直接链接" title="2. tasks.json：任务自动化的直接链接" translate="no">​</a></h2>
<p><strong>作用</strong>：将命令行脚本集成到编辑器中。<strong>不同语言的配置方式略有差异</strong>（如 Node.js 用 <code>npm</code> 类型，C++/Rust 用 <code>shell</code> 类型），但核心都是为了支持通过<strong>快捷键一键调用</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-nodejs-项目示例-npm">2.1 Node.js 项目示例 (npm)<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#21-nodejs-%E9%A1%B9%E7%9B%AE%E7%A4%BA%E4%BE%8B-npm" class="hash-link" aria-label="2.1 Node.js 项目示例 (npm)的直接链接" title="2.1 Node.js 项目示例 (npm)的直接链接" translate="no">​</a></h3>
<p>定义一个 <code>npm test</code> 任务，并让 <code>npm build</code> 依赖它（即构建前自动测试）。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// .vscode/tasks.json</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 推荐版本</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"tasks"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"label"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm: build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 任务类型：自动识别 package.json</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"script"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 对应 scripts.build (自动执行 npm run build)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"dependsOn"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"npm: typecheck"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 依赖项：先运行 typecheck，成功后再运行 build</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"group"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"kind"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 归类为“构建任务” (Cmd+Shift+B 专用)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"isDefault"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 设为默认，按快捷键直接运行，不弹窗选择</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"problemMatcher"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"$tsc"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 捕获 TS 错误并在代码中高亮</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"label"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm: typecheck"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"script"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"typecheck"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"group"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"test"</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 归类为“测试任务” (可通过 Run Test Task 查找)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-c-项目示例-shell">2.2 C++ 项目示例 (Shell)<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#22-c-%E9%A1%B9%E7%9B%AE%E7%A4%BA%E4%BE%8B-shell" class="hash-link" aria-label="2.2 C++ 项目示例 (Shell)的直接链接" title="2.2 C++ 项目示例 (Shell)的直接链接" translate="no">​</a></h3>
<p>C++/Rust 等项目通常使用 <code>shell</code> 类型直接调用编译器。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"label"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build cpp"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"shell"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 任务类型：直接在终端运行命令</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"command"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"g++"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 命令</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"args"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"-g"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"main.cpp"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"-o"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"main"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 参数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"group"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"kind"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"isDefault"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-核心概念解析">2.3 核心概念解析<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#23-%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="2.3 核心概念解析的直接链接" title="2.3 核心概念解析的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong><code>type</code></strong>：决定任务的执行方式。<!-- -->
<ul>
<li class=""><code>"npm"</code>, <code>"gulp"</code>, <code>"grunt"</code> 等: <strong>智能模式</strong>。VS Code 插件提供的特定类型，能自动识别配置文件并补全命令。</li>
<li class=""><code>"shell"</code>: 通用模式。直接在终端执行你指定的 <code>command</code>。</li>
</ul>
</li>
<li class=""><strong><code>kind</code></strong>：任务的<strong>身份分类</strong>。<!-- -->
<ul>
<li class=""><code>"build"</code>: 标记为构建任务 -&gt; <strong><code>Cmd+Shift+B</code></strong> 快捷键专用。</li>
<li class=""><code>"test"</code>: 标记为测试任务 -&gt; 方便筛选。</li>
</ul>
</li>
<li class=""><strong><code>dependsOn</code></strong>：任务依赖链。<!-- -->
<ul>
<li class="">逻辑类似 <code>&amp;&amp;</code>：先执行依赖任务，<strong>成功后</strong>才执行当前任务。</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="24-使用方式">2.4 使用方式<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#24-%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F" class="hash-link" aria-label="2.4 使用方式的直接链接" title="2.4 使用方式的直接链接" translate="no">​</a></h3>
<ol>
<li class=""><strong>快捷键（推荐）</strong>：直接按 <strong><code>Cmd+Shift+B</code></strong>。<!-- -->
<ul>
<li class="">因配置了 <code>isDefault: true</code>，会直接触发默认构建任务。</li>
</ul>
</li>
<li class=""><strong>命令面板</strong>：<code>Cmd+Shift+P</code> -&gt; 输入 <code>Run Task</code> -&gt; 选择任务。</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-launchjson调试配置">3. launch.json：调试配置<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#3-launchjson%E8%B0%83%E8%AF%95%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="3. launch.json：调试配置的直接链接" title="3. launch.json：调试配置的直接链接" translate="no">​</a></h2>
<p><strong>作用</strong>：配置调试器，支持断点、变量查看等。</p>
<p><strong>示例</strong>：调试 Node.js 应用，并在启动前先运行构建任务。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// .vscode/launch.json</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0.2.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"configurations"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 调试环境 (常用：node, chrome, python等, 想调试什么语言，就装对应的插件，然后这里填对应的类型。)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"request"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"launch"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 核心模式仅两种：launch (启动新进程) / attach (附加到已有进程)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Debug App"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"program"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${workspaceFolder}/dist/index.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 调试构建后的文件</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"preLaunchTask"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm: build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 选填：调试前是否先运行构建任务（如无需构建可删除行）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"env"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"NODE_ENV"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"development"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-前端项目示例-vitereactvue">3.2 前端项目示例 (Vite/React/Vue)<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#32-%E5%89%8D%E7%AB%AF%E9%A1%B9%E7%9B%AE%E7%A4%BA%E4%BE%8B-vitereactvue" class="hash-link" aria-label="3.2 前端项目示例 (Vite/React/Vue)的直接链接" title="3.2 前端项目示例 (Vite/React/Vue)的直接链接" translate="no">​</a></h3>
<p>对于 Vite 项目，<strong>不需要构建</strong>。你只需要启动开发服务器 (<code>npm run dev</code>)，然后让 VS Code 连接到浏览器。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// .vscode/launch.json</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"0.2.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"configurations"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"chrome"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 调试浏览器</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"request"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"launch"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Debug Vite App"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"url"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"http://localhost:5173"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Vite 默认端口</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"webRoot"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"${workspaceFolder}/src"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 源码目录</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"preLaunchTask"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm: dev"</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 选填：调试前是否先运行构建任务（如无需构建可删除此行）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p><strong>使用方式</strong>：</p>
<ol>
<li class=""><strong>打断点</strong>：在源码文件（如 <code>src/index.js</code>）的行号左侧点击，出现红点即为断点。</li>
<li class=""><strong>启动调试</strong>：按 <code>F5</code>，或者点击左侧“运行和调试”图标 -&gt; 选择 <code>Debug App</code> -&gt; 点击绿色播放键。</li>
<li class=""><strong>效果</strong>：VS Code 会先运行 <code>npm: build</code>，构建成功后自动启动调试器，程序运行到断点处会自动暂停，你可以查看变量状态。</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="总结">总结<a href="http://localhost:3000/blog/2024/12/04/VSCode%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3%EF%BC%9ALaunch%E3%80%81Settings%E4%B8%8ETasks#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>settings.json</strong>：管<strong>环境</strong>（怎么看、怎么写）。</li>
<li class=""><strong>tasks.json</strong>：管<strong>动作</strong>（怎么构建、怎么跑脚本）。</li>
<li class=""><strong>launch.json</strong>：管<strong>运行</strong>（怎么调试）。</li>
</ul>
<p>三者结合：<code>launch.json</code> 通过 <code>preLaunchTask</code> 调用 <code>tasks.json</code>，在符合 <code>settings.json</code> 定义的环境中高效开发。</p>]]></content>
        <category label="VS Code" term="VS Code"/>
        <category label="技巧" term="技巧"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Antigravity 登录卡住问题解决办法]]></title>
        <id>http://localhost:3000/blog/antigravity-login-stuck-issue</id>
        <link href="http://localhost:3000/blog/antigravity-login-stuck-issue"/>
        <updated>2025-11-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文总结了 Antigravity 登录卡住问题的解决方法，并解释了背后的原因。如果你在使用 Antigravity 时遇到登录无法完成的情况，本指南将提供直接可用的解决方案和原理说明，帮助你快速恢复正常使用]]></summary>
        <content type="html"><![CDATA[<p>本文总结了 Antigravity 登录卡住问题的解决方法，并解释了背后的原因。如果你在使用 Antigravity 时遇到登录无法完成的情况，本指南将提供直接可用的解决方案和原理说明，帮助你快速恢复正常使用</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="前置环境">前置环境<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E5%89%8D%E7%BD%AE%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="前置环境的直接链接" title="前置环境的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>操作系统</strong>: macOS</li>
<li class=""><strong>代理工具</strong>: <a href="https://github.com/MetaCubeX/ClashX.Meta/releases" target="_blank" rel="noopener noreferrer" class="">ClashX Meta</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="第一部分网络连接问题">第一部分：网络连接问题<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E9%97%AE%E9%A2%98" class="hash-link" aria-label="第一部分：网络连接问题的直接链接" title="第一部分：网络连接问题的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="1-现象描述">1. 现象描述<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#1-%E7%8E%B0%E8%B1%A1%E6%8F%8F%E8%BF%B0" class="hash-link" aria-label="1. 现象描述的直接链接" title="1. 现象描述的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>症状</strong>：登录 Antigravity Google 账号成功后跳转回客户端，界面无反应或一直加载。</li>
<li class=""><strong>核心矛盾</strong>：同一网络环境下，Chrome 浏览器可以正常访问 Google 服务，但 Antigravity 客户端却无法登录，即使开启了 Clash 的系统代理也无效。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="2-诊断步骤">2. 诊断步骤<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#2-%E8%AF%8A%E6%96%AD%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="2. 诊断步骤的直接链接" title="2. 诊断步骤的直接链接" translate="no">​</a></h3>
<p>排查此类问题的第一步是判断 <strong>DNS 解析</strong>是否正常。由于浏览器和客户端应用（如 Node.js/Electron）处理网络请求的机制不同，我们需要使用命令行工具来模拟客户端行为。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="使用-nslookup-诊断">使用 <code>nslookup</code> 诊断<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E4%BD%BF%E7%94%A8-nslookup-%E8%AF%8A%E6%96%AD" class="hash-link" aria-label="使用-nslookup-诊断的直接链接" title="使用-nslookup-诊断的直接链接" translate="no">​</a></h4>
<p>在终端执行以下命令：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">nslookup accounts.google.com</span><br></div></code></pre></div></div>
<p><strong>结果分析</strong>：</p>
<ul>
<li class="">
<p><strong>错误配置（直连解析）</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">Server:		114.114.114.114</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Non-authoritative answer:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Name:	accounts.google.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Address: 64.233.187.84  &lt;-- 真实的 Google IP</span><br></div></code></pre></div></div>
<p><strong>解读</strong>：命令返回了一个真实的 Google IP。这说明 DNS 请求走了系统默认 DNS，未被代理工具接管。</p>
</li>
<li class="">
<p><strong>正确配置（Fake-IP）</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">Server:		198.18.0.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Non-authoritative answer:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Name:	accounts.google.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Address: 198.18.0.x     &lt;-- 虚假 IP (Fake-IP)</span><br></div></code></pre></div></div>
<p><strong>解读</strong>：返回了 <code>198.18.x.x</code> 网段的 IP，说明 Clash 的 DNS 劫持已生效，流量成功进入代理通道。</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="3-技术深究为什么浏览器能用app-却不行">3. 技术深究：为什么浏览器能用，App 却不行？<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#3-%E6%8A%80%E6%9C%AF%E6%B7%B1%E7%A9%B6%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B5%8F%E8%A7%88%E5%99%A8%E8%83%BD%E7%94%A8app-%E5%8D%B4%E4%B8%8D%E8%A1%8C" class="hash-link" aria-label="3. 技术深究：为什么浏览器能用，App 却不行？的直接链接" title="3. 技术深究：为什么浏览器能用，App 却不行？的直接链接" translate="no">​</a></h3>
<p>这是一个常见的误区。浏览器和普通应用在处理代理时有本质区别。通过以下两个具体例子，你可以清晰地看到差异：</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="例子-1浏览器访问走代理配置">例子 1：浏览器访问（走代理配置）<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E4%BE%8B%E5%AD%90-1%E6%B5%8F%E8%A7%88%E5%99%A8%E8%AE%BF%E9%97%AE%E8%B5%B0%E4%BB%A3%E7%90%86%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="例子 1：浏览器访问（走代理配置）的直接链接" title="例子 1：浏览器访问（走代理配置）的直接链接" translate="no">​</a></h4>
<p>当你开启系统代理后，浏览器访问 <code>https://accounts.google.com</code> 的流程如下：</p>
<ol>
<li class=""><strong>用户输入 URL</strong>：<code>https://accounts.google.com</code></li>
<li class=""><strong>检查代理配置</strong>：浏览器发现配置了代理（例如 <code>127.0.0.1:7890</code>）。</li>
<li class=""><strong>发送请求给代理</strong>：浏览器<strong>不进行本地 DNS 解析</strong>，直接将请求（包含域名）发送给代理服务器。</li>
<li class=""><strong>代理服务器处理</strong>：<!-- -->
<ul>
<li class="">代理软件（如 Clash）接收到请求。</li>
<li class="">代理软件在远程服务器上进行 DNS 解析（获取到 Google 的真实 IP）。</li>
<li class="">代理软件建立连接并转发数据。</li>
</ul>
</li>
<li class=""><strong>结果</strong>：连接成功。</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="例子-2普通应用--electron--node-程序依赖系统-dns--最容易出问题">例子 2：普通应用 / Electron / Node 程序（依赖系统 DNS → 最容易出问题）<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E4%BE%8B%E5%AD%90-2%E6%99%AE%E9%80%9A%E5%BA%94%E7%94%A8--electron--node-%E7%A8%8B%E5%BA%8F%E4%BE%9D%E8%B5%96%E7%B3%BB%E7%BB%9F-dns--%E6%9C%80%E5%AE%B9%E6%98%93%E5%87%BA%E9%97%AE%E9%A2%98" class="hash-link" aria-label="例子 2：普通应用 / Electron / Node 程序（依赖系统 DNS → 最容易出问题）的直接链接" title="例子 2：普通应用 / Electron / Node 程序（依赖系统 DNS → 最容易出问题）的直接链接" translate="no">​</a></h4>
<p>你运行一个 Node 服务或 Electron 应用（Antigravity 也是此类）：
<code>fetch("https://accounts.google.com")</code></p>
<p>Node 默认不会自动使用浏览器的代理配置，真实流程如下：</p>
<ol>
<li class=""><strong>Node 程序发起请求</strong>：我要访问 <code>accounts.google.com</code>。</li>
<li class=""><strong>本地 DNS 解析</strong>：<!-- -->
<ul>
<li class="">请求发送给本机 DNS 服务器（例如 <code>114.114.114.114</code> 或路由器 DNS）。</li>
<li class=""><strong>注意</strong>：如果未开启 TUN 模式或 DNS 劫持，这里走的是普通网络路径。</li>
</ul>
</li>
<li class=""><strong>DNS 返回结果</strong>：<!-- -->
<ul>
<li class="">DNS 返回真实的 Google IP（例如 <code>64.233.187.84</code>）。</li>
</ul>
</li>
<li class=""><strong>尝试建立连接</strong>：<!-- -->
<ul>
<li class="">Node 尝试直接连接 <code>64.233.187.84:443</code>。</li>
<li class="">由于国内网络环境，无法直连该 IP。</li>
</ul>
</li>
<li class=""><strong>结果</strong>：连接超时或失败。</li>
</ol>
<p>这就是为什么浏览器能打开，但终端或应用却报错的原因。开启 Clash 的 TUN 模式并启用 DNS 劫持（Fake-IP）可以解决这个问题，因为它会让步骤 2 中的 DNS 解析返回一个虚假 IP，从而将流量“骗”进代理通道。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="4-解决方案">4. 解决方案<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#4-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="4. 解决方案的直接链接" title="4. 解决方案的直接链接" translate="no">​</a></h3>
<p>要解决此问题，必须启用 Clash 的 <strong>DNS 劫持</strong> 和 <strong>TUN 模式</strong>。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="步骤一修正-clash-dns-配置">步骤一：修正 Clash DNS 配置<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E6%AD%A5%E9%AA%A4%E4%B8%80%E4%BF%AE%E6%AD%A3-clash-dns-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="步骤一：修正 Clash DNS 配置的直接链接" title="步骤一：修正 Clash DNS 配置的直接链接" translate="no">​</a></h4>
<p>打开 Clash 配置文件（通常在 <code>~/.config/clash.meta</code> 或通过 GUI 配置），确保 DNS 模块已启用：</p>
<div class="language-yaml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-yaml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">dns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">enable</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># 必须为 true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">ipv6</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">listen</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> 0.0.0.0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">1053</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">enhanced-mode</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> fake</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">ip </span><span class="token comment" style="color:#999988;font-style:italic"># 推荐使用 fake-ip 模式</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="步骤二开启-tun-模式">步骤二：开启 TUN 模式<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E6%AD%A5%E9%AA%A4%E4%BA%8C%E5%BC%80%E5%90%AF-tun-%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="步骤二：开启 TUN 模式的直接链接" title="步骤二：开启 TUN 模式的直接链接" translate="no">​</a></h4>
<p>在 ClashX Meta 界面中：</p>
<ol>
<li class="">找到 <strong>"TUN Mode"</strong> 开关并开启。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2025-11-24-Antigravity%20%E7%99%BB%E5%BD%95%E5%8D%A1%E4%BD%8F%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/tun-mode.png" alt="TUN 模式开关" class="img_gjoA"></li>
<li class="">如果提示需要权限，请输入系统密码安装辅助工具。</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="常见疑问只开启-dns-enable-true-不开-tun-模式行吗">常见疑问：只开启 <code>dns: enable: true</code> 不开 TUN 模式行吗？<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E5%B8%B8%E8%A7%81%E7%96%91%E9%97%AE%E5%8F%AA%E5%BC%80%E5%90%AF-dns-enable-true-%E4%B8%8D%E5%BC%80-tun-%E6%A8%A1%E5%BC%8F%E8%A1%8C%E5%90%97" class="hash-link" aria-label="常见疑问只开启-dns-enable-true-不开-tun-模式行吗的直接链接" title="常见疑问只开启-dns-enable-true-不开-tun-模式行吗的直接链接" translate="no">​</a></h4>
<p><strong>不行。</strong></p>
<ul>
<li class=""><strong><code>dns: enable: true</code></strong>：仅仅是让 Clash <strong>启动</strong>了一个内部的 DNS 服务器。</li>
<li class=""><strong>TUN 模式</strong>：负责将操作系统的所有网络流量（包括 DNS 查询）强行<strong>劫持</strong>并转发给 Clash。</li>
</ul>
<p>如果你只开启了 DNS 功能但没有开启 TUN 模式（且没有手动修改系统 DNS 指向 Clash），操作系统依然会使用默认的 DNS（如路由器 DNS）。Node 程序的 DNS 请求根本不会到达 Clash，自然也就无法获取 Fake-IP，问题依旧存在。</p>
<blockquote>
<p><strong>💡 什么是 TUN 模式？</strong></p>
<p>TUN 模式会在系统中创建一个虚拟网卡。操作系统会将<strong>所有网络流量</strong>（包括终端、应用、系统更新等）都发送给这个虚拟网卡，从而让 Clash 能够接管并处理本机的所有网络请求。它是实现“全局代理”和处理非浏览器应用流量的关键。</p>
<p><strong>🤔 TUN 模式 vs 全局模式 (Global Mode) / 系统代理</strong></p>
<ul>
<li class=""><strong>系统代理 (System Proxy)</strong>：只是告诉软件“请使用这个代理”。但很多软件（如终端、Node、Java）会<strong>忽略</strong>这个设置，直接发起连接。</li>
<li class=""><strong>全局模式 (Global Mode)</strong>：这只是 Clash 内部的一种<strong>策略</strong>（即“凡是进来的流量统统走代理”）。<strong>但它不具备强制捕获流量的能力</strong>。如果 App（如 Node）忽略系统代理设置，直接向公网发起连接（即流量绕过了 Clash），那么 Clash 根本接触不到这些数据包，全局模式自然也就无法生效。</li>
<li class=""><strong>TUN 模式</strong>：这是<strong>强制手段</strong>。它在网卡层截获所有流量。无论软件是否愿意走代理，流量都会被 TUN 捕获并交给 Clash 处理。</li>
</ul>
<p><strong>结论</strong>：解决 Antigravity/Node 问题必须用 <strong>TUN 模式</strong>，单纯开“全局模式”或“系统代理”通常无效。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="第二部分账号资格问题">第二部分：账号资格问题<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86%E8%B4%A6%E5%8F%B7%E8%B5%84%E6%A0%BC%E9%97%AE%E9%A2%98" class="hash-link" aria-label="第二部分：账号资格问题的直接链接" title="第二部分：账号资格问题的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="1-现象描述-1">1. 现象描述<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#1-%E7%8E%B0%E8%B1%A1%E6%8F%8F%E8%BF%B0-1" class="hash-link" aria-label="1. 现象描述的直接链接" title="1. 现象描述的直接链接" translate="no">​</a></h3>
<p>网络问题解决后，登录可能遇到以下报错：</p>
<blockquote>
<p>"Your current account is not eligible for Antigravity, because it is not currently available in your location."</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="2-根因分析">2. 根因分析<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#2-%E6%A0%B9%E5%9B%A0%E5%88%86%E6%9E%90" class="hash-link" aria-label="2. 根因分析的直接链接" title="2. 根因分析的直接链接" translate="no">​</a></h3>
<p>Antigravity 对账号归属地有严格限制。</p>
<ul>
<li class=""><strong>误区</strong>：以为只要挂了新加坡/美国的 VPN 就能通过。</li>
<li class=""><strong>真相</strong>：Google 判定资格时，主要依据 <strong>Google 账号的归属地（Play Store 地区）</strong>，而不仅仅是当前的 IP 地址。</li>
<li class=""><strong>案例</strong>：用户使用新加坡节点，但 Google 账号归属地为 <strong>香港 (Hong Kong)</strong>。由于香港不在 <a href="https://antigravity.google/docs/faq" target="_blank" rel="noopener noreferrer" class="">Antigravity 支持列表</a>（支持列表通常包括美国、新加坡、台湾等），因此被拒绝。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="3-解决方案">3. 解决方案<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#3-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="3. 解决方案的直接链接" title="3. 解决方案的直接链接" translate="no">​</a></h3>
<p>将 Google 账号的地区更改为支持的区域（推荐 <strong>新加坡</strong>）。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="操作步骤">操作步骤<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E6%93%8D%E4%BD%9C%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="操作步骤的直接链接" title="操作步骤的直接链接" translate="no">​</a></h4>
<ol>
<li class="">
<p>访问 <a href="https://policies.google.com/country-association-form" target="_blank" rel="noopener noreferrer" class="">Google 账号地区设置</a>。</p>
</li>
<li class="">
<p>更改区域。</p>
</li>
<li class="">
<p>理由选择其他：<strong>填写理由建议</strong>：
为了提高通过率，建议强调“功能需求”而非“绕过限制”。可以使用以下模板：</p>
<blockquote>
<p>I need to change my account region to Singapore because the software/service I am using is only available in the Singapore region.
My current region setting prevents me from downloading or updating this software.
This is a functional requirement based on the software provider's region restriction.</p>
<p>Please help update my account region to Singapore so I can continue using the service normally.</p>
</blockquote>
<p>成功率提示</p>
<ul>
<li class="">强调软件功能需求，通常会被视为合理请求。</li>
<li class="">避免提及价格、支付或仅仅为了“翻墙”。</li>
<li class="">通常不需要提供居住证明。</li>
</ul>
</li>
<li class="">
<p>等待审核（通常 1-2 个工作日）。</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="总结">总结<a href="http://localhost:3000/blog/antigravity-login-stuck-issue#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>顺利登录 Antigravity 的终极清单：</p>
<ol>
<li class="">
<p><strong>网络层</strong>：</p>
<ul class="contains-task-list containsTaskList_bCh3">
<li class="task-list-item"><input type="checkbox" disabled="" checked=""> <!-- -->Clash 配置中 <code>dns: enable: true</code>。</li>
<li class="task-list-item"><input type="checkbox" disabled="" checked=""> <!-- -->开启 <strong>TUN 模式</strong> (Fake-IP)。</li>
<li class="task-list-item"><input type="checkbox" disabled="" checked=""> <!-- -->终端 <code>nslookup accounts.google.com</code> 返回虚假 IP。</li>
</ul>
</li>
<li class="">
<p><strong>账号层</strong>：</p>
<ul class="contains-task-list containsTaskList_bCh3">
<li class="task-list-item"><input type="checkbox" disabled="" checked=""> <!-- -->使用 <strong>新加坡</strong> 节点。</li>
<li class="task-list-item"><input type="checkbox" disabled="" checked=""> <!-- -->确保 Google 账号归属地为 <strong>新加坡</strong>（或美国等支持地区）。</li>
</ul>
</li>
</ol>
<p>遵循以上步骤，你应该能够解决登录卡住或资格验证失败的问题。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="教程" term="教程"/>
        <category label="技巧" term="技巧"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Cursor最佳实践]]></title>
        <id>http://localhost:3000/blog/cursor-best-practices</id>
        <link href="http://localhost:3000/blog/cursor-best-practices"/>
        <updated>2025-09-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Cursor 是一款专为开发者设计的 AI 编程助手与集成开发环境（IDE），它通过智能补全、自动生成代码、文档理解、测试驱动开发等功能，帮助开发者提升开发效率、优化协作流程。Cursor 支持多种主流编程语言，并可通过自定义规则与插件，适配不同项目需求，是现代软件开发中 AI 辅助开发的代表性工具之一。]]></summary>
        <content type="html"><![CDATA[<p>Cursor 是一款专为开发者设计的 AI 编程助手与集成开发环境（IDE），它通过智能补全、自动生成代码、文档理解、测试驱动开发等功能，帮助开发者提升开发效率、优化协作流程。Cursor 支持多种主流编程语言，并可通过自定义规则与插件，适配不同项目需求，是现代软件开发中 AI 辅助开发的代表性工具之一。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-cursor-最佳实践清单">1. Cursor 最佳实践清单<a href="http://localhost:3000/blog/cursor-best-practices#1-cursor-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E6%B8%85%E5%8D%95" class="hash-link" aria-label="1. Cursor 最佳实践清单的直接链接" title="1. Cursor 最佳实践清单的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-制定-prd-规划">1.1 制定 PRD 规划<a href="http://localhost:3000/blog/cursor-best-practices#11-%E5%88%B6%E5%AE%9A-prd-%E8%A7%84%E5%88%92" class="hash-link" aria-label="1.1 制定 PRD 规划的直接链接" title="1.1 制定 PRD 规划的直接链接" translate="no">​</a></h3>
<p>利用 Cursor 的 AI 生成产品需求文档（PRD.md），为项目指明方向与结构（在团队协作中，可由产品经理在飞书等平台维护完整 PRD（面向人），同时在项目仓库中维护简化版 PRD.md（面向开发与 AI））。</p>
<ul>
<li class="">在 PRD.md 中对目标、用户故事、非功能需求、范围、成功度量做最小完备定义。</li>
<li class="">将关键决策条目化，减少提示歧义，避免历史“飘移”。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-在项目添加-cursor-配置规则">1.2 在项目添加 Cursor 配置规则<a href="http://localhost:3000/blog/cursor-best-practices#12-%E5%9C%A8%E9%A1%B9%E7%9B%AE%E6%B7%BB%E5%8A%A0-cursor-%E9%85%8D%E7%BD%AE%E8%A7%84%E5%88%99" class="hash-link" aria-label="1.2 在项目添加 Cursor 配置规则的直接链接" title="1.2 在项目添加 Cursor 配置规则的直接链接" translate="no">​</a></h3>
<ul>
<li class="">
<p><a href="https://docs.cursor.com/en/context/ignore-files" target="_blank" rel="noopener noreferrer" class="">.cursorignore</a></p>
<p>.cursorignore 用来告诉 Cursor 哪些文件或目录不要被索引或引用，从而提升性能并避免泄露敏感信息。</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># .cursorignore（精简示意）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">node_modules/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dist/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">build/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.tmp/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.cache/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">coverage/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.env.*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*.pem</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*.key</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*.crt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*.cert</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*.p12</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*.keystore</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><a href="https://docs.cursor.com/en/context/rules" target="_blank" rel="noopener noreferrer" class="">rules</a></p>
<p>规则文件用来指导 AI，每个规则文件使用 MDC（.mdc）格式编写，这种格式同时支持元数据和内容。在 Cursor 中打开 .mdc 文件后，可通过顶部的类型下拉菜单选择规则类型，该操作会自动更新 description、globs 和 alwaysApply 属性。</p>
<table><thead><tr><th>规则类型</th><th>描述</th></tr></thead><tbody><tr><td>Always</td><td>始终包含在模型上下文中</td></tr><tr><td>Auto Attached</td><td>当引用与某个 glob 模式匹配的文件时包含</td></tr><tr><td>Agent Requested</td><td>提供给 AI，由其决定是否包含。必须提供描述</td></tr><tr><td>Manual</td><td>只有在使用 <code>@ruleName</code> 明确提及时才会包含</td></tr></tbody></table>
<blockquote>
<p>规则适用于 Chat 和 Inline Edit。已启用的规则会显示在 Agent 对话框的上下文管理栏（顶部）。</p>
</blockquote>
<ul>
<li class="">可按模块拆分：<!-- -->
<ul>
<li class=""><code>.cursor/rules/frontend.mdc</code></li>
<li class=""><code>.cursor/rules/backend.mdc</code></li>
<li class=""><code>.cursor/rules/tests.mdc</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="13-选择合适的-agent-工作模式">1.3 选择合适的 Agent 工作模式<a href="http://localhost:3000/blog/cursor-best-practices#13-%E9%80%89%E6%8B%A9%E5%90%88%E9%80%82%E7%9A%84-agent-%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="1.3 选择合适的 Agent 工作模式的直接链接" title="1.3 选择合适的 Agent 工作模式的直接链接" translate="no">​</a></h3>
<p>Cursor Agent 提供三种工作模式，适用于不同开发场景：</p>
<ul>
<li class="">
<p><strong>Plan 模式（规划模式）</strong>：在编写代码前先生成详细的实现方案。Agent 会研究你的代码库、提出澄清问题，并生成可审阅的方案，你可以在开始构建前进行编辑。适合<strong>复杂任务、架构设计、大规模重构</strong>等需要系统性规划的场景。</p>
<ul>
<li class="">工作流程：<!-- -->
<ol>
<li class="">Agent 提出澄清性问题以了解需求</li>
<li class="">检索代码库并收集相关上下文</li>
<li class="">制定完整实现计划（以虚拟文件形式呈现）</li>
<li class="">你可审阅、编辑计划</li>
<li class="">点击"构建该计划"开始实施</li>
</ol>
</li>
<li class="">计划保存：可保存到 <code>.cursor/plans/</code> 目录，便于团队共享和文档化</li>
</ul>
</li>
<li class="">
<p><strong>Agent 模式</strong>：直接自动执行任务（如批量重构、自动测试、快速实现），适合<strong>明确目标和批量操作</strong>场景。</p>
</li>
<li class="">
<p><strong>Ask 模式</strong>：以对话为主，适合<strong>需求澄清、方案讨论、探索式协作</strong>。</p>
</li>
</ul>
<p><strong>使用建议</strong>：</p>
<ul>
<li class="">复杂任务/架构设计 → 优先用 <strong>Plan 模式</strong>，先规划后执行</li>
<li class="">明确的开发/测试/重构 → 用 <strong>Agent 模式</strong>，快速迭代</li>
<li class="">需求沟通/方案探讨 → 用 <strong>Ask 模式</strong>，深度对话</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="14-选择合适的-ai-模型">1.4 选择合适的 AI 模型<a href="http://localhost:3000/blog/cursor-best-practices#14-%E9%80%89%E6%8B%A9%E5%90%88%E9%80%82%E7%9A%84-ai-%E6%A8%A1%E5%9E%8B" class="hash-link" aria-label="1.4 选择合适的 AI 模型的直接链接" title="1.4 选择合适的 AI 模型的直接链接" translate="no">​</a></h3>
<p>主流模型区别与推荐场景：</p>
<table><thead><tr><th>模型</th><th>特点/优势</th><th>推荐场景</th></tr></thead><tbody><tr><td>GPT-4.1</td><td>代码/推理能力强，兼容性好</td><td>日常开发、测试、复杂推理</td></tr><tr><td>GPT-5</td><td>最新一代，推理与生成更强</td><td>架构设计、长文本、复杂任务</td></tr><tr><td>Claude-4.5</td><td>代码与推理全面升级</td><td>高质量代码生成、架构设计</td></tr><tr><td>Claude-4 Sonnet</td><td>语境理解好，文本推理强</td><td>需求澄清、文档生成</td></tr><tr><td>Claude-4 Opus</td><td>超长上下文、推理极强</td><td>大型项目、长链路推理</td></tr><tr><td>Claude-3.5/3.7</td><td>性能均衡，成本低</td><td>日常对话、轻量任务</td></tr><tr><td>Gemini 2.5 Pro</td><td>多模态支持，速度快</td><td>图文混合、快速实验</td></tr><tr><td>Grok 系列</td><td>速度快，适合实时场景</td><td>快速问答、低延迟需求</td></tr><tr><td>o3/o4-mini</td><td>成本极低，适合批量任务</td><td>批量生成、低优先级任务</td></tr><tr><td>Deepseek</td><td>中文支持好，代码能力强</td><td>中文开发、代码生成</td></tr><tr><td>Kimi-K2</td><td>中文长文本处理能力突出</td><td>中文文档、长文本摘要</td></tr><tr><td>GPT-5 Codex</td><td>代码理解/重构/迁移更强</td><td>大规模重构、复杂代码生成</td></tr><tr><td>GPT-5 Mini</td><td>低成本、延迟低</td><td>轻量开发、原型验证</td></tr><tr><td>GPT-5 Nano</td><td>体积小、响应快</td><td>快速问答、简单脚本、批量任务</td></tr><tr><td>Gemini 2.5 Flash</td><td>速度快、成本低，多模态</td><td>高并发、图文混合、快速试验</td></tr><tr><td>Grok Code</td><td>面向代码优化、速度快</td><td>代码阅读、修复、测试生成</td></tr><tr><td>Haiku 4.5</td><td>轻量稳定、成本友好</td><td>文案润色、摘要、快速问答</td></tr><tr><td>DeepSeek R1</td><td>强推理、数学表现佳</td><td>复杂推理、数学/算法题</td></tr><tr><td>DeepSeek V3.1</td><td>代码与中文双优、性价比高</td><td>中文开发、代码补全/生成</td></tr><tr><td>o3 Pro</td><td>更强思考链路与工具使用</td><td>深度推理、系统设计、复杂规划</td></tr></tbody></table>
<ul>
<li class="">实践建议：<!-- -->
<ul>
<li class="">日常开发/测试：优先 GPT-4.1、Claude-4 Sonnet</li>
<li class="">架构设计/复杂推理：可选 GPT-5、Claude-4 Opus</li>
<li class="">快速实验/低成本：Gemini、Grok、o3/o4-mini</li>
<li class="">多模态（图文/代码）：Gemini 2.5 Pro</li>
</ul>
</li>
<li class="">可根据任务难度、上下文长度、成本灵活切换，优先保证结果质量和语境理解。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="15-使用--标签提供上下文">1.5 使用 <a href="https://docs.cursor.com/en/context/@-symbols/overview" target="_blank" rel="noopener noreferrer" class="">@ 标签</a>提供上下文<a href="http://localhost:3000/blog/cursor-best-practices#15-%E4%BD%BF%E7%94%A8--%E6%A0%87%E7%AD%BE%E6%8F%90%E4%BE%9B%E4%B8%8A%E4%B8%8B%E6%96%87" class="hash-link" aria-label="15-使用--标签提供上下文的直接链接" title="15-使用--标签提供上下文的直接链接" translate="no">​</a></h3>
<p>通过合理使用 @File、@Web、@Code、@Terminal 等标签，将关键上下文信息注入 prompt，可显著提升 AI 的理解度与结果质量。例如：</p>
<ul>
<li class="">@File：指定具体文件内容或路径，适合代码变更、定位 bug、结构分析。</li>
<li class="">@Code：直接引用代码片段，适合讨论实现细节、重构建议、单元测试。</li>
<li class="">@Web：补充外部网页或文档链接，适合查阅 API、第三方库、设计规范。</li>
<li class="">@Terminal：引入终端命令或运行结果，适合调试、构建、测试反馈。</li>
</ul>
<p>建议：每次协作时，优先补充与目标相关的上下文标签，减少歧义，提升沟通效率。
此外，你也可以直接选中代码片段添加到对话，或将代码/文本复制粘贴到对话框，AI 同样能自动识别并应用这些上下文信息，无需额外标签。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="16-tdd-驱动迭代先测后码">1.6 TDD 驱动迭代（先测后码）<a href="http://localhost:3000/blog/cursor-best-practices#16-tdd-%E9%A9%B1%E5%8A%A8%E8%BF%AD%E4%BB%A3%E5%85%88%E6%B5%8B%E5%90%8E%E7%A0%81" class="hash-link" aria-label="1.6 TDD 驱动迭代（先测后码）的直接链接" title="1.6 TDD 驱动迭代（先测后码）的直接链接" translate="no">​</a></h3>
<ul>
<li class="">先为关键用户流写测试（最开始失败），再最小实现直至通过。</li>
<li class="">单元测试覆盖组件输入/输出与边界；集成测试覆盖核心操作流（新增 → 勾选 → 删除 → 筛选/排序等）。</li>
<li class="">测试环境要保证用例隔离（如清理 localStorage、组件卸载等）。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="17-自动运行">1.7 自动运行<a href="http://localhost:3000/blog/cursor-best-practices#17-%E8%87%AA%E5%8A%A8%E8%BF%90%E8%A1%8C" class="hash-link" aria-label="1.7 自动运行的直接链接" title="1.7 自动运行的直接链接" translate="no">​</a></h3>
<ul>
<li class="">Auto-Run Mode 允许 Agent 在安全边界内自动执行任务，如跑测试、类型检查、Lint。</li>
<li class="">推荐默认 Ask Every Time；必要时仅对白名单命令自动运行：<code>npm test</code>（或 <code>npm run test:watch</code>）、<code>npm run build</code>（可选；如已配置 <code>lint</code>/<code>typecheck</code> 再加入）。</li>
<li class="">每次只围绕一个清晰目标：先加测试 → 跑测（红）→ 最小实现 → 跑测（绿）。</li>
<li class="">大改前先建分支并提交快照；限定可改目录与行数，超限需人工确认。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="18-基于测试驱动策略构建迭代反馈循环">1.8 基于测试驱动策略构建迭代反馈循环<a href="http://localhost:3000/blog/cursor-best-practices#18-%E5%9F%BA%E4%BA%8E%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E7%AD%96%E7%95%A5%E6%9E%84%E5%BB%BA%E8%BF%AD%E4%BB%A3%E5%8F%8D%E9%A6%88%E5%BE%AA%E7%8E%AF" class="hash-link" aria-label="1.8 基于测试驱动策略构建迭代反馈循环的直接链接" title="1.8 基于测试驱动策略构建迭代反馈循环的直接链接" translate="no">​</a></h3>
<p>在较大项目中，建议每完成一个阶段性功能后，设置 1–2 个关键集成测试作为 checkpoint。通过自动化测试及时发现并修复编码错误，既能保障项目安全边界，又能提升开发效率。AI 可根据测试结果自动定位并修复问题，实现高效迭代。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-todolist-实践案例">2. <a href="https://github.com/fengyueran/cursor-lab" target="_blank" rel="noopener noreferrer" class="">TodoList 实践案例</a><a href="http://localhost:3000/blog/cursor-best-practices#2-todolist-%E5%AE%9E%E8%B7%B5%E6%A1%88%E4%BE%8B" class="hash-link" aria-label="2-todolist-实践案例的直接链接" title="2-todolist-实践案例的直接链接" translate="no">​</a></h2>
<p>本章节基于 TodoList 项目，详细记录每个开发阶段的具体操作步骤、命令和提示词。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-第一步制定-prd-规划">2.1 第一步：制定 PRD 规划<a href="http://localhost:3000/blog/cursor-best-practices#21-%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%88%B6%E5%AE%9A-prd-%E8%A7%84%E5%88%92" class="hash-link" aria-label="2.1 第一步：制定 PRD 规划的直接链接" title="2.1 第一步：制定 PRD 规划的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：明确产品需求和技术边界</p>
<p><strong>具体操作</strong>：</p>
<p>创建 <code>PRD.md</code> 文件，定义：</p>
<ul>
<li class="">用户故事（Given/When/Then 格式）</li>
<li class="">验收标准（如：输入验证、状态切换、数据持久化）</li>
<li class="">技术栈选择（React + TypeScript + Vite + Vitest）</li>
<li class="">MVP 范围（核心组件：TodoItem、TodoEditor）</li>
</ul>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">帮我创建一个 TodoList 应用的 PRD.md，包含：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 6个核心用户故事（增删改查、筛选、搜索）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 每个故事的 Given/When/Then 验收标准</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 明确 MVP 边界，排除用户系统和多端同步</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-第二步生成项目骨架">2.2 第二步：生成项目骨架<a href="http://localhost:3000/blog/cursor-best-practices#22-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE%E9%AA%A8%E6%9E%B6" class="hash-link" aria-label="2.2 第二步：生成项目骨架的直接链接" title="2.2 第二步：生成项目骨架的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：搭建可运行的开发环境</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">帮我配基础开发环境：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 使用 Vite 初始化 React+TS 项目</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 创建 vitest.config.ts，使用 jsdom 环境</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 创建 vitest.setup.ts，导入 @testing-library/jest-dom</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 确保组件测试可以在浏览器外运行</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-第三步添加-cursor-配置">2.3 第三步：添加 Cursor 配置<a href="http://localhost:3000/blog/cursor-best-practices#23-%E7%AC%AC%E4%B8%89%E6%AD%A5%E6%B7%BB%E5%8A%A0-cursor-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="2.3 第三步：添加 Cursor 配置的直接链接" title="2.3 第三步：添加 Cursor 配置的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：建立 AI 协作的行为约束</p>
<p><strong>具体操作</strong>：</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="配置-cursorignore-文件">配置 .cursorignore 文件<a href="http://localhost:3000/blog/cursor-best-practices#%E9%85%8D%E7%BD%AE-cursorignore-%E6%96%87%E4%BB%B6" class="hash-link" aria-label="配置 .cursorignore 文件的直接链接" title="配置 .cursorignore 文件的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">请根据官方与社区常见规范，生成一份 .cursorignore 文件。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">要求：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 排除构建产物、依赖目录（如 node_modules、dist、build 等）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 排除临时文件、日志、系统文件（如 *.log、*.tmp、.DS_Store）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 排除测试覆盖率报告（如 coverage、.nyc_output）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 排除敏感文件（如 .env*、*.pem、*.key）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 包含常见前端/后端项目的约定忽略项</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="创建通用开发规则">创建通用开发规则<a href="http://localhost:3000/blog/cursor-best-practices#%E5%88%9B%E5%BB%BA%E9%80%9A%E7%94%A8%E5%BC%80%E5%8F%91%E8%A7%84%E5%88%99" class="hash-link" aria-label="创建通用开发规则的直接链接" title="创建通用开发规则的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 .cursor/rules/index.mdc 通用开发规则：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alwaysApply: true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 技术栈约束</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- TypeScript 严格模式，React 18 + Vite</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 函数式组件 + Hooks，避免类组件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 测试使用 Vitest + @testing-library/react</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 文件命名：kebab-case，组件用 PascalCase.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">确保 AI 在所有开发中遵循这些约束</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="创建测试专用规则">创建测试专用规则<a href="http://localhost:3000/blog/cursor-best-practices#%E5%88%9B%E5%BB%BA%E6%B5%8B%E8%AF%95%E4%B8%93%E7%94%A8%E8%A7%84%E5%88%99" class="hash-link" aria-label="创建测试专用规则的直接链接" title="创建测试专用规则的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 .cursor/rules/testing.mdc 测试规则：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">globs: **/*.test.tsx, **/__tests__/**</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 测试约定</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 优先 TDD：先写失败测试，再实现功能</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 覆盖：正常路径、边界条件、异常输入</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 循环：执行 npm test，失败时自动修复</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">自动应用到测试相关文件</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="24-第四步启用自动化工作流">2.4 第四步：启用自动化工作流<a href="http://localhost:3000/blog/cursor-best-practices#24-%E7%AC%AC%E5%9B%9B%E6%AD%A5%E5%90%AF%E7%94%A8%E8%87%AA%E5%8A%A8%E5%8C%96%E5%B7%A5%E4%BD%9C%E6%B5%81" class="hash-link" aria-label="2.4 第四步：启用自动化工作流的直接链接" title="2.4 第四步：启用自动化工作流的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：配置 Cursor Agent 自动运行测试和构建</p>
<p><strong>具体操作</strong>：</p>
<p><strong>配置路径</strong>：Cursor → Settings → Agents → Auto-Run Mode(版本 2.0.43，不同版本可能会有差异)</p>
<p>在 Cursor 设置中配置 Auto-Run Mode 为 "Use Allowlist"，并设置命令白名单：</p>
<ul>
<li class="">允许：<code>npm test</code>、<code>npm run build</code>、<code>npm run dev</code>、<code>npm run lint</code></li>
<li class="">禁止：<code>rm</code>、<code>git push</code>、<code>npm publish</code> 等危险命令</li>
</ul>
<p><strong>安全实践</strong>：</p>
<ul>
<li class="">在开启自动运行前先提交代码（<code>git commit</code>）</li>
<li class="">限制 AI 权限在安全命令范围内</li>
<li class="">不授予生产环境凭证的写权限</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="25-第五步tdd-红-绿-重构循环开发">2.5 第五步：TDD 红-绿-重构循环开发<a href="http://localhost:3000/blog/cursor-best-practices#25-%E7%AC%AC%E4%BA%94%E6%AD%A5tdd-%E7%BA%A2-%E7%BB%BF-%E9%87%8D%E6%9E%84%E5%BE%AA%E7%8E%AF%E5%BC%80%E5%8F%91" class="hash-link" aria-label="2.5 第五步：TDD 红-绿-重构循环开发的直接链接" title="2.5 第五步：TDD 红-绿-重构循环开发的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：在自动化环境下遵循 TDD 最佳实践，逐个组件进行红-绿-重构循环</p>
<p><strong>TDD 循环说明</strong>：</p>
<ul>
<li class="">🔴 <strong>红</strong>：写一个失败的测试</li>
<li class="">🟢 <strong>绿</strong>：写最少代码让测试通过</li>
<li class="">🔵 <strong>重构</strong>：在保持测试通过的前提下优化代码（可选）</li>
</ul>
<p><strong>重构完成后的下一步</strong>：</p>
<ol>
<li class=""><strong>验证测试通过</strong>：确保所有现有测试仍然通过，重构没有破坏功能</li>
<li class=""><strong>评估覆盖度</strong>：检查是否需要补充边界条件或异常情况的测试</li>
<li class=""><strong>开始新循环</strong>：<!-- -->
<ul>
<li class="">如果当前组件功能完整，进入下一个组件的红-绿-重构循环</li>
<li class="">如果需要新功能，为新功能编写失败测试，开始新的 TDD 循环</li>
</ul>
</li>
<li class=""><strong>集成验证</strong>：定期运行完整测试套件，确保各组件协同工作正常</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="todoitem-组件-tdd-循环">TodoItem 组件 TDD 循环<a href="http://localhost:3000/blog/cursor-best-practices#todoitem-%E7%BB%84%E4%BB%B6-tdd-%E5%BE%AA%E7%8E%AF" class="hash-link" aria-label="TodoItem 组件 TDD 循环的直接链接" title="TodoItem 组件 TDD 循环的直接链接" translate="no">​</a></h4>
<ul>
<li class="">
<p>红阶段 - 写失败测试</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 src/components/__tests__/todo-item.test.tsx：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">测试用例：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 渲染文本与初始完成状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 勾选触发 onToggle(id, next)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 点击删除触发 onDelete(id)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Todo 模型：{ id: string, text: string, completed: boolean, createdAt: string }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">使用 Vitest + Testing Library，包含 vi.fn() mock</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>绿阶段 - 最小实现</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">实现 src/components/todo-item.tsx，仅满足测试通过：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@Files src/components/__tests__/todo-item.test.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">最小实现要求：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 接收 todo、onToggle、onDelete props</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 复选框绑定 completed 状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 删除按钮触发 onDelete</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">AI 将自动运行 npm test 确保测试通过（绿）</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>重构阶段 - 优化代码</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">重构 TodoItem 组件，保持测试通过：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 优化组件结构和可读性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 改进无障碍访问性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 优化样式和用户体验</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">AI 将在每次修改后自动运行 npm test 确保测试仍然通过</span><br></div></code></pre></div></div>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="todoeditor-组件-tdd-循环">TodoEditor 组件 TDD 循环<a href="http://localhost:3000/blog/cursor-best-practices#todoeditor-%E7%BB%84%E4%BB%B6-tdd-%E5%BE%AA%E7%8E%AF" class="hash-link" aria-label="TodoEditor 组件 TDD 循环的直接链接" title="TodoEditor 组件 TDD 循环的直接链接" translate="no">​</a></h4>
<ul>
<li class="">
<p>红阶段 - 写失败测试</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 src/components/__tests__/todo-editor.test.tsx：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 受控输入：输入文本后 value 更新</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 空值禁用：空字符串时提交按钮禁用</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 提交清空：提交后触发 onAdd({text}) 并清空输入框</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 键盘支持：回车键提交</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
</li>
<li class="">
<p>绿阶段 - 最小实现</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">实现 src/components/todo-editor.tsx 最小功能：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@Files src/components/__tests__/todo-editor.test.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">基本功能：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 受控文本输入框</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 空值时禁用提交按钮</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 提交时调用 onAdd({text}) 并清空</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 支持回车键提交</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">运行 npm test 确保测试通过（绿）</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>重构阶段 - 优化代码</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">重构 TodoEditor 组件：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 优化表单验证逻辑</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 添加适当的 loading 状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">保持测试通过的前提下进行优化</span><br></div></code></pre></div></div>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="app-组件-tdd-循环">App 组件 TDD 循环<a href="http://localhost:3000/blog/cursor-best-practices#app-%E7%BB%84%E4%BB%B6-tdd-%E5%BE%AA%E7%8E%AF" class="hash-link" aria-label="App 组件 TDD 循环的直接链接" title="App 组件 TDD 循环的直接链接" translate="no">​</a></h4>
<ul>
<li class="">
<p>红阶段 - 写失败测试</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 src/app/__tests__/app.integration.test 集成测试：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 页面加载：从 localStorage 读取数据</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 完整流程：添加 → 切换完成 → 筛选 → 删除</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 数据持久化：操作后 localStorage 更新</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">使用 jsdom 模拟 localStorage</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>绿阶段 - 最小实现</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">实现 src/app/app.tsx 基本功能：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@Files src/app/__tests__/app.test.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">核心功能：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. localStorage 数据持久化（key: 'todo-app:v1'）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 基本状态管理：todos、filter</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 事件处理：onAdd、onToggle、onDelete</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 简单筛选逻辑：all/active/completed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">运行 npm test 确保测试通过（绿）</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>重构阶段 - 优化架构</p>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">重构 App 组件架构：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 提取状态管理逻辑（useReducer 或自定义 hooks）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 改进错误处理和边界情况</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 添加按创建时间排序等高级功能</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">每次重构后自动确保所有测试通过</span><br></div></code></pre></div></div>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="26-第六步配置-cicd-流水线">2.6 第六步：配置 CI/CD 流水线<a href="http://localhost:3000/blog/cursor-best-practices#26-%E7%AC%AC%E5%85%AD%E6%AD%A5%E9%85%8D%E7%BD%AE-cicd-%E6%B5%81%E6%B0%B4%E7%BA%BF" class="hash-link" aria-label="2.6 第六步：配置 CI/CD 流水线的直接链接" title="2.6 第六步：配置 CI/CD 流水线的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：建立自动化测试和部署流程</p>
<p><strong>具体操作</strong>：</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="创建-github-actions">创建 GitHub Actions<a href="http://localhost:3000/blog/cursor-best-practices#%E5%88%9B%E5%BB%BA-github-actions" class="hash-link" aria-label="创建 GitHub Actions的直接链接" title="创建 GitHub Actions的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">生成 .github/workflows/ci.yml 工作流：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 触发条件：push 和 PR 到 master 分支</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 环境：Node.js 20</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 步骤：checkout → install → build → test → coverage</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 失败时阻止合并</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="配置部署流程">配置部署流程<a href="http://localhost:3000/blog/cursor-best-practices#%E9%85%8D%E7%BD%AE%E9%83%A8%E7%BD%B2%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="配置部署流程的直接链接" title="配置部署流程的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 Vercel 部署配置：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 生成 vercel.json 配置文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 设置构建命令和输出目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 配置环境变量和重定向规则</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="27-第七步完善文档和验收">2.7 第七步：完善文档和验收<a href="http://localhost:3000/blog/cursor-best-practices#27-%E7%AC%AC%E4%B8%83%E6%AD%A5%E5%AE%8C%E5%96%84%E6%96%87%E6%A1%A3%E5%92%8C%E9%AA%8C%E6%94%B6" class="hash-link" aria-label="2.7 第七步：完善文档和验收的直接链接" title="2.7 第七步：完善文档和验收的直接链接" translate="no">​</a></h3>
<p><strong>目标</strong>：生成完整的项目文档和验收测试</p>
<p><strong>具体操作</strong>：</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="生成项目文档">生成项目文档<a href="http://localhost:3000/blog/cursor-best-practices#%E7%94%9F%E6%88%90%E9%A1%B9%E7%9B%AE%E6%96%87%E6%A1%A3" class="hash-link" aria-label="生成项目文档的直接链接" title="生成项目文档的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">更新 README.md 包含：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 项目介绍和功能特性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 技术栈和架构说明</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 本地开发指南（安装、运行、测试）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 部署链接和演示</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5. 贡献指南和许可证</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="创建验收测试清单">创建验收测试清单<a href="http://localhost:3000/blog/cursor-best-practices#%E5%88%9B%E5%BB%BA%E9%AA%8C%E6%94%B6%E6%B5%8B%E8%AF%95%E6%B8%85%E5%8D%95" class="hash-link" aria-label="创建验收测试清单的直接链接" title="创建验收测试清单的直接链接" translate="no">​</a></h4>
<p><strong>示例提示词</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">创建 ACCEPTANCE.md 验收清单：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 功能测试：所有用户故事验证通过</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 技术测试：测试覆盖率 &gt; 80%，构建成功</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 用户体验：响应式设计，无障碍访问</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 性能测试：首屏加载 &lt; 2s</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="总结">总结<a href="http://localhost:3000/blog/cursor-best-practices#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>Cursor 最佳实践的核心在于建立<strong>系统化的 AI 协作流程</strong>，通过以下关键要素实现高效开发：</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="核心原则">核心原则<a href="http://localhost:3000/blog/cursor-best-practices#%E6%A0%B8%E5%BF%83%E5%8E%9F%E5%88%99" class="hash-link" aria-label="核心原则的直接链接" title="核心原则的直接链接" translate="no">​</a></h3>
<ol>
<li class=""><strong>TDD 驱动迭代</strong>：以测试为先导，相比于人工开发中“先实现再测试”的习惯，TDD 在 AI 辅助下更具价值，
它能作为清晰的反馈循环与安全护栏，帮助 AI 保持正确的开发方向。</li>
<li class=""><strong>结构化配置</strong>：通过 PRD 规划、规则文件、上下文标签等，为 AI 提供明确的行为约束和项目背景</li>
<li class=""><strong>自动化反馈</strong>：利用 Auto-Run 模式建立快速验证机制，实现"红-绿-重构"的高效循环</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="适用范围">适用范围<a href="http://localhost:3000/blog/cursor-best-practices#%E9%80%82%E7%94%A8%E8%8C%83%E5%9B%B4" class="hash-link" aria-label="适用范围的直接链接" title="适用范围的直接链接" translate="no">​</a></h3>
<p>这套最佳实践不仅适用于 Cursor，也可推广到其他 AI 编程助手（如 Trae、GitHub Copilot 等），只需根据具体工具的配置方式进行调整。关键在于理解 AI 协作的本质：<strong>通过结构化输入和反馈循环，让 AI 成为更可靠的编程伙伴</strong>。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="参考资料">参考资料<a href="http://localhost:3000/blog/cursor-best-practices#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99" class="hash-link" aria-label="参考资料的直接链接" title="参考资料的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://docs.cursor.com/en/welcome" target="_blank" rel="noopener noreferrer" class="">Cursor 官方文档</a></li>
<li class=""><a href="https://medium.com/%40roberto.g.infante/mastering-cursor-ide-10-best-practices-building-a-daily-task-manager-app-0b26524411c1" target="_blank" rel="noopener noreferrer" class="">Mastering Cursor IDE: 10 Best Practices Building a Daily Task Manager App (Medium)</a></li>
<li class=""><a href="https://github.com/digitalchild/cursor-best-practices" target="_blank" rel="noopener noreferrer" class="">Cursor Best Practices (GitHub)</a></li>
<li class=""><a href="https://kirill-markin.com/articles/cursor-ide-rules-for-ai" target="_blank" rel="noopener noreferrer" class="">Cursor IDE 规则与 AI 协作（Kirill Markin 博客）</a></li>
<li class=""><a href="https://forum.cursor.com/t/cursor-prompt-engineering-best-practices/1592?utm_source=chatgpt.com" target="_blank" rel="noopener noreferrer" class="">Cursor Prompt Engineering 最佳实践（官方论坛）</a></li>
<li class=""><a href="https://www.builder.io/blog/cursor-tips" target="_blank" rel="noopener noreferrer" class="">Cursor Tips（Builder.io 博客）</a></li>
<li class=""><a href="https://forum.cursor.com/t/best-practices-for-medium-large-projects" target="_blank" rel="noopener noreferrer" class="">中大型项目最佳实践（官方论坛）</a></li>
<li class=""><a href="https://medium.com/%40vignarajj/mastering-cursor-ide-thinking-models-cursor-rules-and-effective-usage-6e512437bbc3" target="_blank" rel="noopener noreferrer" class="">Mastering Cursor IDE: Thinking Models, Cursor Rules and Effective Usage (Medium)</a></li>
<li class=""><a href="https://www.reddit.com/r/cursor/comments/1ikq9m6/cursor_ide_setup_and_workflow_in_larger_projects" target="_blank" rel="noopener noreferrer" class="">Cursor IDE Setup and Workflow in Larger Projects（Reddit）</a></li>
<li class=""><a href="https://dev.to/heymarkkop/cursor-tips-10f8" target="_blank" rel="noopener noreferrer" class="">Cursor Tips（dev.to）</a></li>
</ul>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Programming" term="Programming"/>
        <category label="技术概念" term="技术概念"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Mac 系统 Jenkins Agent 服务配置指南]]></title>
        <id>http://localhost:3000/blog/mac-jenkins-agent-setup</id>
        <link href="http://localhost:3000/blog/mac-jenkins-agent-setup"/>
        <updated>2025-09-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文档说明如何在 macOS 上配置 Jenkins Agent 服务，实现自动启动并防止息屏/休眠导致连接断开。通过 LaunchDaemon 和 caffeinate 命令确保服务稳定运行。]]></summary>
        <content type="html"><![CDATA[<p>本文档说明如何在 macOS 上配置 Jenkins Agent 服务，实现自动启动并防止息屏/休眠导致连接断开。通过 LaunchDaemon 和 caffeinate 命令确保服务稳定运行。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-核心原理">1. 核心原理<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#1-%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86" class="hash-link" aria-label="1. 核心原理的直接链接" title="1. 核心原理的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-launchdaemon-vs-launchagent">1.1 LaunchDaemon vs LaunchAgent<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#11-launchdaemon-vs-launchagent" class="hash-link" aria-label="1.1 LaunchDaemon vs LaunchAgent的直接链接" title="1.1 LaunchDaemon vs LaunchAgent的直接链接" translate="no">​</a></h3>
<p>macOS 提供两种自动启动机制：</p>
<table><thead><tr><th>特性</th><th>LaunchDaemon</th><th>LaunchAgent</th></tr></thead><tbody><tr><td>运行权限</td><td>root</td><td>当前用户</td></tr><tr><td>启动时机</td><td>系统启动时</td><td>用户登录时</td></tr><tr><td>配置位置</td><td><code>/Library/LaunchDaemons/</code></td><td><code>~/Library/LaunchAgents/</code></td></tr><tr><td>息屏影响</td><td>不受影响</td><td><strong>可能断开</strong></td></tr><tr><td>适用场景</td><td>系统级服务</td><td>用户级应用</td></tr></tbody></table>
<p><strong>Jenkins Agent 应使用 LaunchDaemon</strong> 以确保服务稳定运行且不受用户会话影响。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-防休眠机制">1.2 防休眠机制<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#12-%E9%98%B2%E4%BC%91%E7%9C%A0%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="1.2 防休眠机制的直接链接" title="1.2 防休眠机制的直接链接" translate="no">​</a></h3>
<p>使用 <code>caffeinate</code> 命令包裹 Jenkins Agent 进程，防止系统休眠导致网络断开：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">caffeinate -s java -jar agent.jar [options]</span><br></div></code></pre></div></div>
<p>参数说明：</p>
<ul>
<li class=""><code>-s</code>: 防止系统休眠（但允许屏幕息屏）</li>
<li class="">进程存活期间持续生效</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-前置要求">2. 前置要求<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#2-%E5%89%8D%E7%BD%AE%E8%A6%81%E6%B1%82" class="hash-link" aria-label="2. 前置要求的直接链接" title="2. 前置要求的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><strong>Java 环境</strong>：已安装 JDK（Jenkins Agent 需要）</li>
<li class=""><strong>Jenkins 凭据</strong>：从 Jenkins Master 获取 Agent 连接信息</li>
<li class=""><strong>管理员权限</strong>：配置 LaunchDaemon 需要 sudo 权限</li>
<li class=""><strong>工作目录</strong>：准备 Jenkins 工作目录（如 <code>/Users/xhm/jenkins</code>）</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-配置步骤">3. 配置步骤<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#3-%E9%85%8D%E7%BD%AE%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="3. 配置步骤的直接链接" title="3. 配置步骤的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-第一步创建-plist-配置文件">3.1 第一步：创建 Plist 配置文件<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#31-%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%88%9B%E5%BB%BA-plist-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" class="hash-link" aria-label="3.1 第一步：创建 Plist 配置文件的直接链接" title="3.1 第一步：创建 Plist 配置文件的直接链接" translate="no">​</a></h3>
<p>创建 <code>org.jenkins.agent.plist</code> 文件（建议先在用户目录创建，测试后再移动）：</p>
<div class="language-xml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-xml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token prolog" style="color:#999988;font-style:italic">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token doctype punctuation" style="color:#393A34;font-style:italic">&lt;!</span><span class="token doctype doctype-tag" style="color:#999988;font-style:italic">DOCTYPE</span><span class="token doctype" style="color:#999988;font-style:italic"> </span><span class="token doctype name" style="color:#999988;font-style:italic">plist</span><span class="token doctype" style="color:#999988;font-style:italic"> </span><span class="token doctype name" style="color:#999988;font-style:italic">PUBLIC</span><span class="token doctype" style="color:#999988;font-style:italic"> </span><span class="token doctype string" style="color:#e3116c;font-style:italic">"-//Apple//DTD PLIST 1.0//EN"</span><span class="token doctype" style="color:#999988;font-style:italic"> </span><span class="token doctype string" style="color:#e3116c;font-style:italic">"http://www.apple.com/DTDs/PropertyList-1.0.dtd"</span><span class="token doctype punctuation" style="color:#393A34;font-style:italic">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">plist</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">version</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">1.0</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">dict</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 服务唯一标识 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">Label</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">org.jenkins.agent</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 使用 caffeinate 防休眠 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">ProgramArguments</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">array</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/usr/bin/caffeinate</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">-s</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/usr/bin/java</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">-jar</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/Users/xhm/jenkins/agent.jar</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">-url</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">http://your-jenkins-server:8080/</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">-secret</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">YOUR_SECRET_KEY</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">-name</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">YOUR_AGENT_NAME</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">-workDir</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/Users/xhm/jenkins</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">array</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 运行用户（保持与文件所有者一致）--&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">UserName</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">xhm</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 工作目录 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">WorkingDirectory</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/Users/xhm/jenkins</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 自动启动 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">RunAtLoad</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">true</span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 崩溃后自动重启 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">KeepAlive</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">true</span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 标准输出日志 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">StandardOutPath</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/Users/xhm/jenkins/jenkins-agent.log</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 错误输出日志 --&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">StandardErrorPath</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/Users/xhm/jenkins/jenkins-agent-error.log</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- 环境变量（可选）--&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">EnvironmentVariables</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">dict</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">JAVA_HOME</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">key</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">/path/to/your/jdk</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">string</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">dict</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">dict</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">plist</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-第二步部署配置文件">3.2 第二步：部署配置文件<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#32-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E9%83%A8%E7%BD%B2%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" class="hash-link" aria-label="3.2 第二步：部署配置文件的直接链接" title="3.2 第二步：部署配置文件的直接链接" translate="no">​</a></h3>
<p>将配置文件复制到系统目录并设置正确的权限：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 复制配置文件到系统目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo cp ~/org.jenkins.agent.plist /Library/LaunchDaemons/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置文件所有者和所属组</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo chown root:wheel /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置文件权限</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo chmod 644 /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="权限配置详解">权限配置详解<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#%E6%9D%83%E9%99%90%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="权限配置详解的直接链接" title="权限配置详解的直接链接" translate="no">​</a></h4>
<p><strong>1. 设置所有者和组（chown）</strong></p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo chown root:wheel /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div></code></pre></div></div>
<ul>
<li class=""><strong>作用</strong>：将文件的所有者改为 <code>root</code>，所属组改为 <code>wheel</code></li>
<li class=""><strong>含义</strong>：<!-- -->
<ul>
<li class=""><code>root</code> 是系统超级用户，拥有最高权限</li>
<li class=""><code>wheel</code> 是 macOS 中传统的管理员组（继承自 Unix 系统）</li>
</ul>
</li>
<li class=""><strong>为什么需要</strong>：系统级 LaunchDaemons 必须由 root 拥有，以确保安全性和系统启动时的可靠加载</li>
</ul>
<p><strong>2. 设置文件权限（chmod）</strong></p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo chmod 644 /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div></code></pre></div></div>
<ul>
<li class=""><strong>作用</strong>：设置文件的权限模式为 <code>644</code></li>
<li class=""><strong>权限分解</strong>：<!-- -->
<ul>
<li class=""><code>6</code> (所有者 root): 读(4) + 写(2) = 6 → 可读写</li>
<li class=""><code>4</code> (组 wheel): 只读(4) → 仅可读</li>
<li class=""><code>4</code> (其他用户): 只读(4) → 仅可读</li>
</ul>
</li>
<li class=""><strong>为什么需要</strong>：<!-- -->
<ul>
<li class="">launchd 需要读取这些文件来管理服务</li>
<li class="">普通用户不应能修改系统服务配置，防止安全风险</li>
<li class="">遵循最小权限原则，是 macOS 系统服务的标准配置方式</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="33-第三步加载并启动服务">3.3 第三步：加载并启动服务<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#33-%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%8A%A0%E8%BD%BD%E5%B9%B6%E5%90%AF%E5%8A%A8%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="3.3 第三步：加载并启动服务的直接链接" title="3.3 第三步：加载并启动服务的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 加载服务</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo launchctl load /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 验证服务状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">launchctl list | grep jenkins</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="34-第四步验证运行状态">3.4 第四步：验证运行状态<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#34-%E7%AC%AC%E5%9B%9B%E6%AD%A5%E9%AA%8C%E8%AF%81%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81" class="hash-link" aria-label="3.4 第四步：验证运行状态的直接链接" title="3.4 第四步：验证运行状态的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看服务列表</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">launchctl list | grep org.jenkins.agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tail -f /Users/xhm/jenkins/jenkins-agent.log</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 确认 caffeinate 进程存在</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ps aux | grep caffeinate | grep jenkins</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-服务管理">4. 服务管理<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#4-%E6%9C%8D%E5%8A%A1%E7%AE%A1%E7%90%86" class="hash-link" aria-label="4. 服务管理的直接链接" title="4. 服务管理的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-常用命令">4.1 常用命令<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#41-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="4.1 常用命令的直接链接" title="4.1 常用命令的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 停止服务</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo launchctl unload /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 启动服务</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo launchctl load /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 重启服务（先停止再启动）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo launchctl unload /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo launchctl load /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看服务状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">launchctl list | grep jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看实时日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tail -f /Users/xhm/jenkins/jenkins-agent.log</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看错误日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tail -f /Users/xhm/jenkins/jenkins-agent-error.log</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-常见问题">4.2 常见问题<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#42-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98" class="hash-link" aria-label="4.2 常见问题的直接链接" title="4.2 常见问题的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="421-息屏后仍然断开">4.2.1 息屏后仍然断开<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#421-%E6%81%AF%E5%B1%8F%E5%90%8E%E4%BB%8D%E7%84%B6%E6%96%AD%E5%BC%80" class="hash-link" aria-label="4.2.1 息屏后仍然断开的直接链接" title="4.2.1 息屏后仍然断开的直接链接" translate="no">​</a></h4>
<p><strong>检查清单</strong>：</p>
<ol>
<li class="">
<p>确认使用了 <code>caffeinate</code>：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ps aux | grep caffeinate | grep jenkins</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>检查网络配置（防止 Wi-Fi 休眠）：</p>
<ul>
<li class="">系统偏好设置 → 电池 → 电源适配器</li>
<li class="">取消勾选"当显示器关闭时，防止电脑自动进入睡眠"</li>
</ul>
</li>
<li class="">
<p>验证 caffeinate 参数：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 确保配置中使用了 -s 参数</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">grep -A10 ProgramArguments /Library/LaunchDaemons/org.jenkins.agent.plist</span><br></div></code></pre></div></div>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="422-权限问题">4.2.2 权限问题<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#422-%E6%9D%83%E9%99%90%E9%97%AE%E9%A2%98" class="hash-link" aria-label="4.2.2 权限问题的直接链接" title="4.2.2 权限问题的直接链接" translate="no">​</a></h4>
<p><strong>症状</strong>：日志文件无法写入或工作目录访问失败</p>
<p><strong>解决方法</strong>：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 确保工作目录存在且有正确权限</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /Users/xhm/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chown xhm:staff /Users/xhm/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod 755 /Users/xhm/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 确保日志文件可写</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touch /Users/xhm/jenkins/jenkins-agent.log</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chown xhm:staff /Users/xhm/jenkins/jenkins-agent.log</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-参考资源">5. 参考资源<a href="http://localhost:3000/blog/mac-jenkins-agent-setup#5-%E5%8F%82%E8%80%83%E8%B5%84%E6%BA%90" class="hash-link" aria-label="5. 参考资源的直接链接" title="5. 参考资源的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><a href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html" target="_blank" rel="noopener noreferrer" class="">Apple LaunchDaemon 官方文档</a></li>
<li class=""><a href="https://ss64.com/osx/caffeinate.html" target="_blank" rel="noopener noreferrer" class="">caffeinate 命令手册</a></li>
<li class=""><a href="https://www.jenkins.io/doc/book/using/using-agents/" target="_blank" rel="noopener noreferrer" class="">Jenkins Agent 配置指南</a></li>
</ul>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="教程" term="教程"/>
        <category label="最佳实践" term="最佳实践"/>
        <category label="Linux" term="Linux"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Jenkins Agent Linux 系统服务安装指南]]></title>
        <id>http://localhost:3000/blog/jenkins-agent-linux-service-setup</id>
        <link href="http://localhost:3000/blog/jenkins-agent-linux-service-setup"/>
        <updated>2025-09-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文档详细介绍如何在 Linux 系统上将 Jenkins Agent 配置为 systemd 系统服务，实现开机自动启动。涵盖 Java 17 安装、服务配置、故障排查等完整流程。]]></summary>
        <content type="html"><![CDATA[<p>本文档详细介绍如何在 Linux 系统上将 Jenkins Agent 配置为 systemd 系统服务，实现开机自动启动。涵盖 Java 17 安装、服务配置、故障排查等完整流程。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-前置条件">1. 前置条件<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#1-%E5%89%8D%E7%BD%AE%E6%9D%A1%E4%BB%B6" class="hash-link" aria-label="1. 前置条件的直接链接" title="1. 前置条件的直接链接" translate="no">​</a></h2>
<ul>
<li class="">Linux 系统（支持 systemd）</li>
<li class="">sudo 权限</li>
<li class="">网络连接（用于下载 Java）</li>
<li class="">Jenkins 服务端的 URL 和 Secret</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-安装步骤">2. 安装步骤<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#2-%E5%AE%89%E8%A3%85%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="2. 安装步骤的直接链接" title="2. 安装步骤的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-步骤-1-安装-java-17">2.1 步骤 1: 安装 Java 17<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#21-%E6%AD%A5%E9%AA%A4-1-%E5%AE%89%E8%A3%85-java-17" class="hash-link" aria-label="2.1 步骤 1: 安装 Java 17的直接链接" title="2.1 步骤 1: 安装 Java 17的直接链接" translate="no">​</a></h3>
<p>Jenkins Agent 需要 Java 17 或更高版本。检查系统中的 Java 版本：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">java -version</span><br></div></code></pre></div></div>
<p>如果系统没有 Java 或版本低于 17，需要安装 Java 17。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="方法-1-从-adoptium-下载安装推荐">方法 1: 从 Adoptium 下载安装（推荐）<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#%E6%96%B9%E6%B3%95-1-%E4%BB%8E-adoptium-%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E6%8E%A8%E8%8D%90" class="hash-link" aria-label="方法 1: 从 Adoptium 下载安装（推荐）的直接链接" title="方法 1: 从 Adoptium 下载安装（推荐）的直接链接" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 创建临时目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd ~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p java-install</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd java-install</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 下载 OpenJDK 17</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.10%2B7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.10_7.tar.gz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 解压</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tar -xzf OpenJDK17U-jdk_x64_linux_hotspot_17.0.10_7.tar.gz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安装到系统目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo mv jdk-17.0.10+7 /usr/local/jdk-17</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 验证安装</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/local/jdk-17/bin/java -version</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-步骤-2-准备-agent-文件">2.2 步骤 2: 准备 Agent 文件<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#22-%E6%AD%A5%E9%AA%A4-2-%E5%87%86%E5%A4%87-agent-%E6%96%87%E4%BB%B6" class="hash-link" aria-label="2.2 步骤 2: 准备 Agent 文件的直接链接" title="2.2 步骤 2: 准备 Agent 文件的直接链接" translate="no">​</a></h3>
<ol>
<li class=""><strong>创建工作目录</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /home/xhm/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd /home/xhm/jenkins</span><br></div></code></pre></div></div>
<ol>
<li class=""><strong>下载 agent.jar</strong></li>
</ol>
<p>从 Jenkins 服务端下载 agent.jar 文件，或使用已有的 agent.jar，确保文件位于：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">/home/xhm/jenkins/agent.jar</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-步骤-3-创建服务文件">2.3 步骤 3: 创建服务文件<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#23-%E6%AD%A5%E9%AA%A4-3-%E5%88%9B%E5%BB%BA%E6%9C%8D%E5%8A%A1%E6%96%87%E4%BB%B6" class="hash-link" aria-label="2.3 步骤 3: 创建服务文件的直接链接" title="2.3 步骤 3: 创建服务文件的直接链接" translate="no">​</a></h3>
<p>创建 systemd 服务文件 <code>/home/xhm/jenkins/jenkins-agent.service</code>：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo nano /home/xhm/jenkins/jenkins-agent.service</span><br></div></code></pre></div></div>
<p>服务文件内容如下（<strong>请根据实际情况修改相关参数</strong>）：</p>
<div class="language-ini codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-ini codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">[Unit]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Description=Jenkins Agent Service</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">After=network.target</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Wants=network.target</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[Service]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Type=simple</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">User=xhm</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Group=xhm</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">WorkingDirectory=/home/xhm/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ExecStart=/usr/local/jdk-17/bin/java -jar /home/xhm/jenkins/agent.jar -url http://192.168.20.35:11080/ -secret 9e96e61eba4156e1076d77375aaefde46f99721cec6dcdsafascddaa8091d721b05 -name "linux-agent" -webSocket -workDir "/home/xhm/jenkins"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Restart=always</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RestartSec=10</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">StandardOutput=journal</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">StandardError=journal</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SyslogIdentifier=jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Environment variables (if needed)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Environment=JAVA_HOME=/usr/local/jdk-17</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Environment=PATH=/usr/local/jdk-17/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Security settings</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">NoNewPrivileges=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PrivateTmp=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ProtectSystem=strict</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ProtectHome=read-only</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ReadWritePaths=/home/xhm/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[Install]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">WantedBy=multi-user.target</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="配置说明">配置说明<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="配置说明的直接链接" title="配置说明的直接链接" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_iy8F" id="服务文件参数详解">服务文件参数详解<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#%E6%9C%8D%E5%8A%A1%E6%96%87%E4%BB%B6%E5%8F%82%E6%95%B0%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="服务文件参数详解的直接链接" title="服务文件参数详解的直接链接" translate="no">​</a></h5>
<table><thead><tr><th>参数</th><th>说明</th><th>示例</th></tr></thead><tbody><tr><td><code>Type</code></td><td>服务类型</td><td><code>simple</code> (简单类型)</td></tr><tr><td><code>User/Group</code></td><td>运行用户/组</td><td><code>xhm/xhm</code></td></tr><tr><td><code>WorkingDirectory</code></td><td>工作目录</td><td><code>/home/xhm/jenkins</code></td></tr><tr><td><code>ExecStart</code></td><td>启动命令</td><td>Java 启动 agent.jar 的命令</td></tr><tr><td><code>Restart</code></td><td>重启策略</td><td><code>always</code> (总是重启)</td></tr><tr><td><code>RestartSec</code></td><td>重启延迟</td><td><code>10</code> (10 秒)</td></tr></tbody></table>
<h5 class="anchor anchorTargetStickyNavbar_iy8F" id="agent-参数说明">Agent 参数说明<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#agent-%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="Agent 参数说明的直接链接" title="Agent 参数说明的直接链接" translate="no">​</a></h5>
<table><thead><tr><th>参数</th><th>说明</th><th>必需</th></tr></thead><tbody><tr><td><code>-url</code></td><td>Jenkins 服务端 URL</td><td>是</td></tr><tr><td><code>-secret</code></td><td>Agent 连接密钥</td><td>是</td></tr><tr><td><code>-name</code></td><td>Agent 名称</td><td>否</td></tr><tr><td><code>-webSocket</code></td><td>使用 WebSocket 连接</td><td>否</td></tr><tr><td><code>-workDir</code></td><td>Agent 工作目录</td><td>否</td></tr></tbody></table>
<h5 class="anchor anchorTargetStickyNavbar_iy8F" id="安全设置">安全设置<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#%E5%AE%89%E5%85%A8%E8%AE%BE%E7%BD%AE" class="hash-link" aria-label="安全设置的直接链接" title="安全设置的直接链接" translate="no">​</a></h5>
<p>服务文件中包含以下安全设置：</p>
<ul>
<li class=""><code>NoNewPrivileges=true</code>: 禁止获取新权限</li>
<li class=""><code>PrivateTmp=true</code>: 使用私有临时目录</li>
<li class=""><code>ProtectSystem=strict</code>: 保护系统目录</li>
<li class=""><code>ProtectHome=read-only</code>: 保护家目录为只读</li>
<li class=""><code>ReadWritePaths</code>: 指定可写路径</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="24-步骤-4-安装并启用服务">2.4 步骤 4: 安装并启用服务<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#24-%E6%AD%A5%E9%AA%A4-4-%E5%AE%89%E8%A3%85%E5%B9%B6%E5%90%AF%E7%94%A8%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="2.4 步骤 4: 安装并启用服务的直接链接" title="2.4 步骤 4: 安装并启用服务的直接链接" translate="no">​</a></h3>
<ol>
<li class=""><strong>复制服务文件到 systemd 目录</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo cp /home/xhm/jenkins/jenkins-agent.service /etc/systemd/system/</span><br></div></code></pre></div></div>
<ol>
<li class=""><strong>重新加载 systemd 配置</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl daemon-reload</span><br></div></code></pre></div></div>
<ol>
<li class=""><strong>启用开机自启动</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl enable jenkins-agent.service</span><br></div></code></pre></div></div>
<ol>
<li class=""><strong>启动服务</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl start jenkins-agent.service</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="25-步骤-5-验证服务">2.5 步骤 5: 验证服务<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#25-%E6%AD%A5%E9%AA%A4-5-%E9%AA%8C%E8%AF%81%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="2.5 步骤 5: 验证服务的直接链接" title="2.5 步骤 5: 验证服务的直接链接" translate="no">​</a></h3>
<ol>
<li class=""><strong>检查服务状态</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl status jenkins-agent</span><br></div></code></pre></div></div>
<p>正常运行的输出应该显示：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">● jenkins-agent.service - Jenkins Agent Service</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Loaded: loaded (/etc/systemd/system/jenkins-agent.service; enabled)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Active: active (running) since ...</span><br></div></code></pre></div></div>
<ol>
<li class=""><strong>查看服务日志</strong></li>
</ol>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看实时日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo journalctl -u jenkins-agent -f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看最近50条日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo journalctl -u jenkins-agent -n 50</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看今天的日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo journalctl -u jenkins-agent --since today</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-服务管理">3. 服务管理<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#3-%E6%9C%8D%E5%8A%A1%E7%AE%A1%E7%90%86" class="hash-link" aria-label="3. 服务管理的直接链接" title="3. 服务管理的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-常用命令">3.1 常用命令<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#31-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="3.1 常用命令的直接链接" title="3.1 常用命令的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 启动服务</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl start jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 停止服务</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl stop jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 重启服务</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl restart jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看服务状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl status jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看服务日志</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo journalctl -u jenkins-agent -f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 启用开机自启动</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl enable jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 禁用开机自启动</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl disable jenkins-agent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 检查服务是否开机自启</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo systemctl is-enabled jenkins-agent</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-服务自动重启">3.2 服务自动重启<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#32-%E6%9C%8D%E5%8A%A1%E8%87%AA%E5%8A%A8%E9%87%8D%E5%90%AF" class="hash-link" aria-label="3.2 服务自动重启的直接链接" title="3.2 服务自动重启的直接链接" translate="no">​</a></h3>
<p>服务配置中已设置 <code>Restart=always</code>，当服务异常退出时会在 10 秒后自动重启。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-故障排查">4. 故障排查<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#4-%E6%95%85%E9%9A%9C%E6%8E%92%E6%9F%A5" class="hash-link" aria-label="4. 故障排查的直接链接" title="4. 故障排查的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-问题-1-服务无法启动">4.1 问题 1: 服务无法启动<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#41-%E9%97%AE%E9%A2%98-1-%E6%9C%8D%E5%8A%A1%E6%97%A0%E6%B3%95%E5%90%AF%E5%8A%A8" class="hash-link" aria-label="4.1 问题 1: 服务无法启动的直接链接" title="4.1 问题 1: 服务无法启动的直接链接" translate="no">​</a></h3>
<p><strong>症状</strong>: <code>systemctl status</code> 显示 <code>failed</code> 或 <code>inactive (dead)</code></p>
<p><strong>排查步骤</strong>:</p>
<ol>
<li class="">
<p>查看详细日志：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo journalctl -u jenkins-agent -n 100 --no-pager</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>检查 Java 路径是否正确：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ls -la /usr/local/jdk-17/bin/java</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>检查 agent.jar 是否存在：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ls -la /home/xhm/jenkins/agent.jar</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>检查工作目录权限：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ls -ld /home/xhm/jenkins</span><br></div></code></pre></div></div>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-问题-2-java-版本不匹配">4.2 问题 2: Java 版本不匹配<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#42-%E9%97%AE%E9%A2%98-2-java-%E7%89%88%E6%9C%AC%E4%B8%8D%E5%8C%B9%E9%85%8D" class="hash-link" aria-label="4.2 问题 2: Java 版本不匹配的直接链接" title="4.2 问题 2: Java 版本不匹配的直接链接" translate="no">​</a></h3>
<p><strong>症状</strong>: 日志中出现 <code>UnsupportedClassVersionError</code></p>
<p><strong>错误示例</strong>:</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">java.lang.UnsupportedClassVersionError: class file version 61.0 ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">this version of the Java Runtime only recognizes class file versions up to 55.0</span><br></div></code></pre></div></div>
<p><strong>解决方案</strong>:</p>
<ul>
<li class=""><code>class file version 61.0</code> 表示需要 Java 17</li>
<li class=""><code>55.0</code> 表示当前 Java 版本是 11</li>
<li class="">需要安装 Java 17 或更高版本（参考步骤 1）</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="43-问题-3-无法连接到-jenkins">4.3 问题 3: 无法连接到 Jenkins<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#43-%E9%97%AE%E9%A2%98-3-%E6%97%A0%E6%B3%95%E8%BF%9E%E6%8E%A5%E5%88%B0-jenkins" class="hash-link" aria-label="4.3 问题 3: 无法连接到 Jenkins的直接链接" title="4.3 问题 3: 无法连接到 Jenkins的直接链接" translate="no">​</a></h3>
<p><strong>症状</strong>: 日志中显示连接失败</p>
<p><strong>排查步骤</strong>:</p>
<ol>
<li class="">
<p>检查网络连接：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ping 192.168.20.35</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">curl -I http://192.168.20.35:18080/</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>验证 URL 和 Secret 是否正确</p>
</li>
<li class="">
<p>检查防火墙设置：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo ufw status</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>查看详细错误信息：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo journalctl -u jenkins-agent -f</span><br></div></code></pre></div></div>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="44-问题-4-权限问题">4.4 问题 4: 权限问题<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#44-%E9%97%AE%E9%A2%98-4-%E6%9D%83%E9%99%90%E9%97%AE%E9%A2%98" class="hash-link" aria-label="4.4 问题 4: 权限问题的直接链接" title="4.4 问题 4: 权限问题的直接链接" translate="no">​</a></h3>
<p><strong>症状</strong>: 日志中显示 <code>Permission denied</code></p>
<p><strong>解决方案</strong>:</p>
<ol>
<li class="">
<p>检查文件所有权：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">sudo chown -R xhm:xhm /home/xhm/jenkins</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>检查文件权限：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">chmod 644 /home/xhm/jenkins/agent.jar</span><br></div></code></pre></div></div>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="45-问题-5-服务频繁重启">4.5 问题 5: 服务频繁重启<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#45-%E9%97%AE%E9%A2%98-5-%E6%9C%8D%E5%8A%A1%E9%A2%91%E7%B9%81%E9%87%8D%E5%90%AF" class="hash-link" aria-label="4.5 问题 5: 服务频繁重启的直接链接" title="4.5 问题 5: 服务频繁重启的直接链接" translate="no">​</a></h3>
<p><strong>症状</strong>: 服务状态显示 <code>activating (auto-restart)</code></p>
<p><strong>排查步骤</strong>:</p>
<ol>
<li class="">查看详细错误日志</li>
<li class="">检查 Java 路径和 agent.jar 路径是否正确</li>
<li class="">检查工作目录是否可写</li>
<li class="">检查 Jenkins 服务端是否可访问</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-总结">5. 总结<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#5-%E6%80%BB%E7%BB%93" class="hash-link" aria-label="5. 总结的直接链接" title="5. 总结的直接链接" translate="no">​</a></h2>
<p>完成以上步骤后，Jenkins Agent 已配置为系统服务，具备以下特性：</p>
<p>✅ 开机自动启动
✅ 服务异常时自动重启
✅ 日志记录到 systemd journal
✅ 安全配置限制权限
✅ 易于管理和监控</p>
<p>如遇到问题，请参考<a href="http://localhost:3000/blog/jenkins-agent-linux-service-setup#4-%E6%95%85%E9%9A%9C%E6%8E%92%E6%9F%A5" class="">故障排查</a>章节或查看详细日志。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Jenkins" term="Jenkins"/>
        <category label="Linux" term="Linux"/>
        <category label="CI/CD 实践" term="CI/CD 实践"/>
        <category label="DevOps" term="DevOps"/>
        <category label="systemd" term="systemd"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Cursor规则]]></title>
        <id>http://localhost:3000/blog/cursor-rule</id>
        <link href="http://localhost:3000/blog/cursor-rule"/>
        <updated>2025-08-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Cursor 规则是 Cursor AI 编辑器中使用的一套 AI 行为约束与约定机制，通过用户规则和项目规则两个层级，确保 AI 在代码生成、建议和分析过程中保持一致性与可控性]]></summary>
        <content type="html"><![CDATA[<p>Cursor 规则是 <a href="https://cursor.com/" target="_blank" rel="noopener noreferrer" class="">Cursor AI 编辑器</a>中使用的一套 AI 行为约束与约定机制，通过用户规则和项目规则两个层级，确保 AI 在代码生成、建议和分析过程中保持一致性与可控性</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-概念介绍">1. 概念介绍<a href="http://localhost:3000/blog/cursor-rule#1-%E6%A6%82%E5%BF%B5%E4%BB%8B%E7%BB%8D" class="hash-link" aria-label="1. 概念介绍的直接链接" title="1. 概念介绍的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-cursor-规则概述">1.1 Cursor 规则概述<a href="http://localhost:3000/blog/cursor-rule#11-cursor-%E8%A7%84%E5%88%99%E6%A6%82%E8%BF%B0" class="hash-link" aria-label="1.1 Cursor 规则概述的直接链接" title="1.1 Cursor 规则概述的直接链接" translate="no">​</a></h3>
<p>Cursor 规则是一个分层的配置系统，用于指导 AI 助手在代码生成、建议和分析过程中的行为。它由两个互补的层级组成：</p>
<ul>
<li class=""><strong>用户规则（User Rules）</strong>：存储在 Cursor 设置中的全局规则，适用于所有项目</li>
<li class=""><strong>项目规则（Project Rules）</strong>：存储在项目 <code>.cursor/rules/</code> 目录中的特定规则，仅适用于当前项目</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-规则的核心作用">1.2 规则的核心作用<a href="http://localhost:3000/blog/cursor-rule#12-%E8%A7%84%E5%88%99%E7%9A%84%E6%A0%B8%E5%BF%83%E4%BD%9C%E7%94%A8" class="hash-link" aria-label="1.2 规则的核心作用的直接链接" title="1.2 规则的核心作用的直接链接" translate="no">​</a></h3>
<p>规则系统主要解决四个问题：</p>
<ol>
<li class=""><strong>保持一致</strong> - AI 按统一标准工作，代码风格统一</li>
<li class=""><strong>个性定制</strong> - 适应你的习惯和项目需求</li>
<li class=""><strong>提升质量</strong> - 减少错误，自动应用最佳实践</li>
<li class=""><strong>提高效率</strong> - 减少重复说明，AI 更准确</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="13-规则优先级体系">1.3 规则优先级体系<a href="http://localhost:3000/blog/cursor-rule#13-%E8%A7%84%E5%88%99%E4%BC%98%E5%85%88%E7%BA%A7%E4%BD%93%E7%B3%BB" class="hash-link" aria-label="1.3 规则优先级体系的直接链接" title="1.3 规则优先级体系的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">项目规则 &gt; 用户规则 &gt; 默认行为</span><br></div></code></pre></div></div>
<p>这种设计确保了灵活性：用户规则提供一致的个人偏好基线，项目规则可以根据特定需求进行覆盖和补充。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-规则配置详解">2. 规则配置详解<a href="http://localhost:3000/blog/cursor-rule#2-%E8%A7%84%E5%88%99%E9%85%8D%E7%BD%AE%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="2. 规则配置详解的直接链接" title="2. 规则配置详解的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-用户规则格式">2.1 用户规则格式<a href="http://localhost:3000/blog/cursor-rule#21-%E7%94%A8%E6%88%B7%E8%A7%84%E5%88%99%E6%A0%BC%E5%BC%8F" class="hash-link" aria-label="2.1 用户规则格式的直接链接" title="2.1 用户规则格式的直接链接" translate="no">​</a></h3>
<p><strong>存储位置</strong>：Cursor Settings → Rules &amp; Memories → User Rules(不同版本可能有差异)</p>
<p><strong>用户规则特性</strong>：</p>
<table><thead><tr><th>特性</th><th>说明</th></tr></thead><tbody><tr><td><strong>格式支持</strong></td><td>纯文本</td></tr><tr><td><strong>生效范围</strong></td><td>全局，所有项目自动应用</td></tr><tr><td><strong>版本控制</strong></td><td>不纳入项目版本控制</td></tr><tr><td><strong>修改权限</strong></td><td>个人设置，不影响团队成员</td></tr><tr><td><strong>优先级</strong></td><td>低于项目规则</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-项目规则格式mdc">2.2 项目规则格式（MDC）<a href="http://localhost:3000/blog/cursor-rule#22-%E9%A1%B9%E7%9B%AE%E8%A7%84%E5%88%99%E6%A0%BC%E5%BC%8Fmdc" class="hash-link" aria-label="2.2 项目规则格式（MDC）的直接链接" title="2.2 项目规则格式（MDC）的直接链接" translate="no">​</a></h3>
<p><strong>存储位置</strong>：项目根目录 <code>.cursor/rules/*.mdc</code></p>
<p><strong>格式</strong>：MDC（Markdown with Components）</p>
<p><strong>作用范围</strong>：当前项目</p>
<p><strong>MDC 文件结构</strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "规则的简短描述"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">globs: **/*.ts,**/*.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alwaysApply: true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 规则标题</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">规则的具体内容...</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-mdc-元数据字段详解">2.3 MDC 元数据字段详解<a href="http://localhost:3000/blog/cursor-rule#23-mdc-%E5%85%83%E6%95%B0%E6%8D%AE%E5%AD%97%E6%AE%B5%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="2.3 MDC 元数据字段详解的直接链接" title="2.3 MDC 元数据字段详解的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>字段</th><th>类型</th><th>必需</th><th>默认值</th><th>描述</th></tr></thead><tbody><tr><td><code>description</code></td><td>string</td><td>Apply Intelligently 模式必须</td><td>-</td><td>规则的简短描述，用于 AI 智能判断适用场景</td></tr><tr><td><code>globs</code></td><td>string</td><td>否</td><td><code>**/*</code></td><td>文件匹配模式，用逗号分隔多个模式</td></tr><tr><td><code>alwaysApply</code></td><td>boolean</td><td>否</td><td><code>false</code></td><td>是否在所有上下文中强制应用</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="24-规则应用模式">2.4 规则应用模式<a href="http://localhost:3000/blog/cursor-rule#24-%E8%A7%84%E5%88%99%E5%BA%94%E7%94%A8%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="2.4 规则应用模式的直接链接" title="2.4 规则应用模式的直接链接" translate="no">​</a></h3>
<p>Cursor 提供四种规则应用模式，满足不同场景的需求：</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="模式-1always-apply总是应用">模式 1：Always Apply（总是应用）<a href="http://localhost:3000/blog/cursor-rule#%E6%A8%A1%E5%BC%8F-1always-apply%E6%80%BB%E6%98%AF%E5%BA%94%E7%94%A8" class="hash-link" aria-label="模式 1：Always Apply（总是应用）的直接链接" title="模式 1：Always Apply（总是应用）的直接链接" translate="no">​</a></h4>
<p><strong>配置方式</strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alwaysApply: true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div></code></pre></div></div>
<p><strong>特点</strong>：</p>
<ul>
<li class="">在所有对话、编辑、补全中自动应用</li>
<li class="">适用于全局性的规范要求</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">安全规范（如禁止硬编码密钥）</li>
<li class="">代码格式要求（如缩进、命名规范）</li>
<li class="">错误处理标准</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="模式-2apply-intelligently智能应用">模式 2：Apply Intelligently（智能应用）<a href="http://localhost:3000/blog/cursor-rule#%E6%A8%A1%E5%BC%8F-2apply-intelligently%E6%99%BA%E8%83%BD%E5%BA%94%E7%94%A8" class="hash-link" aria-label="模式 2：Apply Intelligently（智能应用）的直接链接" title="模式 2：Apply Intelligently（智能应用）的直接链接" translate="no">​</a></h4>
<p><strong>配置方式</strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "React Hooks 使用规范"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div></code></pre></div></div>
<p><strong>特点</strong>：</p>
<ul>
<li class="">AI 根据 <code>description</code> 和上下文智能判断是否应用</li>
<li class="">无需手动指定文件模式</li>
<li class="">灵活性强，减少配置复杂度</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">特定技术栈的最佳实践（AI 可判断何时相关）</li>
<li class="">业务领域规范（如"支付模块必须有事务处理"）</li>
<li class="">复杂的条件性规则</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="模式-3apply-to-specific-files应用到特定文件">模式 3：Apply to Specific Files（应用到特定文件）<a href="http://localhost:3000/blog/cursor-rule#%E6%A8%A1%E5%BC%8F-3apply-to-specific-files%E5%BA%94%E7%94%A8%E5%88%B0%E7%89%B9%E5%AE%9A%E6%96%87%E4%BB%B6" class="hash-link" aria-label="模式 3：Apply to Specific Files（应用到特定文件）的直接链接" title="模式 3：Apply to Specific Files（应用到特定文件）的直接链接" translate="no">​</a></h4>
<p><strong>配置方式</strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "TypeScript 类型定义规范"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">globs: **/*.ts,**/*.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div></code></pre></div></div>
<p><strong>特点</strong>：</p>
<ul>
<li class="">精确控制规则应用范围</li>
<li class="">基于文件路径模式匹配</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">特定文件类型的规则（如测试文件、配置文件）</li>
<li class="">特定目录的规则（如组件目录、工具目录）</li>
<li class="">需要精确控制作用范围的规则</li>
</ul>
<p><strong>示例</strong>：</p>
<div class="language-yaml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-yaml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 匹配特定文件类型</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">globs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token important">**/*.ts</span><span class="token punctuation" style="color:#393A34">,</span><span class="token important">**/*.tsx</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 匹配特定目录</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">globs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> src/components/</span><span class="token important">**/*</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 匹配测试文件</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">globs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token important">**/*.test.ts</span><span class="token punctuation" style="color:#393A34">,</span><span class="token important">**/*.spec.ts</span><span class="token punctuation" style="color:#393A34">,</span><span class="token important">**/__tests__/**</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 匹配多种文件类型和目录</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">globs</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token important">**/*.js</span><span class="token punctuation" style="color:#393A34">,</span><span class="token important">**/*.jsx</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">src/utils/</span><span class="token important">**/*</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">src/hooks/</span><span class="token important">**/*</span><br></div></code></pre></div></div>
<p><strong>Globs 生效时机</strong>：</p>
<p>当你打开、编辑文件或使用 AI 补全/Chat 时，Cursor 会根据当前文件路径匹配相应的规则。</p>
<p><strong>匹配机制示例</strong>：</p>
<ul>
<li class="">编辑 <code>src/components/Button.tsx</code> 时，会应用所有匹配该路径的规则</li>
<li class="">例如：<code>**/*.tsx</code>（匹配所有 TypeScript React 文件）、<code>src/components/**/*</code>（匹配组件目录下所有文件）</li>
</ul>
<p>Globs 匹配机制确保了不同类型的文件能够应用最适合的规则配置。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="模式-4apply-manually手动应用">模式 4：Apply Manually（手动应用）<a href="http://localhost:3000/blog/cursor-rule#%E6%A8%A1%E5%BC%8F-4apply-manually%E6%89%8B%E5%8A%A8%E5%BA%94%E7%94%A8" class="hash-link" aria-label="模式 4：Apply Manually（手动应用）的直接链接" title="模式 4：Apply Manually（手动应用）的直接链接" translate="no">​</a></h4>
<p><strong>配置方式</strong>：</p>
<p>创建规则文件（如 <code>legacy-code.mdc</code>），不设置 <code>alwaysApply</code> 或 <code>globs</code></p>
<p><strong>使用方式</strong>：</p>
<p>在对话中通过 <code>@</code> 符号手动引用：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">@legacy-code 帮我重构这段代码</span><br></div></code></pre></div></div>
<p><strong>特点</strong>：</p>
<ul>
<li class="">完全由用户控制何时应用</li>
<li class="">不会自动触发</li>
<li class="">可作为临时规则或特殊场景规则</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">遗留代码重构指导</li>
<li class="">特殊的一次性任务规则</li>
<li class="">实验性规范</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="25-规则管理与调试">2.5 规则管理与调试<a href="http://localhost:3000/blog/cursor-rule#25-%E8%A7%84%E5%88%99%E7%AE%A1%E7%90%86%E4%B8%8E%E8%B0%83%E8%AF%95" class="hash-link" aria-label="2.5 规则管理与调试的直接链接" title="2.5 规则管理与调试的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="切换规则类型">切换规则类型<a href="http://localhost:3000/blog/cursor-rule#%E5%88%87%E6%8D%A2%E8%A7%84%E5%88%99%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="切换规则类型的直接链接" title="切换规则类型的直接链接" translate="no">​</a></h4>
<p>在 Cursor 中打开规则文件后，通过顶部的类型下拉菜单选择规则类型，该操作会自动更新 description、globs 和 alwaysApply 属性。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/cursor-rule/select-rule-mode.webp" alt="select-rule-mode" class="img_gjoA"></p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="查看已启用的规则">查看已启用的规则<a href="http://localhost:3000/blog/cursor-rule#%E6%9F%A5%E7%9C%8B%E5%B7%B2%E5%90%AF%E7%94%A8%E7%9A%84%E8%A7%84%E5%88%99" class="hash-link" aria-label="查看已启用的规则的直接链接" title="查看已启用的规则的直接链接" translate="no">​</a></h4>
<p>已启用的规则会显示在 Agent 对话框的上下文管理栏（顶部），如下图所示：</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/cursor-rule/active-rules.webp" alt="active-rules" class="img_gjoA"></p>
<p>如上图所示，编号 2 处展示了激活的两条规则（一条为 <code>alwaysApply: true</code> 的全局应用规则，另一条为通过 <code>globs</code> 匹配到当前文件的规则）。tab 指示的是你正在编辑的文件。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="排查规则问题">排查规则问题<a href="http://localhost:3000/blog/cursor-rule#%E6%8E%92%E6%9F%A5%E8%A7%84%E5%88%99%E9%97%AE%E9%A2%98" class="hash-link" aria-label="排查规则问题的直接链接" title="排查规则问题的直接链接" translate="no">​</a></h4>
<p>如果规则没生效，可以在规则设置中看到错误信息，如下图：</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/cursor-rule/rule-error.webp" alt="rule-error" class="img_gjoA"></p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-最佳实践">3. 最佳实践<a href="http://localhost:3000/blog/cursor-rule#3-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="3. 最佳实践的直接链接" title="3. 最佳实践的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-规则编写技巧">3.1 规则编写技巧<a href="http://localhost:3000/blog/cursor-rule#31-%E8%A7%84%E5%88%99%E7%BC%96%E5%86%99%E6%8A%80%E5%B7%A7" class="hash-link" aria-label="3.1 规则编写技巧的直接链接" title="3.1 规则编写技巧的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="具体明确避免模糊">具体明确，避免模糊<a href="http://localhost:3000/blog/cursor-rule#%E5%85%B7%E4%BD%93%E6%98%8E%E7%A1%AE%E9%81%BF%E5%85%8D%E6%A8%A1%E7%B3%8A" class="hash-link" aria-label="具体明确，避免模糊的直接链接" title="具体明确，避免模糊的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">不好的规则：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- "代码要写得好"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- "保持良好的代码风格"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- "注意性能优化"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">好的规则：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- "使用 2 空格缩进，不使用 Tab"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- "函数命名使用驼峰命名法，类使用 PascalCase"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- "列表渲染超过 100 项时使用虚拟滚动"</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="分层设计规则">分层设计规则<a href="http://localhost:3000/blog/cursor-rule#%E5%88%86%E5%B1%82%E8%AE%BE%E8%AE%A1%E8%A7%84%E5%88%99" class="hash-link" aria-label="分层设计规则的直接链接" title="分层设计规则的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">通用规则（alwaysApply: true）：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 安全规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 错误处理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 代码格式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">特定规则（globs:xx）：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 特定框架约定（React、Vue）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 特定文件类型（测试、配置）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 特定业务场景</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-规则文件组织">3.2 规则文件组织<a href="http://localhost:3000/blog/cursor-rule#32-%E8%A7%84%E5%88%99%E6%96%87%E4%BB%B6%E7%BB%84%E7%BB%87" class="hash-link" aria-label="3.2 规则文件组织的直接链接" title="3.2 规则文件组织的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="推荐的目录结构">推荐的目录结构<a href="http://localhost:3000/blog/cursor-rule#%E6%8E%A8%E8%8D%90%E7%9A%84%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84" class="hash-link" aria-label="推荐的目录结构的直接链接" title="推荐的目录结构的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">.cursor/rules/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── README.md              # 规则文档说明</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── core/                  # 核心规则（alwaysApply: true）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── security.mdc       # 安全规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── errors.mdc         # 错误处理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── format.mdc         # 代码格式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── languages/             # 语言特定规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── typescript.mdc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── python.mdc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── frameworks/            # 框架规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── react.mdc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── project-specific/      # 项目特定规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── api.mdc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── database.mdc</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="33-版本控制与团队协作">3.3 版本控制与团队协作<a href="http://localhost:3000/blog/cursor-rule#33-%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6%E4%B8%8E%E5%9B%A2%E9%98%9F%E5%8D%8F%E4%BD%9C" class="hash-link" aria-label="3.3 版本控制与团队协作的直接链接" title="3.3 版本控制与团队协作的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="规则文件纳入版本控制">规则文件纳入版本控制<a href="http://localhost:3000/blog/cursor-rule#%E8%A7%84%E5%88%99%E6%96%87%E4%BB%B6%E7%BA%B3%E5%85%A5%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6" class="hash-link" aria-label="规则文件纳入版本控制的直接链接" title="规则文件纳入版本控制的直接链接" translate="no">​</a></h4>
<p>.gitignore 中不要忽略 .cursor 目录</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-实用示例">4. 实用示例<a href="http://localhost:3000/blog/cursor-rule#4-%E5%AE%9E%E7%94%A8%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="4. 实用示例的直接链接" title="4. 实用示例的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-用户规则示例">4.1 用户规则示例<a href="http://localhost:3000/blog/cursor-rule#41-%E7%94%A8%E6%88%B7%E8%A7%84%E5%88%99%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="4.1 用户规则示例的直接链接" title="4.1 用户规则示例的直接链接" translate="no">​</a></h3>
<p>用户规则采用纯文本格式，在 Cursor 设置中配置，适用于所有项目：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">1. 语言与注释</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 默认使用中文回答问题，除非用户特别要求英文</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 默认使用英文代码注释，除非特别要求中文</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 公共 API 使用 JSDoc/TSDoc 格式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 回答风格</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 尽量简洁明了，避免不必要的废话和重复说明</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 先给出关键答案，再提供简短解释或示例</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 安全与稳健性（最高优先级）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 绝对禁止硬编码任何敏感信息（密码、API密钥、IP）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 所有配置必须从环境变量或配置文件中读取</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 必须进行错误处理，对可能失败的操作使用 try-catch 或等效机制</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. 代码整洁与可维护性（参考《代码整洁之道》）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 函数短小且单一职责，每个函数只做一件事</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 变量、函数、类命名语义清晰，易读易理解</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 避免重复代码（遵循 DRY 原则）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 错误处理明确且一致，保证程序健壮</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 模块和类职责明确，依赖清晰，便于扩展和维护</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5. 设计模式规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 优先使用常见设计模式优化结构与扩展性。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 推荐使用的设计模式：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 单例模式（Singleton）：用于全局唯一实例。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 工厂方法模式（Factory Method）：避免直接实例化，提升可扩展性。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 策略模式（Strategy）：将可变行为封装为可替换策略。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 观察者模式（Observer）：用于事件驱动和响应式设计。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 装饰器模式（Decorator）：在不修改原类的情况下动态扩展功能。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 命令模式（Command）：将操作封装为对象，便于撤销与队列化。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - 适配器模式（Adapter）：用于兼容不同接口的组件。按这个格式修改</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  - Proxy（代理模式）：控制访问或增强功能（缓存、安全、远程访问）</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-项目规则示例">4.2 项目规则示例<a href="http://localhost:3000/blog/cursor-rule#42-%E9%A1%B9%E7%9B%AE%E8%A7%84%E5%88%99%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="4.2 项目规则示例的直接链接" title="4.2 项目规则示例的直接链接" translate="no">​</a></h3>
<p>项目规则采用 MDC 格式，存储在 <code>.cursor/rules/</code> 目录中，仅适用于当前项目。以下展示不同应用模式的实际使用场景：</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="示例-1always-apply---安全规范">示例 1：Always Apply - 安全规范<a href="http://localhost:3000/blog/cursor-rule#%E7%A4%BA%E4%BE%8B-1always-apply---%E5%AE%89%E5%85%A8%E8%A7%84%E8%8C%83" class="hash-link" aria-label="示例 1：Always Apply - 安全规范的直接链接" title="示例 1：Always Apply - 安全规范的直接链接" translate="no">​</a></h4>
<p><strong><code>.cursor/rules/core/security.mdc</code></strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "全局安全规范，所有代码必须遵守"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alwaysApply: true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安全规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 敏感信息处理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 绝对禁止硬编码任何敏感信息（密码、API密钥、IP地址、Token）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 所有配置必须从环境变量或加密配置文件中读取</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 使用 `.env.example` 提供配置模板，真实配置文件加入 `.gitignore`</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 数据验证</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 所有用户输入必须进行验证和清理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- API 请求参数必须进行类型检查和范围验证</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 数据库查询使用参数化查询，防止 SQL 注入</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="示例-2apply-intelligently---框架最佳实践">示例 2：Apply Intelligently - 框架最佳实践<a href="http://localhost:3000/blog/cursor-rule#%E7%A4%BA%E4%BE%8B-2apply-intelligently---%E6%A1%86%E6%9E%B6%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="示例 2：Apply Intelligently - 框架最佳实践的直接链接" title="示例 2：Apply Intelligently - 框架最佳实践的直接链接" translate="no">​</a></h4>
<p><strong><code>.cursor/rules/frameworks/react-hooks.mdc</code></strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "React Hooks 使用规范和最佳实践"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># React Hooks 规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">AI 会在检测到 React Hooks 相关代码时自动应用此规则。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## Hooks 使用规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 只在 React 函数组件或自定义 Hooks 中调用 Hooks</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 不在循环、条件或嵌套函数中调用 Hooks</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 自定义 Hook 必须以 `use` 开头命名</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 依赖数组规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- useEffect/useMemo/useCallback 必须正确声明依赖项</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 避免遗漏依赖导致的过期闭包问题</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 对象和函数依赖应该用 useMemo/useCallback 包装</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="示例-3apply-to-specific-files---typescript-类型规范">示例 3：Apply to Specific Files - TypeScript 类型规范<a href="http://localhost:3000/blog/cursor-rule#%E7%A4%BA%E4%BE%8B-3apply-to-specific-files---typescript-%E7%B1%BB%E5%9E%8B%E8%A7%84%E8%8C%83" class="hash-link" aria-label="示例 3：Apply to Specific Files - TypeScript 类型规范的直接链接" title="示例 3：Apply to Specific Files - TypeScript 类型规范的直接链接" translate="no">​</a></h4>
<p><strong><code>.cursor/rules/languages/typescript.mdc</code></strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "TypeScript 类型定义和使用规范"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">globs: **/*.ts,**/*.tsx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># TypeScript 规范</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 类型定义</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- Props 接口使用 `interface` 定义并导出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 工具类型使用 `type` 定义</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 避免使用 `any`，优先使用具体类型或泛型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 使用 `unknown` 替代 `any` 处理不确定类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 组件类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- React 组件 Props 必须有完整的类型定义</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 函数组件使用 `React.FC` 或显式声明返回类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 事件处理函数使用正确的事件类型（如 `React.ChangeEvent&lt;HTMLInputElement&gt;`）</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="示例-4apply-manually---遗留代码处理">示例 4：Apply Manually - 遗留代码处理<a href="http://localhost:3000/blog/cursor-rule#%E7%A4%BA%E4%BE%8B-4apply-manually---%E9%81%97%E7%95%99%E4%BB%A3%E7%A0%81%E5%A4%84%E7%90%86" class="hash-link" aria-label="示例 4：Apply Manually - 遗留代码处理的直接链接" title="示例 4：Apply Manually - 遗留代码处理的直接链接" translate="no">​</a></h4>
<p><strong><code>.cursor/rules/project-specific/legacy-refactor.mdc</code></strong>：</p>
<div class="language-mdc codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-mdc codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">description: "遗留代码重构指南，需手动引用"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 遗留代码重构指南</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">通过 @legacy-refactor 手动引用此规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 重构策略</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 保持原有功能不变，先添加测试用例</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 逐步替换旧 API，保持向后兼容</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 使用适配器模式过渡新旧实现</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 重构完成后更新文档和注释</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">## 临时豁免</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">遗留代码重构期间允许：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 使用 `@ts-ignore` 标记已知类型问题</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 保留部分 `any` 类型（需添加 TODO 注释）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 暂不强制执行最新的代码规范</span><br></div></code></pre></div></div>
<p><strong>总结</strong>：</p>
<p>有效的 Cursor 规则体系需要持续迭代和优化。从简单的个人偏好开始，逐步构建团队共享的规则库，结合版本控制和团队协作流程，最终形成提升开发效率和代码质量的强大工具。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Programming" term="Programming"/>
        <category label="技术概念" term="技术概念"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[ABI是什么]]></title>
        <id>http://localhost:3000/blog/what-is-abi</id>
        <link href="http://localhost:3000/blog/what-is-abi"/>
        <updated>2025-07-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[ABI，全称 Application Binary Interface（应用二进制接口），是一种规则，规定不同程序（或模块）在编译后（二进制层面）如何正确交流与协作。]]></summary>
        <content type="html"><![CDATA[<p>ABI，全称 Application Binary Interface（应用二进制接口），是一种规则，规定不同程序（或模块）在编译后（二进制层面）如何正确交流与协作。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-什么是-abi">1. 什么是 ABI？<a href="http://localhost:3000/blog/what-is-abi#1-%E4%BB%80%E4%B9%88%E6%98%AF-abi" class="hash-link" aria-label="1. 什么是 ABI？的直接链接" title="1. 什么是 ABI？的直接链接" translate="no">​</a></h2>
<p>ABI 是一种接口规范，它定义了程序在二进制层面的交互规则：</p>
<table><thead><tr><th>规范内容</th><th>具体说明</th></tr></thead><tbody><tr><td><strong>函数调用约定</strong></td><td>参数传递方式、返回值获取、调用约定（如 SysV）</td></tr><tr><td><strong>数据类型布局</strong></td><td>struct 内存布局、对齐规则</td></tr><tr><td><strong>系统调用接口</strong></td><td>系统调用编号和参数（如 <code>read()</code>、<code>open()</code>）</td></tr><tr><td><strong>符号命名规则</strong></td><td>C++ name mangling、虚函数表布局等</td></tr><tr><td><strong>动态库加载</strong></td><td><code>.so</code> 文件的符号解析、链接、导入导出</td></tr></tbody></table>
<p>这些规则决定了编译后的程序能否在不同系统上正确运行。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-举个例子">1.1 举个例子<a href="http://localhost:3000/blog/what-is-abi#11-%E4%B8%BE%E4%B8%AA%E4%BE%8B%E5%AD%90" class="hash-link" aria-label="1.1 举个例子的直接链接" title="1.1 举个例子的直接链接" translate="no">​</a></h3>
<p>假设你写了一个简单函数：</p>
<div class="language-c codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-c codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> a </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>当你将其编译成 <code>.so</code> 动态库供 Python 调用时，Python 需要知道：</p>
<ul>
<li class="">参数 <code>a</code> 和 <code>b</code> 应该放在哪里？</li>
<li class="">返回值从哪里获取？</li>
<li class="">数据结构如何对齐和布局？</li>
<li class="">函数在库中的实际名称是什么？</li>
</ul>
<p><strong>这一切都由 ABI 规范决定。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-形象比喻abi-就像快递包装标准">1.2 形象比喻：ABI 就像快递包装标准<a href="http://localhost:3000/blog/what-is-abi#12-%E5%BD%A2%E8%B1%A1%E6%AF%94%E5%96%BBabi-%E5%B0%B1%E5%83%8F%E5%BF%AB%E9%80%92%E5%8C%85%E8%A3%85%E6%A0%87%E5%87%86" class="hash-link" aria-label="1.2 形象比喻：ABI 就像快递包装标准的直接链接" title="1.2 形象比喻：ABI 就像快递包装标准的直接链接" translate="no">​</a></h3>
<p>想象两个快递公司需要合作，一个负责发货，一个负责收货。</p>
<p>ABI 就像是规定快递如何打包、寄送地址、标签位置、地址语言的<strong>包装手册</strong>。</p>
<table><thead><tr><th>快递场景</th><th>ABI 对应含义</th></tr></thead><tbody><tr><td>快递箱规格</td><td>数据结构在内存中的布局</td></tr><tr><td>地址语言（中文/英文）</td><td>符号命名方式（是否有 name mangling）</td></tr><tr><td>运单位置</td><td>参数传递方式（寄存器或栈）</td></tr><tr><td>收货仓库</td><td>返回值存储的寄存器位置</td></tr><tr><td>搬运责任</td><td>栈清理责任（调用方或被调用方）</td></tr></tbody></table>
<p><strong>如果不遵守包装标准会怎样？</strong>
快递丢失、无法打开、地址错误、仓库爆满 —— 这和 ABI 不一致时的二进制兼容性错误完全一样！</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-glibc-与-abi-的关系">2. glibc 与 ABI 的关系<a href="http://localhost:3000/blog/what-is-abi#2-glibc-%E4%B8%8E-abi-%E7%9A%84%E5%85%B3%E7%B3%BB" class="hash-link" aria-label="2. glibc 与 ABI 的关系的直接链接" title="2. glibc 与 ABI 的关系的直接链接" translate="no">​</a></h2>
<p><strong>glibc</strong> 是 Linux 系统中 ABI 规范的核心实现之一。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-什么是-glibc">2.1 什么是 glibc？<a href="http://localhost:3000/blog/what-is-abi#21-%E4%BB%80%E4%B9%88%E6%98%AF-glibc" class="hash-link" aria-label="2.1 什么是 glibc？的直接链接" title="2.1 什么是 glibc？的直接链接" translate="no">​</a></h3>
<p><strong>glibc</strong>（GNU C Library）是：</p>
<ul>
<li class="">Linux 上最常用的 C 标准库实现</li>
<li class="">提供核心函数：<code>malloc()</code>、<code>printf()</code>、<code>fork()</code>、<code>pthread_create()</code> 等</li>
<li class="">应用程序与 Linux 系统调用之间的桥梁</li>
<li class="">系统调用的封装层</li>
<li class=""><strong>ABI 规范的具体实现载体</strong></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-glibc-与-abi-的关系">2.2 glibc 与 ABI 的关系<a href="http://localhost:3000/blog/what-is-abi#22-glibc-%E4%B8%8E-abi-%E7%9A%84%E5%85%B3%E7%B3%BB" class="hash-link" aria-label="2.2 glibc 与 ABI 的关系的直接链接" title="2.2 glibc 与 ABI 的关系的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>概念</th><th>说明</th></tr></thead><tbody><tr><td><strong>ABI 是规范</strong></td><td>glibc 实现了其中的大部分内容</td></tr><tr><td><strong>glibc 是共享库</strong></td><td>版本升级可能引入新 ABI（向前兼容）或移除旧 ABI（破坏兼容性）</td></tr><tr><td><strong>程序依赖的 ABI</strong></td><td>程序依赖的是实际使用的函数版本，不是编译时的 glibc 版本</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-实际案例">2.3 实际案例<a href="http://localhost:3000/blog/what-is-abi#23-%E5%AE%9E%E9%99%85%E6%A1%88%E4%BE%8B" class="hash-link" aria-label="2.3 实际案例的直接链接" title="2.3 实际案例的直接链接" translate="no">​</a></h3>
<p>创建一个简单程序 <code>hello.cpp</code>：</p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stdio.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;stdlib.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;string.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;unistd.h&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">printf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hello\n"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">              </span><span class="token comment" style="color:#999988;font-style:italic">// GLIBC_2.2.5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">malloc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">                    </span><span class="token comment" style="color:#999988;font-style:italic">// GLIBC_2.2.5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 使用较新的函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">memcpy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> src</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">         </span><span class="token comment" style="color:#999988;font-style:italic">// GLIBC_2.14 (2011年优化版本)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">reallocarray</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ptr</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">      </span><span class="token comment" style="color:#999988;font-style:italic">// GLIBC_2.27 (2018年新增)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>在 Ubuntu 22.04（glibc 2.35）上编译后，查看依赖的 glibc 版本：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">readelf -s ./a.out | grep GLIBC_</span><br></div></code></pre></div></div>
<p>输出结果：</p>
<div class="language-code codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-code codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">printf@GLIBC_2.2.5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">malloc@GLIBC_2.2.5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">memcpy@GLIBC_2.14</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">reallocarray@GLIBC_2.27</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-跨系统兼容性解决方案">3. 跨系统兼容性解决方案<a href="http://localhost:3000/blog/what-is-abi#3-%E8%B7%A8%E7%B3%BB%E7%BB%9F%E5%85%BC%E5%AE%B9%E6%80%A7%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="3. 跨系统兼容性解决方案的直接链接" title="3. 跨系统兼容性解决方案的直接链接" translate="no">​</a></h2>
<p>如果希望程序能在多个不同的 Linux 系统上运行（Ubuntu 20.04、Debian 10、CentOS 7 等），就必须考虑 ABI 兼容性。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-基本原则向后兼容">3.1 基本原则：向后兼容<a href="http://localhost:3000/blog/what-is-abi#31-%E5%9F%BA%E6%9C%AC%E5%8E%9F%E5%88%99%E5%90%91%E5%90%8E%E5%85%BC%E5%AE%B9" class="hash-link" aria-label="3.1 基本原则：向后兼容的直接链接" title="3.1 基本原则：向后兼容的直接链接" translate="no">​</a></h3>
<p><strong>在较旧版本的 Linux 系统上编译程序</strong>，这样生成的二进制文件才能在较新系统上运行（向前兼容）。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="兼容性示例">兼容性示例<a href="http://localhost:3000/blog/what-is-abi#%E5%85%BC%E5%AE%B9%E6%80%A7%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="兼容性示例的直接链接" title="兼容性示例的直接链接" translate="no">​</a></h4>
<p><strong>正确做法：</strong></p>
<ul>
<li class="">在 CentOS 7（glibc 2.17）上编译 Qt5 应用</li>
<li class="">可以运行在：CentOS 7、Ubuntu 20.04、Ubuntu 22.04</li>
</ul>
<p><strong>错误做法：</strong></p>
<ul>
<li class="">在 Ubuntu 22.04（glibc 2.35）上编译应用</li>
<li class="">只能运行在：Ubuntu 22.04</li>
<li class="">无法运行在：CentOS 7（glibc 版本太旧，找不到符号）</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-解决方案">3.2 解决方案<a href="http://localhost:3000/blog/what-is-abi#32-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="3.2 解决方案的直接链接" title="3.2 解决方案的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="方案一在旧系统上构建">方案一：在旧系统上构建<a href="http://localhost:3000/blog/what-is-abi#%E6%96%B9%E6%A1%88%E4%B8%80%E5%9C%A8%E6%97%A7%E7%B3%BB%E7%BB%9F%E4%B8%8A%E6%9E%84%E5%BB%BA" class="hash-link" aria-label="方案一：在旧系统上构建的直接链接" title="方案一：在旧系统上构建的直接链接" translate="no">​</a></h4>
<table><thead><tr><th>方法</th><th>说明</th></tr></thead><tbody><tr><td><strong>旧系统编译</strong></td><td>在 glibc 2.17 的 CentOS 7 上构建</td></tr><tr><td><strong>容器构建</strong></td><td>使用 Docker + Ubuntu 18.04 编译</td></tr><tr><td><strong>静态链接</strong></td><td>使用 musl libc 静态编译（如 Alpine）避免 glibc 问题</td></tr></tbody></table>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="方案二现代打包格式">方案二：现代打包格式<a href="http://localhost:3000/blog/what-is-abi#%E6%96%B9%E6%A1%88%E4%BA%8C%E7%8E%B0%E4%BB%A3%E6%89%93%E5%8C%85%E6%A0%BC%E5%BC%8F" class="hash-link" aria-label="方案二：现代打包格式的直接链接" title="方案二：现代打包格式的直接链接" translate="no">​</a></h4>
<table><thead><tr><th>打包方式</th><th>特点说明</th></tr></thead><tbody><tr><td><strong>AppImage</strong></td><td>打包动态库，但仍依赖系统 glibc，无法完全避免兼容性问题</td></tr><tr><td><strong>Flatpak</strong></td><td>自带 glibc 运行时，彻底解决 ABI 问题</td></tr><tr><td><strong>Snap</strong></td><td>现代打包系统，提供沙箱和自动依赖管理，需要用户安装运行时</td></tr><tr><td><strong>Docker</strong></td><td>适合服务器环境，不适用于桌面可执行文件</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-总结">4. 总结<a href="http://localhost:3000/blog/what-is-abi#4-%E6%80%BB%E7%BB%93" class="hash-link" aria-label="4. 总结的直接链接" title="4. 总结的直接链接" translate="no">​</a></h2>
<p><strong>ABI 是程序在"机器语言"层面交流的规则手册</strong>，就像快递行业的包装标准，确保每个程序都能正确发货、收货、协作和运行。</p>
<p><strong>glibc 作为 ABI 的具体实现</strong>，其版本兼容性直接影响程序的跨系统运行能力。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Programming" term="Programming"/>
        <category label="技术概念" term="技术概念"/>
        <category label="系统" term="系统"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Cmake配置文件]]></title>
        <id>http://localhost:3000/blog/cmake-configuration-file</id>
        <link href="http://localhost:3000/blog/cmake-configuration-file"/>
        <updated>2024-07-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[CMake 配置文件是现代 C/C++项目构建的核心组件，涵盖了项目构建、工具链配置、依赖管理、打包测试等多个方面。本文将从六个关键配置文件类型详细介绍 CMake 配置体系。]]></summary>
        <content type="html"><![CDATA[<p>CMake 配置文件是现代 C/C++项目构建的核心组件，涵盖了项目构建、工具链配置、依赖管理、打包测试等多个方面。本文将从六个关键配置文件类型详细介绍 CMake 配置体系。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-cmakeliststxt---项目构建规则">1. CMakeLists.txt - 项目构建规则<a href="http://localhost:3000/blog/cmake-configuration-file#1-cmakeliststxt---%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA%E8%A7%84%E5%88%99" class="hash-link" aria-label="1. CMakeLists.txt - 项目构建规则的直接链接" title="1. CMakeLists.txt - 项目构建规则的直接链接" translate="no">​</a></h2>
<p>CMakeLists.txt 是 CMake 项目的核心配置文件，定义项目构建规则和目标。</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 基本项目配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION 3.16)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">project(MyProject VERSION 1.0.0 LANGUAGES CXX)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD 17)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 目标定义</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(myapp src/main.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(mylib STATIC src/lib.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 目标配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(myapp PRIVATE include)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myapp PRIVATE mylib)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 编译选项</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(MSVC)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    target_compile_options(myapp PRIVATE /W4)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">else()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    target_compile_options(myapp PRIVATE -Wall -Wextra)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-toolchaincmake---工具链交叉编译">2. toolchain.cmake - 工具链/交叉编译<a href="http://localhost:3000/blog/cmake-configuration-file#2-toolchaincmake---%E5%B7%A5%E5%85%B7%E9%93%BE%E4%BA%A4%E5%8F%89%E7%BC%96%E8%AF%91" class="hash-link" aria-label="2. toolchain.cmake - 工具链/交叉编译的直接链接" title="2. toolchain.cmake - 工具链/交叉编译的直接链接" translate="no">​</a></h2>
<p>工具链文件定义编译器和构建工具配置，用于交叉编译（在一台电脑上编译，但编译出来的程序是给另一种架构/系统 运行的）。toolchain.cmake 本质上还是一个 普通的 CMake 脚本文件，只是内容和用途不同。</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># toolchain.cmake - 简单的ARM交叉编译配置-x86 PC 上用这个配置编译出在 ARM Linux 上能运行的程序</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 告诉 CMake 目标系统是 Linux，不是宿主机的系统。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_SYSTEM_NAME Linux)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#告诉 CMake 目标 CPU 架构是 ARM</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_SYSTEM_PROCESSOR arm)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置交叉编译器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 指定 C 语言编译器，用交叉编译器arm-linux-gnueabihf-gcc而不是本地 gcc。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 指定 C++ 编译器，同样是交叉编译器 arm-linux-gnueabihf-g++</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置查找路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)</span><br></div></code></pre></div></div>
<p>使用方法：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake ..</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-cmakecachetxt---缓存配置">3. CMakeCache.txt - 缓存配置<a href="http://localhost:3000/blog/cmake-configuration-file#3-cmakecachetxt---%E7%BC%93%E5%AD%98%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="3. CMakeCache.txt - 缓存配置的直接链接" title="3. CMakeCache.txt - 缓存配置的直接链接" translate="no">​</a></h2>
<p>CMakeCache.txt 是 CMake 自动生成的文件，位于你的 build 目录下（比如 build/CMakeCache.txt）。它存储了配置阶段的所有缓存变量，包括编译器路径、编译选项、自定义缓存变量等。CMake 下次配置时会直接读取这个文件，加快配置速度，并保留用户手动修改的变量。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="缓存变量管理">缓存变量管理<a href="http://localhost:3000/blog/cmake-configuration-file#%E7%BC%93%E5%AD%98%E5%8F%98%E9%87%8F%E7%AE%A1%E7%90%86" class="hash-link" aria-label="缓存变量管理的直接链接" title="缓存变量管理的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 设置缓存变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(BUILD_TYPE "Release" CACHE STRING "Build configuration type")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(ENABLE_TESTING ON CACHE BOOL "Enable unit testing")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(INSTALL_PREFIX "/usr/local" CACHE PATH "Installation directory")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 缓存变量选项</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set_property(CACHE BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 强制缓存变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(FORCE_REBUILD OFF CACHE BOOL "Force complete rebuild" FORCE)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="缓存操作命令">缓存操作命令<a href="http://localhost:3000/blog/cmake-configuration-file#%E7%BC%93%E5%AD%98%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="缓存操作命令的直接链接" title="缓存操作命令的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看缓存内容</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -L</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看高级缓存选项</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -LA</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 清除缓存</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm CMakeCache.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 或</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build . --target clean</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 修改缓存变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -DCMAKE_BUILD_TYPE=Debug .</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-findxxxcmake--xxxconfigcmake---依赖库查找">4. FindXXX.cmake / XXXConfig.cmake - 依赖库查找<a href="http://localhost:3000/blog/cmake-configuration-file#4-findxxxcmake--xxxconfigcmake---%E4%BE%9D%E8%B5%96%E5%BA%93%E6%9F%A5%E6%89%BE" class="hash-link" aria-label="4. FindXXX.cmake / XXXConfig.cmake - 依赖库查找的直接链接" title="4. FindXXX.cmake / XXXConfig.cmake - 依赖库查找的直接链接" translate="no">​</a></h2>
<p>这些文件定义了如何查找和配置外部依赖库。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="findxxxcmake-模块">FindXXX.cmake 模块<a href="http://localhost:3000/blog/cmake-configuration-file#findxxxcmake-%E6%A8%A1%E5%9D%97" class="hash-link" aria-label="FindXXX.cmake 模块的直接链接" title="FindXXX.cmake 模块的直接链接" translate="no">​</a></h3>
<p>FindMyLibrary.cmake 定义了 CMake 如何找到你的库，也就是告诉 find_package(MyLibrary)：</p>
<ul>
<li class="">去哪些路径找头文件 (.h)</li>
<li class="">去哪些路径找库文件 (.so/.a/.lib)</li>
<li class="">可选地去哪里读取版本信息</li>
<li class="">最后生成 MyLibrary_FOUND 变量和一个现代 CMake target</li>
</ul>
<p>换句话说，就是在告诉 CMake “如果有人调用 find_package(MyLibrary)，就按我定义的规则去找这个库”。</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># FindMyLibrary.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查找MyLibrary库的CMake模块</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查找头文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_path(MYLIBRARY_INCLUDE_DIR</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    NAMES mylibrary.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PATHS</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        /usr/include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        /usr/local/include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ${MYLIBRARY_ROOT}/include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PATH_SUFFIXES mylibrary</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查找库文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_library(MYLIBRARY_LIBRARY</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    NAMES mylibrary libmylibrary</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PATHS</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        /usr/lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        /usr/local/lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ${MYLIBRARY_ROOT}/lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PATH_SUFFIXES x86_64-linux-gnu</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 版本检查</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(MYLIBRARY_INCLUDE_DIR)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    file(READ "${MYLIBRARY_INCLUDE_DIR}/mylibrary_version.h" VERSION_FILE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    string(REGEX MATCH "#define MYLIBRARY_VERSION \"([0-9.]+)\"" _ ${VERSION_FILE})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    set(MYLIBRARY_VERSION ${CMAKE_MATCH_1})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 结果处理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">include(FindPackageHandleStandardArgs)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package_handle_standard_args(MyLibrary</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    REQUIRED_VARS MYLIBRARY_LIBRARY MYLIBRARY_INCLUDE_DIR</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    VERSION_VAR MYLIBRARY_VERSION</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 创建导入目标</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(MyLibrary_FOUND AND NOT TARGET MyLibrary::MyLibrary)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 创建空target</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_library(MyLibrary::MyLibrary UNKNOWN IMPORTED)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 设置属性，这一步把 target 变得完整，上层 target 才能直接 target_link_libraries 使用它。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    set_target_properties(MyLibrary::MyLibrary PROPERTIES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        IMPORTED_LOCATION "${MYLIBRARY_LIBRARY}"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        INTERFACE_INCLUDE_DIRECTORIES "${MYLIBRARY_INCLUDE_DIR}"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    )</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<p>示例：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_package(MyLibrary REQUIRED)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(MyApp PRIVATE MyLibrary::MyLibrary)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="xxxconfigcmake-配置文件">XXXConfig.cmake 配置文件<a href="http://localhost:3000/blog/cmake-configuration-file#xxxconfigcmake-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" class="hash-link" aria-label="XXXConfig.cmake 配置文件的直接链接" title="XXXConfig.cmake 配置文件的直接链接" translate="no">​</a></h3>
<p>通俗的讲：FindXXX.cmake → “去哪里找这个库？怎么找？”而 XXXConfig.cmake → “库就在这里，按我给的规则用它就行。”</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># MyLibraryConfig.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 由库提供的配置文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@PACKAGE_INIT@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 检查组件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(_supported_components Core Utils Network)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">foreach(_comp ${MyLibrary_FIND_COMPONENTS})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if(NOT _comp IN_LIST _supported_components)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        set(MyLibrary_FOUND False)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        set(MyLibrary_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endforeach()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 包含目标文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># MyLibraryTargets.cmake 包含了库的目标文件和头文件路径，不用像FindMyLibrary.cmake那样去自己搜索</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">include("${CMAKE_CURRENT_LIST_DIR}/MyLibraryTargets.cmake")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 版本检查</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">check_required_components(MyLibrary)</span><br></div></code></pre></div></div>
<p>示例：</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 在CMakeLists.txt中使用</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(MyLibrary 2.0 REQUIRED COMPONENTS Core Utils)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(MyLibrary_FOUND)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    target_link_libraries(myapp PRIVATE MyLibrary::MyLibrary)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message(STATUS "Found MyLibrary version: ${MyLibrary_VERSION}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-cpackconfigcmake--ctestconfigcmake---打包与测试">5. CPackConfig.cmake / CTestConfig.cmake - 打包与测试<a href="http://localhost:3000/blog/cmake-configuration-file#5-cpackconfigcmake--ctestconfigcmake---%E6%89%93%E5%8C%85%E4%B8%8E%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="5. CPackConfig.cmake / CTestConfig.cmake - 打包与测试的直接链接" title="5. CPackConfig.cmake / CTestConfig.cmake - 打包与测试的直接链接" translate="no">​</a></h2>
<p>这些配置文件用于项目的打包发布和测试管理。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="cpackconfigcmake---打包配置">CPackConfig.cmake - 打包配置<a href="http://localhost:3000/blog/cmake-configuration-file#cpackconfigcmake---%E6%89%93%E5%8C%85%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="CPackConfig.cmake - 打包配置的直接链接" title="CPackConfig.cmake - 打包配置的直接链接" translate="no">​</a></h3>
<p>CPackConfig.cmake 和 CMakeLists.txt 在功能上有明确的分工 - CMakeLists.txt 负责项目的构建规则和目标定义，而 CPackConfig.cmake 专注于打包配置和发布相关的设置。虽然这些打包配置技术上可以直接写在 CMakeLists.txt 中，但分离到独立的 CPackConfig.cmake 文件可以让项目结构更清晰，维护更方便。</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># CPackConfig.cmake - 简单的打包配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CPACK_PACKAGE_NAME "MyApplication")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My awesome application")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CPACK_PACKAGE_VENDOR "My Company")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置打包格式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CPACK_GENERATOR "TGZ;ZIP")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 包含CPack</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">include(CPack)</span><br></div></code></pre></div></div>
<p><strong>使用方式：</strong></p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 在CMakeLists.txt中引用</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">include(CPackConfig.cmake)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 构建并打包</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cpack --config build/CPackConfig.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 或者直接在构建目录中</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cpack</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="ctestconfigcmake---测试配置">CTestConfig.cmake - 测试配置<a href="http://localhost:3000/blog/cmake-configuration-file#ctestconfigcmake---%E6%B5%8B%E8%AF%95%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="CTestConfig.cmake - 测试配置的直接链接" title="CTestConfig.cmake - 测试配置的直接链接" translate="no">​</a></h3>
<p>本质上，CTestConfig.cmake 里的配置完全可以写进普通的 CMakeLists.txt，只是“职责分工”不同：</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># CTestConfig.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CTEST_PROJECT_NAME "MyProject")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 测试超时设置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CTEST_TEST_TIMEOUT 300)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 内存检查</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CTEST_MEMORYCHECK_COMMAND "valgrind")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CTEST_MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full --show-reachable=yes")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 覆盖率检查</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CTEST_COVERAGE_COMMAND "gcov")</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="测试脚本示例">测试脚本示例<a href="http://localhost:3000/blog/cmake-configuration-file#%E6%B5%8B%E8%AF%95%E8%84%9A%E6%9C%AC%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="测试脚本示例的直接链接" title="测试脚本示例的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 在CMakeLists.txt中启用测试</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable_testing()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 添加测试</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_test(NAME unit_tests COMMAND myapp_tests)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_test(NAME integration_tests COMMAND myapp_integration)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 测试属性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set_tests_properties(unit_tests PROPERTIES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    TIMEOUT 60</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-cmakepresetsjson---构建预设">6. CMakePresets.json - 构建预设<a href="http://localhost:3000/blog/cmake-configuration-file#6-cmakepresetsjson---%E6%9E%84%E5%BB%BA%E9%A2%84%E8%AE%BE" class="hash-link" aria-label="6. CMakePresets.json - 构建预设的直接链接" title="6. CMakePresets.json - 构建预设的直接链接" translate="no">​</a></h2>
<p>CMakePresets.json，CMake 3.19+ 引入，提供了标准化的构建配置预设，简化了不同环境下的构建过程。该文件应放在项目根目录（与 CMakeLists.txt 同级）。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"configurePresets"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"debug"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"displayName"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Debug Build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"binaryDir"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build/debug"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"cacheVariables"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"CMAKE_BUILD_TYPE"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Debug"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"release"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"displayName"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Release Build"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"binaryDir"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"build/release"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"cacheVariables"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"CMAKE_BUILD_TYPE"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Release"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"buildPresets"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"debug"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"configurePreset"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"debug"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"release"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"configurePreset"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"release"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p><strong>使用方式：</strong></p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 使用预设配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --preset debug</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build --preset debug</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 列出可用预设</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --list-presets</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="总结">总结<a href="http://localhost:3000/blog/cmake-configuration-file#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>通过这六种配置文件的合理组织和使用，可以构建出功能完整、易于维护的 CMake 项目构建系统：</p>
<ul>
<li class=""><strong>CMakeLists.txt</strong> 定义核心构建逻辑</li>
<li class=""><strong>toolchain.cmake</strong> 处理交叉编译和工具链配置</li>
<li class=""><strong>CMakeCache.txt</strong> 管理构建缓存和变量</li>
<li class=""><strong>FindXXX.cmake/XXXConfig.cmake</strong> 处理依赖库查找</li>
<li class=""><strong>CPackConfig.cmake/CTestConfig.cmake</strong> 支持打包和测试</li>
<li class=""><strong>CMakePresets.json</strong> 提供标准化的构建预设</li>
</ul>
<p>这种模块化的配置方式不仅提高了项目的可维护性，还增强了跨平台兼容性和团队协作效率。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="CMake" term="CMake"/>
        <category label="构建系统" term="构建系统"/>
        <category label="C++" term="C++"/>
        <category label="跨平台" term="跨平台"/>
        <category label="Programming" term="Programming"/>
        <category label="开发工具" term="开发工具"/>
        <category label="配置" term="配置"/>
        <category label="Makefile" term="Makefile"/>
        <category label="项目管理" term="项目管理"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[CmakeLists.txt常用命令介绍]]></title>
        <id>http://localhost:3000/blog/cmake-commands-introduction</id>
        <link href="http://localhost:3000/blog/cmake-commands-introduction"/>
        <updated>2024-06-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文档介绍 CMake 构建系统中最常用的命令和最佳实践，适合初学者和进阶开发者参考。]]></summary>
        <content type="html"><![CDATA[<p>本文档介绍 CMake 构建系统中最常用的命令和最佳实践，适合初学者和进阶开发者参考。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-基础配置">1. 基础配置<a href="http://localhost:3000/blog/cmake-commands-introduction#1-%E5%9F%BA%E7%A1%80%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="1. 基础配置的直接链接" title="1. 基础配置的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-cmake_minimum_required">1.1 cmake_minimum_required<a href="http://localhost:3000/blog/cmake-commands-introduction#11-cmake_minimum_required" class="hash-link" aria-label="1.1 cmake_minimum_required的直接链接" title="1.1 cmake_minimum_required的直接链接" translate="no">​</a></h3>
<p>指定项目所需的最低 CMake 版本。虽然不是强制要求，但建议始终显式声明，以确保构建环境兼容并避免因版本差异导致的问题。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION x.y)</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION 3.20)</span><br></div></code></pre></div></div>
<p><strong>版本选择原则：</strong></p>
<ol>
<li class="">
<p><strong>基于项目使用的 CMake 特性</strong></p>
<ul>
<li class=""><code>target_link_options</code> 需要 CMake 3.13+</li>
<li class=""><code>CMAKE_CXX_STANDARD</code> 和 <code>CMAKE_CXX_STANDARD_REQUIRED</code> 需要 CMake 3.1+</li>
<li class=""><code>qt_add_executable</code> 需要 CMake 3.16+</li>
</ul>
</li>
<li class="">
<p><strong>基于第三方库要求</strong></p>
<ul>
<li class="">Qt 6 官方要求 CMake 3.16+</li>
<li class="">OpenCV 4.5+ 推荐 CMake 3.10+</li>
</ul>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-project">1.2 project<a href="http://localhost:3000/blog/cmake-commands-introduction#12-project" class="hash-link" aria-label="1.2 project的直接链接" title="1.2 project的直接链接" translate="no">​</a></h3>
<p>定义项目名称、版本号和编程语言。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">project(ProjectName VERSION major.minor.patch [LANGUAGES ...])</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">project(MyAwesomeApp VERSION 1.2.3 LANGUAGES CXX)</span><br></div></code></pre></div></div>
<p><strong>参数说明：</strong></p>
<ul>
<li class=""><strong>ProjectName</strong>: 项目名称，用于生成工程文件名和变量 <code>PROJECT_NAME</code></li>
<li class=""><strong>VERSION</strong>: 版本号（主版本.次版本.补丁版本），自动生成以下变量：<!-- -->
<ul>
<li class=""><code>PROJECT_VERSION</code></li>
<li class=""><code>PROJECT_VERSION_MAJOR</code></li>
<li class=""><code>PROJECT_VERSION_MINOR</code></li>
<li class=""><code>PROJECT_VERSION_PATCH</code></li>
</ul>
</li>
<li class=""><strong>LANGUAGES</strong>: 支持的编程语言，可选值：<!-- -->
<ul>
<li class=""><code>C</code>: C 语言</li>
<li class=""><code>CXX</code>: C++ 语言</li>
<li class=""><code>Fortran</code>: Fortran 语言</li>
<li class=""><code>ASM</code>: 汇编语言</li>
</ul>
</li>
</ul>
<p><strong>注意事项：</strong></p>
<ul>
<li class="">如果不指定 <code>LANGUAGES</code>，默认启用 C 和 CXX</li>
<li class="">建议明确指定所需语言以避免不必要的编译器检测</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-目标管理">2. 目标管理<a href="http://localhost:3000/blog/cmake-commands-introduction#2-%E7%9B%AE%E6%A0%87%E7%AE%A1%E7%90%86" class="hash-link" aria-label="2. 目标管理的直接链接" title="2. 目标管理的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-add_executable">2.1 add_executable<a href="http://localhost:3000/blog/cmake-commands-introduction#21-add_executable" class="hash-link" aria-label="2.1 add_executable的直接链接" title="2.1 add_executable的直接链接" translate="no">​</a></h3>
<p>定义并创建一个可执行文件目标，将指定的源文件编译链接成可运行的程序（如 Windows 的 .exe 文件）。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(TargetName [WIN32] [MACOSX_BUNDLE] source1 source2 ...)</span><br></div></code></pre></div></div>
<p><strong>参数说明：</strong></p>
<ul>
<li class=""><strong>TargetName</strong>: 目标名称</li>
<li class=""><strong>WIN32</strong>: Windows 平台上创建 GUI 程序（无控制台窗口）</li>
<li class=""><strong>MACOSX_BUNDLE</strong>: macOS 平台上创建 .app 应用包</li>
<li class=""><strong>source1 source2 ...</strong>: 源文件列表</li>
</ul>
<p><strong>基础示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(MyApp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/main.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/app.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<p><strong>跨平台示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 收集源文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">file(GLOB_RECURSE SOURCES "src/*.cpp")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 根据平台添加不同选项</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(WIN32)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_executable(MyApp WIN32 ${SOURCES})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">elseif(APPLE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_executable(MyApp MACOSX_BUNDLE ${SOURCES})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">else()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_executable(MyApp ${SOURCES})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<p><strong>注意事项：</strong></p>
<ul>
<li class="">头文件无需添加到源文件列表中</li>
<li class="">必须包含所有参与编译的 .cpp 文件</li>
<li class="">Qt 项目推荐使用 <code>qt_add_executable</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-add_library">2.2 add_library<a href="http://localhost:3000/blog/cmake-commands-introduction#22-add_library" class="hash-link" aria-label="2.2 add_library的直接链接" title="2.2 add_library的直接链接" translate="no">​</a></h3>
<p>定义并创建一个库目标，将指定的源文件编译成可重用的库文件（如静态库 .a/.lib 或动态库 .so/.dll）。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">add_library(targetName [STATIC|SHARED|MODULE|INTERFACE|OBJECT] [sources...])</span><br></div></code></pre></div></div>
<p><strong>库类型说明：</strong></p>
<ul>
<li class=""><strong>STATIC</strong>: 静态库（.a / .lib）</li>
<li class=""><strong>SHARED</strong>: 动态库（.so / .dll）</li>
<li class=""><strong>MODULE</strong>: 模块库（插件，运行时加载）</li>
<li class=""><strong>INTERFACE</strong>: 接口库（纯头文件库）</li>
<li class=""><strong>OBJECT</strong>: 对象文件库（.o 文件集合）</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 静态库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(mylib STATIC</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/foo.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/bar.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 动态库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(mylib_shared SHARED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/foo.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/bar.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 接口库（仅头文件）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(header_only_lib INTERFACE)</span><br></div></code></pre></div></div>
<p><strong>常见配套命令：</strong></p>
<ul>
<li class=""><code>target_include_directories()</code> - 设置头文件路径</li>
<li class=""><code>target_link_libraries()</code> - 链接依赖库</li>
<li class=""><code>target_compile_options()</code> - 编译选项</li>
<li class=""><code>target_sources()</code> - 管理源文件</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-target_sources">2.3 target_sources<a href="http://localhost:3000/blog/cmake-commands-introduction#23-target_sources" class="hash-link" aria-label="2.3 target_sources的直接链接" title="2.3 target_sources的直接链接" translate="no">​</a></h3>
<p>为已存在的目标添加源文件。相比 add_library 在创建目标时一次性添加源文件，target_sources 的优势在于目标创建后可以分多次、分条件地动态添加源文件。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">target_sources(targetName [PRIVATE | PUBLIC | INTERFACE] sources...)</span><br></div></code></pre></div></div>
<p><strong>可见性说明：</strong></p>
<ul>
<li class=""><strong>PRIVATE</strong>: 源文件仅用于该目标本身</li>
<li class=""><strong>PUBLIC</strong>: 目标本身使用，依赖者也可见（很少用于源文件）</li>
<li class=""><strong>INTERFACE</strong>: 目标本身不用，仅对依赖者可见</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 先创建空库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(mylib STATIC)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 根据平台添加不同源文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(WIN32)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    target_sources(mylib PRIVATE src/windows.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">elseif(APPLE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    target_sources(mylib PRIVATE src/macos.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">else()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    target_sources(mylib PRIVATE src/linux.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<p><strong>使用场景：</strong></p>
<ul>
<li class="">模块化管理源文件</li>
<li class="">条件性添加源文件</li>
<li class="">提高 CMakeLists.txt 可读性</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-依赖管理">3. 依赖管理<a href="http://localhost:3000/blog/cmake-commands-introduction#3-%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86" class="hash-link" aria-label="3. 依赖管理的直接链接" title="3. 依赖管理的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-target_include_directories">3.1 target_include_directories<a href="http://localhost:3000/blog/cmake-commands-introduction#31-target_include_directories" class="hash-link" aria-label="3.1 target_include_directories的直接链接" title="3.1 target_include_directories的直接链接" translate="no">​</a></h3>
<p>为目标设置头文件搜索路径，控制编译器在何处查找 <code>#include</code> 的头文件；若未设置，编译器只会在源文件目录和系统默认路径中查找头文件，其他目录下的头文件将无法找到。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(targetName [PUBLIC|PRIVATE|INTERFACE] dirs...)</span><br></div></code></pre></div></div>
<p><strong>可见性说明：</strong></p>
<ul>
<li class=""><strong>PRIVATE</strong>: 路径仅用于该目标编译</li>
<li class=""><strong>PUBLIC</strong>: 该目标及其依赖者都使用此路径</li>
<li class=""><strong>INTERFACE</strong>: 仅依赖者使用此路径</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 为可执行程序添加私有头文件路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(myapp main.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(myapp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ${CMAKE_CURRENT_SOURCE_DIR}/include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 为库添加公共头文件路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(mylib src/foo.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(mylib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PUBLIC</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ${CMAKE_CURRENT_SOURCE_DIR}/include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<p><strong>目录结构示例：</strong></p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">project_root/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── include/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── foo.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── utils/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│       └── helper.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── src/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── main.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── CMakeLists.txt</span><br></div></code></pre></div></div>
<p><strong>代码中的使用：</strong></p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// main.cpp</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"foo.h"</span><span class="token macro property" style="color:#36acaa">          </span><span class="token macro property comment" style="color:#999988;font-style:italic">// 正确</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"utils/helper.h"</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property comment" style="color:#999988;font-style:italic">// 正确</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"helper.h"</span><span class="token macro property" style="color:#36acaa">       </span><span class="token macro property comment" style="color:#999988;font-style:italic">// 错误：需要包含完整路径</span><br></div></code></pre></div></div>
<p><strong>重要提示：</strong></p>
<ul>
<li class="">CMake 不会递归搜索子目录</li>
<li class="">需在代码中提供相对于 include（target_include_directories 指定的目录）目录的完整路径</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-target_link_libraries">3.2 target_link_libraries<a href="http://localhost:3000/blog/cmake-commands-introduction#32-target_link_libraries" class="hash-link" aria-label="3.2 target_link_libraries的直接链接" title="3.2 target_link_libraries的直接链接" translate="no">​</a></h3>
<p>为目标链接库依赖。也就是告诉 CMake：在编译 target 时，需要额外链接哪些库（依赖的库），才能正常运行。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(targetName [PUBLIC|PRIVATE|INTERFACE] libraries...)</span><br></div></code></pre></div></div>
<p><strong>可见性说明：</strong></p>
<ul>
<li class=""><strong>PRIVATE</strong>: 仅该目标使用</li>
<li class=""><strong>PUBLIC</strong>: 该目标及其依赖者都链接</li>
<li class=""><strong>INTERFACE</strong>: 仅依赖者链接</li>
</ul>
<p><strong>库类型：</strong></p>
<ul>
<li class="">CMake 目标（如自定义库）</li>
<li class="">系统库（如 pthread）</li>
<li class="">第三方库的导入目标（如 Qt6::Core）</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 链接自定义库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(mylib STATIC foo.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(myapp main.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myapp PRIVATE mylib)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 链接第三方库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 REQUIRED COMPONENTS Core Widgets)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myapp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::Core</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::Widgets</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 链接系统库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myapp PRIVATE pthread)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-库和包查找">4. 库和包查找<a href="http://localhost:3000/blog/cmake-commands-introduction#4-%E5%BA%93%E5%92%8C%E5%8C%85%E6%9F%A5%E6%89%BE" class="hash-link" aria-label="4. 库和包查找的直接链接" title="4. 库和包查找的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-find_package">4.1 find_package<a href="http://localhost:3000/blog/cmake-commands-introduction#41-find_package" class="hash-link" aria-label="4.1 find_package的直接链接" title="4.1 find_package的直接链接" translate="no">​</a></h3>
<p>用来自动查找和配置外部依赖库或包，当你的项目依赖第三方库或系统库时就需要。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_package(PackageName [Version] [REQUIRED] [COMPONENTS components...])</span><br></div></code></pre></div></div>
<p><strong>参数说明：</strong></p>
<ul>
<li class=""><strong>PackageName</strong>: 包名称（如 Qt6、OpenCV、Boost）</li>
<li class=""><strong>Version</strong>: 最低版本要求</li>
<li class=""><strong>REQUIRED</strong>: 找不到时停止构建</li>
<li class=""><strong>COMPONENTS</strong>: 指定所需子模块</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 6.6 REQUIRED COMPONENTS Core Widgets Gui)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-查找机制详解">4.2 查找机制详解<a href="http://localhost:3000/blog/cmake-commands-introduction#42-%E6%9F%A5%E6%89%BE%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="4.2 查找机制详解的直接链接" title="4.2 查找机制详解的直接链接" translate="no">​</a></h3>
<p>CMake 使用<strong>严格的优先级顺序</strong>查找包，找到第一个匹配项就立即停止搜索。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="421-完整查找流程">4.2.1 完整查找流程<a href="http://localhost:3000/blog/cmake-commands-introduction#421-%E5%AE%8C%E6%95%B4%E6%9F%A5%E6%89%BE%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="4.2.1 完整查找流程的直接链接" title="4.2.1 完整查找流程的直接链接" translate="no">​</a></h4>
<ol>
<li class=""><strong>检查缓存变量</strong>：如果 <code>&lt;PackageName&gt;_DIR</code> 已经在缓存中，直接使用</li>
<li class=""><strong>模块模式（Module Mode）</strong>：搜索 <code>Find&lt;PackageName&gt;.cmake</code> 文件</li>
<li class=""><strong>配置模式（Config Mode）</strong>：搜索 <code>&lt;PackageName&gt;Config.cmake</code> 或 <code>&lt;lowercase-name&gt;-config.cmake</code> 文件</li>
</ol>
<p><strong>重要：</strong> 一旦在模块模式中找到 <code>Find&lt;PackageName&gt;.cmake</code>，CMake 就会停止搜索，<strong>不会继续尝试配置模式</strong>。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="422-模块模式module-mode">4.2.2 模块模式（Module Mode）<a href="http://localhost:3000/blog/cmake-commands-introduction#422-%E6%A8%A1%E5%9D%97%E6%A8%A1%E5%BC%8Fmodule-mode" class="hash-link" aria-label="4.2.2 模块模式（Module Mode）的直接链接" title="4.2.2 模块模式（Module Mode）的直接链接" translate="no">​</a></h4>
<p>按以下顺序搜索 <code>Find&lt;PackageName&gt;.cmake</code> 文件：</p>
<ol>
<li class=""><code>CMAKE_MODULE_PATH</code> 指定路径（按添加顺序）</li>
<li class="">CMake 内置模块路径（如 <code>/usr/share/cmake/Modules</code>）</li>
</ol>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 如果存在 FindQt6.cmake（不太可能），就会使用模块模式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 REQUIRED)</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="423-配置模式config-mode">4.2.3 配置模式（Config Mode）<a href="http://localhost:3000/blog/cmake-commands-introduction#423-%E9%85%8D%E7%BD%AE%E6%A8%A1%E5%BC%8Fconfig-mode" class="hash-link" aria-label="4.2.3 配置模式（Config Mode）的直接链接" title="4.2.3 配置模式（Config Mode）的直接链接" translate="no">​</a></h4>
<p>只有在模块模式<strong>失败</strong>后才会尝试配置模式，搜索 <code>&lt;PackageName&gt;Config.cmake</code> 文件：</p>
<ol>
<li class=""><code>&lt;PackageName&gt;_DIR</code> 变量指定路径</li>
<li class=""><code>CMAKE_PREFIX_PATH</code> 路径（最重要）：<!-- -->
<ul>
<li class=""><code>&lt;prefix&gt;/</code></li>
<li class=""><code>&lt;prefix&gt;/cmake/</code></li>
<li class=""><code>&lt;prefix&gt;/lib/cmake/&lt;PackageName&gt;/</code></li>
<li class=""><code>&lt;prefix&gt;/lib/&lt;PackageName&gt;/</code></li>
<li class=""><code>&lt;prefix&gt;/lib/&lt;PackageName&gt;/cmake/</code></li>
<li class=""><code>&lt;prefix&gt;/share/&lt;PackageName&gt;/</code></li>
<li class=""><code>&lt;prefix&gt;/share/&lt;PackageName&gt;/cmake/</code></li>
</ul>
</li>
<li class=""><code>CMAKE_FRAMEWORK_PATH</code>（macOS 框架）</li>
<li class=""><code>CMAKE_APPBUNDLE_PATH</code>（macOS App Bundle）</li>
<li class=""><code>CMAKE_FIND_ROOT_PATH</code>（交叉编译）</li>
<li class="">系统默认路径：<!-- -->
<ul>
<li class=""><code>/usr/lib/cmake/&lt;PackageName&gt;/</code></li>
<li class=""><code>/usr/local/lib/cmake/&lt;PackageName&gt;/</code></li>
<li class=""><code>/opt/local/lib/cmake/&lt;PackageName&gt;/</code></li>
<li class="">Windows: <code>C:/Program Files/&lt;PackageName&gt;/</code></li>
</ul>
</li>
<li class="">环境变量 <code>PATH</code> 路径</li>
<li class="">平台注册表（Windows）</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="424-强制使用配置模式">4.2.4 强制使用配置模式<a href="http://localhost:3000/blog/cmake-commands-introduction#424-%E5%BC%BA%E5%88%B6%E4%BD%BF%E7%94%A8%E9%85%8D%E7%BD%AE%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="4.2.4 强制使用配置模式的直接链接" title="4.2.4 强制使用配置模式的直接链接" translate="no">​</a></h4>
<p>可以通过 <code>CONFIG</code> 关键字强制跳过模块模式：</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 强制使用配置模式，跳过 FindQt6.cmake 查找</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 CONFIG REQUIRED)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 等价写法</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 CONFIG REQUIRED COMPONENTS Core Widgets)</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="425-windows-查找-qt6-实例">4.2.5 Windows 查找 Qt6 实例<a href="http://localhost:3000/blog/cmake-commands-introduction#425-windows-%E6%9F%A5%E6%89%BE-qt6-%E5%AE%9E%E4%BE%8B" class="hash-link" aria-label="4.2.5 Windows 查找 Qt6 实例的直接链接" title="4.2.5 Windows 查找 Qt6 实例的直接链接" translate="no">​</a></h4>
<p>假设在 Windows 上安装了 Qt6 到 <code>C:/Qt/6.7.0/msvc2022_64/</code>，执行以下查找：</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 REQUIRED COMPONENTS Core Widgets)</span><br></div></code></pre></div></div>
<p><strong>查找流程：</strong></p>
<ol>
<li class="">
<p><strong>检查缓存变量</strong></p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">检查 CMakeCache.txt 中是否有 Qt6_DIR</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">如果有：Qt6_DIR:PATH=C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>模块模式</strong>（通常 Qt6 不使用此模式）</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">查找 FindQt6.cmake：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- CMAKE_MODULE_PATH 路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- C:/Program Files/CMake/share/cmake-3.x/Modules/FindQt6.cmake（不存在）</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>配置模式</strong>（Qt6 的标准方式）</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">查找 Qt6Config.cmake，按以下顺序：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a) Qt6_DIR 变量指定路径：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/Qt6Config.cmake ✓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b) CMAKE_PREFIX_PATH 路径（如果设置了）：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   假设设置了 CMAKE_PREFIX_PATH=C:/Qt/6.7.0/msvc2022_64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt/6.7.0/msvc2022_64/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt/6.7.0/msvc2022_64/cmake/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/Qt6Config.cmake ✓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt/6.7.0/msvc2022_64/lib/Qt6/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt/6.7.0/msvc2022_64/share/Qt6/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">c) 系统默认路径：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Program Files/Qt6/lib/cmake/Qt6/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Program Files (x86)/Qt6/lib/cmake/Qt6/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - C:/Qt6/lib/cmake/Qt6/Qt6Config.cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">d) 注册表查找：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\Qt6</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   - HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\Qt6</span><br></div></code></pre></div></div>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="426-默认搜索的局限性">4.2.6 默认搜索的局限性<a href="http://localhost:3000/blog/cmake-commands-introduction#426-%E9%BB%98%E8%AE%A4%E6%90%9C%E7%B4%A2%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7" class="hash-link" aria-label="4.2.6 默认搜索的局限性的直接链接" title="4.2.6 默认搜索的局限性的直接链接" translate="no">​</a></h4>
<p><strong>重要：</strong> 如果 Qt 安装在 <code>C:/Qt/</code> 下（如 <code>C:/Qt/6.7.0/msvc2022_64/</code>），<strong>不设置 <code>CMAKE_PREFIX_PATH</code> 通常找不到</strong>。</p>
<p><strong>原因分析：</strong></p>
<ol>
<li class="">
<p><strong>CMake 默认搜索路径</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">C:/Program Files/Qt6/lib/cmake/Qt6/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">C:/Program Files (x86)/Qt6/lib/cmake/Qt6/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">C:/Qt6/lib/cmake/Qt6/                    # 注意：只查找 C:/Qt6，不查找 C:/Qt/</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>Qt 实际安装路径</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/Qt6Config.cmake  # 不在默认搜索路径中</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>路径不匹配</strong>：</p>
<ul>
<li class="">默认搜索：<code>C:/Qt6/lib/cmake/Qt6/</code></li>
<li class="">实际路径：<code>C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/</code></li>
<li class="">两者不匹配！</li>
</ul>
</li>
</ol>
<p><strong>测试验证：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 清除所有前缀路径，仅使用默认搜索</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unset(CMAKE_PREFIX_PATH)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unset(CMAKE_PREFIX_PATH CACHE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unset(Qt6_DIR CACHE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 尝试查找 Qt6</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 COMPONENTS Core)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(Qt6_FOUND)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message(STATUS "✓ 在默认路径找到 Qt6: ${Qt6_DIR}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">else()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message(WARNING "✗ 默认路径未找到 Qt6")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message(STATUS "需要设置 CMAKE_PREFIX_PATH 或 Qt6_DIR")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<p><strong>可能的例外情况：</strong></p>
<ol>
<li class="">
<p><strong>注册表信息</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">如果 Qt 安装程序向注册表写入了路径信息：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\Qt6</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>符号链接</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">如果存在符号链接：C:/Qt6 -&gt; C:/Qt/6.7.0/msvc2022_64</span><br></div></code></pre></div></div>
</li>
<li class="">
<p><strong>环境变量</strong>：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">如果系统环境变量中设置了相关路径（不常见）</span><br></div></code></pre></div></div>
</li>
</ol>
<p><strong>解决方案（按推荐程度排序）：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 方案1：设置前缀路径（推荐）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_PREFIX_PATH "C:/Qt/6.7.0/msvc2022_64")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 方案2：直接指定 Qt6 路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(Qt6_DIR "C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 方案3：环境变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># set CMAKE_PREFIX_PATH=C:\Qt\6.7.0\msvc2022_64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 方案4：命令行参数</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># cmake -DCMAKE_PREFIX_PATH="C:/Qt/6.7.0/msvc2022_64" ..</span><br></div></code></pre></div></div>
<p><strong>总结：</strong> C:/Qt/ 路径下的 Qt 安装<strong>需要手动配置路径</strong>，CMake 默认搜索机制无法自动找到。</p>
<p><strong>重要提示：</strong></p>
<ul>
<li class=""><code>CMAKE_PREFIX_PATH</code> 是最常用的配置变量</li>
<li class="">添加 <code>NO_DEFAULT_PATH</code> 可限制搜索范围</li>
<li class=""><code>CMAKE_FIND_ROOT_PATH</code> 主要用于交叉编译</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="427-默认搜索路径不设置前缀路径时">4.2.7 默认搜索路径（不设置前缀路径时）<a href="http://localhost:3000/blog/cmake-commands-introduction#427-%E9%BB%98%E8%AE%A4%E6%90%9C%E7%B4%A2%E8%B7%AF%E5%BE%84%E4%B8%8D%E8%AE%BE%E7%BD%AE%E5%89%8D%E7%BC%80%E8%B7%AF%E5%BE%84%E6%97%B6" class="hash-link" aria-label="4.2.7 默认搜索路径（不设置前缀路径时）的直接链接" title="4.2.7 默认搜索路径（不设置前缀路径时）的直接链接" translate="no">​</a></h4>
<p>如果不手动设置 <code>CMAKE_PREFIX_PATH</code>，CMake 会使用<strong>系统默认路径</strong>进行搜索：</p>
<p><strong>Linux/Unix 系统：</strong></p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">/usr/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/local/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/opt/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/lib/x86_64-linux-gnu/  (架构相关)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/share/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/local/share/</span><br></div></code></pre></div></div>
<p><strong>macOS 系统：</strong></p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">/usr/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/local/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/opt/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/opt/local/                  (MacPorts)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/local/Cellar/          (Homebrew)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/Applications/              (应用程序)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/System/Library/Frameworks/ (系统框架)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/Library/Frameworks/        (用户框架)</span><br></div></code></pre></div></div>
<p><strong>Windows 系统：</strong></p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">C:/Program Files/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">C:/Program Files (x86)/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">C:/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">注册表路径 (Registry)</span><br></div></code></pre></div></div>
<p><strong>常见问题：</strong></p>
<ol>
<li class="">
<p><strong>找不到包</strong>：如果库安装在非标准路径（如 <code>/opt/Qt6</code>），CMake 在默认路径中找不到，需要设置 <code>CMAKE_PREFIX_PATH</code>。</p>
</li>
<li class="">
<p><strong>找到错误版本</strong>：系统中安装多个版本时，CMake 可能找到旧版本而不是期望的版本。</p>
</li>
</ol>
<p><strong>验证默认搜索：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看系统默认前缀路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">message(STATUS "CMAKE_SYSTEM_PREFIX_PATH: ${CMAKE_SYSTEM_PREFIX_PATH}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 测试不设置前缀路径的查找</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unset(CMAKE_PREFIX_PATH)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(Qt6_FOUND)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message(STATUS "Found Qt6 in system default paths: ${Qt6_DIR}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">else()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message(WARNING "Qt6 not found in system default paths")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="43-find_library">4.3 find_library<a href="http://localhost:3000/blog/cmake-commands-introduction#43-find_library" class="hash-link" aria-label="4.3 find_library的直接链接" title="4.3 find_library的直接链接" translate="no">​</a></h3>
<p>查找指定库文件的路径，当库没有 CMake 配置文件或你只想手动指定库路径时使用。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_library(variable_name library_name [PATHS path_list] [REQUIRED] [NO_DEFAULT_PATH])</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_library(MYLIB_PATH mylib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PATHS /usr/local/lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    REQUIRED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myapp PRIVATE ${MYLIB_PATH})</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="44-find_path">4.4 find_path<a href="http://localhost:3000/blog/cmake-commands-introduction#44-find_path" class="hash-link" aria-label="4.4 find_path的直接链接" title="4.4 find_path的直接链接" translate="no">​</a></h3>
<p>查找指定文件的目录，返回包含该文件的完整目录路径，可以用于 target_include_directories。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_path(variable_name file_name [PATHS path_list] [REQUIRED] [NO_DEFAULT_PATH])</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">find_path(MYLIB_INCLUDE_DIR mylib.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PATHS /usr/local/include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    REQUIRED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(myapp PRIVATE ${MYLIB_INCLUDE_DIR})</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-编译配置">5. 编译配置<a href="http://localhost:3000/blog/cmake-commands-introduction#5-%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="5. 编译配置的直接链接" title="5. 编译配置的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="51-set">5.1 set<a href="http://localhost:3000/blog/cmake-commands-introduction#51-set" class="hash-link" aria-label="5.1 set的直接链接" title="5.1 set的直接链接" translate="no">​</a></h3>
<p>设置变量值。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">set(VAR value)</span><br></div></code></pre></div></div>
<p><strong>常用预定义变量：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># C++ 标准配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD 17)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD_REQUIRED ON)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 构建类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_BUILD_TYPE Release)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 输出目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="52-target_compile_definitions">5.2 target_compile_definitions<a href="http://localhost:3000/blog/cmake-commands-introduction#52-target_compile_definitions" class="hash-link" aria-label="5.2 target_compile_definitions的直接链接" title="5.2 target_compile_definitions的直接链接" translate="no">​</a></h3>
<p>target_compile_definitions 用来给目标添加编译宏，在需要条件编译、传递特性标记或调试开关时使用</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">target_compile_definitions(target_name [PUBLIC|PRIVATE|INTERFACE] &lt;definition&gt;...)</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 编译 app 时会定义 USE_FEATURE_X，启用条件代码</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_compile_definitions(app PRIVATE USE_FEATURE_X)</span><br></div></code></pre></div></div>
<p><strong>条件编译：</strong></p>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">ifdef</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property expression" style="color:#36acaa">USE_FEATURE_X</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">featureX</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">endif</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="53-target_compile_options">5.3 target_compile_options<a href="http://localhost:3000/blog/cmake-commands-introduction#53-target_compile_options" class="hash-link" aria-label="5.3 target_compile_options的直接链接" title="5.3 target_compile_options的直接链接" translate="no">​</a></h3>
<p>用来为目标添加编译器选项。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">target_compile_options(targetName [PUBLIC|PRIVATE|INTERFACE] options...)</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># GCC/Clang 编译选项， -Wall启用一组常用的编译器警告</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_compile_options(myapp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        -Wall</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-安装和导出">6. 安装和导出<a href="http://localhost:3000/blog/cmake-commands-introduction#6-%E5%AE%89%E8%A3%85%E5%92%8C%E5%AF%BC%E5%87%BA" class="hash-link" aria-label="6. 安装和导出的直接链接" title="6. 安装和导出的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="61-installtargets">6.1 install(TARGETS)<a href="http://localhost:3000/blog/cmake-commands-introduction#61-installtargets" class="hash-link" aria-label="6.1 install(TARGETS)的直接链接" title="6.1 install(TARGETS)的直接链接" translate="no">​</a></h3>
<p>编译生成的可执行文件或库安装到指定目录或打包中，当你需要发布、共享或正式部署目标文件时使用</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">install(TARGETS target1 target2 ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [RUNTIME DESTINATION &lt;dir&gt;]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [LIBRARY DESTINATION &lt;dir&gt;]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [ARCHIVE DESTINATION &lt;dir&gt;]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [BUNDLE DESTINATION &lt;dir&gt;]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<p><strong>参数说明：</strong></p>
<ul>
<li class=""><strong>RUNTIME DESTINATION</strong>: 可执行文件安装路径</li>
<li class=""><strong>LIBRARY DESTINATION</strong>: 动态库安装路径</li>
<li class=""><strong>ARCHIVE DESTINATION</strong>: 静态库安装路径</li>
<li class=""><strong>BUNDLE DESTINATION</strong>: macOS 应用包安装路径</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">install(TARGETS myapp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    RUNTIME DESTINATION bin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    LIBRARY DESTINATION lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ARCHIVE DESTINATION lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="62-installfiles">6.2 install(FILES)<a href="http://localhost:3000/blog/cmake-commands-introduction#62-installfiles" class="hash-link" aria-label="6.2 install(FILES)的直接链接" title="6.2 install(FILES)的直接链接" translate="no">​</a></h3>
<p>用来把指定的文件直接安装到目标目录，和 install(TARGETS ...) 不同，它不是安装编译生成的目标，而是安装已有文件（比如头文件、配置文件、资源文件等）。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">install(FILES file1 file2 ... DESTINATION path)</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">install(FILES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ${CMAKE_SOURCE_DIR}/config/config.json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ${CMAKE_SOURCE_DIR}/README.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    DESTINATION share/myapp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="7-控制流程">7. 控制流程<a href="http://localhost:3000/blog/cmake-commands-introduction#7-%E6%8E%A7%E5%88%B6%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="7. 控制流程的直接链接" title="7. 控制流程的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="71-ifelseifelseendif">7.1 if/elseif/else/endif<a href="http://localhost:3000/blog/cmake-commands-introduction#71-ifelseifelseendif" class="hash-link" aria-label="7.1 if/elseif/else/endif的直接链接" title="7.1 if/elseif/else/endif的直接链接" translate="no">​</a></h3>
<p>条件控制语句。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">if(condition)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # commands</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">elseif(condition)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # commands</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">else()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # commands</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<p><strong>常用条件：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 平台检测</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(WIN32)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message("Building on Windows")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">elseif(APPLE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message("Building on macOS")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">elseif(UNIX)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message("Building on Linux/Unix")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 变量检测</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(DEFINED MY_VARIABLE)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    message("MY_VARIABLE is defined")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 字符串比较</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(CMAKE_BUILD_TYPE STREQUAL "Debug")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_definitions(-DDEBUG_BUILD)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="72-option">7.2 option<a href="http://localhost:3000/blog/cmake-commands-introduction#72-option" class="hash-link" aria-label="7.2 option的直接链接" title="7.2 option的直接链接" translate="no">​</a></h3>
<p>用来定义布尔开关，让用户选择开启或关闭某个功能，编译流程可根据这个开关灵活控制。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">option(OptionName "description" [ON|OFF])</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">option(BUILD_TESTS "Build unit tests" ON)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(BUILD_TESTS)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    enable_testing()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_subdirectory(tests)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">#CMake 的 option() 定义的开关，用户可以 在命令行配置项目时指定 ON 或 OFF，从而控制编译流程</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build -DBUILD_TESTS=OFF</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="8-实用工具">8. 实用工具<a href="http://localhost:3000/blog/cmake-commands-introduction#8-%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7" class="hash-link" aria-label="8. 实用工具的直接链接" title="8. 实用工具的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="81-add_subdirectory">8.1 add_subdirectory<a href="http://localhost:3000/blog/cmake-commands-introduction#81-add_subdirectory" class="hash-link" aria-label="8.1 add_subdirectory的直接链接" title="8.1 add_subdirectory的直接链接" translate="no">​</a></h3>
<p>用来将另一个子目录加入到当前构建中，并处理该子目录下的 CMakeLists.txt。
换句话说，它让你可以组织项目为多个模块或子项目，并把它们编译到同一个构建中。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">add_subdirectory(path)</span><br></div></code></pre></div></div>
<p><strong>示例：</strong></p>
<p>假设项目结构：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">project_root/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── src/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── main.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── tests/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── test_main.cpp</span><br></div></code></pre></div></div>
<p>主 CMakeLists.txt：</p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION 3.15)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">project(MyApp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(myapp src/main.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">option(BUILD_TESTS "Build unit tests" ON)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(BUILD_TESTS)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    enable_testing()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    add_subdirectory(tests)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="82-include">8.2 include<a href="http://localhost:3000/blog/cmake-commands-introduction#82-include" class="hash-link" aria-label="8.2 include的直接链接" title="8.2 include的直接链接" translate="no">​</a></h3>
<p>包含外部 CMake 脚本文件。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">include(path/to/file.cmake)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="83-message">8.3 message<a href="http://localhost:3000/blog/cmake-commands-introduction#83-message" class="hash-link" aria-label="8.3 message的直接链接" title="8.3 message的直接链接" translate="no">​</a></h3>
<p>输出信息到控制台。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">message([level] "text")</span><br></div></code></pre></div></div>
<p><strong>级别说明：</strong></p>
<ul>
<li class=""><strong>STATUS</strong>: 状态信息（绿色）</li>
<li class=""><strong>WARNING</strong>: 警告信息（黄色）</li>
<li class=""><strong>FATAL_ERROR</strong>: 致命错误（红色，停止构建）</li>
</ul>
<p><strong>示例：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">message(STATUS "Configuring project ${PROJECT_NAME}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">message(WARNING "This feature is deprecated")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">message(FATAL_ERROR "Required dependency not found")</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="9-qt-特有配置">9. Qt 特有配置<a href="http://localhost:3000/blog/cmake-commands-introduction#9-qt-%E7%89%B9%E6%9C%89%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="9. Qt 特有配置的直接链接" title="9. Qt 特有配置的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="91-自动化工具">9.1 自动化工具<a href="http://localhost:3000/blog/cmake-commands-introduction#91-%E8%87%AA%E5%8A%A8%E5%8C%96%E5%B7%A5%E5%85%B7" class="hash-link" aria-label="9.1 自动化工具的直接链接" title="9.1 自动化工具的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_AUTOMOC ON)    # 自动处理 MOC（Meta-Object Compiler）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_AUTORCC ON)    # 自动处理资源文件（.qrc）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_AUTOUIC ON)    # 自动处理界面文件（.ui）</span><br></div></code></pre></div></div>
<p><strong>功能说明：</strong></p>
<ul>
<li class=""><strong>CMAKE_AUTOMOC</strong>: 自动为包含 <code>Q_OBJECT</code> 宏的类生成 moc 文件</li>
<li class=""><strong>CMAKE_AUTORCC</strong>: 自动编译 .qrc 资源文件为 C++ 代码</li>
<li class=""><strong>CMAKE_AUTOUIC</strong>: 自动将 .ui 界面文件转换为头文件</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="92-qt_standard_project_setup">9.2 qt_standard_project_setup()<a href="http://localhost:3000/blog/cmake-commands-introduction#92-qt_standard_project_setup" class="hash-link" aria-label="9.2 qt_standard_project_setup()的直接链接" title="9.2 qt_standard_project_setup()的直接链接" translate="no">​</a></h3>
<p>Qt 6 推荐的项目设置函数，内部已包含上述自动化配置。</p>
<p><strong>语法：</strong></p>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">qt_standard_project_setup(REQUIRES 6.5)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="10-完整示例">10. 完整示例<a href="http://localhost:3000/blog/cmake-commands-introduction#10-%E5%AE%8C%E6%95%B4%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="10. 完整示例的直接链接" title="10. 完整示例的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="101-python-扩展模块pyd">10.1 Python 扩展模块（.pyd）<a href="http://localhost:3000/blog/cmake-commands-introduction#101-python-%E6%89%A9%E5%B1%95%E6%A8%A1%E5%9D%97pyd" class="hash-link" aria-label="10.1 Python 扩展模块（.pyd）的直接链接" title="10.1 Python 扩展模块（.pyd）的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION 3.16)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">project(QComposer VERSION 0.1 LANGUAGES CXX)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># C++ 标准配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD 17)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD_REQUIRED ON)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 项目路径配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(PROJECT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Conda 环境配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(DEFINED ENV{CONDA_PREFIX})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    list(PREPEND CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 常见的前缀路径自动检测</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(DEFINED ENV{VCPKG_ROOT})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    list(APPEND CMAKE_PREFIX_PATH "$ENV{VCPKG_ROOT}/installed/${VCPKG_TARGET_TRIPLET}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if(DEFINED ENV{Qt6_DIR})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    list(APPEND CMAKE_PREFIX_PATH "$ENV{Qt6_DIR}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">endif()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查找依赖</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(pybind11 REQUIRED)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Qt 标准配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qt_standard_project_setup(REQUIRES 6.5)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 收集源文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">file(GLOB_RECURSE SOURCES ${PROJECT_ROOT_DIR}/src/*.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 添加资源</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qt_add_resources(RESOURCES ${PROJECT_ROOT_DIR}/src/resources.qrc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 创建 Python 模块</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pybind11_add_module(QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ${PROJECT_ROOT_DIR}/python-module/binding.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ${SOURCES}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ${RESOURCES}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 配置包含目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE ${PROJECT_ROOT_DIR}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 链接库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::Quick</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::Gui</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::QuickControls2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置输出属性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set_target_properties(QComposer PROPERTIES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    OUTPUT_NAME "QComposer"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PREFIX ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SUFFIX ".pyd"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="102-qt-桌面应用程序">10.2 Qt 桌面应用程序<a href="http://localhost:3000/blog/cmake-commands-introduction#102-qt-%E6%A1%8C%E9%9D%A2%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F" class="hash-link" aria-label="10.2 Qt 桌面应用程序的直接链接" title="10.2 Qt 桌面应用程序的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION 3.16)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">project(QComposer VERSION 0.1 LANGUAGES CXX)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># C++ 标准配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD 17)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD_REQUIRED ON)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查找 Qt6</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Qt 标准配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qt_standard_project_setup(REQUIRES 6.5)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 收集源文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">file(GLOB_RECURSE SOURCES src/*.cpp src/*.h)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 创建可执行程序</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qt_add_executable(QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    src/app/main.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ${CMAKE_SOURCE_DIR}/Resources/icon.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 添加 QML 模块</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qt_add_qml_module(QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    URI QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    VERSION 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SOURCES ${SOURCES}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    RESOURCES src/resources.qrc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置程序属性</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set_target_properties(QComposer PROPERTIES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    MACOSX_BUNDLE TRUE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    MACOSX_BUNDLE_ICON_FILE icon.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    WIN32_EXECUTABLE TRUE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 配置资源文件位置（macOS）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set_source_files_properties(${CMAKE_SOURCE_DIR}/Resources/icon.png</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PROPERTIES MACOSX_PACKAGE_LOCATION "Resources"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 链接库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(QComposer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::Quick</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::Gui</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Qt6::QuickControls2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安装规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">install(TARGETS QComposer BUNDLE DESTINATION .)</span><br></div></code></pre></div></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="11-总结">11. 总结<a href="http://localhost:3000/blog/cmake-commands-introduction#11-%E6%80%BB%E7%BB%93" class="hash-link" aria-label="11. 总结的直接链接" title="11. 总结的直接链接" translate="no">​</a></h2>
<p>本文档涵盖了 CMake 的核心命令和最佳实践。在实际使用中，建议：</p>
<ol>
<li class=""><strong>从简单开始</strong>: 先掌握基础命令，再学习高级特性</li>
<li class=""><strong>使用现代 CMake</strong>: 优先使用 <code>target_*</code> 系列命令</li>
<li class=""><strong>保持一致性</strong>: 统一代码风格和项目结构</li>
<li class=""><strong>合理组织</strong>: 将复杂项目拆分为多个 CMakeLists.txt</li>
<li class=""><strong>版本管理</strong>: 明确指定最低 CMake 版本和依赖版本</li>
</ol>
<p>通过掌握这些命令，你可以构建从简单到复杂的各种项目。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="CMake" term="CMake"/>
        <category label="构建系统" term="构建系统"/>
        <category label="C++" term="C++"/>
        <category label="跨平台" term="跨平台"/>
        <category label="Programming" term="Programming"/>
        <category label="开发工具" term="开发工具"/>
        <category label="配置" term="配置"/>
        <category label="Makefile" term="Makefile"/>
        <category label="项目管理" term="项目管理"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[CMake 构建系统详解]]></title>
        <id>http://localhost:3000/blog/cmake</id>
        <link href="http://localhost:3000/blog/cmake"/>
        <updated>2024-06-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[CMake 是一个跨平台的开源构建系统生成器，专门用于管理 C/C++ 等编译型语言的项目构建过程。它的核心价值在于：]]></summary>
        <content type="html"><![CDATA[<p>CMake 是一个<strong>跨平台</strong>的开源构建系统生成器，专门用于管理 C/C++ 等编译型语言的项目构建过程。它的核心价值在于：</p>
<ul>
<li class=""><strong>统一配置</strong>：通过 <code>CMakeLists.txt</code> 文件定义构建规则</li>
<li class=""><strong>跨平台支持</strong>：一套配置适配多个操作系统和构建工具</li>
<li class=""><strong>目标导向</strong>：以目标（targets）为中心的现代构建理念</li>
</ul>
<p>CMake 本身不直接编译代码，而是<strong>生成适合目标平台</strong>的构建系统文件（如 Makefile、Ninja 文件、Visual Studio 项目等），然后由相应的构建工具执行实际的编译和链接工作。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-什么是目标平台">1. 什么是"目标平台"<a href="http://localhost:3000/blog/cmake#1-%E4%BB%80%E4%B9%88%E6%98%AF%E7%9B%AE%E6%A0%87%E5%B9%B3%E5%8F%B0" class="hash-link" aria-label="1. 什么是&quot;目标平台&quot;的直接链接" title="1. 什么是&quot;目标平台&quot;的直接链接" translate="no">​</a></h2>
<p>CMake 中的"目标平台"是一个多维度概念，主要指<strong>不同的操作系统和构建环境组合</strong>：</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-操作系统层面">1.1 操作系统层面<a href="http://localhost:3000/blog/cmake#11-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%B1%82%E9%9D%A2" class="hash-link" aria-label="1.1 操作系统层面的直接链接" title="1.1 操作系统层面的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>Linux/Unix 系统</strong>：生成 Makefile</li>
<li class=""><strong>Windows 系统</strong>：生成 Visual Studio 项目文件（.sln, .vcxproj）</li>
<li class=""><strong>macOS 系统</strong>：生成 Makefile 或 Xcode 项目文件</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-构建工具层面">1.2 构建工具层面<a href="http://localhost:3000/blog/cmake#12-%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7%E5%B1%82%E9%9D%A2" class="hash-link" aria-label="1.2 构建工具层面的直接链接" title="1.2 构建工具层面的直接链接" translate="no">​</a></h3>
<p>CMake 可以为不同的构建工具生成相应的配置文件：</p>
<ul>
<li class=""><strong>Make</strong>：生成 Makefile</li>
<li class=""><strong>Ninja</strong>：生成 build.ninja 文件</li>
<li class=""><strong>Visual Studio</strong>：生成 .sln 和 .vcxproj 文件</li>
<li class=""><strong>Xcode</strong>：生成 .xcodeproj 文件</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="13-编译器层面">1.3 编译器层面<a href="http://localhost:3000/blog/cmake#13-%E7%BC%96%E8%AF%91%E5%99%A8%E5%B1%82%E9%9D%A2" class="hash-link" aria-label="1.3 编译器层面的直接链接" title="1.3 编译器层面的直接链接" translate="no">​</a></h3>
<p>CMake 在第一次配置时会自动检测系统环境并选择合适的默认编译器，因为生成的构建文件必须与具体的编译器工具链相匹配。你也可以通过 <code>CMAKE_CXX_COMPILER</code> 变量手动指定编译器，例如 <code>cmake -DCMAKE_CXX_COMPILER=clang++</code>。</p>
<ul>
<li class=""><strong>GCC</strong>（GNU Compiler Collection）</li>
<li class=""><strong>Clang</strong></li>
<li class=""><strong>MSVC</strong>（Microsoft Visual C++）</li>
<li class=""><strong>Intel C++ Compiler</strong> 等</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="14-跨平台构建示例">1.4 跨平台构建示例<a href="http://localhost:3000/blog/cmake#14-%E8%B7%A8%E5%B9%B3%E5%8F%B0%E6%9E%84%E5%BB%BA%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="1.4 跨平台构建示例的直接链接" title="1.4 跨平台构建示例的直接链接" translate="no">​</a></h3>
<p>假设你在不同平台上运行相同的 CMakeLists.txt：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># -G 是 --generator 的缩写。它指定 CMake 使用哪种构建系统生成器。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 在 Linux 上</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake .. -G "Unix Makefiles"  # 生成 Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 在 Windows 上</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake .. -G "Visual Studio 16 2019"  # 生成 VS 项目文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 使用 Ninja（跨平台）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake .. -G "Ninja"  # 生成 build.ninja</span><br></div></code></pre></div></div>
<p>正是因为 CMake 能够根据目标平台生成相应的构建文件，所以同一套 <code>CMakeLists.txt</code> 配置可以在不同操作系统上使用，这就是 CMake <strong>"跨平台"特性的核心所在</strong>。开发者只需要编写一次构建配置，CMake 就能自动适配到不同的平台环境，大大简化了跨平台项目的管理复杂度。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-cmake-的核心概念">2. CMake 的核心概念<a href="http://localhost:3000/blog/cmake#2-cmake-%E7%9A%84%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5" class="hash-link" aria-label="2. CMake 的核心概念的直接链接" title="2. CMake 的核心概念的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-cmakeliststxt---项目配置文件">2.1 CMakeLists.txt - 项目配置文件<a href="http://localhost:3000/blog/cmake#21-cmakeliststxt---%E9%A1%B9%E7%9B%AE%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" class="hash-link" aria-label="2.1 CMakeLists.txt - 项目配置文件的直接链接" title="2.1 CMakeLists.txt - 项目配置文件的直接链接" translate="no">​</a></h3>
<ul>
<li class="">项目的核心配置文件，通常位于项目根目录</li>
<li class="">定义构建目标（targets）、依赖项和编译规则</li>
<li class="">使用 CMake 特有的语法和命令</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-目标targets--构建产物">2.2 目标（Targets）- 构建产物<a href="http://localhost:3000/blog/cmake#22-%E7%9B%AE%E6%A0%87targets--%E6%9E%84%E5%BB%BA%E4%BA%A7%E7%89%A9" class="hash-link" aria-label="2.2 目标（Targets）- 构建产物的直接链接" title="2.2 目标（Targets）- 构建产物的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>可执行文件</strong>：<code>add_executable(myApp main.cpp)</code></li>
<li class=""><strong>静态库</strong>：<code>add_library(myLib STATIC lib.cpp)</code></li>
<li class=""><strong>动态库</strong>：<code>add_library(myLib SHARED lib.cpp)</code></li>
<li class=""><strong>接口库</strong>：<code>add_library(myInterface INTERFACE)</code> （仅头文件库）</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-变量系统">2.3 变量系统<a href="http://localhost:3000/blog/cmake#23-%E5%8F%98%E9%87%8F%E7%B3%BB%E7%BB%9F" class="hash-link" aria-label="2.3 变量系统的直接链接" title="2.3 变量系统的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 定义变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(VERSION "1.0.0")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(MY_SOURCES main.cpp utils.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 使用变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">message(STATUS "Version: ${VERSION}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(myApp ${MY_SOURCES})</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="24-依赖管理">2.4 依赖管理<a href="http://localhost:3000/blog/cmake#24-%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86" class="hash-link" aria-label="2.4 依赖管理的直接链接" title="2.4 依赖管理的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查找外部包</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(OpenCV REQUIRED)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find_package(Boost COMPONENTS system filesystem REQUIRED)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 链接库到目标</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myApp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    PRIVATE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        OpenCV::OpenCV</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Boost::system</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Boost::filesystem</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="25-构建流程">2.5 构建流程<a href="http://localhost:3000/blog/cmake#25-%E6%9E%84%E5%BB%BA%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="2.5 构建流程的直接链接" title="2.5 构建流程的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="251-配置阶段configuration-phase">2.5.1 配置阶段（Configuration Phase）<a href="http://localhost:3000/blog/cmake#251-%E9%85%8D%E7%BD%AE%E9%98%B6%E6%AE%B5configuration-phase" class="hash-link" aria-label="2.5.1 配置阶段（Configuration Phase）的直接链接" title="2.5.1 配置阶段（Configuration Phase）的直接链接" translate="no">​</a></h4>
<p>配置阶段是 CMake 构建过程的第一步，主要负责生成构建文件（如 Makefile 或 Visual Studio 项目文件）。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 创建构建目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 生成构建文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake .. -DCMAKE_BUILD_TYPE=Release</span><br></div></code></pre></div></div>
<p><strong>配置阶段的主要工作：</strong></p>
<ul>
<li class="">解析 CMakeLists.txt 文件</li>
<li class="">检查编译器和依赖项</li>
<li class="">生成适合当前平台的构建文件</li>
<li class="">设置构建类型和编译选项</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="252-构建阶段build-phase">2.5.2 构建阶段（Build Phase）<a href="http://localhost:3000/blog/cmake#252-%E6%9E%84%E5%BB%BA%E9%98%B6%E6%AE%B5build-phase" class="hash-link" aria-label="2.5.2 构建阶段（Build Phase）的直接链接" title="2.5.2 构建阶段（Build Phase）的直接链接" translate="no">​</a></h4>
<p>构建阶段使用配置阶段生成的<strong>构建文件</strong>来编译和链接项目。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 执行构建</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build .</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 或者指定配置类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build . --config Release</span><br></div></code></pre></div></div>
<p><strong>构建阶段的主要工作：</strong></p>
<ul>
<li class="">编译源代码文件</li>
<li class="">链接目标文件生成可执行文件或库</li>
<li class="">处理资源文件和依赖项</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-cmake-命令详解">3. CMake 命令详解<a href="http://localhost:3000/blog/cmake#3-cmake-%E5%91%BD%E4%BB%A4%E8%AF%A6%E8%A7%A3" class="hash-link" aria-label="3. CMake 命令详解的直接链接" title="3. CMake 命令详解的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-cmake-命令配置阶段">3.1 <code>cmake</code> 命令：配置阶段<a href="http://localhost:3000/blog/cmake#31-cmake-%E5%91%BD%E4%BB%A4%E9%85%8D%E7%BD%AE%E9%98%B6%E6%AE%B5" class="hash-link" aria-label="31-cmake-命令配置阶段的直接链接" title="31-cmake-命令配置阶段的直接链接" translate="no">​</a></h3>
<p><strong>作用</strong>：分析 <code>CMakeLists.txt</code> 并生成特定构建系统的配置文件，<strong>不执行实际编译</strong>。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 基本语法</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake [选项] &lt;源码目录&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 现代推荐语法</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S &lt;源码目录&gt; -B &lt;构建目录&gt; [选项]</span><br></div></code></pre></div></div>
<p><strong>常用选项</strong>：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 指定源码目录（包含CMakeLists.txt的目录, .表示当前目录）和构建目录（build 目录）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置构建类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build -DCMAKE_BUILD_TYPE=Release</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 指定生成器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build -G "Ninja"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build -G "Unix Makefiles"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置安装前缀</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr/local</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-cmake---build-命令构建阶段">3.2 <code>cmake --build</code> 命令：构建阶段<a href="http://localhost:3000/blog/cmake#32-cmake---build-%E5%91%BD%E4%BB%A4%E6%9E%84%E5%BB%BA%E9%98%B6%E6%AE%B5" class="hash-link" aria-label="32-cmake---build-命令构建阶段的直接链接" title="32-cmake---build-命令构建阶段的直接链接" translate="no">​</a></h3>
<p><strong>作用</strong>：调用生成器（如 Make、Ninja、Visual Studio 等）去执行具体的构建过程。</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 基本语法</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build &lt;构建目录&gt; [选项]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 常用示例</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build                    # 默认构建</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build --config Release   # 指定构建类型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build --parallel 4       # 并行构建</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build --target myApp     # 构建特定目标</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build --clean-first      # 先清理再构建</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="33-cmake-的两阶段构建机制">3.3 CMake 的两阶段构建机制<a href="http://localhost:3000/blog/cmake#33-cmake-%E7%9A%84%E4%B8%A4%E9%98%B6%E6%AE%B5%E6%9E%84%E5%BB%BA%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="3.3 CMake 的两阶段构建机制的直接链接" title="3.3 CMake 的两阶段构建机制的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>阶段</th><th>命令</th><th>作用</th><th>输出</th><th>频率</th></tr></thead><tbody><tr><td>配置</td><td><code>cmake</code></td><td>解析配置，生成构建文件</td><td>Makefile/build.ninja 等</td><td>配置变更时</td></tr><tr><td>构建</td><td><code>cmake --build</code></td><td>执行编译链接</td><td>可执行文件/库文件</td><td>代码变更时</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-快速入门示例">4. 快速入门示例<a href="http://localhost:3000/blog/cmake#4-%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="4. 快速入门示例的直接链接" title="4. 快速入门示例的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-项目结构">4.1 项目结构<a href="http://localhost:3000/blog/cmake#41-%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84" class="hash-link" aria-label="4.1 项目结构的直接链接" title="4.1 项目结构的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">MyProject/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── src/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── main.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── utils.cpp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── include/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── utils.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── tests/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── test_main.cpp</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-cmakeliststxt-配置">4.2 CMakeLists.txt 配置<a href="http://localhost:3000/blog/cmake#42-cmakeliststxt-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="4.2 CMakeLists.txt 配置的直接链接" title="4.2 CMakeLists.txt 配置的直接链接" translate="no">​</a></h3>
<div class="language-cmake codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cmake codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">cmake_minimum_required(VERSION 3.16)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">project(MyProject VERSION 1.0.0 LANGUAGES CXX)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置 C++ 标准</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD 17)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_STANDARD_REQUIRED ON)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 包含头文件目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">include_directories(include)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 创建库目标</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_library(utils src/utils.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_include_directories(utils PUBLIC include)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 创建可执行文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">add_executable(myApp src/main.cpp)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(myApp PRIVATE utils)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="43-构建命令">4.3 构建命令<a href="http://localhost:3000/blog/cmake#43-%E6%9E%84%E5%BB%BA%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="4.3 构建命令的直接链接" title="4.3 构建命令的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 配置项目</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -S . -B build -DCMAKE_BUILD_TYPE=Release</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 构建项目</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --build build</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-构建工具生态关系">5. 构建工具生态关系<a href="http://localhost:3000/blog/cmake#5-%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7%E7%94%9F%E6%80%81%E5%85%B3%E7%B3%BB" class="hash-link" aria-label="5. 构建工具生态关系的直接链接" title="5. 构建工具生态关系的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="51-工具链分工">5.1 工具链分工<a href="http://localhost:3000/blog/cmake#51-%E5%B7%A5%E5%85%B7%E9%93%BE%E5%88%86%E5%B7%A5" class="hash-link" aria-label="5.1 工具链分工的直接链接" title="5.1 工具链分工的直接链接" translate="no">​</a></h3>
<p>CMake 生态系统采用<strong>分层架构</strong>，各工具职责明确：</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/cmake%E6%9E%84%E5%BB%BA%E7%B3%BB%E7%BB%9F%E8%AF%A6%E8%A7%A3/cmake.png" alt="cmake分层架构" class="img_gjoA"></p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="52-cmake构建系统生成器">5.2 CMake：构建系统生成器<a href="http://localhost:3000/blog/cmake#52-cmake%E6%9E%84%E5%BB%BA%E7%B3%BB%E7%BB%9F%E7%94%9F%E6%88%90%E5%99%A8" class="hash-link" aria-label="5.2 CMake：构建系统生成器的直接链接" title="5.2 CMake：构建系统生成器的直接链接" translate="no">​</a></h3>
<p><strong>核心职责</strong>：</p>
<ul>
<li class="">解析 <code>CMakeLists.txt</code> 配置</li>
<li class="">检测编译器和系统环境</li>
<li class="">处理依赖关系和包查找</li>
<li class="">生成特定构建工具的配置文件</li>
</ul>
<p><strong>支持的生成器</strong>：</p>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看所有可用生成器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake --help</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 常用生成器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -G "Unix Makefiles"     # 生成 Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -G "Ninja"              # 生成 build.ninja</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -G "Xcode"              # 生成 Xcode 项目</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cmake -G "Visual Studio 16 2019"  # 生成 VS 项目</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="53-构建执行器对比">5.3 构建执行器对比<a href="http://localhost:3000/blog/cmake#53-%E6%9E%84%E5%BB%BA%E6%89%A7%E8%A1%8C%E5%99%A8%E5%AF%B9%E6%AF%94" class="hash-link" aria-label="5.3 构建执行器对比的直接链接" title="5.3 构建执行器对比的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>特性</th><th>Make</th><th>Ninja</th><th>MSBuild</th></tr></thead><tbody><tr><td><strong>平台</strong></td><td>Unix/Linux/macOS</td><td>跨平台</td><td>Windows</td></tr><tr><td><strong>配置文件</strong></td><td>Makefile</td><td>build.ninja</td><td>.vcxproj/.sln</td></tr><tr><td><strong>并行构建</strong></td><td>✅ 支持</td><td>✅ 优化更好</td><td>✅ 支持</td></tr><tr><td><strong>增量构建</strong></td><td>✅ 基础支持</td><td>✅ 高度优化</td><td>✅ 支持</td></tr><tr><td><strong>构建速度</strong></td><td>中等</td><td>最快</td><td>中等</td></tr><tr><td><strong>内存占用</strong></td><td>中等</td><td>最低</td><td>较高</td></tr><tr><td><strong>适用场景</strong></td><td>传统项目</td><td>大型项目</td><td>Windows 生态</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-为什么-cmake-不能像-webpack-那样自动分析依赖">6. 为什么 CMake 不能像 Webpack 那样自动分析依赖？<a href="http://localhost:3000/blog/cmake#6-%E4%B8%BA%E4%BB%80%E4%B9%88-cmake-%E4%B8%8D%E8%83%BD%E5%83%8F-webpack-%E9%82%A3%E6%A0%B7%E8%87%AA%E5%8A%A8%E5%88%86%E6%9E%90%E4%BE%9D%E8%B5%96" class="hash-link" aria-label="6. 为什么 CMake 不能像 Webpack 那样自动分析依赖？的直接链接" title="6. 为什么 CMake 不能像 Webpack 那样自动分析依赖？的直接链接" translate="no">​</a></h2>
<p><strong>核心原因：C++ 传统上缺乏真正的模块系统，<code>#include</code> 只是预处理器的文本替换。</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="61-根本差异模块系统-vs-文本替换">6.1 根本差异：模块系统 vs 文本替换<a href="http://localhost:3000/blog/cmake#61-%E6%A0%B9%E6%9C%AC%E5%B7%AE%E5%BC%82%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9F-vs-%E6%96%87%E6%9C%AC%E6%9B%BF%E6%8D%A2" class="hash-link" aria-label="6.1 根本差异：模块系统 vs 文本替换的直接链接" title="6.1 根本差异：模块系统 vs 文本替换的直接链接" translate="no">​</a></h3>
<div class="language-javascript codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-javascript codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// JavaScript - 显式模块导入，可静态分析</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports punctuation" style="color:#393A34">{</span><span class="token imports"> utils </span><span class="token imports punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./utils.js"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword module" style="color:#00009f">import</span><span class="token plain"> </span><span class="token imports maybe-class-name">React</span><span class="token plain"> </span><span class="token keyword module" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// C++ - 预处理器文本替换，无法分析依赖结构</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"utils.h"</span><span class="token macro property" style="color:#36acaa">  </span><span class="token macro property comment" style="color:#999988;font-style:italic">// 直接把 utils.h 的内容粘贴到这里</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">&lt;iostream&gt;</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property comment" style="color:#999988;font-style:italic">// 编译器看不到原始的依赖关系</span><br></div></code></pre></div></div>
<p><strong>关键问题</strong>：</p>
<ul>
<li class=""><strong>JavaScript</strong>：<code>import</code> 是语言级特性，构建工具可以解析 AST 分析依赖</li>
<li class=""><strong>C++</strong>：<code>#include</code> 在预处理阶段就被展开，编译器看到的是已经"破坏"了结构的代码</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="62-为什么构建工具无法分析">6.2 为什么构建工具无法分析<a href="http://localhost:3000/blog/cmake#62-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7%E6%97%A0%E6%B3%95%E5%88%86%E6%9E%90" class="hash-link" aria-label="6.2 为什么构建工具无法分析的直接链接" title="6.2 为什么构建工具无法分析的直接链接" translate="no">​</a></h3>
<p>除了语言层面的限制，<strong>CMake 的角色定位</strong>也是一个重要因素：</p>
<ul>
<li class=""><strong>CMake 不是编译工具</strong>：它只生成构建配置文件（Makefile、build.ninja 等）</li>
<li class=""><strong>真正的编译由其他工具完成</strong>：Make、Ninja、MSBuild 等才是实际执行编译的工具</li>
<li class=""><strong>分层架构的限制</strong>：CMake 在配置阶段就需要知道所有依赖关系，但此时还没有进行实际的代码分析</li>
</ul>
<p>相比之下：</p>
<ul>
<li class=""><strong>Webpack 既是分析工具又是打包工具</strong>：可以在运行时动态分析和处理依赖</li>
<li class=""><strong>JavaScript 的运行时特性</strong>：允许构建工具在执行过程中发现新的依赖关系</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="63-c20-模块系统问题的解决方案">6.3 C++20 模块系统：问题的解决方案<a href="http://localhost:3000/blog/cmake#63-c20-%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9F%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="6.3 C++20 模块系统：问题的解决方案的直接链接" title="6.3 C++20 模块系统：问题的解决方案的直接链接" translate="no">​</a></h3>
<div class="language-cpp codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-cpp codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 新的模块语法 - 真正的语言级特性</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token module">std</span><span class="token module punctuation" style="color:#393A34">.</span><span class="token module">iostream</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token module">my</span><span class="token module punctuation" style="color:#393A34">.</span><span class="token module">utils</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">module</span><span class="token plain"> </span><span class="token module">my</span><span class="token module punctuation" style="color:#393A34">.</span><span class="token module">library</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p><strong>优势</strong>：</p>
<ul>
<li class="">显式的依赖声明，类似 JavaScript 的 <code>import</code></li>
<li class="">构建工具可以静态分析模块依赖关系</li>
<li class="">未来的 CMake 版本将支持自动依赖分析</li>
</ul>
<p><strong>总结</strong>：CMake 需要手动配置依赖的根本原因是 C++ 历史上只有预处理器文本替换，没有真正的模块系统。C++20 模块系统的引入正在改变这一现状。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="CMake" term="CMake"/>
        <category label="构建系统" term="构建系统"/>
        <category label="C++" term="C++"/>
        <category label="跨平台" term="跨平台"/>
        <category label="Programming" term="Programming"/>
        <category label="开发工具" term="开发工具"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[搭建 Jenkins]]></title>
        <id>http://localhost:3000/blog/setup-jenkins</id>
        <link href="http://localhost:3000/blog/setup-jenkins"/>
        <updated>2024-01-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文详细介绍了如何从零搭建 Jenkins 环境，集成 Gitee、Node.js、Maven、Docker 等工具，实现自动化构建与部署（CI/CD）流程。]]></summary>
        <content type="html"><![CDATA[<p>本文详细介绍了如何从零搭建 Jenkins 环境，集成 Gitee、Node.js、Maven、Docker 等工具，实现自动化构建与部署（CI/CD）流程。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-搭建-jenkins">1. 搭建 Jenkins<a href="http://localhost:3000/blog/setup-jenkins#1-%E6%90%AD%E5%BB%BA-jenkins" class="hash-link" aria-label="1. 搭建 Jenkins的直接链接" title="1. 搭建 Jenkins的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>拉取 jenkins 镜像</p>
<p>执行以下命令拉取镜像(以 2.433-jdk17 版本为例):</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">docker pull jenkins/jenkins:2.433-jdk17</span><br></div></code></pre></div></div>
<p>需要注意的是 jenkins 最新镜像是 jenkins/jenkins，而不是 jenkins:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/jenkins.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>运行 jenkins 镜像</p>
<p>执行以下命令拉取镜像(以 2.433-jdk17 版本为例):</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">//var/jenkins/jenkins-data为本机某个目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">//外网访问端口设置为18080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker run \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--name jenkins \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--rm \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-u root \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-p 18080:8080 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-v /var/jenkins/jenkins-data:/var/jenkins_home \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">jenkins/jenkins:2.433-jdk17</span><br></div></code></pre></div></div>
<p>或者通过 docker-compose 启动，以下是 docker-compose.yml 文件:</p>
<div class="language-yml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-yml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">#docker-compose.yml</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"3"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">services</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">jenkins</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> jenkins/jenkins</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">2.433</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">jdk17</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">container_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">user</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">ports</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"18080:8080"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">environment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> TZ=Asia/Shanghai</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">volumes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> /var/jenkins/jenkins</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">/var/jenkins_home</span><br></div></code></pre></div></div>
<p>执行<code>docker-compose up -d</code>命令启动。</p>
</li>
<li class="">
<p>浏览器访问 18080 端口</p>
<p>加载可能需要一些时间，完成后会出现下图的界面:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/unlock.png" alt="" class="img_gjoA"></p>
<p>执行以下命令获取管理员密码:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">docker exec jenkins bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">=&gt;d1bc30kecf304f1489423a2c74b2b59e</span><br></div></code></pre></div></div>
<p>填入管理员密码后继续，等待片刻后，安装推荐的插件。</p>
</li>
<li class="">
<p>安装推荐的插件</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/install-plugins.png" alt="" class="img_gjoA"></p>
<p>部分插件可能安装失败，安装失败后可尝试重试安装。安装完成后会进入到管理员账户的创建页面。</p>
</li>
<li class="">
<p>创建管理员账户</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/create-admin.png" alt="" class="img_gjoA">
创建用户后会进入到示例配置页面。</p>
</li>
<li class="">
<p>示例配置</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-root.png" alt="" class="img_gjoA"></p>
<p>点击保存后，就能进入 jenkins 操作界面了:</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/jenkins-home.png" alt="" class="img_gjoA"></p>
<p>但是最好重启下容器(有些插件重启才会生效)，执行以下命令:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">docker restart jenkins</span><br></div></code></pre></div></div>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-配置-node-环境">2. 配置 Node 环境<a href="http://localhost:3000/blog/setup-jenkins#2-%E9%85%8D%E7%BD%AE-node-%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="2. 配置 Node 环境的直接链接" title="2. 配置 Node 环境的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>安装 Node 插件</p>
<p>重启容器后访问 18080 端口，登录后就能进入 jenkins 主页了。进入主页后选择系统管理=&gt;插件管理:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/plugins.png" alt="" class="img_gjoA"></p>
<p>在 Avaliable plugins 中搜索 nodejs，点击安装:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/install-node.png" alt="" class="img_gjoA">
安装完成后重启容器。</p>
</li>
<li class="">
<p>配置 Node</p>
<p>重启完成后，在 jenkins 主页选择系统管理=&gt;全局工具配置:
node 版本选择的与开发环境一致，需预装 yarn(前端项目用 yarn 做包管理工具) 包管理工具。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-node.png" alt="" class="img_gjoA"></p>
<p>安装 yarn 的 npm 镜像源可以配置成淘宝:</p>
<div class="language-code codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-code codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">--registry=https://registry.npm.taobao.org yarn</span><br></div></code></pre></div></div>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-配置-gitee">3. 配置 Gitee<a href="http://localhost:3000/blog/setup-jenkins#3-%E9%85%8D%E7%BD%AE-gitee" class="hash-link" aria-label="3. 配置 Gitee的直接链接" title="3. 配置 Gitee的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>配置 Gitee 登录凭证</p>
<p>在 jenkins docker 运行所在的服务器上生成 ssh key(如果有则不需要重新生成)，执行命令:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ssh-keygen -t rsa</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/ssh-key.png" alt="" class="img_gjoA">
将公钥 id_rsa.pub 的内容拷贝到 Gitee 设置页面 SSH 公钥配置当中:</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/public-key.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>在 jenkins 中添加凭证</p>
<p>在 jenkins 主页选择系统管理=&gt;凭据=&gt;系统(system)=&gt;全局凭据:
下图中，用户名为 docker 运行的用户，Private Key 为上一步生成的 id_rsa 的内容。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/private-key.png" alt="" class="img_gjoA">
点击 Create 创建生成凭证。</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-创建流水线">4. 创建流水线<a href="http://localhost:3000/blog/setup-jenkins#4-%E5%88%9B%E5%BB%BA%E6%B5%81%E6%B0%B4%E7%BA%BF" class="hash-link" aria-label="4. 创建流水线的直接链接" title="4. 创建流水线的直接链接" translate="no">​</a></h2>
<p>在创建流水线前先安装 Git Parameter 插件(为了支持配置 Git 参数)，在 jenkins 主页选择系统管理=&gt;插件管理，在 Avaliable plugins 中搜索 Git Parameter plugin，点击安装，安装完成后重启容器。完成后进行以下操作:</p>
<ul>
<li class="">
<p>创建文件夹</p>
<p>为了方便管理，先创建一个文件夹(在 jenkins 主页选择新建任务)，名为 multi-body:</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/create-folder.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>添加自由风格项目</p>
<p>在上一步中创建的 multi-body 文件中选择新建 Item，创建一个自由风格的软件项目名为 micro-simulation:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/pipeline.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>添加编译配置</p>
<p>在上一步创建的 micro-simulation 项目中选择配置:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-pipeline.png" alt="" class="img_gjoA"></p>
<ul>
<li class="">
<p>配置参数</p>
<p>为了构建时可以手动选择不同的分支进行编译，在参数化构建过程中选择添加 Git 参数:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/git-params.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>配置源码管理</p>
<p>URL 填写 Gitee 上项目的 ssh 地址，Credentials 选前述生成的凭证(gitee-ssh)，分支填写上一步配置的名字(BRANCH_NAME):
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/code-control.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>配置 Node 环境</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-env.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>配置 build 命令</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">yarn  //安装node_modules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">yarn build //执行build命令，build完后会在项目根目录生成rand-batch文件夹</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tar -czf rand-batch.tar.gz rand-batch</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-build-steps.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>归档上一步生成的 tar 文件</p>
<p>下图中用于存档的文件目录是相对于项目根目录，归档后就能生成该 tar 文件的下载链接。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/archive.png" alt="" class="img_gjoA"></p>
</li>
</ul>
</li>
<li class="">
<p>开始构建</p>
<p>上一步配置完成后，就可以开始根据配置文件构建项目了:</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/start-build.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>查看构建结果</p>
<p>构建完成后就能看到最后生成的 tar 文件了，点击可以下载。</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/build-result.png" alt="" class="img_gjoA"></p>
<p>此外，对于构建的相关信息都可以点击构建序列号进行查看:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/console.png" alt="" class="img_gjoA"></p>
</li>
</ul>
<p>通过以上步骤，就能通过 jenkens 构建在 gitee 上的前端项目了。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-部署">5. 部署<a href="http://localhost:3000/blog/setup-jenkins#5-%E9%83%A8%E7%BD%B2" class="hash-link" aria-label="5. 部署的直接链接" title="5. 部署的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>安装 Publish Over SSH 插件</p>
<p>jenkins 主页选择系统管理=&gt;插件管理，在 Avaliable plugins 中搜索 Publish Over SSH，点击安装:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/publish-over-ssh.png" alt="" class="img_gjoA">
安装完成后重启容器。</p>
</li>
<li class="">
<p>配置 SSH 免密登录</p>
<p>首先在 Jenkins 服务器上生成 SSH 密钥对:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">ssh-keygen -t rsa</span><br></div></code></pre></div></div>
<p>然后将 Jenkins 服务器的公钥添加到目标服务器的 authorized_keys 中，实现免密登录。</p>
<p>在目标服务器上执行命令(将 Jenkins 服务器的公钥内容追加到 authorized_keys):</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 将Jenkins服务器的公钥内容追加到authorized_keys</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Jenkins服务器的公钥内容" &gt;&gt; ~/.ssh/authorized_keys</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 或者直接编辑authorized_keys文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vi ~/.ssh/authorized_keys</span><br></div></code></pre></div></div>
<p>确保 authorized_keys 文件权限正确:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">chmod 600 ~/.ssh/authorized_keys</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod 700 ~/.ssh</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>配置 Publish Over SSH 插件</p>
<p>重启完成后在系统管理=&gt;系统配置会多出一个 Publish over SSH:</p>
<p>下图中，Key 填入上一步生成的私钥 id_rsa 的内容，Name 随意起一个目标服务器的名称，Hostname 为目标服务器 IP，Username 为链接目标服务的用户名, 可以点击右下角的 Test Configution 进行连通性测试。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-ssh.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>添加构建后操作步骤 Send build artifacts over SSH</p>
<p>进入项目配置页面，添加构建后操作步骤 Send build artifacts over SSH:
Name 选择上一步配置好 ssh server，Source files 文件是相对于工作区，Remote directory 目录是相对于用户 ssh 登录默认目录，比如用户是 abc，ssh 默认登录目录可能是/home/abc，则最后上传的目录是/home/abc/www/packages，Exec command 就是登录到目标服务器后要执行的脚本，这里主要是将 tar 文件解压到目标目录。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/config-deploy.png" alt="" class="img_gjoA"></p>
</li>
</ul>
<p>自此就能够一键构建并部署项目了。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-通过-docker-进行编译">6. 通过 docker 进行编译<a href="http://localhost:3000/blog/setup-jenkins#6-%E9%80%9A%E8%BF%87-docker-%E8%BF%9B%E8%A1%8C%E7%BC%96%E8%AF%91" class="hash-link" aria-label="6. 通过 docker 进行编译的直接链接" title="6. 通过 docker 进行编译的直接链接" translate="no">​</a></h2>
<p>有时候我们编译一个项目，需要安装很多依赖，比如编译 c++项目，可能需要安装 g++、cmake 等环境，而其他项目又可能需要其他环境，这时候配置 Jenkins 编译的同学就需要知道各个项目的上下文，编译方式等，这样就太过麻烦。假如各个项目的同学直接提供一个编译自己项目的 docker 镜像，那么配置 Jenkins 的同学只需要提供一个简单的配置模板就可以了。</p>
<p>假设编译项目的镜像已预先生成好并推送到镜像仓库 harbor(这里是私有部署的镜像仓库 192.168.30.32:18082)，镜像名为<code>192.168.30.32:18082/library/semd-builder:0.0.1</code>，接下来我们首先需要在 jenkins 里能执行 docker 命令:</p>
<ul>
<li class="">
<p>支持执行脚本时能够访问 docker 命令</p>
<p>在执行脚本时能够访问 docker 命令，即在 docker 容器内部执行 docker 命令，可以在 jenkins <strong>容器内</strong>安装 Docker 客户端</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">apt-get update &amp;&amp; apt-get install -y docker.io</span><br></div></code></pre></div></div>
<p>但是在容器删除后，基于 Jenkins 基础镜像重启 docker.io 会丢失，因此为了持久化，我们基于 jenkins 镜像生成一个安装了 docker.io 的镜像，Dockerfile 如下:</p>
<div class="language-yml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-yml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># jenkins-docker-file</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FROM  jenkins/jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">USER root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RUN apt</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">get update </span><span class="token important">&amp;&amp;</span><span class="token plain"> \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">apt</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">get install </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">y docker.io</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">USER jenkins</span><br></div></code></pre></div></div>
<p>执行生成镜像命令, 生成名为 192.168.30.32:18082/library/xhm-jenkins:0.0.1 的镜像:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">docker image build --platform linux/amd64 -t 192.168.30.32:18082/library/xhm-jenkins:0.0.1 -f jenkins-docker-file .</span><br></div></code></pre></div></div>
<p>镜像生成后推送到本地镜像仓库，这样就可以使用基于官方镜像且安装好 docker.io 的镜像了。为了能在 Jenkins docker 内部使用 docker 命令，还需要在启动容器时映射 docker.sock:</p>
<div class="language-yml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-yml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">//docker</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">compose.yml</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'3'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">services</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">jenkins</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> 192.168.30.32</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">18082/library/xhm</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">jenkins</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">0.0.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">container_name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> jenkins</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">user</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">ports</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"18080:8080"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">volumes</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> /var/run/docker.sock</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">/var/run/docker.sock</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> /var/jenkins/jenkins</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">/var/jenkins_home</span><br></div></code></pre></div></div>
<p>重启容器。</p>
</li>
<li class="">
<p>配置 build 命令</p>
<p>在 Build Steps 中添加执行 shell，运行 docker 就可以了。
下图中<code>/var/jenkins/jenkins-data</code>是我们运行 jenkins 时映射的<code>/var/jenkins_home</code>路径，<code>$JOB_NAME</code>在这里是<code>multi-body/semd-build</code>。
当运行 semd-build 镜像会执行内部的一个 build 脚本(生成镜像时已配置)。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/docker.png" alt="" class="img_gjoA"></p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="7-支持编译-electron-windows-版本软件">7. 支持编译 Electron Windows 版本软件<a href="http://localhost:3000/blog/setup-jenkins#7-%E6%94%AF%E6%8C%81%E7%BC%96%E8%AF%91-electron-windows-%E7%89%88%E6%9C%AC%E8%BD%AF%E4%BB%B6" class="hash-link" aria-label="7. 支持编译 Electron Windows 版本软件的直接链接" title="7. 支持编译 Electron Windows 版本软件的直接链接" translate="no">​</a></h2>
<p>通过 electronuserland/builder<!-- -->:wine<!-- --> 这个镜像就能够在 linux 编译 windows 版本软件，为了方便使用将其生成本地镜像并推送到私有部署镜像仓库中，Dockerfile 如下:</p>
<div class="language-yml codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-yml codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># wine-docker-file</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FROM electronuserland/builder</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">wine</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">WORKDIR /app</span><br></div></code></pre></div></div>
<p>该镜像命名为 192.168.30.32:18082/library/xhm-wine:0.0.1，镜像生成好后就可以配置 Jenkins 的 build 脚本了:</p>
<div class="language-sh codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-sh codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">#安装依赖，有可能有新的依赖</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">yarn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#将我们的项目目录映射到xhm-wine docker的/app目录，$JOB_NAME在这里是multi-body/rbmd-client-build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker run -v /home/xhm/services/jenkins/jenkins-data/workspace/$JOB_NAME:/app   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#映射electron cache目录，防止每次编译都下载</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-v ~/.cache/electron:/root/.cache/electron \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#映射electron-builder cache目录，防止每次编译都下载</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-v  ~/.cache/electron-builder:/root/.cache/electron-builder \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#用上述生成的xhm-wine:0.0.1镜像编译，yarn build:win是项目打包windows版本软件命令</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">192.168.30.32:18082/library/xhm-wine:0.0.1 yarn build:win</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#编译完成后会在dist/win-unpacked目录下生成windows版本的软件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tar -czf rbmd-client.tar.gz -C dist win-unpacked</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/electron-build-windows-app.webp" alt="" class="img_gjoA"></p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="8-支持编译-java-项目">8. 支持编译 Java 项目<a href="http://localhost:3000/blog/setup-jenkins#8-%E6%94%AF%E6%8C%81%E7%BC%96%E8%AF%91-java-%E9%A1%B9%E7%9B%AE" class="hash-link" aria-label="8. 支持编译 Java 项目的直接链接" title="8. 支持编译 Java 项目的直接链接" translate="no">​</a></h2>
<ul>
<li class="">
<p>安装 Maven Integration plugin 插件</p>
<p>jenkins 主页选择系统管理=&gt;插件管理，在 Avaliable plugins 中搜索 Maven Integration plugin，点击安装，安装完成后重启容器。</p>
</li>
<li class="">
<p>配置 Maven</p>
<p>重启完成后，在 jenkins 主页选择系统管理=&gt;全局工具配置=&gt;新增 Maven=&gt;自动安装:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/maven.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>创建 Maven 项目</p>
<p>jenkins 主页选择新建任务=&gt;构建一个 maven 项目:
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/create-maven-project.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>配置源码管理</p>
<p>同上，只需要换成 Java 项目地址。</p>
</li>
<li class="">
<p>配置 build 命令</p>
<ul>
<li class="">
<p>Root POM</p>
<p>pom.xml 文件相对于 workspace 的路径</p>
</li>
<li class="">
<p>Goals and options</p>
<p>添加 Maven 命令比如: package、clean 等。</p>
</li>
</ul>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/maven-build.png" alt="" class="img_gjoA"></p>
</li>
<li class="">
<p>归档上一步生成的 jar 文件</p>
<p>同上，只需要修改生成的 jar 文件的地址。</p>
</li>
</ul>
<p>这样就可以 build 一个 Java 项目了。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="9-配置自动构建-通用-webhook--nginx">9. 配置自动构建 (通用 WebHook + Nginx)<a href="http://localhost:3000/blog/setup-jenkins#9-%E9%85%8D%E7%BD%AE%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA-%E9%80%9A%E7%94%A8-webhook--nginx" class="hash-link" aria-label="9. 配置自动构建 (通用 WebHook + Nginx)的直接链接" title="9. 配置自动构建 (通用 WebHook + Nginx)的直接链接" translate="no">​</a></h2>
<p>通过 "触发远程构建" 以及 Nginx 转发来实现自动构建。这种方式不需要依赖特定的 Gitee 插件，且可以通过 Nginx 增加一层安全校验。</p>
<ul>
<li class="">
<p>配置 Jenkins 任务</p>
<p><img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/jenkins-trigger.webp" alt="" class="img_gjoA"></p>
<p>进入 Jenkins 任务配置页面，找到 <strong>构建触发器 (Build Triggers)</strong> 区域。</p>
<ol>
<li class="">勾选 <strong>触发远程构建 (例如,使用脚本)</strong> (Trigger builds remotely)。</li>
<li class="">在 <strong>身份验证令牌 (Authentication Token)</strong> 中填写一个复杂的 Token（例如 <code>Jk5s5T2r6Xp3M7n1V6b3H0fL1zW8</code>）。</li>
</ol>
<p>此时，可以通过访问 <code>JENKINS_URL/job/YOUR_JOB_NAME/build?token=TOKEN_NAME</code> 来触发构建。</p>
</li>
<li class="">
<p>配置 Nginx 转发与鉴权</p>
<p>为了安全起见（避免直接暴露 Jenkins 端口或 Token），以及适配某些 Git 平台（如 Gitee）的 WebHook 请求格式，我们通过 Nginx 进行转发和简单的鉴权。</p>
<p>在 Nginx 配置文件中添加以下 location：</p>
<div class="language-nginx codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-nginx codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">location /trigger-build {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 简单的鉴权：检查 URL 参数 secret 是否匹配</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if ($arg_secret != "rB9x217mP6vL2nQ3wE6jZ9yA1dC0") {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return 401;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 清空参数，避免将 secret 透传给 Jenkins (可选)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    set $args "";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 强制使用 GET 方法，绕过 Jenkins 对 POST 请求的 CSRF 检查</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    proxy_method GET;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Content-Length "";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    proxy_set_header Content-Type "";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 转发到 Jenkins 内部地址</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 注意：替换下面的 URL 为你实际的 Jenkins 构建地址, token 为上一步配置的 Token</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    proxy_pass http://127.0.0.1:18024/view/all/job/unitarylab/job/unitarylab-developers-guide-deploy/build?token=Jk1s8T3r6Xp4M7n1V6b3H0fL1zW9;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 隐藏 Jenkins 的响应头，避免暴露内网信息</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    proxy_hide_header X-Jenkins;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    proxy_hide_header X-Hudson;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">}</span><br></div></code></pre></div></div>
</li>
<li class="">
<p>配置 Gitee WebHook</p>
<p>登录 Gitee，进入对应的代码仓库，选择 <strong>仓库设置</strong> =&gt; <strong>WebHooks</strong> =&gt; <strong>新建 WebHook</strong>。
<img decoding="async" loading="lazy" src="https://blog-bed.oss-cn-beijing.aliyuncs.com/2024-01-04-%E6%90%AD%E5%BB%BAjenkins/webhook.webp" alt="" class="img_gjoA"></p>
<ol>
<li class=""><strong>URL</strong>: 填入 Nginx 暴露的地址，并带上 secret 参数（上一步 Nginx 配置的）。
例如: <code>http://YOUR_NGINX_DOMAIN/trigger-build?secret=rB9x217mP6vL2nQ3wE6jZ9yA1dC0</code></li>
<li class=""><strong>WebHook 密码/签名密钥</strong>: 不需要填写（鉴权已在 Nginx 地址参数中处理）。</li>
<li class=""><strong>事件</strong>: 勾选 <strong>推送代码</strong>。</li>
</ol>
</li>
</ul>
<p>点击新建进行创建，创建完成后可以点击 <strong>测试</strong> ，观察 Jenkins 是否触发构建。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Programming" term="Programming"/>
        <category label="Jenkins" term="Jenkins"/>
        <category label="CI/CD" term="CI/CD"/>
        <category label="Docker" term="Docker"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[软件许可证协议详解]]></title>
        <id>http://localhost:3000/blog/software-licenses</id>
        <link href="http://localhost:3000/blog/software-licenses"/>
        <updated>2023-04-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[软件许可证协议（Software License Agreements）是规定软件使用、修改和分发权利的法律文件。对于开发者而言，了解不同协议的区别至关重要，以免陷入法律纠纷。]]></summary>
        <content type="html"><![CDATA[<p>软件许可证协议（Software License Agreements）是规定软件使用、修改和分发权利的法律文件。对于开发者而言，了解不同协议的区别至关重要，以免陷入法律纠纷。</p>
<p>本文将常见的软件许可证分为三大类：<strong>宽松型</strong>、<strong>弱 Copyleft 型</strong>和<strong>强 Copyleft 型</strong>，并按限制从少到多的顺序进行介绍。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="一宽松型许可证-permissive-licenses">一、宽松型许可证 (Permissive Licenses)<a href="http://localhost:3000/blog/software-licenses#%E4%B8%80%E5%AE%BD%E6%9D%BE%E5%9E%8B%E8%AE%B8%E5%8F%AF%E8%AF%81-permissive-licenses" class="hash-link" aria-label="一、宽松型许可证 (Permissive Licenses)的直接链接" title="一、宽松型许可证 (Permissive Licenses)的直接链接" translate="no">​</a></h2>
<p>这类许可证限制最少，通常只要求<strong>保留版权声明</strong>。它们鼓励代码的广泛采用，允许闭源商业化。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="1-mit-license">1. MIT License<a href="http://localhost:3000/blog/software-licenses#1-mit-license" class="hash-link" aria-label="1. MIT License的直接链接" title="1. MIT License的直接链接" translate="no">​</a></h3>
<p><strong>特点</strong>：</p>
<ul>
<li class="">最简单、最宽松。</li>
<li class="">允许任意使用、修改、分发、私有化（闭源）。</li>
<li class=""><strong>唯一义务</strong>：在软件副本中包含原作者的版权声明和许可声明。</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">希望代码被最大限度地使用，不在意衍生品是否闭源。</li>
<li class="">如：jQuery, Node.js, React。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="2-bsd-license">2. BSD License<a href="http://localhost:3000/blog/software-licenses#2-bsd-license" class="hash-link" aria-label="2. BSD License的直接链接" title="2. BSD License的直接链接" translate="no">​</a></h3>
<p>与 MIT 非常相似，主要分为两个版本：</p>
<ul>
<li class=""><strong>BSD 2-Clause</strong>：基本等同于 MIT。</li>
<li class=""><strong>BSD 3-Clause</strong>：多了一条<strong>禁止使用原作者名义进行推广</strong>的条款。</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">学术界或希望保护声誉的项目。</li>
<li class="">如：Nginx, Go 语言。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="3-apache-license-20">3. Apache License 2.0<a href="http://localhost:3000/blog/software-licenses#3-apache-license-20" class="hash-link" aria-label="3. Apache License 2.0的直接链接" title="3. Apache License 2.0的直接链接" translate="no">​</a></h3>
<p><strong>特点</strong>：</p>
<ul>
<li class="">
<p>在宽松的基础上，增加了<strong>专利授权</strong>和<strong>商标保护</strong>条款。</p>
</li>
<li class="">
<p><strong>明确的专利授权</strong>：贡献者自动授予用户专利使用权；若用户发起专利诉讼，授权自动终止。</p>
<blockquote>
<p><strong>示例</strong>：若贡献者（如公司 A）向项目贡献了包含专利的代码，则自动授予用户（如公司 B）专利使用权，用户(公司 B)无需担心被起诉侵权。</p>
</blockquote>
</li>
<li class="">
<p><strong>修改标注</strong>：修改后的文件需明确标注。</p>
</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">大型企业级开源项目，关注专利风险。</li>
<li class="">如：Android, Kubernetes, TensorFlow。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="二弱-copyleft-许可证-weak-copyleft-licenses">二、弱 Copyleft 许可证 (Weak Copyleft Licenses)<a href="http://localhost:3000/blog/software-licenses#%E4%BA%8C%E5%BC%B1-copyleft-%E8%AE%B8%E5%8F%AF%E8%AF%81-weak-copyleft-licenses" class="hash-link" aria-label="二、弱 Copyleft 许可证 (Weak Copyleft Licenses)的直接链接" title="二、弱 Copyleft 许可证 (Weak Copyleft Licenses)的直接链接" translate="no">​</a></h2>
<p>这类许可证介于宽松和严格之间，通常要求<strong>修改过的文件</strong>必须开源，但允许与其他闭源模块链接（Link）。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="1-mpl-20-mozilla-public-license">1. MPL 2.0 (Mozilla Public License)<a href="http://localhost:3000/blog/software-licenses#1-mpl-20-mozilla-public-license" class="hash-link" aria-label="1. MPL 2.0 (Mozilla Public License)的直接链接" title="1. MPL 2.0 (Mozilla Public License)的直接链接" translate="no">​</a></h3>
<p><strong>特点</strong>：</p>
<ul>
<li class=""><strong>文件级 Copyleft</strong>：如果你修改了现有的源代码文件，该文件必须开源。</li>
<li class=""><strong>混合开发友好</strong>：新增的文件或链接的模块可以是闭源的。</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">混合型项目，希望核心代码开源，但允许扩展闭源。</li>
<li class="">如：Firefox, LibreOffice。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="2-lgpl-lesser-gpl">2. LGPL (Lesser GPL)<a href="http://localhost:3000/blog/software-licenses#2-lgpl-lesser-gpl" class="hash-link" aria-label="2. LGPL (Lesser GPL)的直接链接" title="2. LGPL (Lesser GPL)的直接链接" translate="no">​</a></h3>
<p><strong>特点</strong>：</p>
<ul>
<li class="">GPL 的妥协版本。</li>
<li class=""><strong>动态链接豁免</strong>：如果你的程序只是动态链接（Dynamic Link）到 LGPL 库，你的主程序可以闭源。</li>
<li class="">若修改了库本身，则修改部分必须开源。</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">通用类库，希望被商业软件使用，但又要改进回馈给库本身。</li>
<li class="">如：FFmpeg, GLib。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="三强-copyleft-许可证-strong-copyleft-licenses">三、强 Copyleft 许可证 (Strong Copyleft Licenses)<a href="http://localhost:3000/blog/software-licenses#%E4%B8%89%E5%BC%BA-copyleft-%E8%AE%B8%E5%8F%AF%E8%AF%81-strong-copyleft-licenses" class="hash-link" aria-label="三、强 Copyleft 许可证 (Strong Copyleft Licenses)的直接链接" title="三、强 Copyleft 许可证 (Strong Copyleft Licenses)的直接链接" translate="no">​</a></h2>
<p>这类许可证具有很强的“传染性”，要求衍生作品必须在<strong>相同协议下开源</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="1-gpl-v2--v3">1. GPL (v2 / v3)<a href="http://localhost:3000/blog/software-licenses#1-gpl-v2--v3" class="hash-link" aria-label="1. GPL (v2 / v3)的直接链接" title="1. GPL (v2 / v3)的直接链接" translate="no">​</a></h3>
<p><strong>特点</strong>：</p>
<ul>
<li class=""><strong>传染性</strong>：如果你的软件使用了 GPL 代码（包括复制或静态链接），整个软件必须开源。</li>
<li class=""><strong>GPLv2 vs GPLv3</strong>：v3 增加了以下条款：<!-- -->
<ul>
<li class=""><strong>反 Tivoization</strong>：只要厂商用了自由软件（如 GPLv3），用户就必须能在设备上安装并运行自己改过的版本，不能被硬件限制</li>
<li class=""><strong>专利报复</strong>：若用户发起专利诉讼，其获得的专利授权自动终止。</li>
</ul>
</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">坚定的自由软件支持者，防止代码被私有化。</li>
<li class="">如：Linux Kernel (v2), Git, WordPress。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="2-agpl-affero-gpl">2. AGPL (Affero GPL)<a href="http://localhost:3000/blog/software-licenses#2-agpl-affero-gpl" class="hash-link" aria-label="2. AGPL (Affero GPL)的直接链接" title="2. AGPL (Affero GPL)的直接链接" translate="no">​</a></h3>
<p><strong>特点</strong>：</p>
<ul>
<li class="">堵上了“SaaS 漏洞”。</li>
<li class=""><strong>网络分发视为分发</strong>：如果通过网络提供服务（如网站），也必须向用户公开源代码。</li>
</ul>
<p><strong>适用场景</strong>：</p>
<ul>
<li class="">云服务、Web 应用，防止云厂商“白嫖”而不回馈。</li>
<li class="">如：MongoDB (旧版), Grafana (旧版)。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="四其他特殊类型">四、其他特殊类型<a href="http://localhost:3000/blog/software-licenses#%E5%9B%9B%E5%85%B6%E4%BB%96%E7%89%B9%E6%AE%8A%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="四、其他特殊类型的直接链接" title="四、其他特殊类型的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="1-unlicense--cc0">1. Unlicense / CC0<a href="http://localhost:3000/blog/software-licenses#1-unlicense--cc0" class="hash-link" aria-label="1. Unlicense / CC0的直接链接" title="1. Unlicense / CC0的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>特点</strong>：放弃所有权利，将代码置于<strong>公共领域 (Public Domain)</strong>。</li>
<li class=""><strong>义务</strong>：无任何义务。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="2-专有软件-proprietary">2. 专有软件 (Proprietary)<a href="http://localhost:3000/blog/software-licenses#2-%E4%B8%93%E6%9C%89%E8%BD%AF%E4%BB%B6-proprietary" class="hash-link" aria-label="2. 专有软件 (Proprietary)的直接链接" title="2. 专有软件 (Proprietary)的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>特点</strong>：保留所有权利。</li>
<li class=""><strong>形式</strong>：EULA（最终用户许可协议），禁止反编译、限制安装设备数等。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="3-商业开源-commercial-open-source">3. 商业开源 (Commercial Open Source)<a href="http://localhost:3000/blog/software-licenses#3-%E5%95%86%E4%B8%9A%E5%BC%80%E6%BA%90-commercial-open-source" class="hash-link" aria-label="3. 商业开源 (Commercial Open Source)的直接链接" title="3. 商业开源 (Commercial Open Source)的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>双重许可 (Dual Licensing)</strong>：同时提供 GPL（免费开源）和商业许可（付费闭源）。如 Qt, MySQL。</li>
<li class=""><strong>SSPL</strong>：MongoDB 发明的协议，要求云厂商若提供托管服务需开源整个管理栈（不被 OSI 认可为开源协议）。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="五总结与选择指南">五、总结与选择指南<a href="http://localhost:3000/blog/software-licenses#%E4%BA%94%E6%80%BB%E7%BB%93%E4%B8%8E%E9%80%89%E6%8B%A9%E6%8C%87%E5%8D%97" class="hash-link" aria-label="五、总结与选择指南的直接链接" title="五、总结与选择指南的直接链接" translate="no">​</a></h2>
<table><thead><tr><th style="text-align:left">序号</th><th style="text-align:left">协议</th><th style="text-align:left">简述</th><th style="text-align:center">商业闭源</th><th style="text-align:center">专利授权</th><th style="text-align:center">传染性</th></tr></thead><tbody><tr><td style="text-align:left">1</td><td style="text-align:left"><strong>MIT</strong></td><td style="text-align:left">随便用，保留署名</td><td style="text-align:center">✅</td><td style="text-align:center">❌</td><td style="text-align:center">无</td></tr><tr><td style="text-align:left">2</td><td style="text-align:left"><strong>Apache 2.0</strong></td><td style="text-align:left">随便用，有专利保护</td><td style="text-align:center">✅</td><td style="text-align:center">✅</td><td style="text-align:center">无</td></tr><tr><td style="text-align:left">3</td><td style="text-align:left"><strong>BSD</strong></td><td style="text-align:left">随便用，禁借名推广</td><td style="text-align:center">✅</td><td style="text-align:center">❌</td><td style="text-align:center">无</td></tr><tr><td style="text-align:left">4</td><td style="text-align:left"><strong>MPL</strong></td><td style="text-align:left">修改文件需开源</td><td style="text-align:center">⚠️ (部分)</td><td style="text-align:center">❌</td><td style="text-align:center">文件级</td></tr><tr><td style="text-align:left">5</td><td style="text-align:left"><strong>LGPL</strong></td><td style="text-align:left">链接库可闭源</td><td style="text-align:center">⚠️ (链接)</td><td style="text-align:center">❌</td><td style="text-align:center">库级</td></tr><tr><td style="text-align:left">6</td><td style="text-align:left"><strong>GPL</strong></td><td style="text-align:left">必须全部开源</td><td style="text-align:center">❌</td><td style="text-align:center">v3✅</td><td style="text-align:center">强</td></tr><tr><td style="text-align:left">7</td><td style="text-align:left"><strong>AGPL</strong></td><td style="text-align:left">服务端也得开源</td><td style="text-align:center">❌</td><td style="text-align:center">✅</td><td style="text-align:center">最强</td></tr></tbody></table>
<p><strong>快速选择建议</strong>：</p>
<ol>
<li class=""><strong>简单、无脑、想被广泛使用</strong> 👉 <strong>MIT</strong></li>
<li class=""><strong>大公司、防专利流氓</strong> 👉 <strong>Apache 2.0</strong></li>
<li class=""><strong>写库、允许别人闭源链接</strong> 👉 <strong>LGPL</strong></li>
<li class=""><strong>强迫症、不仅要代码开源还要你也开源</strong> 👉 <strong>GPL</strong></li>
<li class=""><strong>做云服务、防云厂商白嫖</strong> 👉 <strong>AGPL</strong></li>
</ol>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Programming" term="Programming"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[子网掩码与网段计算详解]]></title>
        <id>http://localhost:3000/blog/subnet-mask-and-network-calculation</id>
        <link href="http://localhost:3000/blog/subnet-mask-and-network-calculation"/>
        <updated>2021-09-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文详细讲解子网掩码、网段、CIDR 以及 IP 地址计算的核心概念，帮助理解网络配置中的基础知识。]]></summary>
        <content type="html"><![CDATA[<p>本文详细讲解子网掩码、网段、CIDR 以及 IP 地址计算的核心概念，帮助理解网络配置中的基础知识。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-ip-地址的基本构成">1. IP 地址的基本构成<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#1-ip-%E5%9C%B0%E5%9D%80%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%9E%84%E6%88%90" class="hash-link" aria-label="1. IP 地址的基本构成的直接链接" title="1. IP 地址的基本构成的直接链接" translate="no">​</a></h2>
<p>一个 IP 地址（如 <code>192.168.1.10</code>）由两部分组成：</p>
<ul>
<li class=""><strong>网络号 (Network)</strong>：标识属于哪个网段</li>
<li class=""><strong>主机号 (Host)</strong>：标识网段中的具体设备</li>
</ul>
<p><strong>子网掩码（Subnet Mask）</strong> 的作用就是确定这两个部分的分界线。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-示例说明">1.1 示例说明<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#11-%E7%A4%BA%E4%BE%8B%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="1.1 示例说明的直接链接" title="1.1 示例说明的直接链接" translate="no">​</a></h3>
<p>假设：</p>
<ul>
<li class=""><strong>IP</strong>: <code>192.168.1.10</code></li>
<li class=""><strong>子网掩码</strong>: <code>255.255.255.0</code> (即 <code>/24</code>)</li>
</ul>
<p>根据这个掩码可以得出：</p>
<ul>
<li class=""><strong>网络地址</strong>: <code>192.168.1.0</code></li>
<li class=""><strong>网段</strong>: <code>192.168.1.0/24</code></li>
<li class=""><strong>主机范围</strong>: <code>192.168.1.1</code> - <code>192.168.1.254</code></li>
<li class=""><strong>广播地址</strong>: <code>192.168.1.255</code></li>
</ul>
<blockquote>
<p>💡 <strong>说明</strong>：上述结果是通过子网掩码计算得出的。如果你现在还不清楚这些值是如何计算的，不用担心，后续章节会详细讲解：</p>
<ul>
<li class=""><strong>网络地址</strong>的计算方法 → 见第 4 章</li>
<li class=""><strong>主机范围</strong>的计算方法 → 见第 5 章</li>
</ul>
<p>这里先有个整体印象即可。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-理解-cidr-表示法">2. 理解 CIDR 表示法<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#2-%E7%90%86%E8%A7%A3-cidr-%E8%A1%A8%E7%A4%BA%E6%B3%95" class="hash-link" aria-label="2. 理解 CIDR 表示法的直接链接" title="2. 理解 CIDR 表示法的直接链接" translate="no">​</a></h2>
<p>CIDR (Classless Inter-Domain Routing，无类域间路由) 是一种更简洁的网络地址表示方式，用 <code>IP地址/掩码位长度</code> 的格式来替代传统的 A/B/C 类网络划分。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-cidr-与子网掩码的对应关系">2.1 CIDR 与子网掩码的对应关系<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#21-cidr-%E4%B8%8E%E5%AD%90%E7%BD%91%E6%8E%A9%E7%A0%81%E7%9A%84%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB" class="hash-link" aria-label="2.1 CIDR 与子网掩码的对应关系的直接链接" title="2.1 CIDR 与子网掩码的对应关系的直接链接" translate="no">​</a></h3>
<p>CIDR 使用 <strong>"/数字"</strong> 来表示子网掩码中连续 <code>1</code> 的个数：</p>
<table><thead><tr><th style="text-align:left">CIDR</th><th style="text-align:left">等价子网掩码</th></tr></thead><tbody><tr><td style="text-align:left"><code>/8</code></td><td style="text-align:left"><code>255.0.0.0</code></td></tr><tr><td style="text-align:left"><code>/16</code></td><td style="text-align:left"><code>255.255.0.0</code></td></tr><tr><td style="text-align:left"><code>/24</code></td><td style="text-align:left"><code>255.255.255.0</code></td></tr></tbody></table>
<p>CIDR 允许使用任意长度的掩码（如 <code>/13</code>, <code>/22</code>, <code>/27</code>），使网络划分更加灵活。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-为什么-2552552550-对应-24">2.2 为什么 255.255.255.0 对应 /24？<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#22-%E4%B8%BA%E4%BB%80%E4%B9%88-2552552550-%E5%AF%B9%E5%BA%94-24" class="hash-link" aria-label="2.2 为什么 255.255.255.0 对应 /24？的直接链接" title="2.2 为什么 255.255.255.0 对应 /24？的直接链接" translate="no">​</a></h3>
<p>将 <code>255.255.255.0</code> 转换为二进制：</p>
<ul>
<li class=""><code>255</code> → <code>11111111</code> (8 个 1)</li>
<li class=""><code>255</code> → <code>11111111</code> (8 个 1)</li>
<li class=""><code>255</code> → <code>11111111</code> (8 个 1)</li>
<li class=""><code>0</code> → <code>00000000</code> (0 个 1)</li>
</ul>
<p>组合起来：<code>11111111.11111111.11111111.00000000</code></p>
<p>统计开头的连续 <code>1</code> 的数量：<code>8 + 8 + 8 = 24</code>，因此称为 <strong>/24</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-常见掩码对照表">2.3 常见掩码对照表<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#23-%E5%B8%B8%E8%A7%81%E6%8E%A9%E7%A0%81%E5%AF%B9%E7%85%A7%E8%A1%A8" class="hash-link" aria-label="2.3 常见掩码对照表的直接链接" title="2.3 常见掩码对照表的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">子网掩码</th><th style="text-align:left">二进制表示 (部分)</th><th style="text-align:left">1 的数量</th><th style="text-align:left">CIDR</th></tr></thead><tbody><tr><td style="text-align:left"><code>255.0.0.0</code></td><td style="text-align:left"><code>11111111...</code></td><td style="text-align:left">8</td><td style="text-align:left"><code>/8</code></td></tr><tr><td style="text-align:left"><code>255.255.0.0</code></td><td style="text-align:left"><code>11111111.11111111...</code></td><td style="text-align:left">16</td><td style="text-align:left"><code>/16</code></td></tr><tr><td style="text-align:left"><code>255.255.255.0</code></td><td style="text-align:left"><code>11111111.11111111.11111111...</code></td><td style="text-align:left">24</td><td style="text-align:left"><code>/24</code></td></tr><tr><td style="text-align:left"><code>255.255.255.128</code></td><td style="text-align:left"><code>...11111111.10000000</code></td><td style="text-align:left">25</td><td style="text-align:left"><code>/25</code></td></tr><tr><td style="text-align:left"><code>255.255.255.192</code></td><td style="text-align:left"><code>...11111111.11000000</code></td><td style="text-align:left">26</td><td style="text-align:left"><code>/26</code></td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-网络号-vs-网络地址">3. 网络号 vs 网络地址<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#3-%E7%BD%91%E7%BB%9C%E5%8F%B7-vs-%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80" class="hash-link" aria-label="3. 网络号 vs 网络地址的直接链接" title="3. 网络号 vs 网络地址的直接链接" translate="no">​</a></h2>
<p>在网络配置中,<strong>网络号</strong>和<strong>网络地址</strong>这两个术语经常被混用,但它们有细微的区别:</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-网络号-network-id">3.1 网络号 (Network ID)<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#31-%E7%BD%91%E7%BB%9C%E5%8F%B7-network-id" class="hash-link" aria-label="3.1 网络号 (Network ID)的直接链接" title="3.1 网络号 (Network ID)的直接链接" translate="no">​</a></h3>
<p><strong>网络号</strong>是指 IP 地址中属于<strong>网络部分的比特</strong>。</p>
<p>以 <code>192.168.1.10/24</code> 为例:</p>
<ul>
<li class=""><code>/24</code> 表示前 24 位是网络号,后 8 位是主机号</li>
<li class="">网络号(二进制): <code>11000000.10101000.00000001</code> ← 前 24 位</li>
<li class="">网络号(十进制): <code>192.168.1</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-网络地址-network-address">3.2 网络地址 (Network Address)<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#32-%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80-network-address" class="hash-link" aria-label="3.2 网络地址 (Network Address)的直接链接" title="3.2 网络地址 (Network Address)的直接链接" translate="no">​</a></h3>
<p><strong>网络地址</strong>是指<strong>网络号 + 全 0 主机位</strong>组成的完整 IP 地址。</p>
<p>继续上面的例子:</p>
<ul>
<li class="">网络号前 24 位不变,后 8 位主机位全为 0:<!-- -->
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">11000000.10101000.00000001.00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">= 192.168.1.0  ← 网络地址</span><br></div></code></pre></div></div>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="33-关键区别">3.3 关键区别<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#33-%E5%85%B3%E9%94%AE%E5%8C%BA%E5%88%AB" class="hash-link" aria-label="3.3 关键区别的直接链接" title="3.3 关键区别的直接链接" translate="no">​</a></h3>
<table><thead><tr><th style="text-align:left">概念</th><th style="text-align:left">含义</th><th style="text-align:left">例子</th></tr></thead><tbody><tr><td style="text-align:left"><strong>网络号 (Network ID)</strong></td><td style="text-align:left">IP 地址中属于"网络"的比特部分</td><td style="text-align:left"><code>192.168.1</code> (对应前 24 位)</td></tr><tr><td style="text-align:left"><strong>网络地址 (Network Address)</strong></td><td style="text-align:left">一个网段的起点,主机位全部为 0</td><td style="text-align:left"><code>192.168.1.0</code> (完整的 IP 地址)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-如何计算网络地址">4. 如何计算网络地址<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#4-%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80" class="hash-link" aria-label="4. 如何计算网络地址的直接链接" title="4. 如何计算网络地址的直接链接" translate="no">​</a></h2>
<p>网络地址（如 <code>192.168.1.0</code>）可以通过 <strong>IP 地址</strong> 与 <strong>子网掩码</strong> 进行 <strong>按位与 (AND)</strong> 运算来确定。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-计算过程">4.1 计算过程<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#41-%E8%AE%A1%E7%AE%97%E8%BF%87%E7%A8%8B" class="hash-link" aria-label="4.1 计算过程的直接链接" title="4.1 计算过程的直接链接" translate="no">​</a></h3>
<p>以 IP <code>192.168.1.10/24</code> 为例：</p>
<ol>
<li class=""><strong>IP</strong>: <code>11000000.10101000.00000001.00001010</code> (<code>192.168.1.10</code>)</li>
<li class=""><strong>Mask</strong>: <code>11111111.11111111.11111111.00000000</code> (<code>255.255.255.0</code>)</li>
<li class=""><strong>AND</strong>: <code>11000000.10101000.00000001.00000000</code> (<code>192.168.1.0</code>)</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-网络地址的意义">4.2 网络地址的意义<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#42-%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80%E7%9A%84%E6%84%8F%E4%B9%89" class="hash-link" aria-label="4.2 网络地址的意义的直接链接" title="4.2 网络地址的意义的直接链接" translate="no">​</a></h3>
<p><strong>网络地址 (Network Address)</strong>：<code>192.168.1.0</code></p>
<ul>
<li class="">它是该网段的起始地址（所有主机位为 0）</li>
<li class="">用于标识整个网段</li>
<li class=""><strong>不可分配给具体主机</strong></li>
</ul>
<p><strong>判断是否同一网段:</strong></p>
<p>两台设备属于同一网段,需要同时满足:</p>
<ol>
<li class=""><strong>网络地址相同</strong>（通过各自的 IP 与子网掩码计算得出）</li>
<li class=""><strong>子网掩码相同</strong></li>
</ol>
<p><strong>示例:</strong></p>
<ul>
<li class="">设备 A: <code>192.168.1.10/24</code> → 网络地址 <code>192.168.1.0</code></li>
<li class="">设备 B: <code>192.168.1.20/24</code> → 网络地址 <code>192.168.1.0</code></li>
<li class="">结论: 两者网络地址相同且掩码相同,<strong>属于同一网段</strong>,可以直接通信</li>
</ul>
<p><strong>反例:</strong></p>
<ul>
<li class="">设备 A: <code>192.168.1.10/24</code> → 网络地址 <code>192.168.1.0</code></li>
<li class="">设备 C: <code>192.168.2.10/24</code> → 网络地址 <code>192.168.2.0</code></li>
<li class="">结论: 网络地址不同,<strong>不属于同一网段</strong>,需要通过路由器才能通信</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-如何计算主机范围">5. 如何计算主机范围<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#5-%E5%A6%82%E4%BD%95%E8%AE%A1%E7%AE%97%E4%B8%BB%E6%9C%BA%E8%8C%83%E5%9B%B4" class="hash-link" aria-label="5. 如何计算主机范围的直接链接" title="5. 如何计算主机范围的直接链接" translate="no">​</a></h2>
<p>只要知道了 <strong>网段大小</strong> 和 <strong>网络地址</strong>，就可以算出可用的主机范围。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="51-关键地址定义">5.1 关键地址定义<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#51-%E5%85%B3%E9%94%AE%E5%9C%B0%E5%9D%80%E5%AE%9A%E4%B9%89" class="hash-link" aria-label="5.1 关键地址定义的直接链接" title="5.1 关键地址定义的直接链接" translate="no">​</a></h3>
<p>以 <code>192.168.1.0/24</code> 为例：</p>
<ol>
<li class=""><strong>网络地址</strong> (网段起始)：<code>192.168.1.0</code> (主机位全 0)</li>
<li class=""><strong>广播地址</strong> (网段结束)：<code>192.168.1.255</code> (主机位全 1)</li>
<li class=""><strong>可用主机范围</strong>：介于网络地址和广播地址之间</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="52-计算步骤">5.2 计算步骤<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#52-%E8%AE%A1%E7%AE%97%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="5.2 计算步骤的直接链接" title="5.2 计算步骤的直接链接" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>计算总 IP 数</strong>：<code>2^(32 - 掩码位数)</code></p>
<ul>
<li class=""><code>/24</code> → <code>32 - 24 = 8</code> → <code>2^8 = 256</code> 个地址</li>
</ul>
</li>
<li class="">
<p><strong>确定范围</strong>：从 <code>192.168.1.0</code> 到 <code>192.168.1.255</code></p>
</li>
<li class="">
<p><strong>排除首尾</strong>：</p>
<ul>
<li class="">起始 + 1 = <code>192.168.1.1</code> (第一个可用 IP)</li>
<li class="">结束 - 1 = <code>192.168.1.254</code> (最后一个可用 IP)</li>
</ul>
</li>
</ol>
<p><strong>结论</strong>：该网段可用 IP 范围为 <code>192.168.1.1 - 192.168.1.254</code>，共 254 个可用地址。</p>
<blockquote>
<p><strong>注意</strong>：只有在此范围内的 IP 地址才能分配给该网段中的主机使用，超出范围的 IP 地址将无法与该网段内的设备通信。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-总结">6. 总结<a href="http://localhost:3000/blog/subnet-mask-and-network-calculation#6-%E6%80%BB%E7%BB%93" class="hash-link" aria-label="6. 总结的直接链接" title="6. 总结的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>子网掩码</strong>决定了 IP 地址中网络号和主机号的分界线</li>
<li class=""><strong>CIDR</strong> 提供了更简洁的表示方式（如 <code>/24</code>）</li>
<li class=""><strong>网络地址</strong> = IP 地址 AND 子网掩码</li>
<li class=""><strong>可用主机范围</strong> = 网络地址 + 1 到 广播地址 - 1</li>
</ul>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="网络" term="网络"/>
        <category label="教程" term="教程"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[package.json 文件中常用字段]]></title>
        <id>http://localhost:3000/blog/package-json-fields</id>
        <link href="http://localhost:3000/blog/package-json-fields"/>
        <updated>2021-02-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[package.json 是 Node.js 项目的核心配置文件，它定义了项目的元数据、依赖关系、脚本命令等关键信息。深入理解 package.json 中的各个字段，对于 Node.js 开发者来说至关重要——它不仅影响项目的构建和发布流程，还直接关系到包的兼容性、性能优化和开发体验。]]></summary>
        <content type="html"><![CDATA[<p>package.json 是 Node.js 项目的核心配置文件，它定义了项目的元数据、依赖关系、脚本命令等关键信息。深入理解 package.json 中的各个字段，对于 Node.js 开发者来说至关重要——它不仅影响项目的构建和发布流程，还直接关系到包的兼容性、性能优化和开发体验。</p>
<p>本文将详细介绍 package.json 中最重要的 12 个字段，帮助你更好地管理和优化你的 Node.js 项目。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-peerdependencies---对等依赖管理">1. peerDependencies - 对等依赖管理<a href="http://localhost:3000/blog/package-json-fields#1-peerdependencies---%E5%AF%B9%E7%AD%89%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86" class="hash-link" aria-label="1. peerDependencies - 对等依赖管理的直接链接" title="1. peerDependencies - 对等依赖管理的直接链接" translate="no">​</a></h2>
<p><code>peerDependencies</code> 字段用于声明你的包所依赖的<strong>宿主环境</strong>中应该存在的包及其版本。它告诉使用你的包的开发者："我的包需要与这些特定版本的包协同工作"。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="使用场景">使用场景<a href="http://localhost:3000/blog/package-json-fields#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="使用场景的直接链接" title="使用场景的直接链接" translate="no">​</a></h3>
<p>这个字段主要用于以下场景：</p>
<ul>
<li class=""><strong>插件开发</strong>：如 webpack 插件、babel 插件</li>
<li class=""><strong>UI 组件库</strong>：如基于 React、Vue 的组件库</li>
<li class=""><strong>框架扩展</strong>：如 Express 中间件</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="实际案例">实际案例<a href="http://localhost:3000/blog/package-json-fields#%E5%AE%9E%E9%99%85%E6%A1%88%E4%BE%8B" class="hash-link" aria-label="实际案例的直接链接" title="实际案例的直接链接" translate="no">​</a></h3>
<p>假设你正在开发一个 React 组件库，如果使用 <code>dependencies</code>：</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"dependencies"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"react"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"^18.2.0"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p><strong>问题</strong>：使用你组件库的项目可能已经安装了不同版本的 React（如 16.0.0），这会导致：</p>
<ul>
<li class=""><code>node_modules</code> 中存在多个 React 版本</li>
<li class="">版本冲突和兼容性问题</li>
<li class="">包体积增大</li>
</ul>
<p><strong>更好的解决方案</strong>是使用 <code>peerDependencies</code>：</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"peerDependencies"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"react"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"^18.2.0"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"peerDependenciesMeta"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"react"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"optional"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 默认值，表示必须安装</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="优势">优势<a href="http://localhost:3000/blog/package-json-fields#%E4%BC%98%E5%8A%BF" class="hash-link" aria-label="优势的直接链接" title="优势的直接链接" translate="no">​</a></h3>
<p>使用 <code>peerDependencies</code> 的好处：</p>
<ol>
<li class=""><strong>避免重复安装</strong>：确保整个项目只有一个 React 版本</li>
<li class=""><strong>版本一致性</strong>：强制使用兼容的版本</li>
<li class=""><strong>减小包体积</strong>：不会将依赖打包到你的库中</li>
<li class=""><strong>灵活性</strong>：通过 <code>peerDependenciesMeta</code> 可以标记某些依赖为可选</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-sideeffects---tree-shaking-优化">2. sideEffects - Tree Shaking 优化<a href="http://localhost:3000/blog/package-json-fields#2-sideeffects---tree-shaking-%E4%BC%98%E5%8C%96" class="hash-link" aria-label="2. sideEffects - Tree Shaking 优化的直接链接" title="2. sideEffects - Tree Shaking 优化的直接链接" translate="no">​</a></h2>
<p><code>sideEffects</code> 字段是现代打包工具进行 Tree Shaking 优化的重要标识。它告诉打包工具哪些模块是"纯净"的，可以安全地移除未使用的代码。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="什么是副作用">什么是副作用？<a href="http://localhost:3000/blog/package-json-fields#%E4%BB%80%E4%B9%88%E6%98%AF%E5%89%AF%E4%BD%9C%E7%94%A8" class="hash-link" aria-label="什么是副作用？的直接链接" title="什么是副作用？的直接链接" translate="no">​</a></h3>
<p>副作用（Side Effects）是指模块在被导入时会执行一些影响全局状态的代码，例如：</p>
<ul>
<li class="">修改全局变量</li>
<li class="">添加 polyfills</li>
<li class="">导入 CSS 文件</li>
<li class="">执行初始化代码</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="配置示例">配置示例<a href="http://localhost:3000/blog/package-json-fields#%E9%85%8D%E7%BD%AE%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="配置示例的直接链接" title="配置示例的直接链接" translate="no">​</a></h3>
<p><strong>标记为无副作用</strong>（推荐用于纯函数库）：</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"sideEffects"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>也可以指定具有副作用的特定文件：</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"sideEffects"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"./src/polyfills.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"*.css"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"*.scss"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>这对于现代打包工具（如 webpack、vite）进行代码优化非常重要。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-module">3. module<a href="http://localhost:3000/blog/package-json-fields#3-module" class="hash-link" aria-label="3. module的直接链接" title="3. module的直接链接" translate="no">​</a></h2>
<p>定义 npm 包的 ESM 规范（ES Module，import/export 语法）的入口文件，browser 环境和 node 环境均可使用。这个字段主要用于支持 ES6 模块语法的打包工具（如 webpack、rollup）。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// main字段兼容旧工具链</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"main"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.cjs.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"module"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.esm.js"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>当打包工具支持时，会优先使用 module 字段指定的 ESM 版本，这有助于更好的 tree-shaking 优化。</p>
<p>注意：Node.js 并不会识别 module 字段，它是社区约定的，主要用于 webpack、rollup、vite 等现代打包工具优先选择 ESM（ES Module）版本进行打包和优化。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-types---typescript-类型声明">4. types - TypeScript 类型声明<a href="http://localhost:3000/blog/package-json-fields#4-types---typescript-%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E" class="hash-link" aria-label="4. types - TypeScript 类型声明的直接链接" title="4. types - TypeScript 类型声明的直接链接" translate="no">​</a></h2>
<p><code>types</code> 字段指定 TypeScript 类型声明文件的位置，让使用你的包的 TypeScript 项目能获得完整的类型提示和静态检查。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"types"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./types/index.d.ts"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"main"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"build"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"tsc"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="说明">说明<a href="http://localhost:3000/blog/package-json-fields#%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="说明的直接链接" title="说明的直接链接" translate="no">​</a></h3>
<ul>
<li class="">类型声明文件通常具有 <code>.d.ts</code> 扩展名</li>
<li class="">用于描述 JavaScript 代码的类型信息</li>
<li class="">TypeScript 编译器会自动使用这些类型进行静态检查</li>
<li class="">如果不指定，TypeScript 会查找与 <code>main</code> 同名的 <code>.d.ts</code> 文件</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-main---包的主入口">5. main - 包的主入口<a href="http://localhost:3000/blog/package-json-fields#5-main---%E5%8C%85%E7%9A%84%E4%B8%BB%E5%85%A5%E5%8F%A3" class="hash-link" aria-label="5. main - 包的主入口的直接链接" title="5. main - 包的主入口的直接链接" translate="no">​</a></h2>
<p>指定包的主入口文件。当其他模块通过 <code>require()</code> 或 <code>import</code> 导入你的包时，会加载该文件。</p>
<p><code>main</code> 是最基本的入口字段，主要用于 CommonJS 规范，是旧版 Node.js 及部分工具链查找包入口的默认字段。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"main"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.js"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>如果不指定 main 字段，Node.js 会默认查找根目录下的 index.js 文件。</p>
<p><strong>与 module 的关系（简明）：</strong></p>
<ul>
<li class="">【main 是什么】CommonJS 入口。旧版 Node/工具链用它来 <code>require('pkg')</code>；当没有 <code>exports</code> 时，它是 Node 的主要入口。</li>
<li class="">【module 是什么】ESM 构建提示，供打包器（webpack/rollup/vite 等）优先采用以便 tree‑shaking。Node 运行时不读取 <code>module</code> 字段。</li>
<li class="">【有无优先级】<!-- -->
<ul>
<li class="">打包器 import：优先 <code>exports.import</code>，否则尝试 <code>module</code>，再不行用 <code>main</code>。</li>
<li class="">Node require：优先 <code>exports.require</code>，否则用 <code>main</code>（或 <code>index.*</code> 规则）。</li>
<li class="">Node import：优先 <code>exports.import</code>；没有 <code>exports</code> 时不会看 <code>module</code>，会依据 <code>type</code>/扩展名解析 <code>main</code> 或默认入口。</li>
</ul>
</li>
<li class="">【是否同时写】建议三者并存：<code>main</code> 兼容旧链路，<code>module</code> 提示打包器走 ESM，<code>exports</code> 做条件导出（含子路径）。</li>
<li class="">【实践建议】同时产出 CJS/ESM 构建；在 <code>exports</code> 中指明 import/require；<code>types</code> 指向 <code>.d.ts</code>。若设置 <code>"type": "module"</code>，<code>main</code> 应指向 ESM 产物。</li>
<li class="">【常见坑】只有 <code>module</code> 没有 <code>main</code> 会让旧工具找不到入口；只有 <code>main</code> 没有 <code>exports/module</code> 难以获得良好 tree‑shaking 和条件导出；<code>module</code> 指到源码会导致消费者二次编译。</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-exports---现代化导出管理">6. exports - 现代化导出管理<a href="http://localhost:3000/blog/package-json-fields#6-exports---%E7%8E%B0%E4%BB%A3%E5%8C%96%E5%AF%BC%E5%87%BA%E7%AE%A1%E7%90%86" class="hash-link" aria-label="6. exports - 现代化导出管理的直接链接" title="6. exports - 现代化导出管理的直接链接" translate="no">​</a></h2>
<p><code>exports</code> 字段提供了更现代和精确的方式来定义包的导出，支持条件导出、子路径导出等高级功能。它是 Node.js 12+ 和现代打包工具的首选方案。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"exports"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"."</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"import"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist/index.esm.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"require"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist/index.cjs.js"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// import utils from "your-lib/utils";Node.js 会解析到 ./dist/utils.js。</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"./utils"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist/utils.js"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>这样可以为 ESM 和 CommonJS 提供不同的入口文件，同时支持子路径导入。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="7-files---发布文件控制">7. files - 发布文件控制<a href="http://localhost:3000/blog/package-json-fields#7-files---%E5%8F%91%E5%B8%83%E6%96%87%E4%BB%B6%E6%8E%A7%E5%88%B6" class="hash-link" aria-label="7. files - 发布文件控制的直接链接" title="7. files - 发布文件控制的直接链接" translate="no">​</a></h2>
<p>指定发布到 npm 时包含的文件和目录列表。通过精确控制发布内容，可以显著减小包体积并提高下载速度。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"files"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"dist"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"lib"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"README.md"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"package.json"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="使用说明">使用说明<a href="http://localhost:3000/blog/package-json-fields#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="使用说明的直接链接" title="使用说明的直接链接" translate="no">​</a></h3>
<ul>
<li class="">如果不指定，npm 会包含所有文件（除了 <code>.npmignore</code> 或 <code>.gitignore</code> 中排除的）</li>
<li class="">建议只包含必要的文件：构建产物、类型文件、README 等</li>
<li class="">可以使用 <code>npm pack --dry-run</code> 预览将被发布的文件</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="8-engines---环境版本要求">8. engines - 环境版本要求<a href="http://localhost:3000/blog/package-json-fields#8-engines---%E7%8E%AF%E5%A2%83%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82" class="hash-link" aria-label="8. engines - 环境版本要求的直接链接" title="8. engines - 环境版本要求的直接链接" translate="no">​</a></h2>
<p>指定包运行所需的 Node.js 版本或其他运行时环境的版本要求。这有助于避免在不兼容的环境中出现问题。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"engines"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"node"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&gt;=14.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"npm"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&gt;=6.0.0"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="注意事项">注意事项<a href="http://localhost:3000/blog/package-json-fields#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="注意事项的直接链接" title="注意事项的直接链接" translate="no">​</a></h3>
<ul>
<li class="">这只是提示性信息，不会强制阻止安装</li>
<li class="">如需强制检查，可在 <code>.npmrc</code> 中设置 <code>engine-strict=true</code></li>
<li class="">建议设置合理的版本范围，避免过于严格</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="9-scripts---项目自动化脚本">9. scripts - 项目自动化脚本<a href="http://localhost:3000/blog/package-json-fields#9-scripts---%E9%A1%B9%E7%9B%AE%E8%87%AA%E5%8A%A8%E5%8C%96%E8%84%9A%E6%9C%AC" class="hash-link" aria-label="9. scripts - 项目自动化脚本的直接链接" title="9. scripts - 项目自动化脚本的直接链接" translate="no">​</a></h2>
<p>定义可以通过 <code>npm run</code>、<code>yarn run</code> 或 <code>pnpm run</code> 执行的脚本命令。这是项目自动化的核心。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"start"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node server.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"build"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"webpack --mode production"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"test"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"jest"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"dev"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"webpack-dev-server --mode development"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"lint"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"eslint src/"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="常用脚本类型">常用脚本类型<a href="http://localhost:3000/blog/package-json-fields#%E5%B8%B8%E7%94%A8%E8%84%9A%E6%9C%AC%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="常用脚本类型的直接链接" title="常用脚本类型的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>开发脚本</strong>：<code>dev</code>、<code>start</code>、<code>serve</code></li>
<li class=""><strong>构建脚本</strong>：<code>build</code>、<code>compile</code>、<code>bundle</code></li>
<li class=""><strong>测试脚本</strong>：<code>test</code>、<code>test:watch</code>、<code>test:coverage</code></li>
<li class=""><strong>代码质量</strong>：<code>lint</code>、<code>format</code>、<code>type-check</code></li>
<li class=""><strong>发布脚本</strong>：<code>prepublishOnly</code>、<code>publish</code></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="10-keywords---seo-优化关键词">10. keywords - SEO 优化关键词<a href="http://localhost:3000/blog/package-json-fields#10-keywords---seo-%E4%BC%98%E5%8C%96%E5%85%B3%E9%94%AE%E8%AF%8D" class="hash-link" aria-label="10. keywords - SEO 优化关键词的直接链接" title="10. keywords - SEO 优化关键词的直接链接" translate="no">​</a></h2>
<p>用于描述包功能的关键词数组，直接影响在 npm 官网和开发工具中的搜索排名。选择合适的关键词可以显著提高包的可发现性。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-ui-library"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"keywords"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"react"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"ui"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"components"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"typescript"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"design-system"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="11-repository---代码仓库链接">11. repository - 代码仓库链接<a href="http://localhost:3000/blog/package-json-fields#11-repository---%E4%BB%A3%E7%A0%81%E4%BB%93%E5%BA%93%E9%93%BE%E6%8E%A5" class="hash-link" aria-label="11. repository - 代码仓库链接的直接链接" title="11. repository - 代码仓库链接的直接链接" translate="no">​</a></h2>
<p>指定代码仓库的位置和类型。这不仅方便用户查看源代码和提交 issue，还可以让 npm 官网自动显示仓库链接。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"repository"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"git"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"url"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://github.com/username/my-package.git"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="12-license---开源许可证">12. license - 开源许可证<a href="http://localhost:3000/blog/package-json-fields#12-license---%E5%BC%80%E6%BA%90%E8%AE%B8%E5%8F%AF%E8%AF%81" class="hash-link" aria-label="12. license - 开源许可证的直接链接" title="12. license - 开源许可证的直接链接" translate="no">​</a></h2>
<p>指定包的开源许可证类型。这对于明确使用权限和法律责任非常重要，也是开源项目的基本要求。</p>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"license"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"MIT"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="常见许可证类型">常见许可证类型<a href="http://localhost:3000/blog/package-json-fields#%E5%B8%B8%E8%A7%81%E8%AE%B8%E5%8F%AF%E8%AF%81%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="常见许可证类型的直接链接" title="常见许可证类型的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>MIT</strong>：最宽松的许可证，允许几乎任何用途</li>
<li class=""><strong>Apache-2.0</strong>：类似 MIT，但提供专利保护</li>
<li class=""><strong>GPL-3.0</strong>：Copyleft 许可证，衍生作品必须开源</li>
<li class=""><strong>ISC</strong>：与 MIT 类似但更简洁</li>
<li class=""><strong>BSD-3-Clause</strong>：允许修改和重新分发</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="总结">总结<a href="http://localhost:3000/blog/package-json-fields#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>掌握这 12 个 package.json 字段，能够帮你：</p>
<ol>
<li class=""><strong>提升包的兼容性</strong>：通过 <code>peerDependencies</code>、<code>engines</code>、<code>exports</code> 确保在不同环境下正常运行</li>
<li class=""><strong>优化性能</strong>：利用 <code>sideEffects</code>、<code>module</code> 实现更好的 tree-shaking</li>
<li class=""><strong>改善开发体验</strong>：完善的 <code>types</code>、<code>scripts</code> 配置让开发更高效</li>
<li class=""><strong>增强可发现性</strong>：合理的 <code>keywords</code>、<code>repository</code>、<code>license</code> 让包更容易被找到和信任</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="最佳实践建议">最佳实践建议<a href="http://localhost:3000/blog/package-json-fields#%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E5%BB%BA%E8%AE%AE" class="hash-link" aria-label="最佳实践建议的直接链接" title="最佳实践建议的直接链接" translate="no">​</a></h3>
<div class="language-json codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-json codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"awesome-package"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"1.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"description"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"一个很棒的工具包"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"keywords"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"utility"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"typescript"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"modern"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"license"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"MIT"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"repository"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"git"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"url"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://github.com/username/awesome-package.git"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"main"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.cjs.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"module"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.esm.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"types"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"dist/index.d.ts"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"exports"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"."</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"import"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist/index.esm.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"require"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist/index.cjs.js"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"types"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"./dist/index.d.ts"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"files"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"dist"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"README.md"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"engines"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"node"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&gt;=16.0.0"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"build"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"rollup -c"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"test"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"vitest"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type-check"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"tsc --noEmit"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"lint"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"eslint src/"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"prepublishOnly"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npm run build &amp;&amp; npm run test"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"sideEffects"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"peerDependencies"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"react"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&gt;=16.8.0"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"peerDependenciesMeta"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"react"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"optional"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>通过合理配置这些字段，你的 npm 包将具备现代化的特性，为用户提供更好的使用体验。</p>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="Node.js" term="Node.js"/>
        <category label="JavaScript" term="JavaScript"/>
        <category label="技术概念" term="技术概念"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Vi实用技巧]]></title>
        <id>http://localhost:3000/blog/vi-tips</id>
        <link href="http://localhost:3000/blog/vi-tips"/>
        <updated>2019-05-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[vi（或 vim）是类 Unix 系统中非常常用的文本编辑器，凭借其高效的键盘操作和强大的功能，成为许多开发者和运维人员的首选。掌握 vi 的常用技巧，可以大幅提升编辑和处理文件的效率。]]></summary>
        <content type="html"><![CDATA[<p>vi（或 vim）是类 Unix 系统中非常常用的文本编辑器，凭借其高效的键盘操作和强大的功能，成为许多开发者和运维人员的首选。掌握 vi 的常用技巧，可以大幅提升编辑和处理文件的效率。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-基本模式和操作">1. 基本模式和操作<a href="http://localhost:3000/blog/vi-tips#1-%E5%9F%BA%E6%9C%AC%E6%A8%A1%E5%BC%8F%E5%92%8C%E6%93%8D%E4%BD%9C" class="hash-link" aria-label="1. 基本模式和操作的直接链接" title="1. 基本模式和操作的直接链接" translate="no">​</a></h2>
<p>vi 有三种主要模式：</p>
<ul>
<li class=""><strong>命令模式 (Normal mode)</strong>：默认模式，可移动光标、删除、复制等。</li>
<li class=""><strong>插入模式 (Insert mode)</strong>：输入文本。</li>
<li class=""><strong>底线命令模式 (Command-line mode)</strong>：执行保存、退出、搜索等命令（以 <code>:</code> 开头）。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-切换模式命令模式下触发">1.1 切换模式（命令模式下触发）<a href="http://localhost:3000/blog/vi-tips#11-%E5%88%87%E6%8D%A2%E6%A8%A1%E5%BC%8F%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B%E8%A7%A6%E5%8F%91" class="hash-link" aria-label="1.1 切换模式（命令模式下触发）的直接链接" title="1.1 切换模式（命令模式下触发）的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><code>i</code> ：光标前插入（进入插入模式）</li>
<li class=""><code>I</code> ：行首插入（进入插入模式）</li>
<li class=""><code>a</code> ：光标后插入（进入插入模式）</li>
<li class=""><code>A</code> ：行尾插入（进入插入模式）</li>
<li class=""><code>o</code> ：下方新开一行（进入插入模式）</li>
<li class=""><code>O</code> ：上方新开一行（进入插入模式）</li>
<li class=""><code>Esc</code> ：回到命令模式</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-光标移动命令模式下">2. 光标移动（命令模式下）<a href="http://localhost:3000/blog/vi-tips#2-%E5%85%89%E6%A0%87%E7%A7%BB%E5%8A%A8%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B" class="hash-link" aria-label="2. 光标移动（命令模式下）的直接链接" title="2. 光标移动（命令模式下）的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><code>h</code>：左移</li>
<li class=""><code>l</code>：右移</li>
<li class=""><code>j</code>：下移</li>
<li class=""><code>k</code>：上移</li>
<li class=""><code>0</code> ：行首</li>
<li class=""><code>^</code> ：行首非空字符</li>
<li class=""><code>$</code> ：行尾</li>
<li class=""><code>w</code> ：跳到下一个单词开头</li>
<li class=""><code>e</code> ：跳到单词结尾</li>
<li class=""><code>b</code> ：跳到上一个单词开头</li>
<li class=""><code>gg</code> ：文件开头</li>
<li class=""><code>G</code> ：文件结尾</li>
<li class=""><code>H / M / L</code> ：屏幕顶部 / 中间 / 底部</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-文本操作命令模式下">3. 文本操作（命令模式下）<a href="http://localhost:3000/blog/vi-tips#3-%E6%96%87%E6%9C%AC%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B" class="hash-link" aria-label="3. 文本操作（命令模式下）的直接链接" title="3. 文本操作（命令模式下）的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><code>x</code> ：删除光标所在字符</li>
<li class=""><code>dd</code> ：删除整行</li>
<li class=""><code>D</code> ：删除从光标到行尾</li>
<li class=""><code>yy</code> 或 <code>Y</code> ：复制整行</li>
<li class=""><code>p</code> ：粘贴到光标后</li>
<li class=""><code>P</code> ：粘贴到光标前</li>
<li class=""><code>u</code> ：撤销</li>
<li class=""><code>Ctrl+r</code> ：重做</li>
<li class=""><code>&gt;&gt; / &lt;&lt;</code> ：缩进 / 反缩进</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-组合操作命令模式下">3.1 组合操作（命令模式下）<a href="http://localhost:3000/blog/vi-tips#31-%E7%BB%84%E5%90%88%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F%E4%B8%8B" class="hash-link" aria-label="3.1 组合操作（命令模式下）的直接链接" title="3.1 组合操作（命令模式下）的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><code>3dd</code> ：删除 3 行</li>
<li class=""><code>d$</code> ：删除到行尾</li>
<li class=""><code>y}</code> ：复制到段落末尾</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-搜索与替换">4. 搜索与替换<a href="http://localhost:3000/blog/vi-tips#4-%E6%90%9C%E7%B4%A2%E4%B8%8E%E6%9B%BF%E6%8D%A2" class="hash-link" aria-label="4. 搜索与替换的直接链接" title="4. 搜索与替换的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><code>/pattern</code> ：向下搜索 <code>pattern</code>（命令模式触发）</li>
<li class=""><code>?pattern</code> ：向上搜索 <code>pattern</code>（命令模式触发）</li>
<li class=""><code>n</code> ：重复上次搜索（同方向）（命令模式）</li>
<li class=""><code>N</code> ：重复上次搜索（反方向）（命令模式）</li>
<li class=""><code>:%s/old/new/g</code> ：全文件替换 <code>old</code> 为 <code>new</code>（底线命令模式）</li>
<li class=""><code>:%s/old/new/gc</code> ：替换时询问确认（底线命令模式）</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-文件操作底线命令模式">5. 文件操作（底线命令模式）<a href="http://localhost:3000/blog/vi-tips#5-%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E5%BA%95%E7%BA%BF%E5%91%BD%E4%BB%A4%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="5. 文件操作（底线命令模式）的直接链接" title="5. 文件操作（底线命令模式）的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><code>:w</code> ：保存</li>
<li class=""><code>:q</code> ：退出</li>
<li class=""><code>:wq</code> 或 <code>ZZ</code> ：保存并退出</li>
<li class=""><code>:q!</code> ：不保存强制退出</li>
<li class=""><code>:e filename</code> ：打开文件</li>
<li class=""><code>:r filename</code> ：插入另一个文件内容</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-高级技巧">6. 高级技巧<a href="http://localhost:3000/blog/vi-tips#6-%E9%AB%98%E7%BA%A7%E6%8A%80%E5%B7%A7" class="hash-link" aria-label="6. 高级技巧的直接链接" title="6. 高级技巧的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>多行缩进选择</strong>：在命令模式下，<code>V</code> 选择行，然后 <code>&gt;</code> 或 <code>&lt;</code> 缩进</li>
<li class=""><strong>多文件编辑</strong>：<!-- -->
<ul>
<li class=""><code>:n / :N</code> ：下/上一个文件（底线命令模式）</li>
<li class=""><code>:args *.txt</code> ：打开多个文件（底线命令模式）</li>
</ul>
</li>
<li class=""><strong>宏录制</strong>（命令模式）：<!-- -->
<ul>
<li class=""><code>q{register}</code> 开始录制，例如 <code>qa</code></li>
<li class="">执行操作</li>
<li class=""><code>q</code> 停止录制</li>
<li class=""><code>@a</code> 执行宏</li>
</ul>
</li>
<li class=""><strong>折叠代码</strong>（命令模式）：<!-- -->
<ul>
<li class=""><code>zf{motion}</code> ：折叠</li>
<li class=""><code>zo / zc</code> ：打开/关闭折叠</li>
<li class=""><code>za</code> ：切换折叠</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="7-提高效率的技巧">7. 提高效率的技巧<a href="http://localhost:3000/blog/vi-tips#7-%E6%8F%90%E9%AB%98%E6%95%88%E7%8E%87%E7%9A%84%E6%8A%80%E5%B7%A7" class="hash-link" aria-label="7. 提高效率的技巧的直接链接" title="7. 提高效率的技巧的直接链接" translate="no">​</a></h2>
<ul>
<li class="">使用 <code>.</code> 重复上次命令（命令模式）</li>
<li class="">使用 <code>Ctrl+o</code> 返回上次跳转位置（命令模式）</li>
<li class=""><code>:set number</code> 显示行号（底线命令模式）</li>
<li class=""><code>:set relativenumber</code> 显示相对行号（底线命令模式）</li>
<li class="">使用 <code>:set hlsearch</code> 高亮搜索（底线命令模式）</li>
<li class="">使用 <code>:set incsearch</code> 边输入边搜索（底线命令模式）</li>
</ul>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="技术概念" term="技术概念"/>
        <category label="文件操作" term="文件操作"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[进程与线程]]></title>
        <id>http://localhost:3000/blog/process-and-thread</id>
        <link href="http://localhost:3000/blog/process-and-thread"/>
        <updated>2018-06-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[想象你正在经营一家餐厅，需要同时服务多位客人。这个场景恰好能完美地解释操作系统中的进程和线程。]]></summary>
        <content type="html"><![CDATA[<p>想象你正在经营一家餐厅，需要同时服务多位客人。这个场景恰好能完美地解释操作系统中的进程和线程。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-一个餐厅的故事">1. 一个餐厅的故事<a href="http://localhost:3000/blog/process-and-thread#1-%E4%B8%80%E4%B8%AA%E9%A4%90%E5%8E%85%E7%9A%84%E6%95%85%E4%BA%8B" class="hash-link" aria-label="1. 一个餐厅的故事的直接链接" title="1. 一个餐厅的故事的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="11-场景一每个客人一家餐厅多进程模型">1.1 场景一：每个客人一家餐厅（多进程模型）<a href="http://localhost:3000/blog/process-and-thread#11-%E5%9C%BA%E6%99%AF%E4%B8%80%E6%AF%8F%E4%B8%AA%E5%AE%A2%E4%BA%BA%E4%B8%80%E5%AE%B6%E9%A4%90%E5%8E%85%E5%A4%9A%E8%BF%9B%E7%A8%8B%E6%A8%A1%E5%9E%8B" class="hash-link" aria-label="1.1 场景一：每个客人一家餐厅（多进程模型）的直接链接" title="1.1 场景一：每个客人一家餐厅（多进程模型）的直接链接" translate="no">​</a></h3>
<p>假设你为每位客人开一家独立的餐厅：</p>
<ul>
<li class=""><strong>每家餐厅</strong>（进程）都有自己的厨房、餐具、食材、服务员</li>
<li class=""><strong>完全隔离</strong>：A 餐厅的客人不会影响 B 餐厅的客人</li>
<li class=""><strong>成本高昂</strong>：每开一家新餐厅，都要买地、装修、招人、采购设备</li>
<li class=""><strong>沟通困难</strong>：两家餐厅的厨师想交流菜谱，得打电话、发邮件</li>
</ul>
<p>这就是<strong>进程</strong>的特点：<strong>独立、安全，但资源消耗大</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="12-场景二一家餐厅多个服务员多线程模型">1.2 场景二：一家餐厅多个服务员（多线程模型）<a href="http://localhost:3000/blog/process-and-thread#12-%E5%9C%BA%E6%99%AF%E4%BA%8C%E4%B8%80%E5%AE%B6%E9%A4%90%E5%8E%85%E5%A4%9A%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%91%98%E5%A4%9A%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%9E%8B" class="hash-link" aria-label="1.2 场景二：一家餐厅多个服务员（多线程模型）的直接链接" title="1.2 场景二：一家餐厅多个服务员（多线程模型）的直接链接" translate="no">​</a></h3>
<p>现在改成一家大餐厅，有多个服务员：</p>
<ul>
<li class=""><strong>同一个餐厅</strong>（进程）内，多个<strong>服务员</strong>（线程）同时工作</li>
<li class=""><strong>共享资源</strong>：共用一个厨房、仓库、收银台</li>
<li class=""><strong>协作高效</strong>：服务员可以直接在厨房窗口交流</li>
<li class=""><strong>相互影响</strong>：一个服务员打翻了酱料，可能影响其他服务员的工作</li>
<li class=""><strong>成本低</strong>：只需要雇佣新员工，不用再开新餐厅</li>
</ul>
<p>这就是<strong>线程</strong>的特点：<strong>轻量、共享资源，但需要协调</strong>。</p>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-进程独立的餐厅">2. 进程：独立的餐厅<a href="http://localhost:3000/blog/process-and-thread#2-%E8%BF%9B%E7%A8%8B%E7%8B%AC%E7%AB%8B%E7%9A%84%E9%A4%90%E5%8E%85" class="hash-link" aria-label="2. 进程：独立的餐厅的直接链接" title="2. 进程：独立的餐厅的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="21-餐厅的房间内存空间">2.1 餐厅的"房间"（内存空间）<a href="http://localhost:3000/blog/process-and-thread#21-%E9%A4%90%E5%8E%85%E7%9A%84%E6%88%BF%E9%97%B4%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4" class="hash-link" aria-label="2.1 餐厅的&quot;房间&quot;（内存空间）的直接链接" title="2.1 餐厅的&quot;房间&quot;（内存空间）的直接链接" translate="no">​</a></h3>
<p>每个进程就像一家独立餐厅，有自己的"房间"：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">🏢 进程餐厅 A 号</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 📖 菜单（代码段）        ← 固定不变的菜谱</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 🗄️ 仓库（数据段）        ← 存放食材和餐具</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 📦 临时仓库（堆）         ← 随时补货的空间</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 📋 订单板（栈）           ← 当前正在处理的订单</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── 📊 管理记录（PCB）        ← 餐厅运营状态</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="22-餐厅的营业状态进程状态">2.2 餐厅的"营业状态"（进程状态）<a href="http://localhost:3000/blog/process-and-thread#22-%E9%A4%90%E5%8E%85%E7%9A%84%E8%90%A5%E4%B8%9A%E7%8A%B6%E6%80%81%E8%BF%9B%E7%A8%8B%E7%8A%B6%E6%80%81" class="hash-link" aria-label="2.2 餐厅的&quot;营业状态&quot;（进程状态）的直接链接" title="2.2 餐厅的&quot;营业状态&quot;（进程状态）的直接链接" translate="no">​</a></h3>
<p>一家餐厅的一天：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">🏗️ 装修中（新建）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">⏳ 准备营业（就绪） → 等待市场监督局批准</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">🍳 正在营业（运行） → 厨师正在炒菜</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">⏸️ 暂停营业（阻塞） → 食材用完了，等待供应商送货</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ↓</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">🏁 歇业（终止）</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="23-餐厅间如何沟通进程间通信">2.3 餐厅间如何沟通？（进程间通信）<a href="http://localhost:3000/blog/process-and-thread#23-%E9%A4%90%E5%8E%85%E9%97%B4%E5%A6%82%E4%BD%95%E6%B2%9F%E9%80%9A%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1" class="hash-link" aria-label="2.3 餐厅间如何沟通？（进程间通信）的直接链接" title="2.3 餐厅间如何沟通？（进程间通信）的直接链接" translate="no">​</a></h3>
<p>既然每家餐厅独立，它们怎么交流呢？</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="231-方式一电话专线管道-pipe">2.3.1 方式一：电话专线（管道 Pipe）<a href="http://localhost:3000/blog/process-and-thread#231-%E6%96%B9%E5%BC%8F%E4%B8%80%E7%94%B5%E8%AF%9D%E4%B8%93%E7%BA%BF%E7%AE%A1%E9%81%93-pipe" class="hash-link" aria-label="2.3.1 方式一：电话专线（管道 Pipe）的直接链接" title="2.3.1 方式一：电话专线（管道 Pipe）的直接链接" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 餐厅 A 把客流量数据传给餐厅 B 分析</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ps aux | grep "node"</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="232-方式二留言板消息队列">2.3.2 方式二：留言板（消息队列）<a href="http://localhost:3000/blog/process-and-thread#232-%E6%96%B9%E5%BC%8F%E4%BA%8C%E7%95%99%E8%A8%80%E6%9D%BF%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97" class="hash-link" aria-label="2.3.2 方式二：留言板（消息队列）的直接链接" title="2.3.2 方式二：留言板（消息队列）的直接链接" translate="no">​</a></h4>
<div class="language-js codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-js codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 餐厅 A 在公共留言板留言</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">messageQueue</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">send</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword module" style="color:#00009f">from</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"餐厅A"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"今日鱼类特别新鲜"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 餐厅 B 查看留言</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">messageQueue</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">receive</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="233-方式三共享仓库共享内存">2.3.3 方式三：共享仓库（共享内存）<a href="http://localhost:3000/blog/process-and-thread#233-%E6%96%B9%E5%BC%8F%E4%B8%89%E5%85%B1%E4%BA%AB%E4%BB%93%E5%BA%93%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98" class="hash-link" aria-label="2.3.3 方式三：共享仓库（共享内存）的直接链接" title="2.3.3 方式三：共享仓库（共享内存）的直接链接" translate="no">​</a></h4>
<ul>
<li class="">最快，但需要预约制度（锁机制）</li>
<li class="">避免两个餐厅同时去仓库拿同一包面粉</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="234-方式四发传单信号">2.3.4 方式四：发传单（信号）<a href="http://localhost:3000/blog/process-and-thread#234-%E6%96%B9%E5%BC%8F%E5%9B%9B%E5%8F%91%E4%BC%A0%E5%8D%95%E4%BF%A1%E5%8F%B7" class="hash-link" aria-label="2.3.4 方式四：发传单（信号）的直接链接" title="2.3.4 方式四：发传单（信号）的直接链接" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-bash codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain"># 市场监督局给餐厅发停业信号</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">kill -9 &lt;餐厅ID&gt;</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-线程餐厅里的服务员">3. 线程：餐厅里的服务员<a href="http://localhost:3000/blog/process-and-thread#3-%E7%BA%BF%E7%A8%8B%E9%A4%90%E5%8E%85%E9%87%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%91%98" class="hash-link" aria-label="3. 线程：餐厅里的服务员的直接链接" title="3. 线程：餐厅里的服务员的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="31-一个服务员的工具箱">3.1 一个服务员的"工具箱"<a href="http://localhost:3000/blog/process-and-thread#31-%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%91%98%E7%9A%84%E5%B7%A5%E5%85%B7%E7%AE%B1" class="hash-link" aria-label="3.1 一个服务员的&quot;工具箱&quot;的直接链接" title="3.1 一个服务员的&quot;工具箱&quot;的直接链接" translate="no">​</a></h3>
<p>每个线程（服务员）有自己的：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">👤 服务员小李（线程 1）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 🆔 工号牌（线程 ID）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 📝 记事本（程序计数器） → 记住"我刚做到哪一步"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── 👐 手里拿的东西（寄存器） → 当前正在处理的菜单</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── 🎒 个人背包（栈）       → 存放临时数据</span><br></div></code></pre></div></div>
<p>但他们<strong>共享</strong>餐厅的：</p>
<ul>
<li class="">厨房（堆内存）</li>
<li class="">食材仓库（全局变量）</li>
<li class="">收银台（文件句柄）</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="32-两种管理方式">3.2 两种管理方式<a href="http://localhost:3000/blog/process-and-thread#32-%E4%B8%A4%E7%A7%8D%E7%AE%A1%E7%90%86%E6%96%B9%E5%BC%8F" class="hash-link" aria-label="3.2 两种管理方式的直接链接" title="3.2 两种管理方式的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="321-方式一服务员自己协调用户级线程">3.2.1 方式一：服务员自己协调（用户级线程）<a href="http://localhost:3000/blog/process-and-thread#321-%E6%96%B9%E5%BC%8F%E4%B8%80%E6%9C%8D%E5%8A%A1%E5%91%98%E8%87%AA%E5%B7%B1%E5%8D%8F%E8%B0%83%E7%94%A8%E6%88%B7%E7%BA%A7%E7%BA%BF%E7%A8%8B" class="hash-link" aria-label="3.2.1 方式一：服务员自己协调（用户级线程）的直接链接" title="3.2.1 方式一：服务员自己协调（用户级线程）的直接链接" translate="no">​</a></h4>
<ul>
<li class="">服务员们商量好谁做什么</li>
<li class="">老板（操作系统）不关心</li>
<li class="">灵活高效，但一个服务员累倒了，老板都不知道</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="322-方式二老板统一调度内核级线程">3.2.2 方式二：老板统一调度（内核级线程）<a href="http://localhost:3000/blog/process-and-thread#322-%E6%96%B9%E5%BC%8F%E4%BA%8C%E8%80%81%E6%9D%BF%E7%BB%9F%E4%B8%80%E8%B0%83%E5%BA%A6%E5%86%85%E6%A0%B8%E7%BA%A7%E7%BA%BF%E7%A8%8B" class="hash-link" aria-label="3.2.2 方式二：老板统一调度（内核级线程）的直接链接" title="3.2.2 方式二：老板统一调度（内核级线程）的直接链接" translate="no">​</a></h4>
<ul>
<li class="">老板安排每个服务员的工作</li>
<li class="">可以把服务员派到不同区域（多核 CPU）</li>
<li class="">调度有开销，但更可靠</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-形象对比进程-vs-线程">4. 形象对比：进程 vs 线程<a href="http://localhost:3000/blog/process-and-thread#4-%E5%BD%A2%E8%B1%A1%E5%AF%B9%E6%AF%94%E8%BF%9B%E7%A8%8B-vs-%E7%BA%BF%E7%A8%8B" class="hash-link" aria-label="4. 形象对比：进程 vs 线程的直接链接" title="4. 形象对比：进程 vs 线程的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>对比维度</th><th>进程（独立餐厅）</th><th>线程（餐厅服务员）</th></tr></thead><tbody><tr><td><strong>独立性</strong></td><td>🏢 各自有独立的厨房和仓库</td><td>👥 共享同一个厨房和仓库</td></tr><tr><td><strong>开业成本</strong></td><td>💰💰💰 需要买地、装修、采购</td><td>💰 只需雇一个新员工</td></tr><tr><td><strong>沟通方式</strong></td><td>📞 打电话、发邮件</td><td>💬 直接在厨房窗口喊话</td></tr><tr><td><strong>出事影响</strong></td><td>✅ 一家倒闭不影响其他</td><td>⚠️ 一人犯错可能影响全餐厅</td></tr><tr><td><strong>切换成本</strong></td><td>🚗 开车去另一家餐厅（慢）</td><td>🚶 走几步到另一个餐桌（快）</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-协程服务员的分身术">5. 协程：服务员的"分身术"<a href="http://localhost:3000/blog/process-and-thread#5-%E5%8D%8F%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%91%98%E7%9A%84%E5%88%86%E8%BA%AB%E6%9C%AF" class="hash-link" aria-label="5. 协程：服务员的&quot;分身术&quot;的直接链接" title="5. 协程：服务员的&quot;分身术&quot;的直接链接" translate="no">​</a></h2>
<p>如果说线程是服务员，<strong>协程 (Coroutine)</strong> 就是服务员的"分身术"。</p>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="51-核心概念">5.1 核心概念<a href="http://localhost:3000/blog/process-and-thread#51-%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5" class="hash-link" aria-label="5.1 核心概念的直接链接" title="5.1 核心概念的直接链接" translate="no">​</a></h3>
<p>协程是<strong>用户态的轻量级线程</strong>，不由操作系统内核管理，而是由程序自己控制。</p>
<ul>
<li class=""><strong>极度轻量</strong>：占用内存极小（几 KB vs 线程的几 MB）。</li>
<li class=""><strong>完全可控</strong>：程序自己决定何时切换（非抢占式）。</li>
<li class=""><strong>无锁优势</strong>：同一线程内串行执行，无需复杂的锁机制。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="52-形象比喻">5.2 形象比喻<a href="http://localhost:3000/blog/process-and-thread#52-%E5%BD%A2%E8%B1%A1%E6%AF%94%E5%96%BB" class="hash-link" aria-label="5.2 形象比喻的直接链接" title="5.2 形象比喻的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><strong>多线程</strong>：雇佣 10 个服务员，每人专门盯着一桌客人。</li>
<li class=""><strong>协程</strong>：雇佣 1 个超级服务员，利用客人思考（I/O 等待）的空隙，快速在多桌之间切换服务。<!-- -->
<ul>
<li class=""><strong>结果</strong>：一个人干了 10 个人的活，且省去了服务员交接班的开销。</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="6-选择指南开什么样的餐厅">6. 选择指南：开什么样的餐厅？<a href="http://localhost:3000/blog/process-and-thread#6-%E9%80%89%E6%8B%A9%E6%8C%87%E5%8D%97%E5%BC%80%E4%BB%80%E4%B9%88%E6%A0%B7%E7%9A%84%E9%A4%90%E5%8E%85" class="hash-link" aria-label="6. 选择指南：开什么样的餐厅？的直接链接" title="6. 选择指南：开什么样的餐厅？的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="61-场景一数据计算工厂cpu-密集型">6.1 场景一：数据计算工厂（CPU 密集型）<a href="http://localhost:3000/blog/process-and-thread#61-%E5%9C%BA%E6%99%AF%E4%B8%80%E6%95%B0%E6%8D%AE%E8%AE%A1%E7%AE%97%E5%B7%A5%E5%8E%82cpu-%E5%AF%86%E9%9B%86%E5%9E%8B" class="hash-link" aria-label="6.1 场景一：数据计算工厂（CPU 密集型）的直接链接" title="6.1 场景一：数据计算工厂（CPU 密集型）的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="611-问题">6.1.1 问题<a href="http://localhost:3000/blog/process-and-thread#611-%E9%97%AE%E9%A2%98" class="hash-link" aria-label="6.1.1 问题的直接链接" title="6.1.1 问题的直接链接" translate="no">​</a></h4>
<p>需要处理 1000 万张图片，每张都要压缩、加水印。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="612-选择多进程">6.1.2 选择：多进程<a href="http://localhost:3000/blog/process-and-thread#612-%E9%80%89%E6%8B%A9%E5%A4%9A%E8%BF%9B%E7%A8%8B" class="hash-link" aria-label="6.1.2 选择：多进程的直接链接" title="6.1.2 选择：多进程的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">为什么？</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">📷 图片处理 = 厨师做菜（需要真材实料地计算）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">🔥 CPU = 炉灶（只有 4 个炉灶，同时最多炒 4 个菜）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">✅ 开 4 家独立餐厅（4 个进程），每家用一个炉灶</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">❌ 一家餐厅 100 个服务员，但只有 4 个炉灶 → 大家抢着用，效率低</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="613-最优配置">6.1.3 最优配置<a href="http://localhost:3000/blog/process-and-thread#613-%E6%9C%80%E4%BC%98%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="6.1.3 最优配置的直接链接" title="6.1.3 最优配置的直接链接" translate="no">​</a></h4>
<ul>
<li class="">进程数 = CPU 核心数（如 4 核 CPU → 4 个进程）</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="62-场景二客服中心io-密集型">6.2 场景二：客服中心（I/O 密集型）<a href="http://localhost:3000/blog/process-and-thread#62-%E5%9C%BA%E6%99%AF%E4%BA%8C%E5%AE%A2%E6%9C%8D%E4%B8%AD%E5%BF%83io-%E5%AF%86%E9%9B%86%E5%9E%8B" class="hash-link" aria-label="6.2 场景二：客服中心（I/O 密集型）的直接链接" title="6.2 场景二：客服中心（I/O 密集型）的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="621-问题">6.2.1 问题<a href="http://localhost:3000/blog/process-and-thread#621-%E9%97%AE%E9%A2%98" class="hash-link" aria-label="6.2.1 问题的直接链接" title="6.2.1 问题的直接链接" translate="no">​</a></h4>
<p>同时服务 10000 个在线聊天的用户。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="622-选择事件驱动nodejs或协程go">6.2.2 选择：事件驱动（Node.js）或协程（Go）<a href="http://localhost:3000/blog/process-and-thread#622-%E9%80%89%E6%8B%A9%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8nodejs%E6%88%96%E5%8D%8F%E7%A8%8Bgo" class="hash-link" aria-label="6.2.2 选择：事件驱动（Node.js）或协程（Go）的直接链接" title="6.2.2 选择：事件驱动（Node.js）或协程（Go）的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">为什么？</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">💬 聊天 = 客人点餐后等待（大部分时间在等，不占用 CPU）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">✅ 协程/事件驱动：一个超级店员，利用等待间隙处理 10000 个客人</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">❌ 多线程：10000 个服务员挤在一起（内存爆炸，管理混乱）</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="63-场景三视频剪辑软件需要共享数据">6.3 场景三：视频剪辑软件（需要共享数据）<a href="http://localhost:3000/blog/process-and-thread#63-%E5%9C%BA%E6%99%AF%E4%B8%89%E8%A7%86%E9%A2%91%E5%89%AA%E8%BE%91%E8%BD%AF%E4%BB%B6%E9%9C%80%E8%A6%81%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="6.3 场景三：视频剪辑软件（需要共享数据）的直接链接" title="6.3 场景三：视频剪辑软件（需要共享数据）的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="631-问题">6.3.1 问题<a href="http://localhost:3000/blog/process-and-thread#631-%E9%97%AE%E9%A2%98" class="hash-link" aria-label="6.3.1 问题的直接链接" title="6.3.1 问题的直接链接" translate="no">​</a></h4>
<p>多个功能模块需要频繁访问同一段视频数据。</p>
<h4 class="anchor anchorTargetStickyNavbar_iy8F" id="632-选择多线程">6.3.2 选择：多线程<a href="http://localhost:3000/blog/process-and-thread#632-%E9%80%89%E6%8B%A9%E5%A4%9A%E7%BA%BF%E7%A8%8B" class="hash-link" aria-label="6.3.2 选择：多线程的直接链接" title="6.3.2 选择：多线程的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">为什么？</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">🎬 视频数据 = 厨房的食材仓库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">✅ 多个服务员共用一个厨房仓库（多线程共享内存）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">❌ 每个服务员开一家餐厅（多进程）→ 每家都要复制一份食材，浪费</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="7-性能的秘密">7. 性能的秘密<a href="http://localhost:3000/blog/process-and-thread#7-%E6%80%A7%E8%83%BD%E7%9A%84%E7%A7%98%E5%AF%86" class="hash-link" aria-label="7. 性能的秘密的直接链接" title="7. 性能的秘密的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="71-切换的代价">7.1 切换的代价<a href="http://localhost:3000/blog/process-and-thread#71-%E5%88%87%E6%8D%A2%E7%9A%84%E4%BB%A3%E4%BB%B7" class="hash-link" aria-label="7.1 切换的代价的直接链接" title="7.1 切换的代价的直接链接" translate="no">​</a></h3>
<p>想象你在做三件事：<strong>炒菜、接电话、辅导孩子作业</strong>。</p>
<ul>
<li class="">
<p><strong>进程切换</strong> = 🏠 跑到另一个房间</p>
<ul>
<li class="">需要带走所有工具和材料</li>
<li class="">花费时间：<strong>微秒级</strong>（很慢）</li>
</ul>
</li>
<li class="">
<p><strong>线程切换</strong> = 🚶 走到桌子另一边</p>
<ul>
<li class="">只需要换个位置，工具还在</li>
<li class="">花费时间：<strong>纳秒级</strong>（快）</li>
</ul>
</li>
<li class="">
<p><strong>协程切换</strong> = 👀 眼神转移</p>
<ul>
<li class="">只是注意力转移</li>
<li class="">花费时间：<strong>几乎为 0</strong>（超快）</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="8-总结餐厅管理学">8. 总结：餐厅管理学<a href="http://localhost:3000/blog/process-and-thread#8-%E6%80%BB%E7%BB%93%E9%A4%90%E5%8E%85%E7%AE%A1%E7%90%86%E5%AD%A6" class="hash-link" aria-label="8. 总结：餐厅管理学的直接链接" title="8. 总结：餐厅管理学的直接链接" translate="no">​</a></h2>
<table><thead><tr><th style="text-align:left">概念</th><th style="text-align:left">比喻</th><th style="text-align:left">特点</th><th style="text-align:left">适用场景</th></tr></thead><tbody><tr><td style="text-align:left"><strong>进程</strong></td><td style="text-align:left">独立餐厅</td><td style="text-align:left">资源隔离，成本高，安全</td><td style="text-align:left">CPU 密集型 (Chrome 各个 Tab)</td></tr><tr><td style="text-align:left"><strong>线程</strong></td><td style="text-align:left">服务员</td><td style="text-align:left">资源共享，成本低，需同步</td><td style="text-align:left">数据共享型 (视频编辑)</td></tr><tr><td style="text-align:left"><strong>协程</strong></td><td style="text-align:left">分身术</td><td style="text-align:left">极致轻量，用户态调度</td><td style="text-align:left">高并发 I/O (聊天服务、网关)</td></tr></tbody></table>
<p><strong>最佳实践</strong>：</p>
<ul>
<li class=""><strong>CPU 密集型</strong>：进程/线程数 ≈ CPU 核心数</li>
<li class=""><strong>I/O 密集型</strong>：使用协程或事件驱动</li>
<li class=""><strong>资源复用</strong>：使用线程池/连接池</li>
<li class=""><strong>安全第一</strong>：多线程读写必须加锁</li>
</ul>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="操作系统" term="操作系统"/>
        <category label="并发编程" term="并发编程"/>
        <category label="进程" term="进程"/>
        <category label="线程" term="线程"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Glob语法]]></title>
        <id>http://localhost:3000/blog/glob-syntax</id>
        <link href="http://localhost:3000/blog/glob-syntax"/>
        <updated>2018-03-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Glob 是文件路径匹配的一种模式语法，常用于 Node.js、Python 等脚本工具中，比如 glob、fast-glob 或 bash 中的文件匹配。掌握 glob 语法对于文件操作和构建工具配置非常重要。]]></summary>
        <content type="html"><![CDATA[<p>Glob 是文件路径匹配的一种模式语法，常用于 Node.js、Python 等脚本工具中，比如 glob、fast-glob 或 bash 中的文件匹配。掌握 glob 语法对于文件操作和构建工具配置非常重要。</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="1-基本通配符">1. 基本通配符<a href="http://localhost:3000/blog/glob-syntax#1-%E5%9F%BA%E6%9C%AC%E9%80%9A%E9%85%8D%E7%AC%A6" class="hash-link" aria-label="1. 基本通配符的直接链接" title="1. 基本通配符的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>符号</th><th>含义</th><th>示例</th></tr></thead><tbody><tr><td><code>*</code></td><td>匹配任意数量的任意字符（不包括 <code>/</code>）</td><td><code>*.js</code> → 匹配 <code>app.js</code>, <code>index.js</code></td></tr><tr><td><code>?</code></td><td>匹配单个字符</td><td><code>file?.txt</code> → <code>file1.txt</code>, <code>fileA.txt</code></td></tr><tr><td><code>[abc]</code></td><td>匹配方括号内的任意字符</td><td><code>file[12].txt</code> → <code>file1.txt</code>, <code>file2.txt</code></td></tr><tr><td><code>[a-z]</code></td><td>匹配范围内的字符</td><td><code>file[a-c].txt</code> → <code>filea.txt</code>, <code>fileb.txt</code>, <code>filec.txt</code></td></tr><tr><td><code>[!a-c]</code></td><td>匹配不在范围内的字符</td><td><code>file[!a-c].txt</code> → <code>filed.txt</code>, <code>filez.txt</code></td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="2-递归匹配">2. 递归匹配<a href="http://localhost:3000/blog/glob-syntax#2-%E9%80%92%E5%BD%92%E5%8C%B9%E9%85%8D" class="hash-link" aria-label="2. 递归匹配的直接链接" title="2. 递归匹配的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>符号</th><th>含义</th><th>示例</th></tr></thead><tbody><tr><td><code>**</code></td><td>匹配任意数量的子目录</td><td><code>src/**/*.js</code> → <code>src/app.js</code>, <code>src/components/button.js</code></td></tr></tbody></table>
<blockquote>
<p><strong>注意：</strong> 在一些工具中，<code>**</code> 必须与 <code>/</code> 结合才能匹配子目录。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="3-组合和分隔">3. 组合和分隔<a href="http://localhost:3000/blog/glob-syntax#3-%E7%BB%84%E5%90%88%E5%92%8C%E5%88%86%E9%9A%94" class="hash-link" aria-label="3. 组合和分隔的直接链接" title="3. 组合和分隔的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>符号</th><th>含义</th><th>示例</th></tr></thead><tbody><tr><td><code>{a,b}</code></td><td>匹配 a 或 b</td><td><code>*.{js,ts}</code> → 匹配 <code>.js</code> 或 <code>.ts</code> 文件</td></tr><tr><td><code>,</code></td><td>用在 <code>{}</code> 内表示选择</td><td>同上</td></tr><tr><td><code>/</code></td><td>目录分隔符</td><td><code>src/*.js</code> → 匹配 <code>src</code> 目录下的 <code>.js</code> 文件</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="4-实际应用示例">4. 实际应用示例<a href="http://localhost:3000/blog/glob-syntax#4-%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="4. 实际应用示例的直接链接" title="4. 实际应用示例的直接链接" translate="no">​</a></h2>
<p>假设目录结构如下：</p>
<div class="language-text codeBlockContainer_cCYc theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QiGi"><pre tabindex="0" class="prism-code language-text codeBlock_jYaH thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_TDjf"><div class="token-line" style="color:#393A34"><span class="token plain">project/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├─ src/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  ├─ index.js</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  ├─ app.ts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  └─ utils/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│     ├─ helper.js</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│     └─ data.ts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└─ test/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   └─ test.js</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="41-基本匹配示例">4.1 基本匹配示例<a href="http://localhost:3000/blog/glob-syntax#41-%E5%9F%BA%E6%9C%AC%E5%8C%B9%E9%85%8D%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="4.1 基本匹配示例的直接链接" title="4.1 基本匹配示例的直接链接" translate="no">​</a></h3>
<ul>
<li class=""><code>src/*.js</code> → <code>src/index.js</code></li>
<li class=""><code>src/**/*.js</code> → <code>src/index.js</code>, <code>src/utils/helper.js</code></li>
<li class=""><code>**/*.ts</code> → <code>src/app.ts</code>, <code>src/utils/data.ts</code></li>
<li class=""><code>**/*.{js,ts}</code> → 匹配所有 JS 和 TS 文件</li>
<li class=""><code>test/?est.js</code> → <code>test/test.js</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_iy8F" id="42-常用模式">4.2 常用模式<a href="http://localhost:3000/blog/glob-syntax#42-%E5%B8%B8%E7%94%A8%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="4.2 常用模式的直接链接" title="4.2 常用模式的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>模式</th><th>说明</th><th>示例</th></tr></thead><tbody><tr><td><code>**/*.js</code></td><td>匹配所有 JS 文件</td><td>递归查找所有 <code>.js</code> 文件</td></tr><tr><td><code>src/**/*.{js,ts,jsx,tsx}</code></td><td>匹配源码文件</td><td>匹配常见的源码文件类型</td></tr><tr><td><code>!**/*.test.js</code></td><td>排除测试文件</td><td>使用 <code>!</code> 前缀排除匹配</td></tr><tr><td><code>**/node_modules/**</code></td><td>匹配 node_modules</td><td>常用于排除目录</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_iy8F" id="5-注意事项">5. 注意事项<a href="http://localhost:3000/blog/glob-syntax#5-%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9" class="hash-link" aria-label="5. 注意事项的直接链接" title="5. 注意事项的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><strong>工具差异</strong>：不同工具对 glob 语法的支持可能有差异</li>
<li class=""><strong>性能考虑</strong>：<code>**</code> 递归匹配可能影响性能，谨慎使用</li>
<li class=""><strong>转义字符</strong>：特殊字符可能需要转义</li>
<li class=""><strong>大小写敏感</strong>：在 Linux/macOS 上区分大小写，Windows 不区分</li>
</ol>]]></content>
        <author>
            <name>XingHunm</name>
            <email>fengyueran@foxmail.com</email>
            <uri>https://github.com/fengyueran</uri>
        </author>
        <category label="技术概念" term="技术概念"/>
        <category label="文件操作" term="文件操作"/>
    </entry>
</feed>