忍者ブログ

素人翻訳

適当に翻訳する。

pkg-config の手引き

出典:http://people.freedesktop.org/~dbn/pkg-config-guide.html

Dan Nicholson 著
全体像

この文書の狙いは、pkg-config ツールを使うということがどういうことなのか、その全体像を利用者・開発者双方の視点から描き出すことである。本文書では次の3つのものについて述べる。pkg-config の概要、自分のプロジェクトに沿った pkg-config ファイルの書き方、及び pkg-config を使って第三者のプロジェクトを取り込む方法である。

詳しい情報はこのサイトやpkg-config(1) のマニュアル・ページにある。

この文書では、Linux のような Unix 様のオペレーティング・システムで pkg-config を使用することを前提にしている。 他の環境では細かい部分で異同があるだろう。

何故?

現代の計算機システムでは、利用者にアプリケーションを提供するため、多数の階層化された部品を用いている。これらの部品を一つに纏めて組み上げる際、特に問題となるのは各部品を正しく結びつけることである。pkg-config を使えば、利用者はインストール済みライブラリのメタデータ(metadata)を容易く蒐集できる。

pkg-config のようなメタデータを扱う仕組みがない場合、各計算機に備わる機能を検出し、その機能の詳細を得るのは難しい。開発者にとっては、自作パッケージに pkg-config ファイルを仕込んでおくことで、自分の API が利用されやすくなるという利がある。

概要

pkg-config の主要な用途は、プログラムをコンパイル&リンクしてライブラリを生成する際に必要となる、細かい情報を取得することである。このメタデータは pkg-config ファイルに書いておく。同ファイルの拡張子は「.pc」である。pkg-config に認識される所定の場所に「.pc」ファイルを置く。これは後ほど詳説する。

pkg-config ファイルは、予め定義されているメタデータの鍵語の群と、自由形式の変数群から成る。例を見た方が分かり易いだろう

prefix=/usr/local
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: foo
Description: The foo library
Version: 1.0.0
Cflags: -I${includedir}/foo
Libs: -L${libdir} -lfoo

上記の「Name:」のような鍵語の定義は、鍵語、コロン、値の順で記述する。「prefix=」のような変数は、文字列、等号、値の順で記述する。鍵語は pkg-config によって定義され、共有される(exported)。変数群は必ず要るわけではないが、鍵語の定義に柔軟性を持たせたり、pkg-config の担当外の情報を記憶したりするために使われる。

以下は鍵語の欄の簡単な説明である。鍵語の欄の詳しい説明と効果的な活用方法はpkg-config ファイルの書き方の項を参照。

  • Name: 人間に読める形の、ライブラリもしくはパッケージの名前。pkg-config は「.pc」ファイルのファイル名を利用するので、この定義は直接影響しない。
  • Description: パッケージ(package)の簡単な説明。
  • URL: パッケージに関する更なる情報が得られるURL。パッケージが取得できるURL。
  • Version: パッケージの版を一貫した様式で定義する文字列。
  • Requires: このパッケージの利用に必要となるパッケージの一覧表。ここで挙げるパッケージ群の版は比較演算子 =、<、>、<=、もしくは >= を使って指定する。
  • Requires.private: このパッケージには必要とされるが、アプリケーションには見せない非公開パッケージの一覧表。「Requires」の欄と同じく比較演算子を用いて版を指定する。
  • Conflicts: このパッケージと衝突するパッケージを記述する任意欄。「Requires」の欄と同じく比較演算子を用いて版を指定する。同一パッケージの複数の版に関する記述を持つことができる。例えば、「Conflicts: bar < 1.2.3, bar >= 1.3.0.」のように。
  • Cflags: コンパイラ・フラグのうち、このパッケージと pkg-config に対応していない必須ライブラリのためのもの。もし必須ライブラリが pkg-config に対応している場合、そうしたライブラリは「Requires」もしくは「Requires.private」の欄に書き加えるべきである。
  • Libs: リンカ・フラグ(link flags)のうち、このパッケージと pkg-config に対応していない必須ライブラリのためのもの。pkg-config 対応の必須ライブラリについては「Cflags」に同じ。
  • Libs.private: リンカ・フラグ(link flags)のうち、このパッケージには必要とされるがアプリケーションには見せない非公開ライブラリに適用されるもの。pkg-config 対応の必須ライブラリについては「Cflags」に同じ。
pkg-config ファイルの書き方

あるパッケージのために pkg-config ファイルを作成する場合、pkg-config ファイル群がパッケージ内でどのように配置されるのかを最初に決める必要がある。各 pkg-config ファイルがそれぞれライブラリ1個の説明を担う時、同ファイルは最も威力を発揮する。そのため各パッケージには、利用するインストール済みライブラリと(少なくとも)同数の pkg-config ファイルを同梱するべきである。

パッケージの名前は pkg-config メタデータ・ファイルのファイル名を通じて決定される。ファイル名の拡張子「.pc」より前の部分がパッケージ名になる。大抵はライブラリの名前と「.pc」ファイルの名前を合わせる。例えば、「libfoo.so」をインストールするパッケージには、pkg-config メタデータを含むファイルとして「libfoo.pc」を用意する。名前をこのように決めなければいけない訳ではない。「.pc」ファイルが自作ライブラリの固有な識別子として機能すれば足りる。上の例で言えば、「foo.pc」でも「foolib.pc」でも上手く行くだろう。

「Name」「Description」「URL」の欄は単に情報を伝える場所なので、書くのは易しい。「Version」欄は気をつけて書かないと、データの消費者にとって使えないものになる可能性がある。pkg-config は版番号を比較するアルゴリズムを RPM から借りている。これは小数点で区切られた十進数(例えば 1.2.3)の比較に向いている。版番号の表記の途中に文字(letters)を使うと予期せぬ結果を引き起こす。数字の番号は単調に増していくべきであり、ライブラリの版を確実に特定できるようにするべきである。通常、パッケージの版番号を「Version」欄に使えば十分である。そうすれば、この情報の消費者が版を辿りやすくなる。

もっと有用な鍵語を説明する前に、変数の定義を例示しておこう。変数定義の最も一般的な使い方は、メタデータ欄が煩雑にならないよう、インストール場所へのパス(path、経路)を定義しておく、というものである。変数は再帰的に展開されるので、autoconf で得られた経路と組み合わせて使うと役に立つ。

prefix=/usr/local
includedir=${prefix}/include

Cflags: -I${includedir}/foo

最も重要な pkg-config メタデータ欄は「Requires」「Requires.private」「Cflags」「Libs」及び「Libs.private」である。ここに記述されたメタデータは、外部のプロジェクトがライブラリのコンパイルとリンクを行う際に使用する。

「Requires」と「Requires.private」には、ライブラリに必要な他のモジュール群を記述する。自作ライブラリをリンクしようとするプログラムに対して、そのプログラムが必要としていないライブラリを見せたくない場合、「private」で修飾された「Requires」を使用するのが望ましい。同プログラムが必須とされたライブラリのシンボル(symbols)を利用しないのであれば、そのライブラリはプログラムに直接リンクされるべきではない。詳しい説明は過剰結合(overlinking)の考察を参照。

pkg-config が「Requires」欄のライブラリのリンカ・フラグ(link flags)を常に公開してしまうため、この欄のモジュール群は上記プログラムが直接依存するものとして認識されてしまう。一方、「Requires.private」欄のライブラリは静的リンクの時しか組み込まれない。以上の理由から、通常は「Requires」に書かれているパッケージと同一のモジュール群だけを繋げるべきである。

「Libs」欄には、ライブラリを使用するのに必要なリンカ・フラグ(link flags)を記す。それ加えて、「Libs」と「Libs.private」には pkg-config に対応していない他のライブラリのリンカ・フラグ(link flags)も入れる。「Requires」欄と同じく、外部ライブラリのリンカ・フラグ(link flags)は「Libs.private」欄に加えるのが好ましい。それによってプログラムは余計な直接依存関係を抱え込まなくて済む。

最後に、ライブラリを使うためのコンパイラ・フラグを記す「Cflags」がある。「Libs」欄と異なり、「Cflags」に「private」形は存在しない。データの型とマクロの定義は、リンクの方法に関わりなく必要だからである。

pkg-config ファイルの利用

システムに「.pc」ファイルが然るべく配置されていれば、pkg-config でメタデータを引き出して活用できる。「pkg-config --help」を実行することで、実行時オプションの簡単な説明が見られる。詳細な記述は pkg-config(1) のマニュアル・ページにある。この項では一般的な使用方法について手短に解説する。

「foo」と「bar」の二つのモジュールを含むシステムを考える。「.pc」ファイルは次のようなものだとしよう。

foo.pc:
prefix=/usr
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: foo
Description: The foo library
Version: 1.0.0
Cflags: -I${includedir}/foo
Libs: -L${libdir} -lfoo

bar.pc:
prefix=/usr
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: bar
Description: The bar library
Version: 2.1.2
Requires.private: foo >= 0.7
Cflags: -I${includedir}
Libs: -L${libdir} -lbar

モジュールの版番号は「--modversion」指定を付して取得できる。

$ pkg-config --modversion foo
1.0.0
$ pkg-config --modversion bar
2.1.2

各々のモジュールに必要なリンカ・フラグ(link flags)は、「--libs」指定を付して表示できる。

$ pkg-config --libs foo
-lfoo
$ pkg-config --libs bar
-lbar

pkg-config が両モジュールの「Libs」欄の一部を表示していないことに注意して欲しい。これは pkg-config が「-L」指定を特別扱いしており、「$(libdir)」ディレクトリ即ち「/usr/lib」がシステムのリンカの標準的な参照場所であることを知っているからである。このお陰で、リンカの動作が pkg-config によって妨げられずに済む。

また、「bar」は「foo」を必須指定しているが、「foo」を示すリンカ・フラグ(link flags)は出力されていない。「bar」ライブラリだけを要求しているアプリケーションは、「foo」ライブラリを直に必要としているわけではないからである。「bar」を利用したアプリケーションを静的にリンクするには、両モジュールのリンカ・フラグが要る。

$ pkg-config --libs --static bar
-lbar -lfoo

pkg-config はこの場合、双方のリンカ・フラグ(link flags)一式を出力しなければならない。静的にリンクされたアプリケーションが必要なシンボル(symbols)の全てを見つけられるようにするためである。一方、pkg-config は全ての「Cflags」を常に出力する。

$ pkg-config --cflags bar
-I/usr/include/foo
$ pkg-config --cflags --static bar
-I/usr/include/foo

「--exists」指定も役に立つ。これを使えば、モジュールが利用可能か否かを検査できる。(訳註、利用できる時は 0、利用できないときは 1 が出力される。)

$ pkg-config --exists foo
$ echo $?
0

最もありがたい pkg-config の機能の一つに、版番号の確認がある。条件を満たした版が利用可能かどうかを判定するのに使える。

$ pkg-config --libs "bar >= 2.7"
Requested 'bar >= 2.7' but version of bar is 2.1.2

「--print-errors」指定と組み合わせて使った場合に、長文を出力する命令もある。

$ pkg-config --exists --print-errors xoxo
Package xoxo was not found in the pkg-config search path.
Perhaps you should add the directory containing `xoxo.pc'
to the PKG_CONFIG_PATH environment variable
No package 'xoxo' found

上の出力は環境変数 PKG_CONFIG_PATH に触れている。この変数は pkg-config の検索経路を増やすために使用される。典型的な UNIX システムでは、pkg-config はディレクトリ「/usr/lib/pkgconfig」と「/usr/share/pkgconfig」の中を検索する。大抵はこれでシステムにインストールされているモジュールを網羅できる。しかし、モジュールの中には「/usr/local」のような異なるディレクトリにインストールされているものもあるかもしれない。そのような場合、pkg-config が「.pc」ファイルを探し出せるよう、検索経路を追加する必要がある。

$ pkg-config --modversion hello
Package hello was not found in the pkg-config search path.
Perhaps you should add the directory containing `hello.pc'
to the PKG_CONFIG_PATH environment variable
No package 'hello' found
$ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
$ pkg-config --modversion hello
1.0.0

pkg-config を利用しているモジュール群をプロジェクトに組み込み易くする目的で、autoconf マクロも幾つか用意されている。

  • PKG_PROG_PKG_CONFIG([MIN-VERSION]): システム内の pkg-config を探し出し、版を調べて互換性の有無を確認する。
  • PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]): 特定のモジュール群が存在するか調べる。
  • PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]): 特定のモジュール群が存在するか調べる。もし存在すれば、「pkg-config --cflags」と「pkg-config --libs」の出力結果に従って、 「<VARIABLE-PREFIX>_CFLAGS」と「<VARIABLE-PREFIX>_LIBS」を設定する。
よくある質問
  • 自作プログラムがライブラリ「x」を使っている。どうすればいいか。

    pkg-config の出力は、簡単にコンパイラ宛ての命令文の中で使用できる。「x」ライブラリが「x.pc」という pkg-config ファイルを持っている場合:

    cc `pkg-config --cflags --libs x` -o myapp myapp.c

    autoconfautomake とともに用いることで、プログラムの統合作業がより堅牢になる。予め用意されている PKG_CHECK_MODULES マクロを使うことで、構築処理中でも簡単にメタデータを取得できるようになる。

    configure.ac:
    PKG_CHECK_MODULES([X], [x])

    Makefile.am:
    myapp_CFLAGS = $(X_CFLAGS)
    myapp_LDADD = $(X_LIBS)

    もし機能「x」を発見した場合、マクロは変数「X_CFLAGS」と「X_LIBS」を実際の値に書き換える。もしその機能が見つからなければエラーを出す。PKG_CHECK_MODULES マクロに任意で第三第四引数を追加すると、モジュールの有無に従って動作を変えることができる。

  • 自作ライブラリ「z」はヘッダ・ファイルの中で「libx」のヘッダを取り込んでいる。「z.pc」ファイルには何を書くべきか。

    もしライブラリ「x」が pkg-config に対応しているなら、「Requires.private」欄に書き加える。対応していなければ、「libx」ヘッダを使うために必要なコンパイラ・フラグを「Cflags」欄に追加する。どちらの場合でも、「--static」の使用不使用にかかわらず、pkg-config はコンパイラ・フラグを出力する。

  • 自作ライブラリ「z」は内部で「libx」を使用しているが、公開 API では「libx」のデータ型を公表していない。「z.pc」ファイルには何を書くべきか。

    先と同様、「libx」が pkg-config に対応していれば「Requires.private」にモジュールを追加するだけでよい。この場合、コンパイラ・フラグが無駄に吐かれるが、同時に静的リンクにおけるリンカ・フラグの存在が保証される。もし「libx」が pkg-config に対応していなければ、必要とされるリンカ・フラグを「Libs.private」に追加する。

Dan Nicholson <dbn.lists (at) gmail (dot) com>

Dan Nicholson 著
この文書は GNU General Public License 第二版もしくはそれ以降の版に則っている。
PR

コメント

お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード Vodafone絵文字 i-mode絵文字 Ezweb絵文字

カレンダー

06 2020/07 08
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

最新コメント

[04/05 NONAME]

ブログ内検索

広告

バーコード

広告