天天看點

Qt應用程式部署—X11平台

DerryZhang/2010-4-10 譯自:http://doc.trolltech.com/4.5/deployment-x11.html 

轉載請注明:http://blog.csdn.net/derryzhang/archive/2010/04/10/5469978.aspx

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

    由于Unix作業系統(包括商業版Unix、發行版Linux等等)應用範圍不斷增加,在Unix上部署應用程式顯得十分複雜。在開始之前,我們需知道在一種Unix平台上編譯成功的程式不一定能在其他Unix作業系統上正常運作。例如,除非你使用跨編譯器機制,否則在lrix上編譯的程式就無法部署在AIX上。

内容:

l  靜态連結

n  靜态建構Qt

n  把應用程式連接配接到Qt的靜态版本

l  共享庫

n  建構Qt為共享庫

n  把應用程式連接配接到共享庫的Qt

n  建立應用程式包

l  應用程式依賴

n  附加庫

n  Qt插件

本文将讨論以下話題:在應用程式釋出的時候應該包含哪些檔案,并且確定程式運作的時候能夠找到它們。将結合Plug&Paint程式(在Qt示例程式目錄下)的部署來示範這些過程。

靜态連結

       在Unix上靜态連結通常是最安全最簡單的方式,因為它使你免于部署Qt庫的煩惱,確定他們部署在目标系統的預設的庫查找路徑。

靜态建構Qt

       使用該方法必須從安裝Qt庫的靜态版本開始:

cd /path/to/Qt

./configure -static -prefix /path/to/Qt <other parameters>

make sub-src

 指定prefix選項以免覆寫了已有的Qt安裝。上述示例僅建構Qt庫,例如示例程式及Qt設計器将不會被建構。當make完成後,就可以在/path/to/Qt/lib目錄看到Qt庫。

       當連結應用程式到Qt靜态庫的時候,需要注意可能需要在project檔案中的LIBS添加額外的庫。參見應用程式依賴一節擷取更多資訊。

把應用程式連結到Qt的靜态版本

       一旦Qt靜态建構,接下來就需要重新生成makefile,重新建構程式。首先必須進入到包含應用程式的目錄:

       cd /path/to/Qt/examples/tools/plugandpaint

       現在運作qmake為應用程式建立新的makefile檔案,然後執行幹淨的建構來建立靜态連結的可執行程式:

       make clean

PATH=/path/to/Qt/bin:$PATH

export PATH

qmake -config release

make

       也許你想連結釋出版的庫檔案,這就需要在調用qmake的時候進行指定。需要注意的是必須設定剛才建構的靜态Qt所在的路徑。

       為了檢驗應用程式是不是真的靜态連結到了Qt,可以執行ldd工具(在大多Unix系統上都可用):

       ldd ./application

       核實一下在上面的輸出中沒有Qt的庫。

       現在如果所有編譯和連結都無錯誤,我們應該能夠得到可用于部署的plugandpaint檔案。檢驗程式可以震的獨立運作的一種簡便方法就是把它拷貝到一台不包含Qt或者沒有安裝過任何Qt應用程式的機器上,然後運作看看是否正常。

       值得注意的是如果你的應用程式依賴于編譯器相關的庫,這些庫同時也要和應用程式一起釋出。參見應用程式依賴一節擷取更多資訊。

       Plug&Paint示例程式是由若幹個元件構成的:核心程式(Plug&Paint),基本工具(Basic Tools)以及附加過濾器(Extra Filters)插件。由于無法通過靜态連結方式部署插件,目前的可執行程式尚未完成。應用程式雖然可以運作,但是由于插件丢失功能将無法使用。部署基于插件的應用程式我們需要使用共享庫的方式。

共享庫

       使用共享庫方式部署Plug&Paint程式面臨着兩個挑戰:在目标系統上Qt運作時庫必須和可執行程式正确的釋出,插件必須在正确的位置上安裝,以便于讓應用程式可以找到它們。

建構Qt為共享庫

       假設你已經以共享庫方式安裝了Qt,而共享庫安裝時Qt的預設安裝方式,它們被安裝在目錄/path/to/Qt上。關于如何建構Qt,參見Qt文檔的“安裝”部分内容。

把應用程式連接配接到共享庫的Qt

       在確定Qt以共享庫方式建構後,我們就可以着手建構Plug&Paint程式了。首先需要到應用程式所在目錄:

        cd /path/to/Qt/examples/tools/plugandpaint

      現在執行qmake來建立新的makefile,然後執行一個幹淨的建構建立動态連結可執行程式:

       make clean

qmake -config release

make

       這将會建構主程式,下面的指令将建構插件:

       cd ../plugandpaintplugins

make clean

qmake -config release

make

       如果編譯連接配接無誤,我們會得到一個plugandpaint可執行檔案以及libpnp_basictools.so、libpnp_extrafilters.so插件檔案。

建立應用程式包

       在Unix上尚無标準的安裝包管理工具,是以下面展示的是一種通用的解決方案。可以檢視目标系統的聯機文檔來檢視如何建立安裝包。

       部署應用程式的時候,我們必須確定拷貝了相關的Qt庫(要和你應用程式所使用的Qt子產品一緻)以及可執行檔案到相同的目錄下。需注意的是如果應用程式依賴于編譯器相關的庫,這些庫也必須和應用程式一起分發。參見應用程式依賴一節擷取更多資訊。

       對于插件我們将簡要叙述,但關于共享庫的主題是必須確定動态連結程式能夠找到Qt庫。如果不明确告知,動态連結程式不會查找到應用程式所依賴的庫路徑。有幾種方法來解決這個問題:

l  可以将Qt庫安裝到某個系統庫目錄下(例如:在多數作業系統上的/usr/lib目錄)。

l  當連結程式的時候傳遞預定義的路徑給-rpath指令行選項。這将會告訴動态連結程式在啟動你的應用程式時查找這個目錄。

l  可以為應用程式寫一個啟動shell腳本,在這個腳本裡修改動态連結配置(例如把你的應用程式目錄添加到LD_LIBRARY_PATH環境變量。注意:如果應用程式将會以“運作時設定使用者ID”方式運作,并且擁有者為root使用者,那麼某些平台将會忽略LD_LIBRARY_PATH。在這種情況下不宜使用LD_LIBRARY_PATH方法)。

       第一種方法的缺點是使用者必須具備超級使用者權限。第二種方法的不足在于使用者有可能不具備安裝程式到預定目錄的權限。其他情況是,使用者可能不具備将程式安裝到home目錄的選擇。我們建議使用第三種方法,因為它最靈活。例如下面的plugandpaint.sh腳本:

       #!/bin/sh

appname=`basename $0 | sed s,/.sh$,,`

dirname=`dirname $0`

tmp="${dirname#?}"

if [ "${dirname%$tmp}" != "/" ]; then

dirname=$PWD/$dirname

fi

LD_LIBRARY_PATH=$dirname

export LD_LIBRARY_PATH

$dirname/$appname $*

     通過運作該腳本而不是直接運作可執行程式,就能保證動态連結程式能夠找到Qt庫。需注意的是如果需要運作其他應用程式的話,隻需要重命名一下腳本就行了。

       當查找插件的時候,應用程式将會在目前目錄下的插件子目錄查找。既可以手動拷貝插件到plugins目錄,也可以在插件工程檔案中設定DESTDIR選項:

       DESTDIR = /path/to/Qt/plugandpaint/plugins

       包含了Plug&Paint程式所需要的Qt庫、所有插件的存檔檔案将包括:

元件 檔案名
可執行程式 plugandpaint
執行腳本 plugandpaint.sh
基本工具插件 plugins/libpnp_basictools.so
附加過濾器插件 plugins/libpnp_extrafilters.so
Qt核心子產品 libQtCore.so.4
Qt GUI子產品 libQtGui.so.4

       在多數作業系統下,共享庫的擴充名是.so,但要注意的是在HP-UX上例外,它是.sl。

       需要注意的是如果應用程式依賴于編譯器相關的其他庫,這些庫也必須和程式一起分發。參見應用程式依賴一節擷取更多資訊。

       為了驗證程式現在可以成功部署,你可以解壓縮這個歸檔包到一個沒有安裝Qt以及編譯器的機器上,嘗試運作一下,例如運作plugandpaint.sh腳本。

       将插件放入plugins子目錄的替代方法是在應用程式啟動的時候,使用QApplication::addLibraryPath()或QApplication::setLibraryPaths()方法來添加一個自定義的查找路徑:

       qApp->addLibraryPath("/some/other/path");

應用程式依賴

附加庫

       執行ldd指令(大多數Unix系統都可用)來檢視應用程式依賴哪些庫:

       ldd ./application

       這就會把程式依賴的共享庫都列出來。根據配置,這些庫必須和程式同步分發。特别是标準C++庫,如果你的應用程式使用了與系統編譯器二進制不比對的編譯器,那麼它也必須一起分發。如果可能的話,最安全的方法就是以靜态的方式連結這些庫。

       也許你想與标準的X11庫進行動态連結,但是某些程式會嘗試使用dlopen()方法來打開其他共享庫,那麼一旦調用失敗,X11庫可能會導緻應用程式崩潰。

       同樣值得一提的是,Qt會查找某些X11擴充,例如Xinerama及Xrandr,可能把它們都放了進來,包括它們所連結的所有庫。如果你不能保證某些擴充确實存在,最安全的方法就是在配置Qt到時候禁用該功能(例如/configure -no-xrandr)。

       FontConfig及FreeType是其它經常不可用或者經常二進制不比對的例子。聽起來也許很怪,一些軟體廠商通過在非常陳舊的機器上編譯他們的軟體已經獲得成功,并且很小心的不去更新運作在其中的任何軟體。

       當把程式連結到Qt靜态庫的時候,你必須顯式的連接配接上述所有依賴庫。通過在project檔案中添加LIBS選項來實作。

Qt插件

       可能你的程式也會依賴某個或者多個Qt插件,例如JPEG圖檔格式插件,或者SQL驅動插件。一定要確定你程式裡用到的插件也一同分發,并且要注意每一種類型的插件都應該部署到應用程式所在目錄的指定子目錄下(如:imageformats或sqldrivers目錄)。

注意:如果需部署一個使用了QtWebKit來展現網際網路的HTML頁面的程式,那麼就需要包含所有文本編碼插件以便于支援足夠多的HTML編碼。

       Qt插件的查找路徑(同樣也有一些其它路徑)在QtCore庫裡是寫死的,第一個寫死的插件查找路徑是:/path/to/Qt/plugins。就像上面提到的那樣,使用預定的路徑會有一些不足,是以你需要評估幾種替代方案來確定Qt插件能被正常找到:

l  使用qt.conf。由于它提供了極大的靈活性,我們推薦用這種方法。

l  使用QApplication::addLibraryPath()或QApplication::setLibraryPaths()。

l  使用第三方安裝包打包工具或者目标系統的安裝包管理工具來改變QtCore裡寫死的路徑。

如何建立Qt插件這篇文章展示了建構和部署Qt插件程式的相關注意事項。

繼續閱讀