ページ 1 / 1
「shared library」とDLL----追加質問
Posted: 2018年1月13日(土) 21:27
by さまよい
今晩は
「shared library」とDLLに関して追加質問させて下さい。
前回:
かずまさん書かれました:
>> DLL の場合、実行ファイルを生成する時に情報を与えることもできるし、与えないこともできます。
Q1: どんな場合、実行ファイルを生成する時に情報を与えることが必要でしょうか。
Q2: もし生成する時に情報を与えることが必要とすれば、DLLの意味がなくなり、「静的」になってしまったのでは?
Q3: DLLを生成するために、どうしてMS流ではわざわざソースコードの中に「余計」な文「__declspec(dllexport)」を挿入しなければならないのでしょうか。
「__declspec(dllexport)はアプリケーションロジックとは関係ないですね。
DLLとしない場合、ソースコードをいじらなくてはならなくなります。非常に不合理なやりかた?
宜しくお願い致します
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月14日(日) 00:41
by かずま
さまよい さんが書きました:
Q1: どんな場合、実行ファイルを生成する時に情報を与えることが必要でしょうか。
暗黙のリンクを行う場合です。すなわち、
プログラムで LoadLibrary を実行しない場合です。
これは説明済みです。
さまよい さんが書きました:
Q2: もし生成する時に情報を与えることが必要とすれば、DLLの意味がなくなり、「静的」になってしまったのでは?
sum.dll を作成するときにできた sum.lib は静的にリンク
されますが、これには関数 sum の入り口しか存在せず、
そこから sum.dll 内の関数 sum を呼び出します。
sum.lib をリンクした main.exe は関数 sum の本体を
持っていないから、サイズは小さくなります。
さまよい さんが書きました:
Q3: DLLを生成するために、どうしてMS流ではわざわざソースコードの中に「余計」な文「__declspec(dllexport)」を挿入しなければならないのでしょうか。
「__declspec(dllexport)はアプリケーションロジックとは関係ないですね。
DLLとしない場合、ソースコードをいじらなくてはならなくなります。非常に不合理なやりかた?
DLL を作成するとき、エクスポートする関数名をリンクオプション
で指定すれば、__declspec(dllexport) を書かなくても構いません。
コード:
C:\tmp\DLL>cl /LD sum.c /link /EXPORT:sum
エクスポートする関数名がたくさんあるときは、
.defファイルに書いて、それを指定することもできます。
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月14日(日) 07:04
by あたっしゅ
そんなに M$ が嫌いなら、Windows でプログラムしなきゃいいでしょ。
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月14日(日) 10:24
by さまよい
かずま 様
丁寧なご教授本当にありがとうございます。
かなり分かったような感じですけれども、追加質問させて下さい。
Q1. DLLを生成するために、必ずLIBも同時に生成されますね(同名?)。
これはLINUX系においても同じでしょうか。
Q2. 通常DLLに入れられた関数は当然「 エクスポート」のためだと思いますが、
なぜその名前を一つ一つ列挙しなければならないのでしょうか。
エクスポートする関数名がたくさんあるときは.defファイルに指定することは便利ですが、
これはLINUX世界においても同じやり方でしょうか。
また宜しくお願い致します。
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月14日(日) 11:40
by かずま
さまよい さんが書きました:
Q1. DLLを生成するために、必ずLIBも同時に生成されますね(同名?)。
__declspec(dllexport) をソースに記述せず、かつ、DLL
生成時にリンクオプションの /EXPORT を指定しなかった
場合は、.libファイルは生成されません。ただし、生成
された .dllファイルは何もエクスポートしないので
使い道がありません。
さまよい さんが書きました:
これはLINUX系においても同じでしょうか。
Linux においては、説明済みです。
.soファイルを作成したとき、.aファイルは作成されません。
実行ファイル生成時に .soファイルを指定すると、
dlopen なしで、.dllファイル内の関数を呼び出せます。
さまよい さんが書きました:
Q2. 通常DLLに入れられた関数は当然「 エクスポート」のためだと思いますが、
なぜその名前を一つ一つ列挙しなければならないのでしょうか。
DLL内部だけで使いたい関数があるかもしれません。
さまよい さんが書きました:
エクスポートする関数名がたくさんあるときは.defファイルに指定することは便利ですが、
これはLINUX世界においても同じやり方でしょうか。
Linux でエクスポートは聞いたことがありません。
static でない関数は全部呼び出し可能なんだと思いますが、
調べてみないと分かりません。
質問です。
Windows で DLL を作成する環境をお持ちですか?
Linux で shared library を作成する環境をお持ちですか?
最初の回答の例を自分で試してみましたか?
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月14日(日) 17:45
by さまよい
かずま 様
お世話になっております。
大変分かりやすくご解説頂き誠に有難うございます。
>>Windows で DLL を作成する環境をお持ちですか?
>>Linux で shared library を作成する環境をお持ちですか?
WindowsにするかLinuxにするか実は環境整備これからです。
ということはこれから開発しようとするAPPはC言語で実装した多量の実体(*.dllか *.so)をPythonでcallするのを想定しており、
こんな場合
WindowsとLinuxとどっちがdllの生成と動的にcallするのはより簡単かを調べています。
どうもLinux系のほうがシンプルな印象ですけれども、
ただLinux系の場合*.so(dll)を生成するために補助的にlibのようなファイルを生成しないのは逆に不思議に思います。
DLLの中の関数に関する情報ファイル(eg., まがいのLIB)を生成しなければ、
DLL関数を利用する側は「まがいのLIB」とリンクできず、リンクエラーが発生するのではと思いますが?
この辺ご説明頂ければ幸せです。
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月15日(月) 18:06
by かずま
さまよい さんが書きました:
どうもLinux系のほうがシンプルな印象ですけれども、
ただLinux系の場合*.so(dll)を生成するために補助的にlibのようなファイルを生成しないのは逆に不思議に思います。
DLLの中の関数に関する情報ファイル(eg., まがいのLIB)を生成しなければ、
DLL関数を利用する側は「まがいのLIB」とリンクできず、リンクエラーが発生するのではと思いますが?
Linux では、実行ファイルを生成するときに .soファイルを指定
しますから、リンカは何でもできるはずです。
呼び出し元には、静的リンクの関数を呼び出すようにみせて、
.soファイル内の関数を呼び出すような「つなぎの部分」を
生成することは可能です。
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月16日(火) 22:50
by さまよい
かずま 様
さすが! ありがとうございました。
Re: 「shared library」とDLL----追加質問
Posted: 2018年1月17日(水) 21:59
by かずま
つなぎの部分を私の妄想で作ってみました。
コード:
#include <stdlib.h>
#include <dlfcn.h>
int sum(int n);
void sum1(void);
int sum2(char *s, const char *t);
struct FuncTable {
void (*func)(void);
const char *name;
};
struct FuncTable ft[3] = {
{ 0, "sum" },
{ 0, "sum1" },
{ 0, "sum2" },
};
void *so;
void set_ft(int i)
{
if (!so) {
so = dlopen("sum.so", RTLD_LAZY);
if (!so) exit(1);
}
ft[i].func = dlsym(so, ft[i].name);
if (!ft[i].func) exit(2);
}
int sum(int n)
{
if (!ft[0].func) set_ft(0);
return ((int (*)(int))ft[0].func)(n);
}
void sum1(void)
{
if (!ft[1].func) set_ft(1);
return ((void (*)(void))ft[1].func)();
}
int sum2(char *s, const char *t)
{
if (!ft[2].func) set_ft(2);
return ((int (*)(char *, const char *))ft[2].func)(s, t);
}
sum 1個だけではつまらないので、sum1、sum2 を追加してみました。
gcc -o main main.c sum.dll で実行ファイル生成しようとすると、
sum.dll があるため、 上記のような「つなぎの部分」を自動的に
作ります。sum.dll は、中に呼び出し可能な関数の情報を持っている
はずですから、このようなことができます。これを仮に libsum.c とすると、
内部で次のような手順でリンクを行えばよいでしょう。
コード:
gcc -c -o main.o main.c
gcc -c -o libsum.o libsum.c
gcc -o main main.o libsum.o -ldl