LoginSignup
0
1

上級者のための Hello World! 2 ~C/C++ プログラミング~

Last updated at Posted at 2023-10-19

前:上級者のための Hello World! ~C/C++ プログラミング~

はじめに

これは C/C++ に関する記事の二つ目である。今回はライブラリの作成者が作るべきツールについて書く。今回はそれぞれのツールについては深入りしない。

Make

C/C++ のコンパイル方法は前回みたように長かった。また、ファイルやライブラリも増えていくとコンパイルに時間がかかり大変だ。そこで、コンパイルを自動化するために Make がうまれた。我々が Makefile というテキストファイルにコンパイル方法を書き込んでおくと、勝手にコンパイルがおこなわれるのである。

書き方

前回作ったバイナリファイルを全て消しておこう。

ターミナル
$ rm lib/* ./hello*

Makefile の基本的な書き方は下の通りである。<コマンド> の左は必ず Tab でなくてはならない。空白だと動かない。<ターゲット> とは通常、生成されるファイルのことである。

基本的な Makefile
<ターゲット>: <依存ファイル>
	<コマンド>

<依存ファイル><コマンド> は 0 個でも 100 個でもいい。

実行するときは下のようにする。

ターミナル
$ make <ターゲット>

Make ではまず <ターゲット> のところが呼ばれる。そして依存ファイルを再帰的にたどっていって、もし前回の Make と違っていればコマンドを実行する。下にフローチャートを書いた。

make-ページ2 (1).jpg

ライブラリの作成

前回のライブラリを生成する Makefile を下に書く。静的ライブラリと共有ライブラリをどちらも作る。先に言っておくが、これはスマートな書き方ではない。これを lib ディレクトリに入ってそこに置いておく。

ターミナル
$ cd lib
$ touch Makefile
lib/Makefile
.PHONY: all
all: libhello.a libhello.so

libhello.a: hello.o
	ar r libhello.a hello.o

libhello.so: hello.o
	gcc hello.o -o libhello.so -shared

hello.o: ../src/hello.c ../include/hello.h
	gcc -c ../src/hello.c -I../include

ここで 1 行目の .PHONY: all をみてほしい。これは「all というのがファイルではない」という意味だ。これで下のように打つと、all の依存関係のファイルがすべて作られ、コマンドが実行される(この例だとコマンドはない)。

ターミナル
$ make all

次に、lib/libhello.so を生成するところを見てほしい。前回と違い lib/hello.o から共有ライブラリを作っている。Makefile では、.c などのソースコードからまず .o ファイルを作成する。こうすることでソースコードが変更されても、そのファイルだけをコンパイルしなおすことができる。

もう一度 make all を打ってみよう。

ターミナル
$ make all
make: Nothing to be done for 'all'.

これは依存ファイルがすべて編集されていないため、なにも起こらなかったのである。例えば include/hello.h の編集時刻を更新してみよう。

ターミナル
$ touch hello.h
$ make all

コマンドが再び実行されているのがわかるだろう。

Makefile から Makefile を呼ぶ

別のディレクトリから Makefile を呼ぶには、-C オプションを使う。

ターミナル
$ cd .. && touch include/hello.h
$ make all -C lib

hello_ws 直下に Makefile を書くと統合できる。

ターミナル
$ touch Makefile include/hello.h
Makefile
.PHONY: all
all:
	make all -C lib
ターミナル
$ make all

Makefile の書き方は以下に詳しい。

makeコマンドを使ってみよう #1 — MIRACLE LINUX サポート&テクノロジー | サイバートラスト株式会社

ついにッ!最強のMakefileが完成したぞッッッ!!! - Qiita

pkg-config

ライブラリの作成は自動化できたが、コンパイルの引数の問題は解決していない。例えば画像処理に使われるOpenCV では現在、ライブラリが50個以上ある。コンパイルのたびにライブラリを50個以上指定するさまを想像してほしい。 pkg-config はライブラリを使うときにコンパイラへ引数を渡す役割を負う。ライブラリの製作者が pc という拡張子のファイルを作成することで使用できる。

書き方

<ライブラリ>.pc ファイルの基本的な書き方は下のとおりである。

<ライブラリ>.pc
<オプション>: <出力>

また、.pc ファイルでは変数も使える(Makefile でも使える)。

<ライブラリ>.pc
<変数名>=<値>

変数を使いたいところに ${<変数名>} と書けば、そこが <値> で置き換わって使うことができる。

オプションは自由に決められないが、変数は自由に決められる。

.pc ファイルの作成

ではライブラリを使うための .pc ファイルを作ろう。 lib/pkgconfig の配下に hello.pc ファイルを作る。

ターミナル
$ mkdir lib/pkgconfig
$ touch lib/pkgconfig/hello.pc

1行目の <hello_wsへのパス> には pwd コマンドの出力をコピペして書き換えてほしい。

hello.pc
prefix=<hello_wsへのパス>

Name: HelloLib
Version: 1.0
Description: Hello World! を出力するライブラリ

Libs: -L${prefix}/lib -lhello

Cflags: -I${prefix}/include

Name, Version, Description がないとエラーが出る。適当に書いておこう。

このままでは pkg-config.pc ファイルを探せないので、環境変数 PKG_CONFIG_PATHlib/pkgconfig を指定しておこう。

ターミナル
$  export PKG_CONFIG_PATH=$PWD/lib/pkgconfig:$PKG_CONFIG_PATH

pkg-config はオプションに応じて文字列を出力するだけのコマンドである。下のコマンドをそれぞれ実行してみよう。オプションの最初の文字が小文字になっていることに注意してほしい。

ターミナル
$ pkg-config --libs hello
$ pkg-config --cflags hello

オプションはまとめることができる。コンパイルしてみよう。$() は先に () 内のコマンドを実行して文字列を置換する。

ターミナル
$ gcc main.c -o hello $(pkg-config --cflags --libs hello)
$ ./hello

下のエラーが出るときはライブラリへのパスを指定していないためなので、 export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH を実行してほしい。(ここを参照

ターミナル
./hello: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1