読者です 読者をやめる 読者になる 読者になる

標準出力

新しいもの、変わらないこと 自分の頭を通して考えてみました (stdout)

Windows と Linux の共有ライブラリ

c言語

分けあってWindows向けの共有ライブラリ(dll) と Linux向けの共有ライブラリ(so) を
一つのC言語のソースで用意する必要が生じだ。

後にも先にもこれ一回限りな気がするけど一応メモ
検証環境は、

Windows 7 64bit版 C Compiler: gcc ライブラリを使う言語とコンパイラ Delphi XE2
Linux (RHEL) C Compiler: gcc ライブラリを使う言語とコンパイラ Fortran 90  pgfortran



まずは、ヘッダファイルとソース

add.h

#ifndef ADD_H
#define ADD_H

int add_(int *a, int *b)

int devide_(float *a, float *b, float *c)
#endif


add.c
#include


int add_(int *a, int *b){
    int c;

  c = *a + *b;
  return c;
}

int devide_(float *a, float *b, float *c){

    *c = *a / *b;

    return 0;
}

ポイントは、引数がすべて参照渡しになっている点です。 Fortranが参照渡しがデフォルトなためです。 また、関数名がアンダースコアで終わっているのは、また後で。。。

お次は、コンパイル
まずは、Windows

gcc -shared -m32 -o add.dll add.c

-m32 は、32bi tPEバイナリを出力するためのオプションでdllを使う、アプリケーション(exe)が32bitであるため。

次に、Linux
gcc -fPIC -shared -o libadd.so add.c

-fPICは、位置独立コード(Position Independent Code)というメモリのどのアドレにもロード可能にするためのオプションです。


そして、使う側。
まずは、Delphi

unit use;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm6 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;

TAdd = function(a : PInteger; b : PInteger) : integer ; stdcall;
TDevide = function(a : PSingle; b : PSingle; c : PSingle) : integer ; stdcall;

var
Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.Button1Click(Sender: TObject);
var
ret : integer;
a,b : integer;
c,d,e : single;
Handle : THandle;
Add : TAdd;
Devide : TDevide;
begin
a := 4;
b := 2;
c := 4.0;
d := 2.0;
Handle := LoadLibrary('add.dll');
if Handle
0 then
begin
@Add := GetProcAddress(Handle, 'add_');
if @Add
nil then
begin
ret := add(@a, @b);
ShowMessage(IntToStr(ret));
end;
@Devide := GetProcAddress(Handle, 'devide_');
if @Devide
nil then
begin
ret := devide(@c, @d, @e);
ShowMessage(FloatToStr(e));
end;
FreeLibrary(Handle);
end;
end;

end.

関数をtypedefして、GetProcAddress にて関数のあるアドレスを取得する。

次は、Linux上のFortran
interface節を記述したインクルードファイルを作成

addf.h
      interface
        integer function add(a,b)
          integer a,b
        end function add

        integer function devide(a,b,c)
          real  a,b,c
        end function devide

      end interface

次にFortranのソース本体
       program test
       include 'addf.h'
       integer c,d
       real e,f,g
       c=4
       d=2
       e=4.0 
       f=2.0
       d = add(c,d)
       i = devide(e,f,g)
       write(*,*) d,g,i
       end program test

pgfortran -I./include -L./lib -ladd src/use.f

-l で使用するライブラリを指定します。
また、Fortranの場合、関数名は、アンダースコアがついたシンボルを探すのでCの関数名には、アンダースコアをつける必要があります。