linux共有ライブラリのコンパイルと接続

23255 ワード

現在のディレクトリの下には合計7つのソースファイルがあります:slib.h、slib1.c、slib2.c、main.c、dlib.h、dlib1.c、dlib2.c,そのうちslib.hは静的ライブラリの共通ヘッダファイルであるslib 1.c静的ライブラリlibslib 1にコンパイルする.a,slib2.c静的ライブラリlibslib 2にコンパイル.a,dlib.hは共有ライブラリ(すなわち通常動的ライブラリ)の共通ヘッダファイルであるdlib 1.c共有ライブラリlibdlib 1にコンパイルする.so,dlib2.c共有ライブラリlibdlib 2にコンパイルする.so,main.cはメインプログラムであり、libslib 1をリンクする.a、libslib1.a、libdlib1.so、libdlib2.so.
slib.h、slib1.c、slib2.cこの3つのファイルは、linux静的ライブラリのコンパイルと接続プロセスで発生した問題と同じです.
dlib.h、dlib1.c、dlib2.c、main.cのソース:
// dlib.h
#include 

int dlib_add(int a, int b);
void dlib_print(const char *str);

int dlib_sub(int a, int b);
void dlib_print2(const char *str);
// dlib1.c
#include "dlib.h"

int dlib_add(int a, int b)
{
    return a + b;
}

void dlib_print(const char *str)
{
    if(str)
        printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); }
// dlib2.c
#include "dlib.h"

int dlib_sub(int a, int b)
{
    return a - b;
}

void dlib_print2(const char *str)
{
    if(str)
        printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); }
// main.c 
#include "slib.h"
#include "dlib.h"

int main(int agrc, char **agrv)
{
    printf("*.a .....
"
); printf("add:%d, sub:%d
"
, add(1, 2), sub(3, 4)); print("Hello world!"); print2("Hi, world!"); printf("
*.so .....
"
); printf("add:%d, sub:%d
"
, dlib_add(1, 2), dlib_sub(3, 4)); dlib_print("Hello world!"); dlib_print2("Hi, world!"); return 0; }

一、so共有ライブラリのコンパイル、リンク、実行:
1、静的ライブラリlibslib 1を以前の方法でコンパイルする.a、libslib2.a,main.o gcc -c slib1.c slib2.c main.c ar -rs libslib1.a slib1.o ar -rs libslib2.a slib2.o 2、コンパイルso共有ライブラリ:gcc-fPIC-c dlib 1.c#ここでは-fPICオプションを追加する必要があります.そうしないと、次のステップでlibdlib 1を生成します.so時報ミスgcc-fPIC-shared-o libdlib 1.so dlib1.o gcc -fPIC -c dlib2.c#ここでは-fPICオプションを追加する必要があります.そうしないと、次のステップでlibdlib 2が生成されます.so時報ミスgcc-fPIC-shared-o libdlib 2.so dlib2.oまたは、中間ファイル:gcc-fPIC-shared-o libdlib 1を生成しない.so dlib1.c gcc -fPIC -shared -o libdlib2.so dlib2.c 3、実行可能ファイルmain:gcc-o main main.o-L.-lslib 1-lslib 2-ldlib 1-ldlib 2またはこれにより、gcc-o main-ldlib 1-ldlib 2 mainをコンパイルすることもできる.o-L.-lslib 1-lslib 2すなわち共有ライブラリは静的ライブラリのようなものではなく、リンク時に呼び出し者mainに置く必要がある.oの後の4、mainを実行して以下のエラーを報告します:
./main 
./main: error while loading shared libraries: libdlib2.so: cannot open shared object file: No such file or directory

共有ライブラリファイルが見つかりません.lddを確認してください.
ldd main
linux-vdso.so.1 =>  (0x00007fff86974000)
libdlib1.so => not found
libdlib2.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f332bd79000)
/lib64/ld-linux-x86-64.so.2 (0x00007f332bfb9000)

やっぱり!解決策は以下の3種類がある:1、lnで必要なsoファイルを/usr/libまたは/libの2つのデフォルトのディレクトリの下にリンクする:ln-s./*.so/usr/lib 2、修正/etc/ld.so.confファイルは、そのファイルにsoライブラリファイルが存在するパスを加える、ldconfigリフレッシュ:vim/etc/ldを実行する.so.conf#soライブラリファイルがあるパスsudo ldconfig 3を追加、環境変数LD_を修正LIBRARY_PATH,soライブラリファイルが存在するパスを追加する(/home/chenwucai/tmp/libに設定):export LD_LIBRARY_PATH=/home/chenwucai/tmp/lib:${LD_LIBRARY_PATH}前の第1、2の方法はいずれもrootライセンスが必要であり、root権限がないか一時的なテストがなければ、第3の方法を使用することができます.lddビューを再実行するには、次の手順に従います.
ldd main                                                         
linux-vdso.so.1 =>  (0x00007fff73e72000)
libdlib2.so => /home/chenwucai/tmp/lib/libdlib2.so (0x00007ff6a8783000)
libdlib1.so => /home/chenwucai/tmp/lib/libdlib1.so (0x00007ff6a8682000)
libc.so.6 => /lib64/libc.so.6 (0x00007ff6a8442000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff6a8884000)

システムはlibdlib 1を見つけることができます.so、libdlib2.soライブラリファイルです.mainを正常に実行できます.
./main 
*.a .....
add:3, sub:-1
file:slib1.c, fun:print, line:11, str:Hello world!
file:slib2.c, fun:print2, line:11, str:Hi, world!

*.so .....
add:3, sub:-1
file:dlib1.c, fun:dlib_print, line:11, str:Hello world!
file:dlib2.c, fun:dlib_print2, line:11, str:Hi, world!

二、soライブラリ関数の重名状況:
dlib 1.cにprint関数(静的ライブラリの関数と重複する)とdlib_を追加print 2関数(共有ライブラリlibdlib 2.soの関数と重複)
// dlib1.c
//  
void print(const char *str)
{
    if(str)
        printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); } void dlib_print2(const char *str) { if(str) printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); }

先に前回コンパイルしたファイルを削除して、rm-f.o .a *.so main. 次に、上記のコンパイル、リンク、実行手順を繰り返します.実行結果は次のとおりです.
./main 
*.a .....
add:3, sub:-1
file:slib1.c, fun:print, line:11, str:Hello world!
file:slib2.c, fun:print2, line:11, str:Hi, world!

*.so .....
add:3, sub:-1
file:dlib1.c, fun:dlib_print, line:11, str:Hello world!
file:dlib1.c, fun:dlib_print2, line:27, str:Hi, world!

静的ライブラリの同名関数printは共有ライブラリによって上書きされない(同じホストの同名関数も共有ライブラリによって上書きされない)、あるいは接続時にホストまたは静的ライブラリの同名関数が共有ライブラリを上書きし、共有ライブラリlibdlib 2が上書きされる.soの同名関数は上書きされ、リンクはlibdlib 1である.soライブラリのdlib_print 2関数!前の各ライブラリにリンクされているgccコマンド:gcc-o main main.o-L.-lslib 1-lslib 2-ldlib 1-ldlib 2 dlib 1はdlib 2の前、すなわちdlib 1が先に接続する、接続コマンドをこのように(dlib 2を前に置く)gcc-o main mainに変更する.o-L.-lslib 1-lslib 2-ldlib 2-ldlib 1をもう一度実行し、実行結果は以下の通りです.
./main 
*.a .....
add:3, sub:-1
file:slib1.c, fun:print, line:11, str:Hello world!
file:slib2.c, fun:print2, line:11, str:Hi, world!

*.so .....
add:3, sub:-1
file:dlib1.c, fun:dlib_print, line:11, str:Hello world!
file:dlib2.c, fun:dlib_print2, line:11, str:Hi, world!

リンクはlibdlib 2を呼び出す.soライブラリのdlib_print 2関数.これにより,2つの共有ライブラリに同名関数がある場合,先にリンクしたライブラリの同名関数が後リンクを上書きすると推定される.
三、静的ライブラリと共有ライブラリが同じ名前の場合:
先に前回コンパイルしたファイルを削除して、rm-f.o .a *.so main. 次に、gcc-c slib 1のコンパイルコマンドを順次実行する.c slib2.c main.c ar -rs libslib1.a slib1.o ar -rs libslib2.a slib2.o gcc -fPIC -shared -o libdlib1.so dlib1.c gcc -fPIC -shared -o libdlib2.so dlib2.c gcc -fPIC -shared -o libslib1.so dlib1.c#ここではdlib 1を用いる.c libslib 1とコンパイルする.a同名の共有ライブラリからリンク:gcc-o main main.o-L.-lslib 1-lslib 2-ldlib 1-ldlib 2次のエラーを報告します.
main.o: In function `main':
main.c:(.text+0x36): undefined reference to `add'
collect2: ld returned 1 exit status

dlib 1のため.cにはadd関数、すなわちlibslib 1は定義されていない.soライブラリにはadd関数がなく,gccリンクの場合,ディレクトリの下に同名の静的ライブラリと共有ライブラリがある場合,共有ライブラリを優先的にリンクすると推定される.この場合、静的ライブラリをリンクする必要がある場合は、リンクのライブラリlibslib 1をこのように指定することができる.a(検証発見、共有ライブラリも同様にすることができる./libslib 1.so指定):gcc-o main main.o -L. ./libslib1.a-lslib 2-ldlib 1-ldlib 2コンパイルに合格し、実行結果は以下の通りである.
./main 
*.a .....
file:slib1.c, fun:add, line:5, it is archives, a=1, b=2  #  , slib1.c add 
add:3, sub:-1
file:slib1.c, fun:print, line:12, str:Hello world!
file:slib2.c, fun:print2, line:11, str:Hi, world!

*.so .....
add:3, sub:-1
file:dlib1.c, fun:dlib_print, line:11, str:Hello world!
file:dlib1.c, fun:dlib_print2, line:35, str:Hi, world!

静的ライブラリlibslib 1が表示されます.aさらに検証するため、ライブラリ名が同じ場合、gccは共有ライブラリを優先的にリンクし、dlib 1にある.cファイルにadd関数(slib 1.cファイルのadd関数と同名)を加え、追加後のdlib 1.cファイル:
// dlib1.c   
#include "dlib.h"

int dlib_add(int a, int b)
{
    return a + b;
}

void dlib_print(const char *str)
{
    if(str)
        printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); } int add(int a, int b) { printf("file:%s, fun:%s, line:%d, here is so lib, a=%d, b=%d
"
, __FILE__, __FUNCTION__, __LINE__, a, b); return a + b; } void print(const char *str) { if(str) printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); } void dlib_print2(const char *str) { if(str) printf("file:%s, fun:%s, line:%d, str:%s
"
, __FILE__, __FUNCTION__, __LINE__, str); else printf("file:%s, fun:%s, line:%d, str is NULL
"
, __FILE__, __FUNCTION__, __LINE__); }

コンパイル:rm-f.o .a *.so main. gcc -c slib1.c slib2.c main.c ar -rs libslib1.a slib1.o ar -rs libslib2.a slib2.o gcc -fPIC -shared -o libdlib1.so dlib1.c gcc -fPIC -shared -o libdlib2.so dlib2.c gcc -fPIC -shared -o libslib1.so dlib1.cリンク:gcc-o main main.o-L.-lslib 1-lslib 2-ldlib 1-ldlib 2実行結果は以下の通りです.
./main 
*.a .....
file:dlib1.c, fun:add, line:18, here is so lib, a=1, b=2
add:3, sub:-1
file:dlib1.c, fun:print, line:25, str:Hello world!
file:slib2.c, fun:print2, line:11, str:Hi, world!

*.so .....
add:3, sub:-1
file:dlib1.c, fun:dlib_print, line:11, str:Hello world!
file:dlib1.c, fun:dlib_print2, line:33, str:Hi, world!

リンクは同名共有ライブラリlibslib 1を呼び出す.soのaddとprint関数.以上のリンクコマンドは、このようなgcc-o main mainであるもよい.o-L.-lslib 1-lslib 2-ldlib 2#後の-ldlib 1を省くlibslib 1.soとlibdlib 1.so関数は完全に同じで、前者は先にリンクして、完全にあるいは関数を遮蔽しました.
四、小結:ダイナミックライブラリ.soには2つのリンク呼び出し形式があり,1つは明示的であり,1つは暗黙的である.上記は暗黙的な呼び出しです.つまり、静的ライブラリに似ています.また、リンクをコンパイルするときにライブラリのパスと名前を指定します.静的ライブラリとは異なり、コンパイラは実際に動的ライブラリを実行可能ファイルにロードしていません.ライブラリ関数インタフェース、レコード関数の数が存在する動的ライブラリと相対アドレスを検証し、実行時になってからライブラリをロードします.共有ライブラリ関数の呼び出しアドレスリダイレクトは、グローバルオフセットテーブル(GOT)によって実現される.明示的な呼び出しは、ライブラリ関数(dlopen、dlsym、dlerror、dlclose)のセットによって実現されます.プライマリ・プログラムは、コンパイル時に共有ライブラリをリンクする必要はありません.ヘッダ・ファイルを含める必要もありません.完全に実行時に動的にロードされ、より柔軟です.Webサーバが実行中にCGIモジュールをロードするのは一般的にこの方法を採用しているので、いつか暇があればこのモードを詳しく検討してみましょう.