gcc 編譯動態庫和靜態庫

來源:互聯網
上載者:User
文章目錄
  • 2.1 首先編譯源檔案產生對象(obj)檔案(main.o, hello_fn.o):
  • 2.2 然後從對象檔案編譯動態庫檔案(libhello.so)和靜態庫(libhello.a)
  • 3.1 如果不連結庫的情況下編譯一個主程式是:
  • 3.2 連結到動態庫libhello.so
  • 3.3 連結到靜態庫libhello.a
Linux C 編程入門之一:gcc 編譯動態庫和靜態庫

cheungmine

2012

1 準備工作

Windows7+Cygwin+gcc

在同一個目錄下準備好下面3個檔案,其中3-2,3-3用來產生動態庫或靜態庫:

主調用程式原始碼3-1:main.c

/** * main.c */#include <stdio.h>#include <math.h>#include "hello_fn.h"intmain (){  hello("cheungmine");  printf("sqrt(2.0) = %f\n", sqrt(2.0));  return 0;}

庫原始碼3-2:hello_fn.c

/** * hello_fn.c */#include <stdio.h>void hello(const char *msg){  printf("Hello %s!\n", msg);} 

庫標頭檔原始碼3-3:hello_fn.h

/** * hello_fn.h */void hello(const char *msg);
2 編譯庫2.1 首先編譯源檔案產生對象(obj)檔案(main.o, hello_fn.o):

$ gcc -W -Wall -ansi -pedantic -I. -c main.c$ gcc -W -Wall -ansi -pedantic -I. -c hello_fn.c
2.2 然後從對象檔案編譯動態庫檔案(libhello.so)和靜態庫(libhello.a)

$ gcc -shared hello_fn.o -o libhello.so或者直接從原始碼編譯:$ gcc -shared -I. hello_fn.c -o libhello.so編譯靜態庫相對簡單,就是相當於目標檔案歸檔:$ ar r libhello.a hello_fn.o

3 編譯使用庫的主程式3.1 如果不連結庫的情況下編譯一個主程式是:

$ gcc main.o -o main或者$ gcc -c main.c -o main

但是由於我們在main.c的代碼中寫固定了調用庫的代碼(hello函數),所以,必須連結到這個庫才行。
3.2 連結到動態庫libhello.so

$ gcc main.o -o main ./libhello.so

這樣在目前的目錄下就產生了:main.exe(我的cygwin環境,Linux環境下沒有副檔名)

運行這個main.exe:

$ ./main.exe

刪除libhello.so,再運行main.exe會報錯誤:error while loading shared libraries: libhello.so: cannot open shared object...
3.3 連結到靜態庫libhello.a

$ gcc main.o -o main2 ./libhello.a

刪除libhello.a,運行main2.exe,一切正常。說明程式的確連結到靜態庫了。
4 查看程式依賴的庫

$ file main.exe main2.exe$ ldd main.exe main2.exe

如果我們的動態庫libhello.so與主程式不在同一個目錄下,怎麼辦?

複製libhello.so和libhello.a到另外一個目錄,比如:/cygdrive/c/temp,那麼編譯主程式為:

$ gcc main.o -o main /cygdrive/c/temp/libhello.so執行:$ export PATH=/cygdrive/c/temp:$PATH$ ./main.exe 
5 運行時載入動態庫

修改main.c檔案為如下清單:

/** * main.c */#include <stdio.h>#include <math.h>#include <dlfcn.h>#include "hello_fn.h"void dl_hello(){  void *dp;  char *error;  void (*fn_hello)(const char*);  dp = dlopen("libhello.so", RTLD_LAZY );  if(!dp) {    printf("%s\n", dlerror());    exit(1);  }  fn_hello = dlsym(dp, "hello");  if(!fn_hello) {    printf("%s\n", dlerror());    exit(1);  }  fn_hello("cheungmine: load library when running");  dlclose(dp);}    intmain (){//  hello("cheungmine");  dl_hello();  printf("sqrt(2.0) = %f\n", sqrt(2.0));  return 0;}

然後重新編譯main.exe和libhello.so如下:

編譯源檔案$ gcc -Wall -I. -c main.c$ gcc -Wall -I. -c hello_fn.c編譯動態庫$ gcc -shared hello_fn.o -o libhello.so連結主程式,但不連結到動態庫。$ gcc main.o -o main.exe執行下面的代碼可以看到libhello.so並不在main.exe的依存之列:$ ldd main.exe移動庫到其他目錄,通過修改環境變數,程式main.exe執行正確: $ mv libhello.so /cygdrive/c/temp$ export PATH=.:/cygdrive/c/temp:$PATH$ ./main.exe

6 總結

通過上面的練習,基本清楚了如何用gcc編譯器,包括靜態連結庫和動態連結程式庫。通過下面的表格可以看到

Linux和Windows的區別:

                               Windows                      Unix/Linux

----------------------------------------------------------------------

靜態連結庫              hello.lib                            libhello.a

動態連結程式庫              hello.dll                            libhello.so

消極式載入                  LoadLibrary                    dlopen

                                  GetProcAddress            dlsym

                                  FreeLibrary                     dlclose

本文全部內容在cygwin上啟動並執行,和真實的Linux環境還是存在差異的。gcc版本3.4.4。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.