# c-modernization-kit サンプル (override-sample)

これは、動的ライブラリのオーバーライド機能を示すサンプルです。

# 1 概要

`libbase` が公開する `sample_func` 関数は、起動時に読み込む設定ファイルによって処理を切り替えます。

funcman 機構 (関数の動的呼び出しキャッシュ) は `prod/funcman/` として独立した静的ライブラリに分離されており、`libbase` はそれをリンクして利用します。

設定ファイルの状態 | 動作
--- | ---
存在しない (または定義なし) | `libbase` 自身が処理を行う (`a + b`)
`sample_func liboverride override_func` を定義 | `dlopen` / `LoadLibrary` で `liboverride` を実行時にロードし、`override_func` に処理を委譲する (`a * b`)

オーバーライドの切り替えは `libbase` がロードされるタイミング (constructor / `DllMain`) で行われます。メインプログラムを変更せずに、設定ファイルを置くだけでライブラリの実装を差し替えられることを示します。

# 2 ファイル構成

    prod/override-sample/
    +-- include/
    |   +-- libbase.h              # libbase ヘッダー (sample_func, console_output 等の宣言)
    |   +-- libbase_ext.h          # liboverride ヘッダー (override_func の宣言)
    +-- libsrc/
    |   +-- base/
    |   |   +-- funcman_libbase.h  # funcman オブジェクトの extern 宣言
    |   |   +-- funcman_libbase.c  # funcman オブジェクトの実体定義
    |   |   +-- sample_func.c      # sample_func の実装 (funcman 経由でオーバーライドを呼び出す)
    |   |   +-- console_output.c   # console_output の実装 (printf ラッパー)
    |   |   +-- dllmain_libbase.c  # onLoad / onUnload の実装
    |   +-- override/
    |       +-- override_func.c    # override_func の実装 (libbase から dlopen で呼ばれる)
    +-- src/
    |   +-- override-sample/
    |       +-- override-sample.c  # メインプログラム
    +-- sample-config/
    |   +-- libbase_extdef.txt     # 設定ファイルのサンプル
    +-- lib/                       # ビルド済みライブラリ (libbase.so / liboverride.so / libbase.dll / liboverride.dll)
    +-- bin/                       # ビルド済み実行ファイル (override-sample / override-sample.exe)

funcman 機構・DllMain ヘルパー・ライブラリパス取得ユーティリティは `prod/funcman/` として独立した静的ライブラリ (`libfuncman.a`) に分離されています。

# 3 ライブラリ

## 3.1 libbase (動的ライブラリ)

`libbase.so` / `libbase.dll` を提供します。

### 3.1.1 sample_func

    int WINAPI sample_func(const int a, const int b, int *result);

- 設定ファイルで `override_func` が定義されているとき: `liboverride.so` / `liboverride.dll` を動的にロードし、`override_func` に処理を委譲する
- それ以外のとき: `*result = a + b` を計算して返す

### 3.1.2 console_output

    void WINAPI console_output(const char *format, ...);

`printf` と同じ書式でコンソールに出力する関数です。
`liboverride` からも呼び出しています。これは、動的にロードされた拡張処理から基底ライブラリの関数を呼び出すことができることのサンプル実装です。

## 3.2 liboverride (動的ライブラリ)

`liboverride.so` / `liboverride.dll` を提供します。`libbase` の `sample_func` から設定に応じて実行時にロードされます。

### 3.2.1 override_func

    int WINAPI override_func(const int a, const int b, int *result);

`sample_func` と同じシグネチャを持ちます。`*result = a * b` を計算して返します。

# 4 動作の仕組み

## 4.1 設定ファイル

`libbase` はロード時 (constructor / `DllMain(DLL_PROCESS_ATTACH)`) に設定ファイルを読み込みます。

プラットフォーム | 設定ファイルパス
--- | ---
Linux | `/tmp/libbase_extdef.txt`
Windows | `%TEMP%\libbase_extdef.txt`

ファイルが存在しない場合はデフォルト動作になります。ファイルのフォーマットは以下のとおりです。

    func_key  lib_name  func_name

lib_name / func_name の値 | 動作
--- | ---
ともに `default` | 明示的デフォルト。設定ファイルなしと同様にデフォルト処理を行う
ライブラリ名 / 関数名 | 指定したライブラリを動的ロードし、関数に処理を委譲する

`sample-config/libbase_extdef.txt` に設定ファイルのサンプルがあります。初期状態では `default default` (明示的デフォルト) が設定されており、オーバーライドする行はコメントアウトされています。

`sample_func` をオーバーライドする場合は以下の行を記述します。

    sample_func  liboverride  override_func

## 4.2 呼び出しフロー

    override-sample (実行ファイル)
        |
        | sample_func(1, 2, &result)
        +---> libbase.so / libbase.dll
                  |
                  funcman が解決済み関数ポインタを確認
                  |
                  [設定ファイルなし / 定義なし → デフォルト動作]
                  |  *result = 1 + 2 = 3
                  |
                  [設定ファイルで liboverride / override_func を定義 → オーバーライド動作]
                  |  funcman が liboverride.so / liboverride.dll を dlopen / LoadLibrary
                  |  override_func に処理を委譲
                  +---> liboverride.so / liboverride.dll (実行時ロード)
                            *result = 1 * 2 = 2

# 5 ビルド

    cd prod/override-sample
    make

ビルド成功後、以下のファイルが生成されます。

ファイル | 説明
--- | ---
`lib/libbase.so` | ベースライブラリ (Linux)
`lib/liboverride.so` | オーバーライドライブラリ (Linux)
`bin/override-sample` | メインプログラム (Linux)
`lib/libbase.dll` | ベースライブラリ (Windows)
`lib/liboverride.dll` | オーバーライドライブラリ (Windows)
`bin/override-sample.exe` | メインプログラム (Windows)

クリーンビルドを行う場合は以下のとおりです。

    make clean && make

# 6 実行

## 6.1 Linux

### 6.1.1 デフォルト動作 (設定ファイルなし)

    cd prod/override-sample/bin
    LD_LIBRARY_PATH=../lib ./override-sample

出力例:

    sample_func: a=1, b=2 の処理 (*result = a + b;) を行います
    result: 3

### 6.1.2 オーバーライド動作 (設定ファイルあり)

`sample-config/libbase_extdef.txt` を `/tmp` にコピーし、オーバーライド行のコメントを外して配置します。

    cp prod/override-sample/sample-config/libbase_extdef.txt /tmp/libbase_extdef.txt
    cd prod/override-sample/bin
    LD_LIBRARY_PATH=../lib ./override-sample

または直接書き込む場合は以下のとおりです。

    echo "sample_func liboverride override_func" > /tmp/libbase_extdef.txt
    cd prod/override-sample/bin
    LD_LIBRARY_PATH=../lib ./override-sample

出力例:

    sample_func: 拡張処理が見つかりました。拡張処理に移譲します
    override_func: a=1, b=2 の処理 (*result = a * b;) を行います
    result: 2

## 6.2 Windows

### 6.2.1 デフォルト動作 (設定ファイルなし)

    cd prod\override-sample\bin
    set PATH=%PATH%;..\lib
    override-sample.exe

### 6.2.2 オーバーライド動作 (設定ファイルあり)

`sample-config\libbase_extdef.txt` を `%TEMP%` にコピーし、オーバーライド行のコメントを外して配置します。

    copy prod\override-sample\sample-config\libbase_extdef.txt %TEMP%\libbase_extdef.txt
    rem エディタで %TEMP%\libbase_extdef.txt を編集し、以下の行のコメントを外す
    rem sample_func  liboverride  override_func
    cd prod\override-sample\bin
    set PATH=%PATH%;..\lib
    override-sample.exe

または直接書き込む場合は以下のとおりです。

    echo sample_func liboverride override_func > %TEMP%\libbase_extdef.txt
    cd prod\override-sample\bin
    set PATH=%PATH%;..\lib
    override-sample.exe