2009年4月19日 星期日

用MinGW編譯DLL

testdll.h:
#ifndef TESTDLL_H
#define TESTDLL_H

#ifdef DLL_EXPORT
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C" {
#endif

DLLAPI float funadd(float a, float b);

#ifdef __cplusplus
}
#endif

#endif


testmain.c:
#include <stdio.h>
#include "testdll.h"

int main(void)
{
float a,b,c;

    a=1.0;
    b=2.0;
    c=funadd(a,b);
    
    printf("%f \n",c);
    getchar();    
}


testdll.c:
#include "testdll.h"

float funadd(float a, float b)
{
    return (a+b);
}


gcc -c -DDLL_EXPORT (-fPIC) testdll.c
PS : 會產生testdll.o的檔案...還有x86平台,-fPIC會忽略

gcc -shared -o testdll.dll testdll.o -Wl,--output-def,testdll.def,--out-implib,testdll.lib
PS : 產生三個檔案:
testdll.dll:也就是程式執行時載入的dll檔
testdll.def:若有需要和VC編譯器連結,這個檔會需要
testdll.lib:export library,用來連結主程式,這樣主程式才能知道找哪個dll,那個dll裡有哪些函式跟參數....

gcc -c testmain.c
PS : 用來使用dll的主程式,會產生一個testmain.o的檔案

gcc -static -o test.exe testmain.o -L. -ltestdll
PS : 會讓主程式和export library(testdll.lib)靜態連結起來,產生test.exe的可執行檔


由於dll和主程式都是用MinGW產生的,所以可以簡化上面的步驟,不過上面的解說,可以對執行檔組成了解多一些,以下舉兩個例子

方法一:
gcc -shared -o testdll.dll testdll.c
PS : -shared是linker的參數,這裡直接產生testdll.dll

gcc -c testmain.c

PS : -c:只編譯不連結,產生testmain.o

gcc -o test.exe testmain.o testdll.dll

PS : 我也不知給什麼規則,反正MinGW搞得定這個testdll.dll就對了

方法二:
gcc -shared -o testdll.dll testdll.c
gcc -o test.exe testmain.c -L. -ltestdll

PS : -l:unix環境裡,會找libtestdll.a(-static) 或 libtestdll.so(-shared),在函式庫名稱的命名上,前面一定要有lib

不過MinGW對於這個慣例,放寬許多,來讓熟悉windows的人習慣
for (-static) : 會找libtestdll.a 或 testdll.lib
for (-shared) : 會找libtestdll.so . testdll.dll 或 libtestdll.dll

希望看完之後是感覺"條條道路通羅馬",而不是給它一整個亂...

這裡又牽扯出另一個疑問,那就是MinGW的make,它對於字尾規則和函式庫的處理,是否有加上這些擴充,有空在研究好了

PS:MinGW的官方網站,有提供一個Shell,叫MSYS,之前發現MinGW和MSYS都有自己的make,MinGW的make叫mingw32-make.exe,MSYS的make叫make.exe,其中MSYS的make是unix style,不能分辨'\',組成的路徑字串(windows是用'\',組成路徑字串),也許這兩個make除了這個區別,還包括了字尾規則和函式庫處理的差異...


testdll.h的補充說明:
關於DLL_EXPORT 的定義,應該要在編譯testdll.c時定義,來分別dllimport和dllexport,不過我沒加,也沒錯誤,我不知道MinGW有沒有支援__declspec(dllimport)和__declspec(dllexport) 這些關鍵字...

關於extern "C" {},如果使用gcc,且souce code的附檔名是.c,會有錯誤,不過__cplusplus沒有定義,會避開...
如果附檔名是.cpp,或gcc改g++,則__cplusplus會定義,就會使函數的Name Mangling使用C的形式(簡單的那一種),常看到...

這裡的紀錄,主要都是看了別人的文章,試出來的...我盡量有系統性,不過最好還是參考相關主要說明文件

相關連結:

MinGW官方整理的FAQ
http://www.mingw.org/wiki/FAQ

這裡有幾篇關於如何用MinGW編譯DLL
http://www.adp-gmbh.ch/win/misc/mingw/dll.html
http://www.mingw.org/wiki/MSVC_and_MinGW_DLLs
http://sig9.com/node/35

用cygwin編譯DLL
http://mqjing.blogspot.com/2009/03/c-cygwin-windows-code.html
http://mqjing.blogspot.com/2009/04/c-gcc-library.html 

用gcc處理static and shared library
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html

有關gcc和g++的區別
http://blog.chinaunix.net/u1/52901/showart_480159.html
http://www.yuanma.org/data/2007/0406/article_2498.htm

沒有留言:

張貼留言