SConsことはじめ　その2


[ここ](http://qiita.com/toshiyukihina/items/e014dfbbdd43d0c87a1b)の続き。
今回は、共有ライブラリを作る手順と、インストールのターゲットの作成方法。（`make install`みたいなの。）

# 共有ライブラリを作成する

入力パラメータとして渡した名前`name`を、`"Hello <name>!"`として標準出力する関数を提供するライブラリを作成してみる。

まずはヘッダ`libhello.h`。

```cc:libhello.h
#ifndef __LIBHELLO_H__
#define __LIBHELLO_H__

void hello(char* in_name);

#endif /* __LIBHELLO_H__ */
```

次に、ソース`libhello.c`。

```cc:libhello.c
#include <stdio.h>

void hello(char* in_name) {
  printf("Hello %s!\n", in_name);
}
```

共有ライブラリを作成する`SConstruct`は、以下。`SharedLibrary()`関数を使って、共有ライブラリを作成する。

```py
env = Environment()

# Create a shared library
lib_target = "libhello"
lib_sources = ["libhello.c"]
env.SharedLibrary(target=lib_target, source=lib_sources)
```

ここまでで作成されたファイルは、以下。

```bash
$PROJ_ROOT
├── libhello.c
├── libhello.h
└── SConstruct
```

ここで一度、`scons`コマンドを実行すると、`$PROJ_ROOT`に`libhello.so`が作成されるはず。

```bash
$PROJ_ROOT
├── libhello.c
├── libhello.h
├── libhello.os
├── libhello.so <= (*)
└── SConstruct
```

# 共有ライブラリの利用者側プログラム

`libhello.so`を利用する側のプログラム`hello`を作成する。ライブラリが提供する`hello()`を呼び出すだけのプログラム。

```cc:hello.c
#include "libhello.h"

int main(void) {
  hello("World");
  return 0;
}
```

`hello`を作成するコードを追加した`SConstruct`は以下。

```py
env = Environment()

# Create a shared library
lib_target = "libhello"
lib_sources = ["libhello.c"]
env.SharedLibrary(target=lib_target, source=lib_sources)

# Create a exectable using libhello.so
bin_target = "hello"
bin_sources = ["hello.c"]
env.Program(target=bin_target, source=bin_sources, parse_flags="-I. -L. -lhello")
```

ここまでで、共有ライブラリ`libhello.so`と、呼び出し側の`hello`プログラムが作成されるはずなので、`scons`コマンドを実行する。ビルドが正常に完了すると、以下のように、それぞれのファイルが作成されているはず。

```bash
$PROJ_ROOT
├── hello <= 実行可能形式のプログラム
├── hello.c
├── hello.o
├── libhello.c
├── libhello.h
├── libhello.os
├── libhello.so <= 共有ライブラリ
└── SConstruct
```

# 実行してみる

`libhello.so`のありかを`hello`に教えてあげるために､`LD_LIBRARY_PATH`に`libhello.so`のパスを設定する。
正常に実行されると、`Hello World!`という文字列が標準出力に出力される。

```bash
$ LD_LIBRARY_PATH=. ./hello
Hello World!
```

# インストールターゲットを定義する

共有ライブラリをインストールするターゲットを定義してみる。
これまでに作成した`SConstruct`を若干いじって以下のようにする。

```py
env = Environment()

# Create a shared library
lib_target = "libhello"
lib_sources = ["libhello.c"]
libhello = env.SharedLibrary(target=lib_target, source=lib_sources)

# Create a exectable using libhello.so
bin_target = "hello"
bin_sources = ["hello.c"]
env.Program(target=bin_target, source=bin_sources, parse_flags="-I. -L. -lhello")

env.Install(dir="/usr/local/lib", source=libhello)
```

変更したのは、`env.SharedLibrary()`の戻り値を`libhello`変数に受けているところと、最後の行である。([差分](https://github.com/toshiyukihina/scons-shared-lib/commit/da02b0427671dac95e630747ac331305c165d3e8))
ここで、`scons /usr/local/lib`コマンドを実行すると、`/usr/local/lib`に`libhello.so`がインストールされているはずである。

```bash
$ sudo scons /usr/local/lib
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
Install file: "libhello.so" as "/usr/local/lib/libhello.so"
scons: done building targets.
```

# インストールターゲットを改良する

`scons`コマンドのターゲットに、フルパスを渡すのは面倒なので、`Alias`という機能を使う。最終行を追加した。([差分](https://github.com/toshiyukihina/scons-shared-lib/commit/037db8f2b0b52c16c2df8171c4dd288f51cca94e))

```py
env = Environment()

# Create a shared library
lib_target = "libhello"
lib_sources = ["libhello.c"]
libhello = env.SharedLibrary(target=lib_target, source=lib_sources)

# Create a exectable using libhello.so
bin_target = "hello"
bin_sources = ["hello.c"]
env.Program(target=bin_target, source=bin_sources, parse_flags="-I. -L. -lhello")

env.Install(dir="/usr/local/lib", source=libhello)
env.Alias("install", ["/usr/local/lib"])
```

今度は、`scons install`コマンドを実行する。先ほどと同様、`/usr/local/lib`にインストールされるはずである。

```bash
$ sudo scons install    
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
Install file: "libhello.so" as "/usr/local/lib/libhello.so"
scons: done building targets.
```

# ソースコード

https://github.com/toshiyukihina/scons-shared-lib