📦

RHEL9でRPMを自作するサンプル(C言語プログラム)

に公開

所用で自分でRPMを作らなくちゃいけなくなったのでメモを残しておきます。
自分の整理のためのメモなので誤字脱字等はご容赦ください。

はじめに

やりたいこと

自作のRPMを作る。
(プログラムはサンプル。今回は自作RPMにフォーカスして記載)

前提

試した環境はRedhatEnterpriseLinux9です。

RPM早わかり図

今回の内容を図にまとめると以下です。

作業内容

面倒なのでrootでやります。()

事前準備

1. 依存関係をセットアップします。

dnf module install rpmdevtools gcc

2. ひな形ディレクトリを生成します。

rpmdev-setuptree

これで事前準備OKです。

ひな形としては以下のようなディレクトリになっているはずです。

rpmbuild/
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

サンプルアプリ作成

続いて、C言語のサンプルアプリを作っていきます。

1. ディレクトリ作成

mkdir SOURCES/hello-1.0

これしとかないとあとでこけます。

2. サンプルプログラムを作成する。

SOURCES/hello-1.0/hello.cというファイルで以下を作成します。

#include <stdio.h>

int main() {
    // printf()関数で文字列を表示します
    printf("Hello, World!\n");
    
    // プログラムの終了ステータスを返します
    return 0;
}

3. Tarで固める

cd SOURCES
tar czvf hello-1.0.tar.gz hello-1.0/

Tarで固める必要があるので注意です。
また、ここでディレクトリがないとあとでこけるのでここも注意です。

RPMビルド

お待たせしました。RPMビルドです。
流れとしては以下です。

  1. レシピを作る(SPEC)
  2. レシピをもとにソースPRMを作る
  3. ソースRPMをもとにバイナリRPMを作る。

1. レシピを作る(SPEC)

SPECS/hello.specとして以下ファイルを作成します。

Name: hello
Version: 1.0
Release: 1%{?dist}
Summary: A simple C program
License: GPLv3
Source0: %{name}-%{version}.tar.gz
BuildRequires: gcc

%description
A simple C program that prints "Hello, World!"

%prep
%autosetup

%build
gcc -g -o hello hello.c

%install
install -Dpm 0755 hello %{buildroot}%{_bindir}/hello

%files
%{_bindir}/hello

これがRPMを作るときのレシピになっています。

2. レシピをもとにソースRPMを作る

レシピができたらソースPRMを作ってみます。

rpmbuild -bs SPECS/hello.spec

これをすると、SRPMS/hello-1.0-1.el9.src.rpmというファイルが生成されると思います。
これをもとにして配布用のRPMを作っていくのですね。

3. ソースRPMをもとにバイナリRPMを作る。

ではいよいよバイナリRPMを作ります。

rpmbuild --rebuild SRPMS/hello-1.0-1.el9.src.rpm

これをすると、RPMS/x86_64/hello-1.0-1.el9.x86_64.rpmが生成されると思います。

RPMインストールしてみる

ではインストールして使ってみましょう。

dnf install RPMS/x86_64/hello-1.0-1.el9.x86_64.rpm}

このコマンドでいつもの通りインストールできます。
あとは、コマンドを実行してみておわりですね。

[root@hogehoge rpmbuild]# hello
Hello, World!
[root@hogehoge rpmbuild]# 

やってみると案外あっけないです。
というか結構シンプルでいいですね。

中身見てみる

これで終わってしまうと、ただ作っただけになってしまうので、軽く成果物を見ていきます。

バイナリRPM

fileコマンドで見てみると、当然ですがRPMとして認識されていますね。

[root@hogehoge rpmbuild]# file RPMS/x86_64/hello-1.0-1.el9.x86_64.rpm
RPMS/x86_64/hello-1.0-1.el9.x86_64.rpm: RPM v3.0 bin i386/x86_64 hello-1.0-1.el9
[root@hogehoge rpmbuild]# 

以下で詳細情報を見ることもできます。

[root@hogehoge rpmbuild]# rpm -qpi RPMS/x86_64/hello-1.0-1.el9.x86_64.rpm
Name : hello
Version: 1.0
~~~ 省略 ~~~
[root@hogehoge rpmbuild]# 

ここの項目はSPECで記載したもののプラスアルファですね。

ソースRPM

ではソースRPMを見てみましょう

[root@hogehoge rpmbuild]# cd SRPMS
[root@hogehoge rpmbuild]# 
[root@hogehoge rpmbuild]# rpm2cpio hello-1.0-1.el9.src.rpm | cpio -idmv
[root@hogehoge rpmbuild]# 
[root@hogehoge rpmbuild]# ls -l
hello-1.0-1.el9.src.rpm
hello1.0.tar.gz
hello.spec

rpm2cpioコマンドで中身を見てみると、C言語プログラムをTarで固めたものとRPMのレシピ(SPEC)であることがわかります。

SPEC・ソースRPM・バイナリRPMの役割

なぜ一旦レシピをもとにソースRPMを作り、バイナリRPMを作るのか、というと以下になります。

  • レシピ(SPEC)
    • RPM自体の情報(名前など)が記載されている
    • ビルドプロセスの定義(どうやってビルドするか)が書かれている)
  • ソースRPM
    • ソースコードとSPECファイルがまとめられているもの
    • これがあることによって、「ビルドをしやすくしている」
    • 例えるなら「具材と調理器具」
  • バイナリRPM
    • コンパイル済み、つまりそのまま実行できるものがまとめられている
    • 例えるなら「完成している料理」

おわり

今時LLMでも手伝ってくれるのであまりまとめる意味ないかもですが、自分用のメモとして。

作ってみると案外簡単であることがわかりますね。
Go言語のサンプルアプリとかもやってみたいです。

Discussion