C言語でシンプルなダイナミックリンクライブラリを書いてみる。
単一のC言語ソースで、複数アーキテクチャ向けの共有ライブラリとしてビルドすることを考える。
想定しているのは以下のプラットフォーム(開発環境)です。
【1/3】DLLを作成してみる
目次
ソースコード
[simple_dll.h]
/****************************************************************//**
* \file simple_dll.h
*
* \brief DLL(ダイナミックリンクライブラリ)のシンプルなサンプル
*
* ファイル
* - 文字コードはUTF-8
* - 改行コードはLF
*
* \author tomyama Sep 2022
********************************************************************/#ifndef _SIMPLE_DLL_H_
#define _SIMPLE_DLL_H_
/********************************************************************/
/* include files */
/********************************************************************/
/********************************************************************/
/* defines */
/********************************************************************/
/********************************************************************/
/* types */
/********************************************************************/typedef char *( *PFN_GETGREETINGMSG )( void );
/********************************************************************/
/* function prototype */
/********************************************************************/extern char *getGreetingMsg( void );
/********************************************************************/
/* static value */
/********************************************************************/
/********************************************************************/
/* globals variable */
/********************************************************************/#endif /* _SIMPLE_DLL_H_ */
[simple_dll.c]
/****************************************************************//**
* \file simple_dll.c
*
* \brief DLL(ダイナミックリンクライブラリ)のシンプルなサンプル
*
* ファイル
* - 文字コードはUTF-8
* - 改行コードはLF
*
* \author tomyama Sep 2022
********************************************************************/
/********************************************************************/
/* include files */
/********************************************************************/#include "simple_dll.h"
/********************************************************************/
/* defines */
/********************************************************************/#define GREETING_MESSAGE "Hello, world!"
/********************************************************************/
/* types */
/********************************************************************/
/********************************************************************/
/* function prototype */
/********************************************************************/
/********************************************************************/
/* static value */
/********************************************************************/
/********************************************************************/
/* globals variable */
/********************************************************************/
/********************************************************************/
/* function (global) */
/********************************************************************//********************************************//**
* \brief "hello, world!"を返す関数
*
* \return "hello, world!"を指すnull終端文字列へのポインタを返す
* \retval NULL以外 正常終了(常に正常終了を返す)
* \author tomyama
* \sa -
* \callgraph
* \callergraph
************************************************/char *getGreetingMsg( void )
{
return GREETING_MESSAGE;
}
/********************************************************************/
/* function (static) */
/********************************************************************/
[simple_dll_msvc.def]
LIBRARY "simple_dll_msvc"
EXPORTS
getGreetingMsg @1
- このファイルは、WindowsのVisual Studio環境でしか使わない。
Windows環境向けにビルドする手順
- スタートメニューからVisual Studioの『x86 Native Tools Command Prompt for VS 20xx』を起動する。
- 以下のバッチファイルを作成して実行する。
- dll,exp,libという3つのファイルが生成されているはずです。
-
simple_dll_msvc.dll ←これがDLLファイル
- simple_dll_msvc.exp
- simple_dll_msvc.lib ←これらのファイルは動的リンクでアプリをビルドする時にリンカが使う
-
- getGreetingMsg()関数がエクスポートされている事を確認する。
- dumpbinコマンド
>dumpbin /exports simple_dll_msvc.dll
Microsoft (R) COFF/PE Dumper Version 14.32.31332.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file simple_dll_msvc.dllFile Type: DLL
Section contains the following exports for simple_dll_msvc.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
1 number of functions
1 number of namesordinal hint RVA name
1 0 00001000 getGreetingMsg
Summary
2000 .data
6000 .rdata
1000 .reloc
C000 .text>
- dumpbinコマンド
Windows以外の環境向けにビルドする手順
- 適当な端末エミュレータを起動する。
- 以下のスクリプトを作成して実行する。
-
[build.sh]
#!/bin/sh
CFLAGS="-fPIC -Wall -O2"
arch=`uname -mos | tr ' ./' '_'`
echo "$arch"dll_prefix="lib"
dll_ext="so"
if [ "`uname -o`" = "Cygwin" ]; then
CFLAGS="-Wall -O2"
dll_prefix=""
dll_ext="dll"
figcc $CFLAGS -o simple_dll_${arch}.o -c simple_dll.c
gcc -o ${dll_prefix}simple_dll_${arch}.${dll_ext} simple_dll_${arch}.o -lc -shared -Wl,-soname,${dll_prefix}simple_dll_${arch}.${dll_ext}
-
- DLLファイルが生成されているはずです。
- getGreetingMsg()関数が外部公開されている事を確認する。
- Linuxの場合
- Cygwinの場合
-
$ nm simple_dll_CYGWIN_NT-10_0-19044_x86_64_Cygwin.dll | grep getGreetingMsg
000000055bb11030 T getGreetingMsg
$ -
CygwinのDLLはWindowsと同じフォーマット(PE)なので、Windows( Visual Studio )環境と同様にdumpbinコマンドを使った確認も可能です。
>dumpbin /exports simple_dll_CYGWIN_NT-10_0-19044_x86_64_Cygwin.dll
Microsoft (R) COFF/PE Dumper Version 14.32.31332.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file simple_dll_CYGWIN_NT-10_0-19044_x86_64_Cygwin.dllFile Type: DLL
Section contains the following exports for simple_dll_CYGWIN_NT-10_0-19044_x86_64_Cygwin.dll
00000000 characteristics
633495DC time date stamp Thu Sep 29 03:43:40 2022
0.00 version
1 ordinal base
3 number of functions
3 number of namesordinal hint RVA name
1 0 00001020 __gcc_deregister_frame
2 1 00001000 __gcc_register_frame
3 2 00001030 getGreetingMsgSummary
1000 .bss
1000 .buildid
1000 .data
1000 .debug_abbrev
1000 .debug_aranges
1000 .debug_frame
6000 .debug_info
1000 .debug_line
2000 .debug_line_str
1000 .debug_loclists
1000 .debug_str
1000 .edata
1000 .idata
1000 .pdata
1000 .rdata
1000 .reloc
1000 .text
1000 .xdata>
-
解説
入力ファイル
プラットフォーム(開発環境) | ファイル | |
---|---|---|
WindowsのDLLファイル(Visual Studio) | simple_dll_msvc.def | |
LinuxのSOファイル(gcc) | - | |
CygwinのDLLファイル(gcc) | ||
Android(Termux)のSOファイル(clang) |
- ソースコードは全プラットフォームで共通化している。ただし、Visual Studio 環境では .def ファイルを使っている。
ビルド用の台本(スクリプト)
プラットフォーム(開発環境) | ファイル |
---|---|
WindowsのDLLファイル(Visual Studio) | build.bat |
LinuxのSOファイル(gcc) | build.sh |
CygwinのDLLファイル(gcc) | |
Android(Termux)のSOファイル(clang) |
- Cygwinの無い環境でもビルドできるように「Visual Studio」の場合は .bat ファイルにしている。その他の環境ではシェルスクリプト。
- clangの場合は、gccでは無くclangを呼び出す方がより厳密的だが、clangはgccに擬態してくれるように作られているので(少なくとも現時点では)、それに頼ってscriptingしている。
中間生成物: 『simple_dll.c』のコンパイル | |
プラットフォーム(開発環境) | コマンド |
---|---|
WindowsのDLLファイル(Visual Studio) | cl.exe %CFLAGS% /Fo:simple_dll_msvc.o /c simple_dll.c |
LinuxのSOファイル(gcc) | gcc -fPIC -Wall -O2 -o simple_dll_${arch}.o -c simple_dll.c |
CygwinのDLLファイル(gcc) | gcc -Wall -O2 -o simple_dll_${arch}.o -c simple_dll.c |
Android(Termux)のSOファイル(clang) |
gcc -fPIC -Wall -O2 -o simple_dll_${arch}.o -c simple_dll.c |
- 呼び出すコマンドやオプションスイッチに差異はあるものの、必要な要素(コマンドライン引数)は全プラットフォームでほぼ同じ。
- Cygwinは、ライブラリ用のソースをコンパイルするときに -fPICオプションを付けなくてもよい。(付けてもよい。どちらでも変わらない。)
- Cygwin(Windowsと同じPEフォーマット)では、常に位置独立コード(Position-Independent Code [ PIC ])が生成される。
最終生成物(DLLなど): リンカでDLLを生成 | |
プラットフォーム(開発環境) | コマンド |
---|---|
WindowsのDLLファイル(Visual Studio) | link.exe /OUT:simple_dll_msvc.dll simple_dll_msvc.o /DEF:simple_dll_msvc.def |
LinuxのSOファイル(gcc) | gcc -o libsimple_dll_${arch}.so simple_dll_${arch}.o -lc -shared -Wl,-soname,libsimple_dll_${arch}.so |
CygwinのDLLファイル(gcc) | gcc -o simple_dll_${arch}.dll simple_dll_${arch}.o -lc -shared -Wl,-soname,simple_dll_${arch}.dll |
Android(Termux)のSOファイル(clang) | gcc -o libsimple_dll_${arch}.so simple_dll_${arch}.o -lc -shared -Wl,-soname,libsimple_dll_${arch}.so |
- Windows(Visual C)では、エクスポートするシンボルを指定する為に、defファイルが使える。コード中に識別子(__declspec(dllexport))を埋め込む方法もあるが、defファイルを使う方がソースコードにコードを追加する必要が無いので使い易いと思います。
- それに対して、Windows以外のプラットフォーム(gcc, clang)では、「エクスポート」という概念が無く(C言語で外部公開しているシンボルには全てアクセス可能なはず)、defファイルのようなものを指定する必要は無い。
- Cygwinでは、共有ライブラリの拡張子は .dll となる。(通常のUNIX(ELFフォーマット)の拡張子は .so )
- Cygwinは、先頭の lib も不要。
- 【1/3】DLLを作成してみる
- 【2/3】DLLを使ってみる(動的リンク版)
- 【3/3】DLLを使ってみる(動的ロード版)