天天看點

與afreez一起學習DirectFB之:編譯運作第一個DirectFB程式

摘要:

本文介紹了如果把一個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

繼續閱讀