利用cmake打deb包

手动打包一个deb,是一件非常复杂的事。 好在有一些工具可以代劳,只需要输入文件和metadata。 对C/C++项目来说,cmake是一个非常好用且流行的编译控制软件。 其中自带的cpack功能,专门用来打包各大平台的软件发布包,包括Debian系的deb。

本文以一个demo项目,展示了如何利用cmake自带的cpack,打包一个deb。

示例项目

这就是一个非常简单的打印示例。 唯一比helloworld复杂的,在于多了链接的过程。

项目结构

$ tree .
.
├── CMakeLists.txt
├── build
│   └── cmake
│       └── deb.cmake
├── include
│   └── greet.h
└── src
    ├── cli
    │   └── main.c
    └── lib
        └── greet.c

项目代码

一共两个源文件,一个头文件。

greet.c

#include "greet.h"

void greet(char *name)
{
    printf("Hello, %s!\n", name);
}

main.c

#include "greet.h"

int main(int args, char **argv)
{
    if (args > 1) {
        greet(argv[1]);
    } else {
        greet("World");
    }
    return 0;
}

greet.h

#include <stdio.h>

void greet(char *);

CMakeList.txt

项目代码本身没有什么好说的,关键是编译部分。 以下CMakeList.txt实现了上述文件,编译成一个动态链接库libgreet.so,和一个可执行文件hello

cmake_minimum_required(VERSION 3.10.2)

set(CMAKE_BUILD_TYPE Release)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")

execute_process(
    COMMAND git describe --abbrev=0
    OUTPUT_VARIABLE PACKAGE_VERSION
    OUTPUT_STRIP_TRAILING_WHITESPACE
)
project(greet VERSION ${PACKAGE_VERSION})

add_library(greet SHARED "src/lib/greet.c")
include_directories(greet PUBLIC include)

add_executable(hello "src/cli/main.c")
target_link_libraries(hello greet)

install(
    TARGETS greet
    COMPONENT libraries
    DESTINATION "lib"
)

install(
    TARGETS hello
    COMPONENT applications
    DESTINATION "bin"
)

install(
    FILES "include/greet.h"
    DESTINATION "include"
    COMPONENT headers
)

include(deb)  # build/cmake/deb.cmake
include(CPack)

在后半部分的三个install,是分别对动态链接库libgreet.so、可执行文件hello和头文件greet.h进行了打包。 可执行文件是执行入口,由于链接了动态链接库,所以运行时依赖于libgreet.sogreet.h是开发时需要的文件,安装后,用户可以在自己的C/C++项目中#include使用。 其中,DESTINATION如果是相对路径,其prefix默认是/usr

debian:buster镜像中执行效果如下:

# cmake .
-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/demo
# make
Scanning dependencies of target greet
[ 25%] Building C object CMakeFiles/greet.dir/src/lib/greet.c.o
[ 50%] Linking C shared library libgreet.so
[ 50%] Built target greet
Scanning dependencies of target hello
[ 75%] Building C object CMakeFiles/hello.dir/src/cli/main.c.o
[100%] Linking C executable hello
[100%] Built target hello

deb.cmake

单独把Debian的配置放在一个文件,是考虑后续兼容其它系统打包的需要。 (当然,目前的demo是不行的。)

set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Yan QiDong")
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "This is a demo package from Yan QiDong.")
set(CPACK_DEBIAN_PACKAGE_VERSION ${PACKAGE_VERSION})
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libc6 (<< 3)")

这里分别对一些比较重要的deb包metadata进行设置。

以下是执行cpack的效果,以及运行hello的情况:

# cpack
CPack: Create package using DEB
CPack: Install projects
CPack: - Run preinstall target for: greet
CPack: - Install project: greet
CPack: Create package
CPack: - package: /root/demo/greet_0.0.1_amd64.deb generated.
# dpkg -i greet_0.0.1_amd64.deb
(Reading database ... 21360 files and directories currently installed.)
Preparing to unpack greet_0.0.1_amd64.deb ...
Unpacking greet (0.0.1) over (0.0.1) ...
Setting up greet (0.0.1) ...
# hello
Hello, World!
# hello Yan QiDong
Hello, Yan!
# which hello
/usr/bin/hello

查看安装效果

以下查看deb包与实际安装到系统的文件。

# dpkg -c greet_0.0.1_amd64.deb
drwxr-xr-x root/root         0 2019-11-06 14:31 ./usr/
drwxr-xr-x root/root         0 2019-11-06 14:31 ./usr/bin/
-rwxr-xr-x root/root     16592 2019-11-06 14:18 ./usr/bin/hello
drwxr-xr-x root/root         0 2019-11-06 14:31 ./usr/include/
-rw-r--r-- root/root        40 2019-11-03 11:05 ./usr/include/greet.h
drwxr-xr-x root/root         0 2019-11-06 14:31 ./usr/lib/
-rw-r--r-- root/root     15984 2019-11-06 14:18 ./usr/lib/libgreet.so
# dpkg -L greet
/usr
/usr/bin
/usr/bin/hello
/usr/include
/usr/include/greet.h
/usr/lib
/usr/lib/libgreet.so

查看metadata:

# dpkg --info greet_0.0.1_amd64.deb
 new Debian package, version 2.0.
 size 4438 bytes: control archive=401 bytes.
     222 bytes,    10 lines      control
     156 bytes,     3 lines      md5sums
 Architecture: amd64
 Depends: libc6 (>= 2.3.1-6), libc6 (<< 3)
 Description: This is a demo package from Yan QiDong.
 Maintainer: Yan QiDong
 Package: greet
 Priority: optional
 Section: devel
 Version: 0.0.1
 Installed-Size: 48

# apt show greet
Package: greet
Version: 0.0.1
Status: install ok installed
Priority: optional
Section: devel
Maintainer: Yan QiDong
Installed-Size: 49.2 kB
Depends: libc6 (>= 2.3.1-6), libc6 (<< 3)
Download-Size: unknown
APT-Manual-Installed: yes
APT-Sources: /var/lib/dpkg/status
Description: This is a demo package from Yan QiDong.

结语

cpack打包的效果,还是值得称赞的。

最新demo版本,请查看cmake-cpack-demo

参考


相关笔记