摘要:
本文介紹瞭如果把一個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+0x5f): 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+0x2c8): 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://blog.csdn.net/ganxingming/article/details/761932