摘要:
本文介紹了如果把一個DirectFB源程式檔案編譯一個可執行的檔案,附帶性的介紹了gcc的常見編譯選項的應用。
---------------------------------------------------------------------------------------------------------------------
聲明:
此文為原創,歡迎轉載,轉載請保留如下資訊
作者:聶飛(afreez)
聯系方式:[email protected] (歡迎與作者交流)
初次釋出時間:2006-05-29
不經本人同意,不得用語商業或赢利性質目的,否則,作者有權追究相關責任!
---------------------------------------------------------------------------------------------------------------------
程式設計環境:
調試環境:FC5(Fedora Core 5)、DirectFB. 0.9.24 或DirectFB.0.9.25
安裝資訊:DirectFB不是預設的安裝方式,安裝路徑為/usr/DirectFB25/
DirectFB源程式
程式名:draw_line.c
功能:在螢幕中間畫一條水準直線
#include <stdio.h>
#include <unistd.h>
#include <directfb.h>
//這是最上層的接口,所有的函數入口均由它(IDirectFB)而來
static IDirectFB *dfb = NULL;
//主平面,也就是“螢幕”了。在互動層使用DFSCL_FULLSCREEN,它是主層平面。
static IDirectFBSurface *primary = NULL;
//這裡存儲主平面的高和寬,進而為其它的操作提供支援
static int screen_width = 0;
static int screen_height = 0;
//用以檢測錯誤的宏定義,用來檢測大部分的函數的傳回值是否正常。隻适合用在小的測試程式
#define DFBCHECK(x...) /
{ /
DFBResult err = x; /
/
if (err != DFB_OK) /
{ /
fprintf( stderr, "%s <%d>:/n/t", __FILE__, __LINE__ ); /
DirectFBErrorFatal( #x, err ); /
} /
}
int main (int argc, char **argv)
{
//為了建立一個平面,需要定義一個平面描述子(surface description)
DFBSurfaceDescription dsc;
//初始化
DFBCHECK (DirectFBInit (&argc, &argv));
DFBCHECK (DirectFBCreate (&dfb));
DFBCHECK (dfb->SetCooperativeLevel (dfb, DFSCL_FULLSCREEN));
//設定dsc的一些屬性,現在可以不用關心
dsc.flags = DSDESC_CAPS;
dsc.caps = DSCAPS_PRIMARY | DSCAPS_FLIPPING;
//使用我們設定的dsc建立主平面(primary)
DFBCHECK (dfb->CreateSurface( dfb, &dsc, &primary ));
//得到主平面的寬與高
DFBCHECK (primary->GetSize (primary, &screen_width, &screen_height));
//通過畫一個和主平面同等大小的矩形來清空主平面;預設顔色為黑色
DFBCHECK (primary->FillRectangle (primary, 0, 0, screen_width, screen_height));
//為了能顯示畫出來的線,先設定一下線的顔色,線的位置在螢幕的中間
DFBCHECK (primary->SetColor (primary, 0x80, 0x80, 0xff, 0xff));
DFBCHECK (primary->DrawLine (primary,0, screen_height / 2,screen_width - 1, screen_height / 2));
//顯示
DFBCHECK (primary->Flip (primary, NULL, 0));
//等待5秒後,程式自動退出
sleep (5);
primary->Release( primary );
dfb->Release( dfb );
return 23;
}
編譯準備
安裝完DirectFB後,由于某種原因,我沒有把/usr/DirectFB25/lib添加到配置檔案/etc/ld.so.conf 中,是以,在進入(每一個)終端時,要設定兩個環境變量,如下所示:
$export PKG_CONFIG_PATH=/usr/DirectFB25/lib/pkgconfig/
$export LD_LIBRARY_PATH=/usr/DirectFB25/lib
編譯
為了詳細分析其編譯過程,先分析幾個使用不當的編譯過程,最後給出兩中常用的編譯方法。
不當編譯1:$gcc draw_line.c -o draw_line
正常情況下,我們做一些練習時,常常使用如下的編譯格式來編譯:
$gcc src.c –o destination
如果這裡,我們同樣使用這樣的編譯選項時,會出現類似如下的編譯錯誤:
draw_line.c:3:22: error: directfb.h: No such file or directory
draw_line.c:4: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
draw_line.c:5: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
draw_line.c: In function 'main':
draw_line.c:20: error: 'DFBSurfaceDescription' undeclared (first use in this function)
draw_line.c:20: error: (Each undeclared identifier is reported only once
draw_line.c:20: error: for each function it appears in.)
draw_line.c:20: error: expected ';' before 'dsc'
draw_line.c:21: error: 'DFBResult' undeclared (first use in this function)
draw_line.c:21: error: expected ';' before 'err'
……
錯誤中顯示了很多編譯異常輸出,最讓人無法忍受的是竟然沒有找到頭檔案directfb.h,編譯DirectFB應用程式,可基本上都需要這個頭檔案的!怎麼會找不到呢?
使用$ls /usr/DirectFB25/include/directfb 檢視一下,發現裡面确實有directfb.h。那麼,就是GCC沒有找到該檔案了,也就是說,gcc預設查找庫檔案的路徑不包括:
/usr/DirectFB25/include/directfb
該路徑是我安裝的目錄,如果不通知gcc的話,它是不會去這裡找相關庫檔案及頭檔案的。
好了,知道了異常輸出的原因之後,我們改用下面的編譯指令進行編譯。
不當編譯2:
$gcc -L/usr/DirectFB25/lib -I/usr/DirectFB25/include/directfb draw_line.c -o draw_line
檢視相關的gcc編譯參數,我們可以知道其中的-L與-I的含義,相關含義大緻如下:
-I(大寫的i)參數是用來指定頭檔案目錄,/usr/include目錄一般是不用指定的,gcc知道去那裡找,但是如果頭檔案不在/usr/include裡我們就要用-I參數指定了,比如頭檔案放在/not_usr目錄裡,那編譯指令行就要加上- I/not_usr參數了,如果不加你會得到一個類似上面的異常輸出。-I參數可以用相對路徑,比如頭檔案在目前目錄,可以用-I.來指定。
-l(小寫的L)參數就是用來指定程式要連結的庫,-l參數緊接着就是庫名。當我們自已要用到一個第三方提供的庫名字libtest.so,那麼我們隻要把libtest.so拷貝到 /usr/lib裡,編譯時加上-ltest參數,我們就能用上libtest.so庫了(當然要用libtest.so庫裡的函數,我們還需要與 libtest.so配套的頭檔案)。
放在/lib和/usr/lib和/usr/local/lib裡的庫直接用-l參數就能連結了,但如果庫檔案沒放在這三個目錄裡,而是放在其他目錄裡,這時我們隻用-l參數的話,連結還是會出錯,出錯資訊大概是:“/usr/bin/ld: cannot find -lxxx”,也就是連結程式ld在那3個目錄裡找不到libxxx.so,這時另外一個參數-L就派上用場了,比如常用的X11的庫,它在 /usr/X11R6/lib目錄下,我們編譯時就要用-L/usr/X11R6/lib -lX11參數,-L參數跟着的是庫檔案所在的目錄名。再比如我們把libtest.so放在/aaa/bbb/ccc目錄下,那連結參數就是- L/aaa/bbb/ccc –ltest。
可是,即使這樣來編譯,還是會出現如下的類似異常輸出資訊,大緻如下:
/tmp/cc4yJt2K.o: In function `main':draw_line.c:(.text+0x1e): undefined reference to `DirectFBInit'
:draw_line.c:(.text+0x 5f ): undefined reference to `DirectFBErrorFatal'
:draw_line.c:(.text+0x6b): undefined reference to `DirectFBCreate'
:draw_line.c:(.text+0xac): undefined reference to `DirectFBErrorFatal'
:draw_line.c:(.text+0x107): undefined reference to `DirectFBErrorFatal'
:draw_line.c:(.text+0x178): undefined reference to `DirectFBErrorFatal'
:draw_line.c:(.text+0x1db): undefined reference to `DirectFBErrorFatal'
:draw_line.c:(.text+0x255): undefined reference to `DirectFBErrorFatal'
/tmp/cc4yJt2K.o:draw_line.c:(.text+0x 2c 8): more undefined references to `DirectFBErrorFatal' follow
collect2: ld returned 1 exit status
這次,頭檔案directfb.h是找到了,可是,好多庫的接口函數卻沒有找到!注意,此時的輸出都是連接配接錯誤,已經沒有了文法錯誤了。也就是說,我們寫的這個draw_line.c源檔案已經通過了預編譯、編譯和彙編階段,隻是最後的連接配接過程出現了異常。Gcc的處理過程會經曆四個過程,分别為∶預處理(也稱 預編譯,Preprocessing)、編譯(Compilation)、彙編(Assembly)和連接配接(Linking),詳細介紹見相關資料。
也就是說,我們現在隻要解決連接配接的問題就ok了。那麼如何才能找到我們需要的函數庫的接口呢?
如果你足夠仔細的話,在安裝DirectFB提供的事例(如:DirectFB-examples- 0.9.23 .tar.gz)的時候,其中會提級到一個檔案,即directfb.pc。該檔案記錄了你的一些安裝資訊,現在讓我們來看看它裡面的内容把。
$ more /usr/DirectFB25/lib/pkgconfig/directfb.pc
prefix=/usr/DirectFB25
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: DirectFB
Description: Graphics and windowing library for the Linux frame buffer device
Version: 0.9.25
Requires: fusion direct
Libs: -L${libdir} -ldirectfb -lpthread -ldl -lz
Cflags: -D_REENTRANT -I${prefix}/include/directfb
裡面詳細記錄了我們安裝的路徑、版本以及庫的資訊。特别注意裡面有一行為:
Libs: -L${libdir} -ldirectfb -lpthread -ldl -lz
乖乖,終于找到它了,呵呵。好了,我們再來編譯一下把。
正确的編譯方式1
$ gcc -L/usr/DirectFB25/lib -I/usr/DirectFB25/include/directfb -ldirectfb -lpthread -ldl -lz draw_line.c -o draw_line
編譯後,再也沒有異常輸出資訊了,好了。終于成功了,還等什麼?先去運作一下,看看效果吧!
如果你已經欣賞完了你“自己”畫的那條直線的話,那麼,我們再來看看另一種簡便的編譯方法。
正确的編譯方式2
$gcc `pkg-config --cflags --libs directfb` -o draw_text draw_text.c
注意,這裡的pkg-config --cflags --libs directfb兩側使用的不是單引号,而是鍵盤上數字鍵1左邊的那個和“~”一體的“`”鍵符号;--libs 後面的包名directfb也不要忘記寫,否則會出下類似如下的錯誤資訊:
Package directfb was not found in the pkg-config search path.
Perhaps you should add the directory containing `directfb.pc'
to the PKG_CONFIG_PATH environment variable
No package 'directfb' found
在編譯DirectFB應用程式和庫的時候,pkg-config是一個十分有用的工具,關于pkg-config的使用方法,詳見:
http://pkgconfig.freedesktop.org/wiki/
補充:
如果你安裝的版本是DirectFB. 0.9.25 的話,在你用gcc編譯時,可能會出現找不到libdirect-0.9.so.24或libdirectfb-0.9.so.24或libfusion-0.9.so.24的情況(反正我的機器是出現了)。檢視你的libs位置:
$ls /usr/DirectFB25/lib
你會發現,其中的庫的版本都是*.so.25,鬼才能找到什麼*.so.24的連接配接庫。不過,也沒有關系了,有條件要上,沒有條件,創造條件,也要上了。來,自己動手,豐衣足食吧。
$cd /usr/DirectFB25/lib
ln -s libdirect-0.9.so.25.0.0 libdirect-0.9.so.24
ln -s libdirectfb-0.9.so.25.0.0 libdirectfb-0.9.so.24
ln -s libfusion-0.9.so.25.0.0 libfusion-0.9.so.24
Reference:
1. 本文中的DirectFB畫線應用程式來自:
http://www.directfb.org/docs/DirectFB_Tutorials/simple.html
2.Man page of gcc 使用$man gcc檢視
3.Gcc相關的中文介紹,參照:
http://www.raidcheng.net/blog/archives/2005/03/
http://www.linuxeden.com/doc/20454.html