May 31, 2008

「尋幽訪勝話系統--以 Linux 探索軟硬體整合設計」簡報上線

本週四 (May 29) 前往南台科技大學,做了一場名為 [尋幽訪勝話系統--以 Linux 探索軟硬體整合設計] 的演講,用了三小時的時間,為該校師生介紹了 Linux 設計的精神與 Device Model,相關資料已上線,可參考: 其中簡報檔採用 Creative Commons 授權 (CC-by-SA),程式檔則是 GNU GPL 授權。這次演講的重心主要強調 UNIX 設計原則 "Everything Is File" 與「真實的虛擬記憶體」,此原則反映到 device driver model,若能充分體驗,應該能對系統設計有適度的切入。再者,我又強調應捨棄過去「逐行 trace Linux kernel」的「陋習」,相反,我們應該掌握 kernel 設計考量與發展趨勢,再回頭思考系統發展,並以軟硬體間的變化為出發,如簡報中「Rosetta Stone:Linux如何建立軟硬體關聯」一節所提及的 "/proc/iomem",交叉觀察分析,進而知曉其奧義。另外,也趁此時機,與該校資工系與電子系的教授交流,參觀了該校在機電整合與機器人設計的成果。

請多指教,謝謝!
由 jserv 發表於 12:01 PM | 迴響 (5)

May 23, 2008

以 ptrace 系統呼叫來追蹤/修改行程

一月份南下分享主題為 [快快樂樂學 GNU Debugger] 的演講,當時為了說明 GNU Debugger (gdb) 在 Linux 運作的原理,提及 ptrace 系統呼叫,這是何以 gdb 能行使動態追蹤、分析,進而修改執行中行程 (process) 的關鍵。本文試著以簡要的案例,說明如何使用 ptrace 系統呼叫,達到類似 gdb 的行為。

在 MS-Windows 中,「攔截」或「追蹤」其他行程,是相當進階的議題,而且為了達到目的,往往得訴諸頗多 hacks,然而,在 UNIX 的世界裡,作業系統提供 ptrace 系統呼叫,允許我們優雅地進行這些動作。且讓我們問問男人 (雙關語,UNIX "manual",縮寫為 "man"),看 ptrace() 的描述:
    # man 2 ptrace
    The ptrace() system call provides a means by which a parent process may observe and control the execution of another process, and examine and change its core image and registers. It is primarily used to implement breakpoint debugging and system call tracing.

    The parent can initiate a trace by calling fork(2) and having the resulting child do a PTRACE_TRACEME, followed (typically) by an exec(3). Alternatively, the parent may commence trace of an existing process using PTRACE_ATTACH.
    ... (後略) ...
整理我們的初步認知:
  • ptrace 系統呼叫用以實做 gdb 一類可斷點 (breakpoint) 的追蹤除錯,或作系統呼叫的追蹤分析
  • ptrace 允許一個 parent process 去監控另一個 process 的執行,並得以檢驗 / 更改執行時期的系統 image (映射於虛擬記憶體) 和暫存器
  • 使用情境可透過 fork 系統呼叫去建立 child process (搭配 exec 系統呼叫) 或者直接追蹤某個已執行的 process
另外,依據此陳述,我們也可發現,在使用者層級 (user-level / user-space) 追蹤其他行程是可行的。而在實際「追蹤」前,我們應該要很清楚無論哪個行程,只要存取到系統服務,哪怕只是 "Hello World" 等級的應用程式想透過標準 C 函式庫呼叫 printf() 印列字元,都涉及系統呼叫 (system call,以下簡稱 "syscall") 的處理,在前年、去年的 [深入淺出 Hello World] 系列演講中,已對此做了系統性的探討,本文不再細究其原理,僅點出重點以銜接 ptrace 的角色。

對 Linux 來說,在 IA32 (32 位元的 x86 系統,本文也記作 i386) 上,一個行程欲使用 syscall 時,需要將相關參數推入至暫存器 (register),並觸發 0x80 (hex) 軟體中斷,就緒後,行程的控制權,就從 user-space 切換到 kernel-space,由核心來完成系統呼叫的具體動作。示意圖如下: (出處:〈Kernel command using Linux system calls〉, M. Tim Jones)

上圖以 getpid() 這個 syscall 為例,實際上,C 語言的應用程式並非直接呼叫 syscall 的,而需要透過 GNU glibc 一類 C-Library 裡頭 syscall wrapper 所提供的函式呼叫進行,其細部的實做就是在 eax 暫存器設定 getpid syscall 的編號 (定義於 syscall 表格的 _NR_getpid 項目),之後觸發 int 0x80。由上圖可見,執行權移轉到核心,核心由剛剛設定的 eax 暫存器作為索引,去 system_call_table[] 找到真正實做 getpid syscall 的進入點 (entry),去呼叫並在執行後,將控制權交回 user-space,對原本的行程來說,就是 getpid() 這個 C 函式的返回。

那麼,ptrace 這個 syscall 在何時現身?本文大幅略過平台相關的部份,僅探討 行為模式:在 syscall 真正呼叫前,Linux 核心會檢查目前的行程是否處於「被追蹤」(traced) 的狀態,若是,核心會暫停 (stop) 目前的行程,並將控制權交與欲追蹤 (主動去追蹤其他行程者) 的行程,讓跟蹤行程得以監控 traced process 的暫存器,當然也包含執行時期的 pc (Program Counter,在 IA32 上,就是 eip 暫存器)。

有了基礎概念後,我們就可實際作點事。筆者於兩年前撰寫過一篇文章 [SM 版 Hello World],談及 Linux/i386 上,如何實現 SMC (Self-Modifying Code),而標題的 "SM" 當然是指一個行程如 "Hello World" 者,如何自我修改執行時期的內容,也就是 Selt-Modifying,感覺是「自虐」,反而不若一般說 SM (施虐與受虐) 的語意。那麼,今天我們就來作個真正有 "SM" 能力的程式,展示動態追蹤 / 修改其他行程的行為,預想的情境為先讓一個無限迴圈的行程保持等待,然後另一個行程透過 ptrace syscall 去攔截該行程並修改執行內容 (是的,就是「施虐」的動作),最後讓被 ptrace 行程產生變化 (也就是「受虐」者)。

ptrace 的函式宣告如下:
long ptrace(enum __ptrace_request request,
            pid_t pid,
            void *addr,
            void *data);
首個引數規範 ptrace syscall 的具體行為與其使用模式,有以下值:
  • PTRACE_TRACEME
  • PTRACE_PEEKTEXT, PTRACE_PEEKDATA
  • PTRACE_PEEKUSER
  • PTRACE_POKETEXT, PTRACE_POKEDATA (*)
  • PTRACE_POKEUSER
  • PTRACE_GETREGS (*), PTRACE_GETFPREGS
  • PTRACE_GETSIGINFO
  • PTRACE_SETREGS (*), PTRACE_SETFPREGS
  • PTRACE_SETSIGINFO
  • PTRACE_SETOPTIONS
  • PTRACE_GETEVENTMSG
  • PTRACE_CONT
  • PTRACE_SYSCALL, PTRACE_SINGLESTEP
  • PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP
  • PTRACE_KILL
  • PTRACE_ATTACH (*)
  • PTRACE_DETACH (*)
標注 (*) 者,為本文範例所用到的 request。其中 PTRACE_GETSIGINFO 與 PTRACE_SETSIGINFO 為 Linux 2.3.99-pre6 後所追加;PTRACE_SETOPTIONS 則為 2.4.6 後追加,引入若干新的 bit mask;PTRACE_GETEVENTMSG 為 2.5.46 後追加;PTRACE_SYSEMU 與 PTRACE_SYSEMU_SINGLESTEP 為 2.6.14 後追加,提供給 UML (User-Mode Linux) 一類的系統作為 syscall 模擬使用。由此可見 Linux 改版時,ptrace 也會隨著更動,注意,addr 與 data 這兩個引數在某些 request 會被忽略,詳情可參考 man-pages 描述。

咱們動手來寫程式,就取名為 [injector.c] 表示符合前述情境。以下為程式碼列表:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h> /* ptrace() */

#include <sys/wait.h>   /* wait() */
#include <sys/types.h>
#include <linux/user.h>   /* struct user_regs_struct */

/* _exit(1) implementation in shellcode */

static char shellcode[] =
    "\x31\xc0" 		/* xor  %eax,%eax */
    "\x40" 			/* inc  %eax */
    "\xcd\x80" 		/* int  $0x80 */ ;


#include <stdarg.h>
#define OUT_MSG(x, ...) printf("* " x "\n",## __VA_ARGS__)
#define ERR_MSG(x) printf("\t[Error] " x "\n")

int main(int argc, char *argv[])
{
    int pid, offset;
    struct user_regs_struct regs;

    OUT_MSG("Injector starts.");
    if (argc < 2) {
        ERR_MSG("PID required in parameter.");
        return -1;
    }

    pid = atoi(argv[1]);
    OUT_MSG("Attaching process (PID=%d)...", pid);
    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
        ERR_MSG("Fail to ptrace process");
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        return -1;
    }

    OUT_MSG("Process attached.");
    /* see if  a child has stopped (but not traced via ptrace(2)) */

    if (waitpid(pid, NULL, WUNTRACED) < 0) {
        ERR_MSG("WUNTRACED");
        exit(1);
    }

    OUT_MSG("Getting registers from process.");
    if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0) {
        ERR_MSG("Fail to get registers.");
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        exit(1);
    }

    OUT_MSG("Injecting shellcode into process...");
    for (offset = 0; offset < sizeof(shellcode); offset++) {
        if (ptrace(PTRACE_POKEDATA, pid,
                   regs.esp + offset,
                   *(int *) &shellcode[offset])) {
            ERR_MSG("Fail to inject.");
            ptrace(PTRACE_DETACH, pid, NULL, NULL);
            exit(1);
        }
    }

    regs.eip = regs.esp;
    regs.eip += 2;

    OUT_MSG("Adjust program counter (EIP) of process to 0x%x",
            (unsigned int) regs.eip);
    if (ptrace(PTRACE_SETREGS, pid, NULL, &regs) < 0) {
        ERR_MSG("Unable to set registers.");
        ptrace(PTRACE_DETACH, pid, NULL, NULL);
        exit(1);
    }

    OUT_MSG("Detach process (PID=%d).", pid);
    ptrace(PTRACE_DETACH, pid, NULL, NULL);
    OUT_MSG("Done");
    return 0;
}
既然有了「施虐」者程式,就再弄個「受虐」者程式,比方說 [dummy-loop-prog.c],以下是程式列表:
#include <unistd.h>
int main()
{
    while (1)
        sleep(1);
    return 0;
}
沒什麼好說,就是一直透過 sleep syscall 等待的小程式。一開始,我們讓 dummy-loop-prog 先執行,如下圖:

而當前述的 injector 執行時,我們將會發現:

injector 透過 ptrace syscall 去 attach 到執行中 dummy-loop-prog 的行程 (PID=943),先取得暫存器的值,當然,最有興趣的是 ESP,也就是指向目前的 stack frame 的指標,因為我們要注入 shellcode。一旦完成注入的動作後,需要將 EIP 暫存器的值調整,這時候 PID=943 的行程就被迫執行到 shellcode 的內容,也就是 _exit(1),這會使原本的無限迴圈因而終止,行程也會結束。

[injector.c] 的程式碼中,將 request 設定為 PTRACE_GETREGS 傳遞給 ptrace syscall 可得到被追蹤的行程現行的暫存器內容,保存於 user_regs_struct 結構體之中,而這定義於 <linux/user.h> 檔頭。而 request 設定為 PTRACE_PEEKDATA / PTRACE_POKEDATA 時,則可窺視 / 修改執行中行程的內容,就像筆者展示植入 shellcode 的行為一般。更甚者,request 設定為 PTRACE_SINGLESTEP 時,ptrace 允許對 child process 進行單步執行的動作,這會使得核心在 child process 的每條指令執行前,會先中斷等待著,而將控制權交給追蹤的行程,就好比 gdb 的行為一般,當然,能做的事情就更多了。

ptrace 系統呼叫無疑是對 Linux 底層運作機制作尋幽訪勝,一個相當強大且優雅的工具,若能善用,並搭配既有的工具如 gdb,將能如虎添翼。另外,由於 ptrace syscall 在若干應用,如 User-Mode-Linux 與 multi-threading 環境中,有先天設計的缺陷,RedHat 工程師 Roland McGrath 則展開 [utrace] 的新發展,目標是完全取代 ptrace,允許 user-space 行程透過 utrace syscall,得以掌握更多 Linux 核心的資訊,並引入名為 "tracing engine" 的新機制,可更深入地追蹤掌控行程的狀態。
由 jserv 發表於 02:07 AM | 迴響 (3)

May 21, 2008

透過 Python 體驗 QtWebKit 快速開發

稍早寫過一篇文章 [QtWebKit: 將 Web 2.0 技術帶入行動通訊的系統設計],談及 Trolltech 對於 Qt Framework 與 WebKit 的整合,提供獨到的設計,不僅可很容易在應用程式中嵌入 WebKit 所帶來的 Web 2.0 網路服務外,還可作無接縫 (seamless) 的整合。不過前文並未解說整合細節,這裡就帶出具體而微的範例,體驗 QtWebKit 的技術突破與先進的特徵,恰好下個月要出席 [PycTW2008],那麼程式語言選用 Python 作為練習。

日前 Trolltech 正式釋出 Qt 4.4,業已整合 QtWebKit,與 Qt framework 銜接的 [PyQt] 日前也推出 v4.4.2,即可透過 Python 來釋放 QtWebKit 的威力。Qt framework 一向最為人知的賣點就是 "signals-slots" 機制,自然在 PyQt 也少不了,而且還透過 [SIP] Python 模組,免去了許多語言層面的繁文縟節。首先,要存取 PyQt 的模組很容易,只要如此宣告:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
在這個範例,筆者設想的操作情境為,展示如何透過 WebKit 顯示 HTML element 與 JavaScript,以及透過 iframe tag 嵌入 Google 首頁,在使用者互動的部份,透過 Javascript 建立對話框,並試著與 Python 的程式通訊。於是,我們建立一個 class 來專門描繪網頁,程式碼如下:
class BrowserScreen(QWebView):
    def __init__(self):
        QWebView.__init__(self)

        self.resize(800, 600)
        self.show()
        self.setHtml("""
           <script>function message() { return "Clicked!"; }</script>
           <h1>QtWebKit + Python sample program</h1>
           <input type="button" value="Click JavaScript!" 
                  onClick="alert('[javascript] ' + message())"/>
           <input type="button" value="Click Python!" 
                  onClick="python.alert('[python] ' +
                                        python.message())"/>
           <br />
           <iframe src="http://www.google.com/"
                   width="750" height="500"
                   scrolling="no"
                   frameborder="0"
                   align="center"></iframe>
        """)
我們定義的 class 繼承自 QtWebKit 中的 class QWebView,在初始化時,即呼叫 resize(), show(), setHTML() 等 method。此外,與其說上述程式列表為 Python 程式語言,不如說就是 HTML 網頁原始碼。熟悉網頁程式設計者,一眼就可發現我們在兩個 input button 上建立 Javascript 事件關聯,其中一個呼叫 alert() method 來顯示對話框,而另一個則比較特別:
onClick="python.alert('[python] ' +
         python.message())
這邊的 "python.alert" 與 "python.message" 就使用了 PyQt + QtWebKit 的專有功能,意思是按下 button 時,會呼叫 python 物件的 message method,而這個 "python" 物件可動態在欲嵌入 WebKit 的 Python 程式中傳入物件,當然,可有頗多變化。筆者這裡僅作字串回傳顯示的動作,不過即使如此,還是有兩項技術細節要思考:
  • QtWebKit 的 class QWebView,其最主要的目標是走訪 HTML 個別 element 並描繪網頁,也就是內部維護著 DOM (Document Object Model),包含我們剛剛看見的那兩個 input button 也在其中
  • Javascript (或 ECMAscript) 內部有自己的字串與物件表示,Python 也有字串,而 Qt framework 更有 class QString,那麼,該如何建立起彼此的關聯呢?至少,在筆者設計的情境中,就得考慮字串與物件遊走於這三方所需面對的議題
實際上,得面對的問題不只如此,不過 QtWebKit + PyQt 都幫我們處理掉,所以,筆者只要另行提供 Python 物件並交予 QtWebKit 即可。以下是傳入到 WebKit 的物件相關的 Python 程式碼:
class PythonJS(QObject):
    __pyqtSignals__ = ("contentChanged(const QString &)")
    @pyqtSignature("QString")
    def alert(self, msg):
        self.emit(SIGNAL('contentChanged(const QString &)'), msg)

    @pyqtSignature("", result="QString")
    def message(self):
        return "Click!"
這個名為 PythonJS 的 class,繼承自 class QObject。透過 PyQt,我們宣告一個自訂的 signal: "contentChanged(const QString &)",這不需要額外的 moc compiler 即可有對應的 metadata 關聯。剛剛在 class BrowserScreen 的 HTML 程式列表中,所提及的 "python.alert" method 就定義於此,筆者依據 Qt 的 Signals-Slot 機制,去 emit 出 "contentChanged(const QString &)" 這個 signal,並將 alert() method 後方的字串 (const QString & 型態) 一併傳出,也可見到 PyQt 中宣告 msg 參數型態為 "QString"。同樣,PythonJS::message method 也是如此,依據上方的執行順序來看,會先呼叫 PythonJS::message() 在將傳回的 QString 字串透過 QtWebKit 內部的轉換,變成 JavaScript 的字串並作物件的合成動作 (即 "'[python] ' + python.message()" 陳述),並將得到的 JavaScript 字串傳遞給 QtWebKit 外部的 Python 物件,呼叫 PythonJS::alert() method,當然,這時候要將 JavaScript 字串轉變成 Pthon 可處理的 QString 字串。

撰寫了以上兩個 class,程式幾乎完成了,只要將兩者整合起來即可,為了增加視覺上的比較效果,筆者透過 Qt 4.4 提供的 System Tray (在 X11/FreeDesktop 的術語為 "Notification Area") 來作訊息顯示的動作。所以修改了 class BrowserScreen,追加兩個 method,程式碼如下:
class BrowserScreen(QWebView):
    def __init__(self):
        QWebView.__init__(self)

        self.createTrayIcon()
        ...
        self.trayIcon.show()

    def createTrayIcon(self):
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setIcon(QIcon("images/trash.svg"))

    def showMessage(self, msg):
        self.trayIcon.showMessage("This is Python", msg,
            QSystemTrayIcon.MessageIcon(0), 15 * 1000)
BrowserScreen::createTrayIcon() method 透過 class QSystemTrayIcon 要求系統配置 system tray,筆者設定了 SVG 圖檔 (向量繪圖,所以不需要考慮顯示端的空間尺寸),而 BrowserScreen::showMessage() method 看似不相關,僅是顯示訊息的動作,稍後,我們可透過 Qt 的 Signals-Slots,將 QtWebKit 中的 DOM/JavaScript 事件與此 method 給予 "connect" 起來。

最後一個部份,就是畫龍點睛了,以下是 main 程式列表:
if __name__=='__main__':
    import sys

    app = QApplication(sys.argv)

    browser = BrowserScreen()
    pjs = PythonJS()
    browser.page().mainFrame().addToJavaScriptWindowObject("python", pjs)

    QObject.connect(pjs, SIGNAL("contentChanged(const QString &)"),
                    browser.showMessage)

    sys.exit(app.exec_())
重點當然是從前面兩個 class 建立 Python 物件,也就是 "browser" 與 "pjs",整個程式最巧妙之處,就在於以下這行:
    browser.page().mainFrame().addToJavaScriptWindowObject(
        "python", pjs)
這也是 QtWebKit 技術的「火力展示」,原來前面的 HTML 列表的 JavaScript 程式的 "python" 物件,就是甫建立的 "pjs" 物件,而下一行也充滿著驚喜:
    QObject.connect(pjs, SIGNAL("contentChanged(const QString &)"),
                    browser.showMessage)
class PythonJS 所生的物件 "pjs" 裡頭的 signal "contentChanged" 被連結 (connect) 到 class BrowserScreen 所生的物件 "browser" 裡頭的 slot "showMessage",原本只是平淡無奇的 PyQt 敘述,但因為 "pjs" 物件被傳入 QtWebKit,WebKit 所描繪的網頁 (範例即 Google 首頁) 有完整的 DOM/JavaScript,依據之前的 HTML 程式列表,已建立這兩者的關聯,如今,再將 PyQt 的事件一舉打通。是此,Python/PyQt - QtWebKit - DOM/JavaScript 的關聯就建立了,咱們來體驗看看,以下是操作時的圖例:

在 system tray 多了一個綠色、類似資源回收桶的圖樣,而主畫面就如預期,就是 QtWebKit。是的,寫 UI 就是這麼簡單,只要 HTML tag 加上 iframe,頓時有聲有色,為了要證明這不是紙老虎,咱們按一下左方的 "Click Javascript!" input button,會得到下方螢幕輸出:

這就是 Javascript 裡頭呼叫 alert() method,展示了 QtWebKit 的基本能力,最後我們看看剛剛張羅許久的展示,當按下 "Click Python!" input button 後...

注意到 system tray 下方彈跳出黃色對話訊息,別小看這個,這可是歷經 Python/PyQt - QtWebKit - DOM/JavaScript 等部份,顯示於我們眼前的。我們也可發現,QtWebKit 要與桌面整合並產生有效的互動,只需要上述這一些程式碼即可,透過 Python 體驗 QtWebKit 快速開發,看來很棒呢。

取得上述程式碼加上 SVG 圖檔: [pyqtwebkit-sample.tar.bz2],因為 Qt framework 與 PyQt 都以 GNU GPL 授權發行,本範例也是如此。
由 jserv 發表於 10:01 PM | 迴響 (0)

「我愛 Git」簡報上線

週二在 TOSSUG 分享 [我愛 Git - 有效使用分散式版本控制系統] 的主題,感謝與會朋友的捧場與容忍小弟的魯莽 (迷路 50 分鐘),所幸還是快速帶過,簡報已上線,可參考 [loving-git.pdf]。當我們思考 Git 這一類的分散式版本控制系統,首先得面對的是整個開發流程與專案管理的途徑已有頗大的轉變,而我們從事程式設計的模式卻無法有顯著變化,這意味著對於工具的使用,得更留意其擴展性與多樣性。

協同合作是軟體專案開發的要素,所以我們有 SCM (Source Control Management),但要如何有效協助開發者,仍是頗大的挑戰。在分散式版本控制系統中,branch/merge 變成理所當然的行為 (核心想法),並到處都有 repository 搭配有完整的歷史紀錄 + 本地端更動,Git 甚至指出,SCM 應該是「檔案工具」,而非限制開發者的「制度」。Git 令人驚艷的高效能,完整的工具組合也值得採用,這幾年快速發展後,也逐漸被許多世界級專案採用,本議程則點出若干重點觀念,希望能協助理解 Git 的設計與實務應用,請多指教,謝謝!
由 jserv 發表於 02:41 AM | 迴響 (3)

May 19, 2008

以 CMake 處理專案的多國語文翻譯

三月份發表 [貓也會的 CMake] 後,陸續有網友來信指教,其中 huki 問及該如何將自由軟體界廣泛使用的 GNU gettext 整合到以 CMake 為建構系統的專案中,又該如何維護 po (原始的翻譯訊息) / gmo (為 GNU gettext 接受的編譯訊息) 檔案呢?這問題很好,但沒有一定的解法。我採用的方式類似 [GTK-Qt Theme Engine] (允許 Gtk+ 程式使用 Qt 外觀的 plugin),在這個專案的 Subversion 檔案庫中,已採用 CMake,詳情可參考 [gtk-qt-engine]。

拜 CMake 簡潔語法所賜,在 gtk-qt-engine 的 po/CMakeLists.txt 是這麼做的:
# .po to .gmo stuff
FILE(GLOB _pofiles *.po)

FOREACH(_file ${_pofiles})
        GET_FILENAME_COMPONENT(_file_we ${_file} NAME_WE)
        SET(_out "${_file_we}.gmo")
        SET(_in "${_file_we}.po")

        ADD_CUSTOM_COMMAND(
                OUTPUT ${_out}
                COMMAND ${MSGFMT_EXECUTABLE} -o ${_out} ${_in}
                DEPENDS ${_in}
        )

        INSTALL(
                FILES ${_out}
                DESTINATION share/locale/${_file_we}/LC_MESSAGES/
                RENAME gtkqtengine.mo
        )

        SET(_outputs ${_outputs} ${_out})
ENDFOREACH(_file)
原理就是將 po/ 目錄下的若干翻譯檔案掃描一次,並呼叫 GNU gettext 套件中的 msgfmt 工具進行轉換編譯的動作,這部份的定義於上一層,以下是程式列表:
# Find xgettext
FIND_PROGRAM(
        XGETTEXT_PATH
        NAMES "xgettext"
        PATHS "/usr/bin"
)
IF(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND")
        MESSAGE(STATUS 
"xgettext not found.  You will not be able to run "
'make extract_messages' in the 'po' directory.")
ELSE(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND")
        MESSAGE(STATUS "Found xgettext: ${XGETTEXT_PATH}")
ENDIF(${XGETTEXT_PATH} STREQUAL "XGETTEXT_PATH-NOTFOUND")
雖然囉唆一點,但是比起 autotools 那些貌似簡短但難以理解的寫法,其實 CMake 的作法既有彈性且清楚。另一個專案 [cmake-modules] 則致力於維護 CMake 的延伸模組,強化 CMake 的 FindPACKAGE 功能,可在 [線上程式碼列表] 中參考其提供的 FindMsgfmt.cmake 與 MacroGeneratePoFiles.cmake (目錄: trunk/Modules/Macros/PoFiles ),與前述程式列表相仿,只是加了簡單的包裝。
由 jserv 發表於 02:33 PM | 迴響 (1)

PycTW2008 (台灣 Python 研討會) 將於六月 15 日登場


[PycTW2008] 是專注於探討 Python 的研討會,名稱的 "pyc" 不僅是 "Python Conference" 的縮寫,也是Python byte code 的副檔名,由此可見主辦者的幽默。以下節錄網站上的資訊: 在議程的安排上,yungyuc, Thinker, lanma, Mat 等人都會分享 Python 從應用面到底層的技術議題,很值得期待!
由 jserv 發表於 01:21 PM | 迴響 (0)

May 17, 2008

自製 Keroro PC

上個月很榮幸能在 OSDC.tw 上介紹 [許我們一個 Keroro 的桌面],分享 Keroro Desktop Environment 的進展與關於桌面系統設計的想法。而在 [PDF 簡報] 中,我提到「科科 PC」的概念 (「科科」是 Keroro 卡通中那群青蛙的發語詞),既然 ASUS 一類的廠商可為了「容易使用電腦」,而開發出「易 PC」,我們何嘗不能作呢?萬事起頭難,咱們就從最簡單的電腦開始吧,參見下圖:

這幾乎就是 Keroro PC 的「雛型機」,以下是其「產品特色」:
  • 節能、環保,並採用太陽能發電
  • 寬 21 cm x 長 30 cm x 厚 1 cm,易於小朋友攜帶
  • 完整的四則運算能力與暫存器
  • 快速開機
  • 內建 Keroro 圖樣
顯示區還有偌大的字樣「995885」呢 (諧音:「救救我、幫幫我」)

感謝 WalkingIce 貢獻 [Keroro Desktop Paster],可取得向量圖 SVG 檔 / 點陣圖 PNG 檔,可自行改作,但 Keroro 的著作權仍屬於原公司角川出版社。
由 jserv 發表於 06:49 AM | 迴響 (3)

演講:尋幽訪勝話系統--以 Linux 探索軟硬體整合設計

應南台科技大學之邀,小弟將於本月份 29 日 (週四) 於該校分享名為「尋幽訪勝話系統--以 Linux 探索軟硬體整合設計」的演講,以下引述 [系上公告] 的內容:
  • 日期:5 /29 (四) 下午1:50
  • 地點:南台科技大學 資訊工程系 S706 教室
  • 題目:「尋幽訪勝話系統:以 Linux 探索軟硬體整合設計」
  • 簡介:Linux 作為開放原始碼的作業系統核心專案,在十幾年全球無數開發者投入下,帶來空前的成功,在諸多電腦主機、手機,機器人,都有其蹤跡。著名電腦技術作家侯捷嘗言:「源碼之前了無秘密」,的確,Linux的意義不僅在於程式碼完全公開,更在於揭露軟硬體設計的細節,進而讓技術得以藝術般走向我們。本議程試圖勾勒 Linux核心的經典設計,並佐以由軟體的觀點,尋訪電子電機系統的奧秘與其資訊處理之道。
  • 建議之聽者背景:C 程式語言設計、單晶片控制概念、微處理機課程
  • 議程大綱:
    • 源碼之前了無秘密:Linux 對工程資訊領域的意義
    • 重返 Linux 核心設計概念
    • 羅塞達碑石 (Rosetta Stone):Linux 如何建立軟硬體關聯
    • Linux 驅動程式架構與發展
隨著製程的進步,我們幾乎難以理解充分理解系統設計的奧秘,當拿到一台 iPhone 時,當下會認同這是「美」精湛的呈現,卻不易聯想到背後無數的電晶體與邏輯電路,更別提其微妙的運作機制。而,作為與硬體溝通的軟體,更是隱藏這神秘的資訊,使我們對如此的系統設計更加惶恐,好似身處於數位資訊時代的我們,只如蘇格拉底所言:「我唯一所知的,是我一無所知」。

好在,Linux 一類開源的作業系統給予劃時代的突破,承諾將這些奧秘揭露於世人面前,本議程可說是從軟體的觀點,靠著自己尋幽訪勝,感受如何探索軟硬體,進而思索工程資訊領域。也因此,預計聽者可在議程中獲得軟硬體整合設計的概念、Linux 核心與硬體介面之典型設計等項目。歡迎前來指教,謝謝!
由 jserv 發表於 04:09 AM | 迴響 (0)

May 16, 2008

QGtkStyle : 讓 Qt 應用程式模擬 GtK+ 的外觀

當我們使用 GNOME 或 [LXDE] 這一類以 Gtk+ 開發的桌面系統時,免不了會需要使用某些重量級 Qt/KDE 應用程式,如 Skype,稍早還做了 [援助 Qt4 style 小記] 的嘗試。現在,Trolltech 的工程師完成了初步的實做,提出 [QGtkStyle],透過 Qt Style plugin,可動態在 Qt 4.4 的應用程式中,模擬 Gtk+ 的外觀,所謂「一圖勝千文」,咱們看看呈現的效果: (click to enlarge)

由圖可見,最上層的 Skype 雖然非自由軟體,但透過 Qt 4.4 加上 [QGtkStyle] 即可有 Gtk+ 的外觀效果,包含按鈕與捲軸都是如此,與下方的 Firefox 瀏覽器的 native Gtk+ 效果就非常一致,比起過去分歧的 Gtk+ vs. Qt 視覺呈現,協調許多。

程式碼可透過 SVN 取得,以 GNU GPLv2 授權釋出。
由 jserv 發表於 04:08 PM | 迴響 (2)

May 15, 2008

演講:我愛 Git - 有效使用分散式版本控制系統

本月份 [TOSSUG] 的心得分享中,小弟將作主題為 [我愛 Git] 的演講,時間是下週二 (May 20) 晚間七點,地點位於「東吳大學城區部 鑄秋大樓 R2523 教室」,詳細資訊可參閱 wiki [SoochowUniversity]。以下摘錄 TOSSUG wiki 的資訊:
  • 主講人: jserv
  • 內容簡介:
      Git 最早是 Linus Torvalds 用以取代非開源的 BitKeeper 分散式版本控制系統,經快速的開發後,現已被全球眾多知名自由軟體專案採用,儼然是新生代的基礎建設之一。本議程從軟體開發維護的模式,面對典範移轉的挑戰,我們該如何因應,並提及 Git, mercurial, Bazaar 等一系列發展活躍的分散式版本控制系統之核心意義。選定 Git 又有何過人之處?Git 提供豐富的開發工具整合,讓我們得以實現過去難以想像的高度自主性與非寡佔性的軟體開發,分享日適逢 "520" (音近「我愛您」),希望您也可因此愛上 Git,提高生產力。
  • 預定提綱:
    • 版本控制的典範移轉 (Paradigm shift):Why and How
    • 分散式版本控制系統與解決方案
    • Git 核心概念與實務
    • 案例探討:Linux Kernel 與 XOrg
稍早的文章 [從 Ditz 談針對分散式版本控制的 Issue Tracker] 間接提及 Git 逐漸廣泛地被採用,與在自由軟體蓬勃發展刺激下,我們所面臨典範移轉 (Paradigm shift) 等議題,而理解 Git 儼然就是極重要的考量。於是,小弟就趁著心得分享的機會,探討這系列的議題,歡迎舊雨新知前來指教,謝謝!
由 jserv 發表於 01:14 PM | 迴響 (7)

May 01, 2008

「親手打造開放原始程式碼的機器人」簡報上線


週二出席 [OpenTech Summit Taiwan 2008],給予一場主題為 [親手打造開放原始程式碼的機器人] 的演講,感謝工作人員、元智大學系學會,以及所有參與者的包容,當天路上出了意外,臨時得搶修機器人,還好最後趕在議程結束前,分享了對實做 open source Robot 的經驗與所採取的途徑,簡報檔案已上線,請參閱 [BuildYourOwnOpenSourceRobot.pdf]。

感謝指教,也歡迎交流,謝謝!
由 jserv 發表於 05:24 PM | 迴響 (3)