tomyamaのブログ

日記・雑記。

シンプルなダイナミックリンクライブラリ(DLL)【2/3】

【1/3】DLLを作成してみる』で作成したDLLを利用するアプリケーションを書いてみる。

 

 

 

繰り返しになりますが、想定しているのは以下のプラットフォーム(開発環境)です。

 

今回も、単一のC言語ソースで、複数アーキテクチャ向けのアプリケーションとしてビルドします。

 

DLLを利用する方法は、大きく分けて2種類あります。

リンカ実行時にDLLのシンボルを紐づけておく「動的リンク(ダイナミックリンク)」と、ビルド時にはシンボルは未解決のままにしておいて実行時にDLLを明示的にロードする「動的ロード(ダイナミックロード)」です。

 

今回は「動的リンク」を使ったアプリケーションを作成してみます。

なお、前回作成した、DLLのファイル,ソースコードは、『../simple_dll』というディレクトリに置いてあるものとします。

「動的ロード」を使ったアプリケーションは次回の記事を参照して下さい。

 


【2/3】DLLを使ってみる(動的リンク版)

 

目次

 


 

ソースコード

[dllUser_DynamicLink.c]

/****************************************************************//**
 * \file  dllUser_DynamicLink.c
 *
 * \brief  DLL(ダイナミックリンクライブラリ)を実行時にリンクするサンプルアプリケーション
 *
 * - 文字コード・改行コード
 *     - 文字コードUTF-8(BOM無し)
 *     - 改行コードは LF
 *
 * \author   tomyama  Sep 2022
 ********************************************************************/


/********************************************************************/
/*        include files                                             */
/********************************************************************/

#include <stdio.h>          // puts()
#include "simple_dll.h"


/********************************************************************/
/*        defines                                                   */
/********************************************************************/


/********************************************************************/
/*        types                                                     */
/********************************************************************/


/********************************************************************/
/*        function prototype (static)                               */
/********************************************************************/


/********************************************************************/
/*        static value                                              */
/********************************************************************/


/********************************************************************/
/*        globals variable                                          */
/********************************************************************/


/********************************************************************/
/*        function (global)                                         */
/********************************************************************/

/********************************************//**
 * \brief  プログラムのエントリポイント。
 *
 * \param[in]  argc  引数の数。
 * \param[in]  argv  引数ポインタの配列。
 * \return     プログラムの終了ステータスを返す。
 * \retval     0      正常終了(常に 正常終了 を返す)
 * \author     tomyama
 * \sa         -
 * \callgraph
 * \callergraph
 ************************************************/

int main( void )
{
    puts( getGreetingMsg() );

    return 0;
}


/********************************************************************/
/*        function (static)                                         */
/********************************************************************/

 

Windows環境向けにビルドして実行する手順

  1. スタートメニューからVisual Studioの『x86 Native Tools Command Prompt for VS 20xx』を起動する。
  2. 以下のバッチファイルを作成して実行する。
    • [build_and_run_DynLink.bat]

      set LIBDIR=../simple_dll
      set CFLAGS=/nologo /source-charset:utf-8 /execution-charset:shift_jis /Wall /wd4464 /wd4668 /wd4710 /wd4820 /wd4996 /wd5045 /O2 /Ob0

      rem 動的リンク [ Dynamic Link ]
      rem   ビルド
      cl.exe %CFLAGS% /I%LIBDIR% /Fo:dllUser_DynamicLink_msvc.o /c dllUser_DynamicLink.c
      link.exe /OUT:dllUser_DynamicLink_msvc.exe dllUser_DynamicLink_msvc.o %LIBDIR%/simple_dll_msvc.lib
      rem   実行
      echo off
      set PATH_ORG=%PATH%
      set PATH=%LIBDIR%;%PATH%
      echo on
      dllUser_DynamicLink_msvc.exe
      echo off
      set PATH=%PATH_ORG%
      set PATH_ORG=
      echo on

       

  3. 実行結果は以下のようになるはずです。赤字箇所がDLLの関数を呼び出した所です。
    • user_app_DynLink>build_and_run_DynLink.bat

      user_app_DynLink>set LIBDIR=../simple_dll

      user_app_DynLink>set CFLAGS=/nologo /source-charset:utf-8 /execution-charset:shift_jis /Wall /wd4464 /wd4668 /wd4710 /wd4820 /wd4996 /wd5045 /O2 /Ob0

      user_app_DynLink>rem 動的リンク [ Dynamic Link ]

      user_app_DynLink>rem   ビルド

      user_app_DynLink>cl.exe /nologo /source-charset:utf-8 /execution-charset:shift_jis /Wall /wd4464 /wd4668 /wd4710 /wd4820 /wd4996 /wd5045 /O2 /Ob0 /I../simple_dll /Fo:dllUser_DynamicLink_msvc.o /c dllUser_DynamicLink.c
      dllUser_DynamicLink.c

      user_app_DynLink>link.exe /OUT:dllUser_DynamicLink_msvc.exe dllUser_DynamicLink_msvc.o ../simple_dll/simple_dll_msvc.lib
      Microsoft (R) Incremental Linker Version 14.32.31332.0
      Copyright (C) Microsoft Corporation.  All rights reserved.


      user_app_DynLink>rem   実行

      user_app_DynLink>echo off

      user_app_DynLink>dllUser_DynamicLink_msvc.exe
      Hello, world!

      user_app_DynLink>echo off

      user_app_DynLink>

       

Windows以外の環境向けにビルドして実行する手順

  1. 適当な端末エミュレータを起動する。
  2. 以下のスクリプトを作成して実行する。
    • [build_and_run_DynLink.sh]

      #!/bin/sh

      LIBDIR=../simple_dll
      CFLAGS="-Wall -O2"

      arch=`uname -mos | tr ' ./' '_'`
      echo "$arch"

      gcc $CFLAGS -I${LIBDIR} -o dllUser_DynamicLink_${arch}.o -c dllUser_DynamicLink.c
      gcc -o dllUser_DynamicLink_${arch}.exe dllUser_DynamicLink_${arch}.o -lsimple_dll_${arch} -L${LIBDIR}

      if [ "`uname -o`" = "Cygwin" ]; then
        PATH=${LIBDIR}:$PATH       ./dllUser_DynamicLink_${arch}.exe
      else
        LD_LIBRARY_PATH=${LIBDIR}  ./dllUser_DynamicLink_${arch}.exe
      fi

       

  3. 実行結果は以下のようになるはずです。赤字箇所がDLLの関数を呼び出した所です。
    • $ ./build_and_run_DynLink.sh
      CYGWIN_NT-10_0-19044_x86_64_Cygwin
      Hello, world!
      $

       

解説

入力ファイル
プラットフォーム(開発環境) ファイル
WindowsのDLLファイル(Visual Studio dllUser_DynamicLink.c
LinuxのSOファイル(gcc
CygwinのDLLファイル(gcc
Android(Termux)のSOファイル(clang)

 

ビルドと実行の台本(スクリプト
プラットフォーム(開発環境) ファイル
WindowsのDLLファイル(Visual Studio build_and_run_DynLink.bat
LinuxのSOファイル(gcc build_and_run_DynLink.sh
CygwinのDLLファイル(gcc
Android(Termux)のSOファイル(clang)
  • Cygwinの無い環境でもビルドできるように「Visual Studio」の場合は .bat ファイルにしている。その他の環境ではシェルスクリプト
  • clangの場合は、gccでは無くclangを呼び出す方がより厳密的だが、clangはgccに擬態してくれるように作られているので(少なくとも現時点では)、それに頼ってscriptingしている。

 

中間生成物: 『dllUser_DynamicLink.c』のコンパイル
プラットフォーム(開発環境) コマンド
WindowsのDLLファイル(Visual Studio cl.exe %CFLAGS% /I../simple_dll /Fo:dllUser_DynamicLink_msvc.o    /c dllUser_DynamicLink.c
LinuxのSOファイル(gcc gcc -Wall -O2   -I../simple_dll  -o dllUser_DynamicLink_${arch}.o -c dllUser_DynamicLink.c
CygwinのDLLファイル(gcc gcc -Wall -O2   -I../simple_dll  -o dllUser_DynamicLink_${arch}.o -c dllUser_DynamicLink.c
Android(Termux)のSOファイル(clang) gcc -Wall -O2   -I../simple_dll  -o dllUser_DynamicLink_${arch}.o -c dllUser_DynamicLink.c
  • 呼び出すコマンドやオプションスイッチに差異はあるものの、必要な要素(コマンドライン引数)は全プラットフォームで同じ
  • ソースコードの中で『simple_dll.h』をインクルードしているので、コンパイラのオプションスイッチ(/I, または -I)で、インクルードパスを追加している。

 

最終生成物(実行ファイル): リンカで実行ファイルを生成
プラットフォーム(開発環境) コマンド
WindowsのDLLファイル(Visual Studio link.exe /OUT:dllUser_DynamicLink_msvc.exe    dllUser_DynamicLink_msvc.o    ../simple_dll/simple_dll_msvc.lib
LinuxのSOファイル(gcc gcc        -o dllUser_DynamicLink_${arch}.exe dllUser_DynamicLink_${arch}.o -lsimple_dll_${arch} -L../simple_dll
CygwinのDLLファイル(gcc gcc        -o dllUser_DynamicLink_${arch}.exe dllUser_DynamicLink_${arch}.o -lsimple_dll_${arch} -L../simple_dll
Android(Termux)のSOファイル(clang) gcc        -o dllUser_DynamicLink_${arch}.exe dllUser_DynamicLink_${arch}.o -lsimple_dll_${arch} -L../simple_dll
  • Windowsでは、DLLのエクスポートした関数を呼び出す部品(LIBファイル)をリンカで組み込む。
  • その他のプラットフォームではDLLを直接参照してシンボルを解決する。その為、DLLの場所と名前をオプションスイッチで指示している。

 

実行: 『dllUser_DynamicLink_${arch}.exe』を実行
プラットフォーム(開発環境) コマンド
WindowsのDLLファイル(Visual Studio set PATH_ORG=%PATH%
set PATH=../simple_dll;%PATH%
dllUser_DynamicLink_msvc.exe
set PATH=%PATH_ORG%
set PATH_ORG=
LinuxのSOファイル(gcc LD_LIBRARY_PATH=../simple_dll  ./dllUser_DynamicLink_${arch}.exe
CygwinのDLLファイル(gcc PATH=../simple_dll:$PATH       ./dllUser_DynamicLink_${arch}.exe
Android(Termux)のSOファイル(clang) LD_LIBRARY_PATH=../simple_dll  ./dllUser_DynamicLink_${arch}.exe
  • Windows, Cygwin環境変数PATH』を使ってDLLの場所を指示している。
  • その他のプラットフォームでは環境変数LD_LIBRARY_PATH』を使っている。このblogの制約で2行になっているように見えるかもしれないが、環境変数の設定と実行ファイルの実行は、1行で記述すること。シェルは、このように書く事で実行時のみ環境変数を変更してくれる。