从 Windows 到 Linux:软件打包入门指南(NSIS vs dpkg)

4 阅读5分钟

image.png

前言

当我们开发完一个应用程序后,需要把它打包成安装包分发给用户。在 Windows 上,我们通常使用 NSIS、Inno Setup 等工具生成 .exe 安装程序;而在 Linux(Debian/Ubuntu 系)上,我们则需要制作 .deb 包。

本文将从一个 Windows 开发者的视角,介绍这两种打包方式的基础知识和核心区别。


一、NSIS 基础知识

1.1 什么是 NSIS?

NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows 安装程序制作工具,由 Winamp 的开发商 Nullsoft 创建。它通过脚本语言来定义安装流程,最终生成一个独立的 .exe 安装程序。

1.2 NSIS 的核心特点

  • 脚本驱动:使用 .nsi 脚本文件定义安装逻辑
  • 高度可定制:支持自定义安装界面、多语言、插件扩展
  • 体积小巧:生成的安装包压缩率高,体积小
  • 功能丰富:支持注册表操作、文件操作、快捷方式创建等

1.3 NSIS 安装包结构

一个典型的 NSIS 项目结构如下:

nsis-project/
├── Setup.nsi                 # 主脚本文件
├── Scripts/
│   ├── Const.nsh            # 常量定义
│   ├── Functions/
│   │   ├── OnInit.nsh       # 初始化函数
│   │   ├── Files.nsh        # 文件安装
│   │   ├── Registry.nsh     # 注册表操作
│   │   ├── ShortCuts.nsh    # 快捷方式创建
│   │   └── OnEnd.nsh        # 安装结束处理
│   └── Languages.nsh        # 多语言支持
├── Plugins/                  # 插件目录
└── Resources/               # 资源文件(图标、图片等)

1.4 NSIS 安装流程

用户双击 Setup.exe
    ↓
OnInit(初始化检查)
    ↓
显示安装界面(欢迎页、协议页、路径选择等)
    ↓
Files(复制文件到安装目录)
    ↓
Registry(写入注册表信息)
    ↓
ShortCuts(创建桌面/开始菜单快捷方式)
    ↓
OnEnd(完成处理)
    ↓
安装完成

1.5 NSIS 核心概念

注册表(Registry)

Windows 的注册表是软件信息的中央数据库。NSIS 安装包通常会写入以下信息:

# 写入卸载信息
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp" "DisplayName" "My Application"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp" "UninstallString" "$INSTDIR\Uninstall.exe"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp" "DisplayVersion" "1.0.0"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp" "Publisher" "My Company"

# 写入软件信息
WriteRegStr HKLM "Software\MyCompany\MyApp" "InstallPath" "$INSTDIR"

快捷方式(.lnk 文件)

# 创建桌面快捷方式
CreateShortCut "$DESKTOP\MyApp.lnk" "$INSTDIR\MyApp.exe"

# 创建开始菜单快捷方式
CreateDirectory "$SMPROGRAMS\MyApp"
CreateShortCut "$SMPROGRAMS\MyApp\MyApp.lnk" "$INSTDIR\MyApp.exe"

1.6 NSIS 常用命令

命令说明
OutFile指定输出的安装包文件名
InstallDir指定默认安装目录
SetOutPath设置文件输出路径
File添加要安装的文件
CreateDirectory创建目录
CreateShortCut创建快捷方式
WriteRegStr写入注册表字符串
DeleteRegKey删除注册表项
ExecWait执行程序并等待
RMDir删除目录
Delete删除文件

二、dpkg 基础知识

2.1 什么是 dpkg?

dpkg(Debian Package)是 Debian 及其衍生发行版(如 Ubuntu、Deepin、Linux Mint 等)的底层包管理工具。它负责 .deb 包的安装、卸载和查询等操作。

可以把 dpkg 理解为 Linux 版的 MSI 安装程序,它是最基础的包管理工具。

2.2 deb 包的结构

一个 .deb 包本质上是一个 ar 格式的压缩文件,包含以下核心部分:

myapp_1.0.0_amd64.deb
├── debian-binary          # deb格式版本号
├── control.tar.gz         # 控制信息
│   ├── control           # 包的元数据(必需)
│   ├── preinst           # 安装前脚本
│   ├── postinst          # 安装后脚本
│   ├── prerm             # 卸载前脚本
│   └── postrm            # 卸载后脚本
└── data.tar.gz           # 实际安装的文件
    └── usr/
        └── local/
            ├── bin/              # 可执行文件
            └── share/
                ├── applications/ # .desktop 文件
                └── icons/        # 图标文件

2.3 control 文件详解

control 文件是 deb 包的核心元数据文件,类似于 package.json

Package: myapp
Version: 1.0.0
Section: utils
Priority: optional
Architecture: amd64
Depends: libc6 (>= 2.17), libgtk-3-0
Maintainer: Your Name <your.email@example.com>
Description: My awesome application
 This is a longer description of my application.
 It can span multiple lines.
Homepage: https://myapp.example.com

字段说明:

字段说明是否必需
Package包名(小写,可含数字和连字符)
Version版本号
Architecture架构(amd64, i386, arm64, all)
Maintainer维护者信息
Description软件描述
Depends依赖包列表
Section软件分类
Priority优先级
Homepage项目主页

2.4 维护者脚本

dpkg 提供了四个维护者脚本,在安装/卸载的不同阶段执行:

脚本执行时机典型用途
preinst安装前停止旧服务、备份配置
postinst安装后创建快捷方式、启动服务、初始化配置
prerm卸载前停止服务、清理运行时数据
postrm卸载后删除快捷方式、清理残留文件

postinst 示例:

#!/bin/bash

# 更新图标缓存
gtk-update-icon-cache /usr/share/icons/hicolor/ -t

# 创建桌面快捷方式
DESKTOP_FILE="/usr/share/applications/myapp.desktop"
for USER_HOME in /home/*; do
    if [ -d "$USER_HOME/Desktop" ]; then
        cp "$DESKTOP_FILE" "$USER_HOME/Desktop/"
        chmod +x "$USER_HOME/Desktop/myapp.desktop"
    fi
done

exit 0

2.5 .desktop 文件

.desktop 文件是 Linux 下的"快捷方式",定义了应用程序的启动信息:

[Desktop Entry]
Version=1.0
Type=Application
Name=My Application
Name[zh_CN]=我的应用
Comment=A great application
Comment[zh_CN]=一个很棒的应用
Exec=/usr/local/bin/myapp %F
Icon=myapp
Terminal=false
Categories=Utility;
StartupWMClass=myapp
MimeType=application/x-myapp;

字段说明:

字段说明
Name应用显示名称
Exec执行命令
Icon图标名称或路径
Terminal是否在终端中运行
Categories应用分类
MimeType支持的文件类型

2.6 dpkg 安装流程

执行 dpkg -i myapp.deb
    ↓
解压 deb 包
    ↓
执行 preinst 脚本(安装前准备)
    ↓
解压 data.tar.gz(复制文件到目标位置)
    ↓
执行 postinst 脚本(安装后配置)
    ↓
更新 dpkg 数据库(/var/lib/dpkg/)
    ↓
安装完成

三、dpkg 常用命令

3.1 安装相关

# 安装 deb 包
sudo dpkg -i package.deb

# 安装目录下所有 deb 包
sudo dpkg -i *.deb

# 强制安装(忽略依赖,谨慎使用)
sudo dpkg -i --force-depends package.deb

# 修复依赖问题(配合 apt 使用)
sudo apt install -f

3.2 卸载相关

# 卸载软件(保留配置文件)
sudo dpkg -r package-name

# 完全卸载(包括配置文件)
sudo dpkg -P package-name
# 或
sudo dpkg --purge package-name

3.3 查询相关

# 列出所有已安装的包
dpkg -l

# 搜索包含特定关键字的包
dpkg -l | grep keyword

# 查看包的详细信息
dpkg -s package-name

# 查看包安装了哪些文件
dpkg -L package-name

# 查看某个文件属于哪个包
dpkg -S /path/to/file

# 查看 deb 包的信息(未安装的包)
dpkg -I package.deb

# 查看 deb 包的内容(未安装的包)
dpkg -c package.deb

3.4 其他常用命令

# 重新配置已安装的包
sudo dpkg-reconfigure package-name

# 查看包的状态
dpkg --status package-name

# 比较版本号
dpkg --compare-versions 1.0 gt 0.9 && echo "1.0 大于 0.9"

# 解压 deb 包到指定目录(不安装)
dpkg -x package.deb /target/directory

# 解压 control 信息到指定目录
dpkg -e package.deb /target/directory

3.5 构建 deb 包

# 从目录构建 deb 包
dpkg-deb --build package-directory

# 指定输出文件名
dpkg-deb --build package-directory output.deb

# 使用 fakeroot 构建(推荐)
fakeroot dpkg-deb --build package-directory

四、NSIS vs dpkg 对比

4.1 核心概念对照表

Windows 概念Linux 对应说明
.exe 安装程序.deb安装包格式
注册表 (Registry)dpkg 数据库软件信息存储
.lnk 快捷方式.desktop 文件桌面/菜单快捷方式
C:\Program Files\/usr/local//opt/默认安装位置
控制面板 → 卸载dpkg -r / apt remove卸载方式
Windows 应用商店apt + 软件仓库软件分发渠道

4.2 安装流程对比

NSIS (Windows):

用户双击 setup.exe 
    → 显示安装界面(可交互)
    → 用户选择安装路径
    → 复制文件到安装目录
    → 写入注册表
    → 创建快捷方式
    → 显示完成页面

dpkg (Linux):

执行 sudo dpkg -i xxx.deb
    → 解压deb包
    → 运行 preinst 脚本
    → 复制文件到目标位置(路径固定)
    → 运行 postinst 脚本
    → 更新dpkg数据库
    → 命令行显示完成

4.3 主要差异

特性NSISdpkg
安装界面图形化、可交互命令行、无界面
安装路径用户可选择包内固定
依赖处理需自行打包或检测声明依赖,由系统处理
软件信息存储注册表数据库文件
卸载方式运行 Uninstall.exedpkg -r 或 apt remove
多版本共存可以(不同目录)通常不可以

4.4 图标格式差异

在electron-builder 里面会要求不同的图标格式,看看他们的区别

Windows (.ico 格式)

Windows 使用 .ico 格式的图标文件,这是一个容器格式,可以在单个文件中包含多种尺寸的图标:

myapp.ico
├── 16x16
├── 32x32
├── 48x48
├── 64x64
├── 128x128
└── 256x256

特点:

  • 单个 .ico 文件包含所有尺寸
  • NSIS 安装时只需指定一个图标文件
  • 系统自动选择合适尺寸显示

NSIS 中使用图标:

# 设置安装程序图标
Icon "resources\app.ico"

# 设置卸载程序图标
UninstallIcon "resources\uninstall.ico"

# 快捷方式会自动使用 exe 内嵌的图标
CreateShortCut "$DESKTOP\MyApp.lnk" "$INSTDIR\MyApp.exe"

Linux (多尺寸 PNG 格式)

Linux 采用 freedesktop.org 图标主题规范,使用独立的 PNG 文件存放在特定目录结构中:

/usr/share/icons/hicolor/
├── 16x16/apps/
│   └── myapp.png
├── 32x32/apps/
│   └── myapp.png
├── 48x48/apps/
│   └── myapp.png
├── 64x64/apps/
│   └── myapp.png
├── 128x128/apps/
│   └── myapp.png
├── 256x256/apps/
│   └── myapp.png
└── scalable/apps/
    └── myapp.svg      # 可选:SVG 矢量图标

特点:

  • 每个尺寸是独立的 PNG 文件
  • 遵循 hicolor 图标主题规范
  • 支持 SVG 矢量图标(scalable 目录)
  • 需要在安装后执行 gtk-update-icon-cache 更新缓存

deb 包中的图标目录结构:

myapp_1.0.0_amd64/
└── usr/
    └── share/
        └── icons/
            └── hicolor/
                ├── 48x48/
                │   └── apps/
                │       └── myapp.png
                ├── 128x128/
                │   └── apps/
                │       └── myapp.png
                └── 256x256/
                    └── apps/
                        └── myapp.png

postinst 中更新图标缓存:

#!/bin/bash
# 更新图标缓存,使新图标生效
gtk-update-icon-cache /usr/share/icons/hicolor/ -t 2>/dev/null || true
exit 0

.desktop 文件中引用图标:

[Desktop Entry]
Name=MyApp
Exec=/usr/local/bin/myapp
Icon=myapp          # 只需写图标名称,系统自动查找对应尺寸
Terminal=false
Type=Application

图标格式对比总结

特性Windows (.ico)Linux (.png)
文件格式单个 .ico 容器文件多个独立 .png 文件
尺寸管理内嵌在一个文件分目录存放
矢量支持❌ 不支持✅ 支持 SVG
主题支持❌ 不支持✅ 支持图标主题
缓存机制系统自动处理需手动更新缓存
引用方式完整路径图标名称(无扩展名)

常用图标尺寸建议

尺寸用途
16x16任务栏、小列表
32x32开始菜单、中等列表
48x48应用程序菜单
64x64大列表视图
128x128文件管理器图标视图
256x256高分辨率显示、软件中心

五、dpkg vs apt

这是新手最容易混淆的概念!

5.1 关系说明

apt = dpkg + 依赖管理 + 网络下载 + 仓库管理

apt 是基于 dpkg 的高级包管理工具。当你执行 apt install 时,apt 实际上在后台调用 dpkg 来完成安装。

5.2 功能对比

特性dpkgapt
层级底层工具高层工具
依赖处理❌ 不处理✅ 自动解决
软件源❌ 只能安装本地包✅ 可从网络仓库下载
自动更新❌ 不支持✅ 支持
软件搜索❌ 只能查已安装✅ 可搜索仓库

5.3 使用场景

使用 dpkg 的场景:

  • 安装本地下载的 .deb 文件
  • 查询已安装软件的详细信息
  • 手动管理软件包
  • 打包制作 deb 包

使用 apt 的场景:

  • 从官方仓库安装软件
  • 自动解决依赖关系
  • 批量更新系统软件
  • 搜索可用软件包

5.4 常见工作流

# 场景1:安装本地 deb 包
sudo dpkg -i downloaded-app.deb
# 如果提示缺少依赖
sudo apt install -f    # apt 帮你自动安装缺失的依赖

# 场景2:从仓库安装
sudo apt update        # 更新软件源
sudo apt install nginx # 自动下载、解决依赖、安装

# 场景3:查看软件信息
dpkg -L nginx          # 查看安装了哪些文件
apt show nginx         # 查看软件详细信息

总结

平台打包工具包格式包管理器
WindowsNSIS, Inno Setup.exe无(注册表)
Debian/Ubuntudpkg-deb.debdpkg, apt
RedHat/CentOSrpmbuild.rpmrpm, yum/dnf
macOSpkgbuild.pkginstaller

从 Windows 迁移到 Linux 的开发者,最重要的是理解以下几点:

  1. Linux 没有注册表,软件信息由包管理器的数据库管理
  2. 快捷方式是 .desktop 文件,而不是 .lnk 文件
  3. dpkg 是底层工具,apt 是建立在它之上的高级工具
  4. deb 包路径是固定的,不像 Windows 可以让用户选择安装位置

希望这篇文章能帮助你快速理解 Linux 下的软件打包!