之前接触到了snap打包自己的应用程序与依赖,但它的默认沙盒隔离的机制导致其访问系统库有局限性,它在访问硬件资源的时候没有的那些权限需要额外声明,不符合应用发布的便携性要求。
本文学习下如何用deb打包的方式打包自己需要调用系统库的程序。顺便将之前的gcc动态链接库的流程走一遍
本文失败的部分是,并没有像预期的那样能将我的so文件复制到usr/local/lib,正常的打包解包是可以的,感觉就只是和压缩包一样......
目录
DEB包的组成:
准备需要打包的程序:
GPIO_LED.c 与 GPIO_LED.h :
编译动态链接库:
程序文件调用动态链接库LED_light.c:
编译C文件为可执行文件:
验证程序运行:
安装必要的工具:
创建 ledlight 的 DEB 包:
创建项目目录结构:
创建control文件:
依赖库的处理_postinst文件:
创建install文件:
卸载前脚本_prerm 文件:
构建规则rules 文件:
创建changelog版本号文件:
设定文件权限:
生成deb包:
解包deb:
参考文章:
DEB包的组成:
DEB(Debian Package)是Debian及其衍生系统(如Ubuntu)使用的软件包格式,主要用于软件的安装、升级和管理。
一个DEB包本质上是一个ar归档文件,他在构建前,包含以下核心组成部分:
myapp-1.0/ # 项目根目录(通常与包名+版本一致) ├── debian/ # Debian 打包专用目录(必须存在) │ ├── control # 包的元数据(名称、版本、依赖等) │ ├── changelog # 包的更新日志(生成版本号) │ ├── rules # 构建规则(Makefile 风格的脚本) │ ├── copyright # 版权信息 │ ├── compat # 兼容性声明(如 "10" 表示 Debian Policy 10) │ ├── source/ # 源码包相关配置(可选) │ ├── install # 指定安装文件的规则(如 `usr/bin/* usr/bin`) │ ├── preinst # 安装前脚本(可选) │ ├── postinst # 安装后脚本(可选) │ ├── prerm # 卸载前脚本(可选) │ ├── postrm # 卸载后脚本(可选) │ └── conffiles # 配置文件列表(如 `/etc/myapp/config.conf`) ├── src/ # 项目源码目录(可选) │ ├── main.c │ └── Makefile └── build/ # 构建临时目录(通常自动生成)
文件名 类型 说明 control
纯文本文件 定义包的元数据(无后缀)。 changelog
纯文本文件 记录版本更新历史(无后缀,格式遵循 Debian Policy
)。rules
可执行脚本 构建规则(无后缀,本质是 Makefile
脚本,需chmod +x
)。copyright
纯文本文件 版权声明(无后缀)。 compat
纯文本文件 兼容性声明(无后缀,内容如 10
)。install
纯文本文件 定义文件安装路径(无后缀,如 usr/bin/* usr/bin
)。preinst
可执行脚本 安装前脚本(无后缀,需 #!/bin/sh
和chmod +x
)。postinst
可执行脚本 安装后脚本(无后缀)。 prerm
可执行脚本 卸载前脚本(无后缀)。 postrm
可执行脚本 卸载后脚本(无后缀)。 conffiles
纯文本文件 列出需要保留的配置文件(无后缀,每行一个路径如 /etc/myapp.conf
)。
准备需要打包的程序:
这一部分先不要在 /home/orangepi/DEB_GPIOLED 进行写程序,推荐另起一个文件夹,后续将必要的内容复制过去即可
GPIO_LED.c 与 GPIO_LED.h :
GPIO_LED.c 与 GPIO_LED.h
这是基础的LED初始化与点亮程序 , 被注释部分用于测试其子函数是否奏效
该程序需要被构建为一个libGPIO_LED.so动态链接库
#include "GPIO_LED.h"void GPIO_LED_init(void) {// 初始化 wiringPi(必须调用,否则会报错)wiringPiSetup(); // 使用 wiringPi 的引脚编号pinMode(LED_BLUE,OUTPUT);pinMode(LED_RED,OUTPUT);pinMode(LED_GREEN,OUTPUT); //初始化全灭digitalWrite(LED_BLUE ,LOW);digitalWrite(LED_RED ,LOW);digitalWrite(LED_GREEN ,LOW); }//控制LED 红色亮灭 void LED_RED_(char flag) {if(flag == 1){digitalWrite(LED_RED ,HIGH);}else if(flag == 0){digitalWrite(LED_RED ,LOW); } }//控制LED 蓝色亮灭 void LED_BLUE_(char flag) {if(flag == 1){digitalWrite(LED_BLUE ,HIGH);}else if(flag == 0){digitalWrite(LED_BLUE ,LOW); } }//控制LED 绿色亮灭 void LED_GREEN_(char flag) {if(flag == 1){digitalWrite(LED_GREEN ,HIGH);}else if(flag == 0){digitalWrite(LED_GREEN ,LOW); } }/* int main(void) {GPIO_LED_init();while(1){LED_GREEN_(0);LED_RED_(1);delay(500);LED_GREEN_(1); LED_RED_(0); delay(500); } } */
#include <stdio.h> #include <wiringPi.h>#define LED_BLUE 13 #define LED_RED 15 #define LED_GREEN 18void GPIO_LED_init(void); void LED_RED_(char flag); void LED_BLUE_(char flag); void LED_GREEN_(char flag);
编译动态链接库:
编译动态链接库:
gcc GPIO_LED.c -fPIC -shared -o libGPIO_LED.so
将该动态链接库复制到目录
/usr/local/lib
: 下:sudo cp libGPIO_LED.so /usr/local/lib
更新动态链接器缓存:
sudo ldconfig
检查动态链接库:
ldd libGPIO_LED.so
但我们发现ldd命令检查出的libGPIO_LED.so是静态的,这是
ldd
的误判,ldd
通常用于检查动态库的依赖关系,但如果库 没有依赖任何其他动态库(比如没有调用libc
的函数,或者 GCC 静态链接了部分库)如果
GPIO_LED.c
没有使用任何libc
函数(如printf
、malloc
等),并且没有链接其他库(如-lpthread
),那么ldd
会认为它“静态链接”,因为没有外部依赖。
此时使用file命令更准确彻底:
根据
file
命令的输出,libGPIO_LED.so
确实是一个 动态链接库(shared object),并且显示为dynamically linked
,这与之前ldd
显示的statically linked
不同。
程序文件调用动态链接库LED_light.c:
现在我有个程序文件交LED_light.c,他会调用动态链接库 libGPIO_LED.so,以及WiringPi库
他会让LED红蓝交替闪烁:
#include <stdio.h> #include "GPIO_LED.h" #include <wiringPi.h>int main(void) {GPIO_LED_init();while(1){LED_BLUE_(0);LED_RED_(1);delay(500);LED_BLUE_(1); LED_RED_(0); delay(500); } }
编译C文件为可执行文件:
编译将LED_Light.c与动态库libGPIO_LED.so 以及libwiringPi 链接生成执行文件ledlight
gcc LED_Light.c -lGPIO_LED -lwiringPi -o ledlight
验证程序运行:
sudo ./ledlight
LED交替亮灭
安装必要的工具:
sudo apt-get update
sudo apt-get install dh-make dpkg-dev build-essential
创建 ledlight
的 DEB 包:
每个文件的代码里的注释要删去!
创建项目目录结构:
一、先创建一个 DEB_GPIOLED 构建Deb包的目录:
cd /home/orangepi
mkdir DEB_GPIOLEDcd /home/orangepi/DEB_GPIOLED
二、创建打包目录:
mkdir DEBIAN
mkdir src
mkdir build
创建control文件:
进入目录:
cd /home/orangepi/DEB_GPIOLED/debian/
使用文本编辑器创建
control
文件nano control
确保wiringpi可通过
apt
安装apt-cache show wiringpi
Package: ledlight Version: 1.0-1 Architecture: arm64 # arm64/amd64/armhf Maintainer: Your Name <your.email@example.com> Description: Control LED lights via GPIOA simple program to control LED lights using GPIO pins,dynamically linked to libGPIO_LED.so and WiringPi library. Depends: libc6 (>= 2.28), wiringpi (>= 2.50) # 不写 libgpio-led ,libgpio-led (>= 1.0) Section: utils Priority: optional
在 Debian/Ubuntu 的
control
文件中,Depends
字段是核心的依赖声明部分,它会告诉包管理系统(如apt
/dpkg
)在安装当前软件包时自动安装所依赖的包。
将程序文件LED_light.c 和 ledlight复制到 /home/orangepi/DEB_GPIOLED/src/:
依赖库的处理_postinst文件:
/usr/local/lib/libGPIO_LED.so 是我自定义的库,手动安装的,不在 APT 仓库中,因此不能通过Depends自动安装,
因此这里将其放在项目的lib文件夹中,以便检查到目标机器没有这个库就复制一个到 /usr/local/lib。
因为库没有打包为debian,所以在
postinst
脚本中执行ldconfig
更新库缓存:nano postinst
#!/bin/sh set -e# 符合FHS的路径定义 TEMP_LIB="/var/lib/ledlight/libGPIO_LED.so" TARGET_LIB="/usr/local/lib/libGPIO_LED.so"case "$1" inconfigure)if [ ! -f "$TARGET_LIB" ]; thenecho "Installing libGPIO_LED.so to /usr/local/lib/"mkdir -p /usr/local/libcp "$TEMP_LIB" "$TARGET_LIB"chmod 644 "$TARGET_LIB"ldconfigfi# 总是清理临时文件rm -f "$TEMP_LIB"rmdir --ignore-fail-on-non-empty /var/lib/ledlight;;abort-upgrade|abort-remove|abort-deconfigure)# 安装失败时也清理rm -f "$TEMP_LIB"rmdir --ignore-fail-on-non-empty /var/lib/ledlight;; esacldconfig # 确保系统能找到 /usr/local/lib 下的库exit 0
最后别忘了把libGPIO_LED.so复制到/home/orangepi/DEB_GPIOLED/lib:
cd /home/orangepi/DEB_GPIOLED/
mdir lib
cd /home/orangepi/gcc_cpp_codes/ #有libGPIO_LED.so的目录
cp libGPIO_LED.so /home/orangepi/DEB_GPIOLED/lib/
1
创建install文件:
nano install
将项目目录下的
lib/libGPIO_LED.so
文件安装到目标系统的
/var/lib/ledlight/
目录(DEB 包内路径)lib/libGPIO_LED.so var/lib/ledlight/
卸载前脚本_prerm
文件:
nano prerm
#!/bin/sh set -eTARGET_LIB="/usr/local/lib/libGPIO_LED.so"case "$1" inremove|upgrade|failed-upgrade)# 仅在完全卸载(purge)时删除库文件if [ "$1" = "remove" ] || [ "$1" = "failed-upgrade" ]; thenif [ -f "$TARGET_LIB" ]; thenecho "Removing libGPIO_LED.so from /usr/local/lib/"rm -f "$TARGET_LIB"fifi;;purge)# 彻底清除时强制删除if [ -f "$TARGET_LIB" ]; thenecho "Purging libGPIO_LED.so from /usr/local/lib/"rm -f "$TARGET_LIB"fi;; esacldconfig # 更新库缓存 exit 0
构建规则rules 文件:
nano rules
#!/usr/bin/make -f%:dh $@ --with autotools-devoverride_dh_auto_configure:@:override_dh_auto_build:$(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS) -lWiringPi -L/usr/local/lib -lGPIO_LED" ledlightoverride_dh_auto_install:# 安装可执行文件到 /usr/bininstall -D -m 0755 ledlight $(CURDIR)/debian/ledlight/usr/bin/ledlight# 将库文件安装到临时位置(由postinst处理)install -D -m 0644 libGPIO_LED.so $(CURDIR)/debian/ledlight/var/lib/ledlight/libGPIO_LED.sooverride_dh_shlibdeps:dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
创建changelog版本号文件:
基本格式:
package (version) distribution; urgency=urgency* change detail 1* change detail 2* change detail 3-- Maintainer Name <email@address> Date
对应编写:
nano changelog
ledlight (1.0-1) unstable; urgency=medium* Initial release.* Includes ledlight executable and libGPIO_LED.so library.* Post-install script handles library installation to /usr/local/lib.-- Your Name <your.email@example.com> Mon, 24 Jun 2024 14:30:00 +0800
生成日期以更新:
可以通过终端得到当前日期以更新changelog中的日期文件
date -R
如果时区不对,如此设置时区为上海:
sudo timedatectl set-timezone Asia/Shanghai
设定文件权限:
chmod 755 debian/postinst debian/prerm
chmod 644 lib/libGPIO_LED.so
生成deb包:
dpkg-deb --build . ../ledlight_1.0-1_arm64.deb
解包deb:
这里我先rm删除掉以前存在的libGPIO_LED.so
尝试解包:
# 创建解压目录并解包 mkdir -p ledlight_extracted dpkg -x ledlight_1.0-1_arm64.deb ledlight_extracted/# 单独提取控制文件(元数据和脚本) dpkg -e ledlight_1.0-1_arm64.deb ledlight_extracted/DEBIAN
发现并没有像预期的那样将我的so文件复制到usr/local/lib :
参考文章:
如何把代码打包成一个 deb package_哔哩哔哩_bilibili文字稿在 haoduoshipin.com, 视频播放量 3715、弹幕量 0、点赞数 42、投硬币枚数 20、收藏人数 88、转发人数 10, 视频作者 好奇猫学院, 作者简介 编程,区块链,密码学等等。,相关视频:数字签名原理,如何把 deb 软件包上传到 apt 仓库中,动画演示 Diffie-Hellman 密钥交换算法,挑战魔改1300天前的塔防代码 | 手把手教你做冰冻炮台??,【网安】编写一个木马有多简单?,什么是密码学?,RSA 算法基本原理,如何使用 font-awesome “字体图标”,什么是 Ajax ?,最大的开放标准--古代中国
https://www.bilibili.com/video/BV1kE411G7vt/?spm_id_from=333.337.search-card.all.click&vd_source=090e0b0724f6022d9ce8b14853097061
deb包构建详解_deb包制作详解-CSDN博客