AVR Libc Home Page | ![]() |
AVR Libc Development Pages | |||
Main Page | User Manual | FAQ | Library Reference | Additional Documentation | Example Projects |
一度つくった関数は繰り返し繰り返し使いますよね?しかしいちいちプロジェクトから別のプロジェクトへカットペーストで関数を移すのでは疲れませんか?その手間を省きたいと思いませんか?
そこで、あなた自身のライブラリを作りましょう! コードの再使用はとてもいいことです(very
laudable goal)。少しの事前の手間でいつでも使えるライブラリを作っておくことで、将来のプロジェクトに関して時間とエネルギーを大いに節約することができます。
この章では自分自身のライブラリを構築して使用するために必要な背景となる情報や、設計方法(design
considerations)や、実践的な知識について説明します。
コンパイラはひとつの高レベル言語(たとえばC言語)ファイルをひとつのオブジェクトモジュールファイルにコンパイルします。
リンカ(ld)は、オブジェクトモジュールを合体させます。オブジェクトモジュールはリンカの対象になるもので最小単位になります。
リンカを起動させるコマンドラインにおいて、事前にコンパイルされたオブジェクトモジュールや、ライブラリのリストを指定できます。ライブラリにはCの標準ライブラリも含まれます。リンカはコマンドラインで指定されたオブジェクトモジュールをリンクしていきます。リンクの後で「未定義参照」というものが残ります。参照というのは基本的には関数呼び出しです(※変数もあり)。未定義参照というのは(与えられたオブジェクトファイルの中に)呼び出しに合致する関数がどこにも定義されていないということです。
リンカはそこで、呼び出しに合致する関数を求めてライブラリを探しに行きます。(もしあれば)リンカは関数を含むオブジェクトモジュール(ライブラリ内にあり)をリンクします。
ここは重要なのですが、リンカはここで関数を含むモジュールを丸ごと全部リンクします。リンカは、オブジェクトモジュールの中身については、提示されているシンボル名(関数名など)以外、何も知りません、リンカにとっての最小単位はオブジェクトモジュール単位なのです。
未定義参照が無くなったとき、リンカは全てをリンクして最終的なアプリケーションを出力します。
リンカの振る舞いはライブラリのデザインにとって重要なことです。
理想的にはライブラリにはあなたが呼び出してリンクし、アプリケーションに組み込みたい関数1つだけを置きたいでしょう。
こうすればコードサイズが最小に収まるからです(※前節参照)。しかしこうすると関数ひとつにつきモジュール1つをリンカ動作指定(※コマンドラインやMakefile)に記入しておかねばなりません。
これだと、関数1つ毎にオブジェクトモジュール1つをコンパイルせねばなりません。これはアプリケーション構築にはいささかまずいやりかたです。
※補足:これを回避するためにライブラリという仕組みがあります。1つまたは関連する数個の関数を1つのモジュールに入れたものを、ライブラリ内にたくさん持つようにすれば、リンカにはライブラリ名の指定をするだけで、いくつもの関数を、使う分だけを(モジュール単位で)取り出してリンクさせることができます。
例: 使う関数に応じてstrcat,strcpy,strstrと個別ライブラリをリンクして使うより、libcを1つ設定すれば済む方が便利である
ルールにはいつも例外というものがあります。オブジェクトモジュール1つから1つ以上の関数を利用する2つのケースがあります。
1つは、分離すると無駄が多い関数を1つにまとめることです。たとえば、 malloc() とfree()があげられます。 malloc()を使う場合、 free() を使わないと言うことはまずありません。この場合、2つの関数は同じオブジェクトモジュールにまとめるのが適切です。
2番目のケースとしては、割り込みサービスルーチン(ISR)をライブラリ内に持ち、これをリンクする場合です。この場合、リンカが未解決参照を探し、ライブラリ内のコードで解決しようとするのが問題になります。参照は関数コールと同じです。しかしISRについては、これは関数コールではなく、ISRルーチンを呼び出す関数コールというものはありません。ISRは割り込みベクタテーブル(IVT)内に置かれ、呼び出されたり参照されたり外部から参照されたりすることはありません。ISRを組み込むには、リンカにある方法でトリックを使わなければなりません。
ISRを他の関数と一緒に同じオブジェクトモジュールにまとめます。その関数はISRを使用するために何かの処理を行うもので、サブシステムの初期化やISRを有効にするためのものです。※これにより、初期化関数を呼び出せばISRルーチンも組み込まれるようにモジュールが構築できます。
ライブラリアン(図書館司書)プログラムは ar(archiver) と呼ばれ、GNU Binutilsプロジェクト内にあります。このプログラムはAVRターゲット用に(も)構築され、(avrターゲットなので)avr-arと名付けられます。
ライブラリアンプログラムはシンプルなものです。オブジェクトモジュールのリストを、1つのライブラリ(アーカイブ)ファイルにまとめ上げ、リンカが利用できる索引を付けるものです。あなたがつけるライブラリのファイル名は以下のパターンに従わなければなりません:
"libname.a"
nameの部分にはあなたが決める独自の名前が入ります。name部分が中身を表す用にしておけばライブラリを楽に扱えます。
name部分の頭には"lib"の文字列をつけなければなりません。また、末尾に".a" (archiveを意味する)をつけなければなりません。この特別なファイル名形式は、ツールチェーン内でこのファイルがどのように扱われるかを決めるためのものです。後に出てきます。
コマンドラインはとてもシンプルです:
avr-as rcs <library name> <list of object modules>
r
コマンドスイッチは、プログラムに対し、オブジェクトモジュールをアーカイブに入れ、同名ファイルがあれば更新するように指示するものです。
c コマンドラインスイッチはアーカイブを作成するよう指示するものです。
s コマンドラインスイッチはオブジェクトファイルの索引をアーカイブ内に書き込み及び既にある分を更新するよう指示します。
最後のスイッチ(s)は重要なもので、これはリンカが何をなすべきか見つけるのを助けます。
MFile と WinAVR 配布物には、ライブラリを構築するために必要なコマンドラインを含んだ Makefile 雛形が含まれています。この雛形を手直ししてアプリケーション構築の代わりにライブラリを作らせることもできます。
arプログラムの詳細については、GNU Binutils マニュアルをご覧ください。
ライブラリを使うには、 -l
スイッチをリンカのコマンドラインに加えます。-l
の後に続く文字列にはライブラリ名の独自部分(libxxxx.a
のxxxx部分)を指定します。たとえば、
-lm
このコマンドラインスイッチは以下のライブラリファイル名に拡張されます。
libm.a
こうして、avr-libcのmathライブラリ名となります。
リンカコマンドラインで以下のような指定をすれば、
-lprintf_flt
リンカは下記のようなライブラリファイルを探します。
libprintf_flt.a
これがライブラリファイルの名前が重要である理由です。
リンカはライブラリを、コマンドラインに現れる順序で(左から)検索していきます。未定義参照に対する関数が見つかった時点でそれがリンクされます。
さらに、GCCに対し、ライブラリをどのディレクトリから探すか指定する
(-L
) スイッチもあります。
GNU linker (ld)の詳細については、 GNU Binutils manual をご覧ください。