自动化部署测试

自动化部署测试 这是一个用于测试自动化部署流程的文档。当这个文档被推送时,应该触发以下流程: obsidian-notes 仓库检测到内容变更 触发 hugo-server 仓库的构建流程 hugo-server 拉取最新内容并构建网站 部署到 GitHub Pages 测试内容 - 自动化部署流程 - 子模块更新 - CI/CD 触发机制 验证 通过创建此文档,我们可以验证: ✅ Obsidian 和 Hugo 集成 ✅ Git 子模块工作流 ✅ GitHub Actions 触发机制 ✅ 自动化部署流程 测试时间: 2025-11-20

 ·   ·  views

Hugo 博客自动化工作流完整指南

Hugo 博客自动化工作流完整指南 这是一份详尽的工作流文档,记录了从零搭建 Hugo + Obsidian + GitHub Actions 自动化博客系统的完整过程,包括所有细节、注意事项和故障排除方法。 📋 目录 系统架构 仓库结构 配置步骤 工作流详解 日常使用 故障排除 注意事项 进阶优化 🏗️ 系统架构 设计理念 目标: 实现"写作 → 提交 → 自动发布"的无缝工作流。 核心原则: 内容与配置分离 环境可复现 自动化部署 本地与 CI 一致 三仓库架构 hugo-server (主仓库) ├── jesse-blog/ │ ├── content/ → obsidian-notes (子模块) │ ├── public/ → JiashuaiXu.github.io (子模块) │ ├── themes/ │ └── hugo.toml └── flake.nix obsidian-notes (内容仓库) ├── posts/ ├── about/ ├── archive/ └── .github/workflows/deploy.yml JiashuaiXu.github.io (部署仓库) └── (Hugo 生成的静态文件) 职责划分 仓库 用途 操作频率 是否需要手动操作 hugo-server Hugo 配置、主题、Nix 环境 偶尔更新配置 是 obsidian-notes 编写内容(日常工作) 频繁提交 是 JiashuaiXu.github.io 托管静态网站 自动更新 否 📁 仓库结构 hugo-server (主仓库) hugo-server/ ├── .gitmodules # ⚠️ 关键:子模块配置 ├── flake.nix # Nix 环境定义 ├── deploy.sh # 本地部署脚本 └── jesse-blog/ ├── content/ # → obsidian-notes (子模块) ├── public/ # → JiashuaiXu.github.io (子模块) ├── themes/ │ └── hugo-PaperMod/ # 当前使用的主题 └── hugo.toml # Hugo 配置文件 obsidian-notes (内容仓库) obsidian-notes/ ├── .github/workflows/ │ └── deploy.yml # ⚠️ 自动部署工作流 ├── README.md ├── posts/ # 博客文章目录 ├── about/ └── archive/ ⚙️ 配置步骤 1. 创建 obsidian-notes 仓库 在 GitHub 创建空仓库: ...

 ·   ·  views

博客自动化部署配置全记录

博客自动化部署配置全记录 记录从零开始搭建 Hugo + Obsidian + GitHub Actions 自动化博客系统的完整过程。 🎯 目标 实现一个完全自动化的博客发布流程: 在 Obsidian 中编写 Markdown 文章 提交到 Git 仓库 自动编译并发布到 GitHub Pages 🏗️ 架构设计 仓库结构 hugo-server (主仓库) ├── jesse-blog/ │ ├── content/ → obsidian-notes (子模块) │ ├── public/ → JiashuaiXu.github.io (子模块) │ ├── themes/ │ └── hugo.toml └── flake.nix obsidian-notes (内容仓库) ├── posts/ ├── about/ ├── archive/ └── .github/workflows/ └── deploy.yml # 自动部署工作流 JiashuaiXu.github.io (部署仓库) └── (Hugo 生成的静态文件) 三个仓库的职责 仓库 用途 操作频率 hugo-server Hugo 项目配置、主题管理 偶尔更新 obsidian-notes 编写内容(日常操作) 频繁提交 JiashuaiXu.github.io 托管静态网站 自动更新 📝 实施步骤 1. 子模块化内容管理 问题: 原来 content/ 目录直接在主仓库中,不便于独立管理。 ...

 ·   ·  views

使用 Nix Flakes 管理 Hugo 开发环境

使用 Nix Flakes 管理 Hugo 开发环境 Nix Flakes 提供了可复现的开发环境,完美适配 Hugo 项目。 为什么选择 Nix? 可复现性:任何人都能获得完全相同的环境 隔离性:不污染系统环境 版本锁定:确保依赖版本一致 flake.nix 配置 { description = "Hugo Development Environment"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; }; outputs = { self, nixpkgs }: { devShells.default = pkgs.mkShell { buildInputs = [ pkgs.hugo pkgs.git ]; }; }; } 使用方法 # 进入开发环境 nix develop # 启动本地服务器 hugo server -D # 构建站点 hugo -D 简单高效!⚡

 ·   ·  views

Obsidian 与 Hugo 完美集成

Obsidian 与 Hugo 完美集成 使用 Obsidian 管理笔记内容,通过 Git 子模块连接到 Hugo 站点。 优势 📝 在 Obsidian 中舒适地写作 🔄 通过 Git 版本控制 🚀 自动发布到博客 🎨 保持 Markdown 格式一致 工作流 # 1. 在 Obsidian 中编写 # 2. 提交到 obsidian-notes 仓库 git add . git commit -m "New article" git push # 3. GitHub Actions 自动完成剩余工作! 完美的写作体验!✨

 ·   ·  views

写作规范与命名规范

写作规范与命名规范 本文档定义了博客文章的写作规范、文件命名规范,以及如何在博客中融合双链笔记(双向链接)功能。 📋 目录 文件命名规范 写作规范 双链笔记融合指南 Front Matter 规范 目录结构规范 最佳实践 📝 文件命名规范 基本原则 使用小写字母和连字符(kebab-case) ✅ 正确:hugo-blog-setup-guide.md ❌ 错误:Hugo_Blog_Setup_Guide.md、hugoBlogSetupGuide.md 使用有意义的描述性名称 ✅ 正确:obsidian-hugo-integration-tutorial.md ❌ 错误:post1.md、article.md、untitled.md 避免特殊字符 不允许:空格、中文标点、特殊符号(!@#$%^&*()) 允许:连字符 -、下划线 _(推荐使用连字符) 包含关键词 文件名应反映文章的核心主题 便于 SEO 和文件查找 命名模式 模式 1:主题-描述(推荐) 技术栈-具体主题.md 示例: hugo-automation-setup.md obsidian-daily-workflow.md github-actions-deployment.md 模式 2:日期-主题(可选) YYYY-MM-DD-主题描述.md 示例: 2025-01-20-writing-guidelines.md 2025-01-15-weekly-summary.md 注意: 如果使用日期前缀,确保在 Front Matter 中也设置正确的 date 字段。 模式 3:分类-主题 分类-主题描述.md 示例: tutorial-hugo-setup.md review-obsidian-plugins.md tutorial-git-workflow.md 命名检查清单 创建新文件前,确认: 文件名全小写 使用连字符分隔单词 文件名清晰描述内容 无空格和特殊字符 长度适中(建议 20-50 个字符) 避免重复(检查现有文件) ✍️ 写作规范 文章结构 每篇博客文章应包含以下部分: ...

 ·   ·  views

--- title: "内核都是c语言,为什么linux上使用so链接库文件,Windows上是dll" date: 2025-12-01T10:00:00+08:00 draft: false tags: - linux - windows - 动态库 - so - dll - 系统编程 categories: - 技术 description: "深入对比 Linux 的 .so 与 Windows 的 .dll 动态链接库机制,涵盖 ELF 与 PE 二进制格式、启动流程、加载运行过程及 ABI 差异,解释为何即使内核均用 C 语言编写,动态库标准仍必须不同。" --- # Linux 与 Windows 动态库机制对比:从二进制格式到加载流程 即使 Linux 和 Windows 的内核大多使用 C 语言编写,它们的动态链接库却分别采用 `.so`(Shared Object)和 `.dll`(Dynamic-Link Library)格式。这种差异并非偶然,而是由操作系统底层的二进制格式、ABI(Application Binary Interface)、加载机制和历史演进路径共同决定的。本文将系统性地对比两者的异同,并详细解析从程序启动到动态库加载运行的全过程。 --- ## 📋 目录 1. [核心前提:C 语言 ≠ 二进制兼容](#核心前提c-语言--二进制兼容) 2. [二进制格式对比:ELF vs PE](#二进制格式对比elf-vs-pe) 3. [Linux 启动与 .so 加载流程](#linux-启动与-so-加载流程) 4. [Windows 启动与 .dll 加载流程](#windows-启动与-dll-加载流程) 5. [为何标准必须不同?](#为何标准必须不同) 6. [关键差异总结](#关键差异总结) 7. [开发者应对策略](#开发者应对策略) --- ## 核心前提:C 语言 ≠ 二进制兼容 C 语言是一种高级源码语言,其编译后的二进制表现形式完全取决于目标平台。即使相同的 C 源码,在 Linux 和 Windows 上编译后: - 生成的**目标文件格式不同**(ELF vs PE) - **函数调用约定**不同(如 `cdecl` vs `stdcall`) - **符号修饰与导出机制**不同 - **内存布局与重定位方式**不同 因此,**“用 C 编写”仅说明实现语言,不决定二进制接口标准**。操作系统必须定义自己的 ABI 和加载模型,以确保稳定性、安全性和性能。 --- ## 二进制格式对比:ELF vs PE | 维度 | Linux(ELF) | Windows(PE) | |------|-------------|---------------| | **全称** | Executable and Linkable Format | Portable Executable | | **动态库扩展名** | `.so` | `.dll` | | **可执行文件标识** | ELF Magic: `7F 45 4C 46` | DOS + PE 头: `"MZ"` + `"PE\0\0"` | | **关键段/节** | `.text`, `.data`, `.dynamic`, `.dynsym`, `.got`, `.plt` | `.text`, `.data`, `.rdata`, `Import Table`, `Export Table`, `.reloc` | | **动态链接元数据** | `.dynamic` 段 + `PT_INTERP` 程序头 | DataDirectory 中的 Import/Export 表 | ELF 是 POSIX 系统的事实标准,而 PE 是 Microsoft 为 Windows 定义的私有格式。两者在结构设计上服务于不同的 OS 模型,因此**无法互操作**。 --- ## Linux 启动与 .so 加载流程 Linux 程序启动时,内核与用户态动态链接器协同完成加载: 1. 用户执行 `./myapp`,Shell 调用 `execve()` 2. 内核识别 ELF 文件,检查 `PT_INTERP` 程序头(通常指向 `/lib64/ld-linux-x86-64.so.2`) 3. 内核将 `myapp` 和 **动态链接器**(`ld-linux.so`)一同映射到进程地址空间 4. **控制权首先交给 `ld-linux.so`**,而非程序本身的 `_start` 5. `ld-linux.so` 执行: - 解析 `.dynamic` 段,获取依赖库列表(如 `libfoo.so.1`) - 根据 `LD_LIBRARY_PATH`、`/etc/ld.so.cache` 或 `rpath` 查找 `.so` 文件 - 使用 `mmap()` 加载所有依赖库 - 执行重定位:填充 GOT(Global Offset Table)和 PLT(Procedure Linkage Table) - (可选)启用延迟绑定(Lazy Binding) 6. 跳转到程序的 `_start` → `main()`,程序开始运行 7. 运行时可通过 `dlopen()` / `dlsym()` 动态加载更多 `.so` > 💡 关键:**动态链接器本身是一个 `.so`,由内核“委托”完成加载任务**。 --- ## Windows 启动与 .dll 加载流程 Windows 的加载由内核组件(`ntdll.dll`)主导: 1. 用户启动 `myapp.exe`,Windows 内核创建新进程 2. 加载器(位于 `ntdll.dll`)解析 PE 头和可选头 3. 读取 **Import Address Table (IAT)**,获取所需 DLL 列表(如 `foo.dll`) 4. 对每个依赖 DLL: - 按固定顺序搜索:exe 同目录 → System32 → Windows → PATH - 调用 `LoadLibraryEx()` 将 DLL 映射到进程地址空间 - 若加载地址 ≠ Preferred Base Address,则应用 **Base Relocation** 表进行重定位 - 填充 IAT:将函数名解析为实际虚拟地址 - 调用 DLL 的 `DllMain`(`DLL_PROCESS_ATTACH`) 5. 跳转到程序入口点(如 `mainCRTStartup` → `main`) 6. 程序运行,可通过 `LoadLibrary()` / `GetProcAddress()` 动态加载更多 `.dll` > 💡 关键:**加载器是 OS 内建组件,直接处理 PE 结构和 DLL 依赖**。 --- ## 为何标准必须不同? 1. **无跨 OS 二进制标准** ELF、PE、Mach-O 是各自生态的基石,互不兼容。 2. **内存与安全模型差异** Linux 依赖 PIC + ASLR,Windows 依赖基址重定位,重定位机制根本不同。 3. **符号导出策略** Linux 默认导出所有符号(可通过编译选项控制),Windows 必须显式使用 `__declspec(dllexport)`。 4. **C 运行时集成方式** glibc 与 MSVCRT/UCRT 在初始化、线程、异常处理等方面深度耦合 OS。 > ✅ **二进制格式是操作系统的“母语”,改变它等于重构整个用户态生态**。 --- ## 关键差异总结 | 阶段 | Linux(ELF/.so) | Windows(PE/.dll) | |------|------------------|---------------------| | **文件格式** | ELF | PE/COFF | | **动态库命名** | `libxxx.so` | `xxx.dll` | | **加载器** | 用户态 `ld-linux.so` | 内核态 `ntdll.dll` | | **依赖描述** | `.dynamic` + `DT_NEEDED` | Import Table | | **符号导出** | 默认全局可见 | 需 `__declspec(dllexport)` | | **运行时加载 API** | `dlopen()` / `dlsym()` | `LoadLibrary()` / `GetProcAddress()` | | **重定位机制** | GOT/PLT(位置无关代码) | Base Relocation Table | | **初始化回调** | 无自动机制(需 `__attribute__((constructor))`) | `DllMain` 自动调用 | --- ## 开发者应对策略 - **跨平台库开发**:使用纯 C ABI 导出接口,避免 C++ 名称修饰 - **动态加载**:封装平台差异(如 Rust 的 `libloading` crate) - **构建系统**:为不同平台生成对应产物(`.so` + `.dll`) - **调试工具**: - Linux:`readelf -d`, `ldd`, `objdump` - Windows:`dumpbin /imports`, `Dependencies.exe` --- ## 🔗 相关链接 - [[操作系统底层开发]] - [[Rust FFI 跨平台实践]] - [[ELF 文件格式详解]] - [[Windows PE 结构分析]] --- **最后更新:** 2025-12-01 **维护者:** Jesse

 ·  views
total views · visitors