但改為使用 Single Process 後,另一個新開啟的 LilyTerm 行程將只會多佔用 172KB:
$ ps aux | grep lilyterm
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2531 0.8 1.7 30220 9164 pts/1 S 00:01 0:00 lilyterm
也就是說,原本一個新開啟的 LilyTerm 行程應該是會再額外佔用 9MB 的記憶體,啟用了 Single Process 機制後一下子減少到只需 172KB!這真的是太驚人了。世界上所有軟體應該把 Single Process 機制列為標準備配才是。
$ ps aux | grep lilyterm
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2531 0.2 1.8 30268 9336 pts/1 S 00:01 0:00 lilyterm
但人們的想法裡,程式在載入記憶體後,會先展開,然後把一堆函式庫抓進來,這也是為什麼明明只有 76KB 的 LilyTerm 在載入到了記憶體裡就變成了 9MB 的主要原因。也就是說,執行檔越大、函式庫連結越多的應用程式,應該會佔用較多的記憶體。
註:
其實新開啟的 LilyTerm 行程並不會佔用到那麼多記憶體。使用 ps 指令並不能精確得指出應用程式實際的記憶體使用量。後文將有說明。
另外,下文中所有的測試數據和您系統所安裝的 字型/輸入法/編譯 方式都有很大關係,所以在您的電腦上數據也許會有一些小出入。
LilyTerm 的執行檔大小約為 evilvte 的 3 倍,也比 evilvte 提供了更多功能,所以 evilvte 理論上應該比較輕巧才是,但載入記憶體後 evilvte 卻比 LilyTerm 佔用了更多的記憶體。為什麼?這並不合理呀?
$ ls -l
-rwxr-xr-x 1 root root 76284 2008-07-01 19:10 /usr/bin/lilyterm
-rwxr-xr-x 1 root root 28636 2008-05-28 17:24 /usr/bin/evilvte
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2550 0.8 2.1 54988 11240 pts/1 S 00:01 0:00 evilvte
tetralet 2531 0.8 1.7 30220 9164 pts/1 S 00:01 0:00 lilyterm
在將 toolbar 及 menubar 隱藏起來後,xfce4-terminal 所佔用的記憶體明顯變少了 - 甚至比 evilvte 還小。也就是說,GNU/Linux 在載入應用程式時,並不是一股腦得把所有函式庫全載進來:只有實際有使用到的元件才會被 Linux 所載入,這的確是相當聰明有彈性的做法。
$ ps aux | grep xfce4-terminal
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2512 0.7 2.4 56480 12732 pts/1 S 00:01 0:00 xfce4-terminal
tetralet 2603 1.0 2.0 31572 10696 pts/1 S 00:03 0:00 xfce4-terminal --hide-toolbars --hide-menubar
這個 gtk_demo 程式在載入後約佔用 4.2MB 的記憶體:
#include <gtk/gtk.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
然後,利用以下程式碼,我們就可以大略估算出:如果再多載入單一 vte 元件,將會比 gtk_demo 再多佔用掉約 3.8MB 的記憶體:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2627 0.0 0.8 12320 4232 pts/1 S 00:05 0:00 ./gtk_demo
做為對照組,如果再多載入單一 gtk_entry 元件(Gtk 的輸入欄位元件)後,將會比 gtk_demo 再多佔用掉約 3.4MB 的記憶體:
#include <vte/vte.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *vte = vte_terminal_new();
vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL,
NULL, NULL, TRUE, TRUE, TRUE);
gtk_container_add(GTK_CONTAINER(window), vte);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
以上的程式其實際執行結果如下:
#include <gtk/gtk.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(window), entry);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
也就是說,若單看記憶體用量的話,載入一個像 vte 那麼複雜的元件也等同載入一個 entry 元件再多一點點而己。請別忘了,比起 entry_demo 來,vte_demo 可還多載入了一個 libvte.so.9 函式庫呢!也就是說,光以記憶體用量來說,或許 libvte 會比 gtk_entry 元件更為輕巧呢!說 libvte 癡肥?個人認為是有點苛刻了。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2627 0.0 0.8 12320 4232 pts/1 S 00:05 0:00 ./gtk_demo
tetralet 2667 0.8 1.5 38164 7828 pts/1 S 00:05 0:00 ./entry_demo
tetralet 2648 0.4 1.5 29532 8068 pts/1 S 00:05 0:00 ./vte_demo
我們比較在一個視窗裡放入了 1 個及 100 個 gtk_entry 元件看執行後會佔用的記憶體會是多少:
#include <gtk/gtk.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
int i;
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
for (i=0;i<100;i++)
{
GtkWidget *entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0);
}
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
結論是,就算多了 99 個 gtk_entry 元件,記憶體用量只多增加了 240KB,平均起來也只是 2.4KB。也就是說,Linux 不但會視情況載入必要的元件,且 Gtk+ 的元件之間還會共用記憶體。
$ ps aux | grep entry_demo
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2667 0.8 1.5 38164 7828 pts/1 S 00:05 0:00 ./entry_demo
tetralet 2668 2.0 1.5 38412 8068 pts/1 S 00:05 0:00 ./entry_demo_100
結果如下:
#include <gtk/gtk.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
int i;
for (i=0;i<100;i++)
{
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(window), entry);
gtk_widget_show_all(window);
}
gtk_main();
return 0;
}
結論是,就算是一次叫出 100 個視窗,只比原本的單一視窗多出了 756KB 的記憶體。Gtk+ 的元件就算是在多視窗之下還是會共享記憶體。
$ ps aux | grep entry_demo
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2667 0.8 1.5 38164 7828 pts/1 S 00:05 0:00 ./entry_demo
tetralet 2668 2.0 1.5 38412 8068 pts/1 S 00:05 0:00 ./entry_demo_100
tetralet 2669 4.4 1.6 38948 8584 pts/1 S 00:05 0:01 ./entry_demo_100_window
以下是其記憶體使用量前後比較表:
#include <vte/vte.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
int i;
for (i=0;i<100;i++)
{
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *vte = vte_terminal_new();
vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL,
NULL, NULL, TRUE, TRUE, TRUE);
gtk_container_add(GTK_CONTAINER(window), vte);
gtk_widget_show_all(window);
}
gtk_main();
return 0;
}
我們可以看到,這個程式執行後約略會吃掉 188MB 的記憶體,且十之八九都是被 bash 給佔用掉的,因為 vte_demo_100 本身只佔用了 11MB 的記憶體。
total used free shared buffers cached
Mem: 515596 111572 404024 0 5648 49588
-/+ buffers/cache: 56336 459260
Swap: 431824 0 431824
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2559 1.0 2.2 33216 11544 pts/1 S 00:40 0:05 ./vte_demo_100
tetralet 3050 0.0 0.5 5388 2780 pts/33 Ss+ 00:41 0:00 /bin/bash x 100
total used free shared buffers cached
Mem: 515596 316172 199424 0 8020 52060
-/+ buffers/cache: 256092 259504
Swap: 431824 0 431824
其結果如下:
$ perl -e 'system("./vte_demo&") for (1...100);'
雖然用 free 指令並不是很精確的估算方式,畢竟系統又不是只在跑這一隻程式。但我們大略可以看出來,跑 100 個獨立的 entry_demo 會佔用掉約 385MB 的記憶體,若再扣掉 bash 所佔用掉的 188MB 的記憶體,我們可以估算出來 entry_demo 約莫是一個 Process 佔用 2MB 的記憶體。雖然比原本的 8MB x 100 節省了不少,但遠不如 Single Process 的 100 個視窗只佔用掉 11MB 的記憶體來得節省。
total used free shared buffers cached
Mem: 515596 111820 403776 0 5896 49588
-/+ buffers/cache: 56336 459260
Swap: 431824 0 431824
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
4411 tetralet 17 0 29536 8060 5996 S 0.0 1.6 0:00.16 vte_demo x 100
tetralet 3050 0.0 0.5 5388 2780 pts/33 Ss+ 00:41 0:00 /bin/bash x 100
total used free shared buffers cached
Mem: 515596 505120 10476 0 10796 52048
-/+ buffers/cache: 442276 73320
Swap: 431824 0 431824
結果如下:
#include <vte/vte.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
GtkWidget *entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(vbox), entry, TRUE, TRUE, 0);
GtkWidget *vte = vte_terminal_new();
vte_terminal_fork_command(VTE_TERMINAL(vte), NULL, NULL,
NULL, NULL, TRUE, TRUE, TRUE);
gtk_box_pack_start(GTK_BOX(vbox), vte, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
也就是說,Gtk+2 就算是不同元件之前也是會用享記憶體!真實在太驚人了。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2627 0.0 0.8 12320 4232 pts/1 S 00:05 0:00 ./gtk_demo
tetralet 2667 0.8 1.5 38164 7828 pts/1 S 00:05 0:00 ./entry_demo
tetralet 2648 0.4 1.5 29532 8068 pts/1 S 00:05 0:00 ./vte_demo
tetralet 2628 0.7 1.9 54464 10272 pts/1 S 00:05 0:00 ./gtk_demo_vte+entry
我們跟系統要了 100MB 的空白記憶體。這時您可能會心想:如果多跑幾隻類似的惡搞程式,系統的記憶體很快就不夠用了。但實際執行結果如下:
#include <gtk/gtk.h>
int main( int argc,
char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(window), "delete_event",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gpointer mem = g_malloc0(100*1024*1024);
gtk_main();
return 0;
}
在上例中,雖然 mem_demo 比 gtk_demo 多要求了 100MB 的記憶體,但最後 mem_demo 實際上只比 gtk_demo 多佔用了 4K 的記憶體。我們可以猜到的是:Linux 不管應用程式請求了多少記憶體,它只有在必要時才會真的把記憶體分配給應用程式。這也就是 Linux 記憶體管理十分了不起的地方。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tetralet 2627 0.0 0.8 12320 4232 pts/1 S 00:05 0:00 ./gtk_demo
tetralet 2647 0.1 0.8 114724 4236 pts/1 S 00:05 0:00 ./mem_demo
其中,xterm 真的是驚人的輕巧,但由於 LilyTerm 支援了 Single Process,所以在此情況下還是能略勝 xterm 一籌。但 vte_demo 則由於既不支援分頁也不支援 Single Process 只好敬陪未座了。
支援
分頁
Single
Process
執行檔大小
測試方式 行程大小
測試結果 LilyTerm
○ ○
76KB
2 分頁 x 5 視窗 11,804K x 1
21,228K xterm
╳
╳ 319KB
10 視窗
2,836K x 10
22,804K mlterm ╳ ○ 291KB
2 Pty x 5 視窗 6,384K x 5
27,676K
urxvt
○ ╳ 1,226KB
2 分頁 x 5 視窗 6,372K x 5
27,964K
evilvte
○ ╳ 28KB
2 分頁 x 5 視窗 11,552K x 5
35,532K vte_demo
╳ ╳ 4KB
10 視窗 8,228K x 10
38,600K
註: 測試環境:Celeron 850 + RAM 512MB。
全數使用程式預設值
mlterm 可用 <Ctrl><F1> 來開啟一個新的 Pty 視窗。
在追一個 Firefox 延伸模組時,試著玩了一下在 Firefox 外掛中使用 Java 的方法。
原來你可以用 XPConnect 來存取 Java Object,甚至將你的 Java object 封裝成 XPCOM,以方便 Java Script 取用。範例可參考 Simile Project 的 Java Firefox Extension。於是乎,你的外掛介面可以用 XUL/Java Script 實做,但後端丟給 Java 來處理,若是拿來整合某些企業應用程式,應該可以比較快速的拉出使用者介面與整合商務邏輯。
或者,你也可以使用 JavaXPCOM,讓你的 Java 程式存取 XPCOM 介面的元件。
今年三月底時,Adobe 在 Adobe Lab 發行了 Adobe AIR for Linux alpha 版本。Adobe AIR 是一種執行環境,提供一個可使用 Adobe Flash, Adobe Flex, HTML 與 Ajax 開發桌面 RIA 應用程式的平台。
試玩了一下,可以安裝 twhirl (Running Twhirl on Ubuntu 7.10) 等軟體沒有問題。可惜的是,目前 Linux 版本還不能支援 XIM,以至於無法輸入中文。
另外一個惱人問題是 Adobe AIR 將 zip 格式檔案都以 xdg-mime (xdg-mime of Portland project) 註冊成使用 Adobe AIR 開啟,以至於你的 zip 檔、OpenOffice 文件檔 (也是 zip 壓縮格式) 都變成以 Adobe AIR 開啟了!
解決辦法是
先移除原本的 xdg-mime 設定 # xdg-mime uninstall –novendor “/opt/Adobe AIR/Versions/1.0/support/AdobeAIR.xml” 以編輯器開啟 “/opt/Adobe AIR/Versions/1.0/support/AdobeAIR.xml”,並移除檔案中以下文字 <magic priority=”100″> <match type=”string” value=”PK\003\004″ offset=”0″ /> </magic> 重新安裝 xgd-mime 設定 # xdg-mime install –novendor “/opt/Adobe AIR/Versions/1.0/support/AdobeAIR.xml”
上述 # 開頭指令,指使用 root 執行。


[huki@pc-huki ~]$ gvim --help
VIM - Vi IMproved 7.1 (2007 May 12, compiled May 4 2008 19:28:36)
..............................
...(繼續閱讀)
vim --servername VIM file1.txt然後再執行
vim --remote-tab file2.txt就可以把 file2.txt 開個 tab 在前面那個 vim-server 裡面了~
by FourDollars (noreply@blogger.com) at June 19, 2008 12:04 PM
nmap viwy::vimgrep /\"\>/ **/*.[ch] **/*.[ch]pp **/*.java **/*.pl **/*.rb **/*.py這樣就可以很方便地在 C/C++/Java/Perl/Ruby/Python 的程式碼樹當中快速搜尋關鍵字~
nmap :cn
nmap :cp
by FourDollars (noreply@blogger.com) at June 19, 2008 11:55 AM
哇,若你是個 Geek, 而且對 Linux, Python, Open Source Software 感興趣,你大約已經常常閱覽 Reddit.com,Reddit 是一個 Social bookmark 網站,使用族群較為偏熟悉技術的工程師。
就像所有的 Social Bookmark 一樣,首頁的排序與計算方式總是受到質疑與挑戰。於是 Reddit 乾脆就把整個網站的程式碼開放原碼,於是所有人都可以看到演算法與修改,也可以回饋建議、甚至 Patch。程式碼可於 code.reddit.com 下載。目前 Reddit 用的其他開放原始碼軟體還包含 Debian, lighttpd, HAProxy, PostgreSQL, Slony-I, 數個 Python libraries, Psychopg, pylons, Solr, Tomcat, Ganglia, Mercurial, Git, gettext, daemontools 與 memcached 等。
於是,好事者再也沒有理由質疑 Reddit 動了手腳。
reddit goes open source: message from the alien mascot
大約任何一個軟體開發者都可能碰到詭異的 undocument API 、噁爛的架構,或者碰到設計有問題的硬體,大約都會情不自盡的爆粗口。偶爾,你甚至會被其他莫名其妙的開發者惹火,例如未充分溝通就擅改程式碼包成套件的情境。
前些時候,quodlibet 的 Debian 套件維護者 Sebastian Dröge 因為誤解了 quodlibet 所使用 GStreamer 中的一個 API 相容問題,於是直接擅改程式碼中的一段,以便可以於新版的 GStreamer 中使用。但是這樣的行為卻未事前於 quodlibet 開發者 Joe Wreschnig 溝通,而那其實算是 GStreamer 的問題,並非 quodlibet 的錯誤。
於是,Joe Wreschnig 惱怒之下,身為一個上游開發者,就在 quodlibet 中也改了一段因應 GStreamer API 更改的措施。而且順便戳了 Sebastian Dröge 一下,要他去死一死吧。於是身為一個 Debian Developer,自然的解決方式當然是發一個 Bug Report。而且解決的討論很自然就往 DFSG 與 Debian Policy 發展。所幸,最後 Tristan Seligmann 另外改了程式碼,並做了一份新的壓縮檔,算是解決了這個幼稚問題。
有趣的是 Joey Hess 在討論中,順便彙整了過去 Debian 修改紀錄中,曾經出現的粗口表,非常好笑,只能說 Software 真是 Sucks。XD
另外一個好玩的研究是 Vidar Holen 研究了 Linux 核心中有多少詛咒粗口,Linux kernel swear counts。我們可以拿程式碼中的髒話平均數量當作判斷品質的一個參考值嗎? ![]()
Firefox 3 正式發行了!快去下載吧!

新版的 Firefox 速度比 Firefox 2 快上好幾倍,由於使用了新的 PGO 編譯技術以及新的 XPCOM Cycle Collector 實做,因此系統不會莫名的吃掉好幾倍的記憶體,以至於行為緩慢。同時在介面上也做了眾多的改善,包含新的「收藏庫」可以用以瀏覽歷史與書籤管理、書籤功能則大幅改善操作方式,並新增了標籤功能、新的下載介面、外掛程式介面、與安全保護機制,終端使用者在瀏覽可能有惡意軟體的頁面時,也會被警告,避免無意瀏覽或下載有病毒的網頁。
諸多的新功能不彷參考 Firefox 3 預覽 (1) 與 Firefox 3 預覽 (2)。或者參考 Mike Beltzner 的新功能簡介:
Debian 的軟體套件原始碼通常包含幾個檔案,分別是 dsc, diff.gz 與 orig.tar.gz.
.dsc 是一個文字檔,包含軟體的基本資訊、如版本、維護者資訊與原始碼檔名與驗證碼 (checksums) 資訊 。.diff.gz 是壓縮過後的差異檔,由於軟體套件都必須針對不同的套件系統進行調整,以便符合套件系統的規矩。而 Debian 的方式是保留由上游所發行的原始碼壓縮檔,也就是 .orig.tar.gz 檔案,並將所有的修改另外儲存於 .diff.gz 檔,包含 Debian 包裝軟體時特有的 debian/* 檔案。
於是,對於使用者/原開發者而言,可以清楚的分辨哪些碼是被 Debian 軟體套件維護者所修改,在除錯或維護上都可以比較清楚的區分。若想了解 Debian 包裝軟體的細節不妨參考我的 Debianziation HOWTO。
至於所有原生套件與非原生的套件的差別,則在於是否有 .diff 檔案。若你所包裝的軟體原始碼中本來就含有所有 Debian 所需要的 debian/rules, debian/* 檔案,你在產生 .deb 安裝檔時,套件包裝軟體就不會/無法生成差異檔,而只會生成 .tar.gz 檔案。
通常包裝成原生軟體套件 (Native Package) 的狀況是維護者手誤所造成,大約是忘記將原始檔名改成正確的 .orig.tar.gz 名稱。但有些時候,是軟體套件維護者刻意製成。但是除非該套件是針對 Debian 所開發,不可能被移植到其他套件系統上,否則不應該包裝成原生套件。
有些開發者原本就使用 Debian 作為開發平台,偶爾為了方便也會直接在發行的壓縮檔案中置入 debian/* 檔案。但是這是不應該的,Debian Mentors FAQ 裡面有稍加解釋,事實上在原始檔壓縮檔中放入 debian/* 檔案,很容易造成誤解與困擾,特別是需要追蹤修改紀錄的狀況。另外還有如下的原因
與 Debian Developer 討論之得。
Evince 是個好用的文件瀏覽器,速度非常的快,是我平時最常用的 PDF 瀏覽器。有時候在編輯文件就會希望可以在轉成 PDF 之後,可以直接更新 Evince 內容。上網搜尋了一下,不只我有這樣的需求,而且已經有 patch 了,這個熱騰騰的 patch 是 6/12 才更新的。
還記得我寫過一篇「來亂者,去死!!」,詳細分析過戳樂 (Troller)。這裡有一個典型的 blog, Linux Hater’s Blog,言詞辛辣、諷刺,有些論點我無法同意,有些則犀利的點出問題。
如果你對 Linux 的各方面軟體開發、應用、文化,都具備一定程度的認知。你讀起此部落格肯定就像是讀幽默短文一樣哈哈大笑 (但別過度反應了,這可以算 Slashdot 上的長篇版機車留言)。
以下幾篇是我個人覺得夠諷刺,或值得思考的議題。
如果你要當一個 Troller, 至少也試著寫些具備觀點的文章。當個直言的真小人,比言之無物的偽君子實在來著有格調多了。

#!/bin/bash
mkdir tmp
cd tmp
pkg_name=easytag-2.1.5
wget -c http://nchc.dl.sourceforge.net/sourceforge/easytag/$pkg_name.tar.bz2
tar xvf $pkg_name.tar.bz2
cd $pkg_name
sudo apt-get -y build-dep easytag
sudo apt-get -y install libid3-3.8.3-dev libogg-dev libflac-dev libflac++-dev libmp4v2-dev libmp4v2-0 libwavpack-dev gettext
sudo apt-get -y install libgmp3-dev libvorbis0a libvorbis-dev libogg0 libogg-dev
sudo apt-get -y install libfaad-dev libfaad2-0 libmp4v2-dev libfaad2-0 libmp4v2-0
sudo apt-get -y install libid3tag0 libid3tag0-dev libspeex-dev
./configure
make
sudo make install
by Cornelius (c9s) (noreply@blogger.com) at June 07, 2008 10:53 AM
[ cpuid:c9s-desktop : 19:05:43 ] $ as -gstabs -o cpuid.o cpuid.s除錯,只需要將連結完的執行檔丟給 gdb 即可:
[ cpuid:c9s-desktop : 19:05:58 ] $ ld -o cpuid cpuid.o
[ cpuid:c9s-desktop : 19:06:04 ] $ gdb cpuid這樣就進入 gdb 了。
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb)
(gdb) break *_start怎麼回事,中斷點無效了?這是 gdb 一個 Bug,他把一開始的中斷點_start忽略了。XD
Breakpoint 1 at 0x8048074: file cpuid.s, line 7.
(gdb) run
Starting program: /home/src/asm-code/cpuid/cpuid
The processor Vendor ID is 'GenuineIntel'
Program exited normally.
(gdb) quit
.globl _start接下來重新組譯後,使用 gdb 除錯:
_start:
nop
movl $0, %eax
cpuid
movl $output,%edi
movl %ebx, 28(%edi)
(gdb) break *_start+1因為 nop 只有一個 byte ,我們將中斷點設置在 _start 位址後的一個 byte ,就會停在中斷點了。
Breakpoint 1 at 0x8048075: file cpuid.s, line 8.
(gdb) run
Starting program: /home/src/asm-code/cpuid/cpuid
Breakpoint 1, _start () at cpuid.s:8
8 movl $0, %eax
Current language: auto; currently asm
| info registers | 顯示所有暫存器內容 |
| 印出特定暫存器或者變數的值 | |
| x | 印出特定記憶體位置的內容 |
x/nyz(gdb) x/42xb *_start其中 x/42xb 代表印出 _start 標籤開始之後的 42 個 Byte ,並以 16 進制印出。 print/x 代表以 16 進制印出。 print/d 以十進制,print/t 以二進制。
0x8048074 _start>: 0x90 0xb8 0x00 0x00 0x00 0x00 0x0f 0xa2
0x804807c _start+8>: 0xbf 0xac 0x90 0x04 0x08 0x89 0x5f 0x1c
0x8048084 _start+16>: 0x89 0x4f 0x24 0xb8 0x04 0x00 0x00 0x00
0x804808c _start+24>: 0xbb 0x01 0x00 0x00 0x00 0xb9 0xac 0x90
0x8048094 _start+32>: 0x04 0x08 0xba 0x2a 0x00 0x00 0x00 0xcd
0x804809c _start+40>: 0x80 0xb8
(gdb) print/x $ebx
$1 = 0x756e6547
(gdb)
by Cornelius (c9s) (noreply@blogger.com) at June 06, 2008 08:10 PM
順便提一下排名第二的音樂下載軟體 - ezPeer+。話說 ezPeer+ 其實為了 Linux 平台開了一版介面 ezPeer+ for Linux 1.0,是使用 XULRunner 與 mplayer 等軟體元件開發。
後端直接呼叫 mplayer 接取線上串流,會同時執行前端介面與後端播放軟體。偶爾會因為軟體處理不當,造成使用者按下暫停時,系統依然於背景播放音樂。稍微有點惱人的小問題。介面上也未提供進階選項,如調整快取大小等,我在 Seednet 上聽取音樂有點停頓。
此外大約是為了 mplayer 拿掉了 Windows Media DRM 功能,目前並沒有提供下載的功能,只能聽線上串流音樂,不過這應該已經可以滿足很多想在 Linux 上享受音樂的朋友。
可惜的是 ezPeer+ for Linux 目前只提供給 ASUS EeePC 的使用者使用,並未提供下載。若你購買了 EeePC,其實可以透過 dpkg-repack 重新將程式包成 .deb 檔案後丟到其他的 Debian/Ubuntu 上執行。

我說,你們這些多媒體娛樂資訊商,快照顧照顧我們卑微的 Linux/Unix 使用者吧。
上次用 Wine 1.0-rc1 測試了一下 KKBOX,由於上次測試時使用 Wine 實做的 ShDocVw 與 MsHtml 等元件。由於無法透過內嵌的網頁登入,因此大部份某些功能無法順利使用。
但你若先將 Microsoft Media Player 與 Microsoft Internet Explorer 裝進 Wine 中,就可以順利執行起 KKBOX 了!安裝過的過程十分繁複,因此我其實是透過 wine-doors 與 IEs4Linux 才安裝成功。由於 IEs4Linux 預設會安裝一個獨立的 wine 系統,並把軟體預設安裝 $HOME/.ies4linux,因此必須稍加修改 IEs4Linux,以便強迫它安裝到正確的 wine 目錄。然後再重新安裝執行一次 KKBOX 即可成功啟動啦。

使用狀況倒是沒有甚麼問題,可聽取線上串流,離線下載由於尚未購買月卡,還無法測試。目前的一點點小問題是,左邊的選單還是亂碼,一般下拉式選單倒是沒有問題。此外嵌於軟體首頁的 Flash-based MV 會有嚴重閃爍的問題。
這是在 wine 1.0-rc1 與 wine 1.0-rc2 上測試。待有善心人士整理 Step by Step HOWTO. 或者乾脆整理成單鍵安裝程式吧。
sudo apt-get install binutils./configure
make
make install.section .data其中 .data 區塊,為放置初始化資料區塊,也就是變數已經有了初始值。.bss 則為未初始化資料區塊,此區塊為非必要。.text 則為程式碼區塊。 _start 為程式一開始的進入點,在 Linking 的時候會自動找到 _start 這個標籤為進入點,若是沒有 _start 標籤的話,Linking 時會出現以下訊息:
# 已初始化的資料
.section .bss
# 未初始化的資料
.section .text
.globl _start
_start:
# 程式碼由此開始
$ ld -o test test.o
ld: warning: cannot find entry symbol _start; defaulting to xxxxxxx# cpuid.s Sample program to extract the processor Vendor ID接下來做大略的解說,為示範整個編寫程式的流程,在此不闡述太多細節。第一段
.section .data
output:
.ascii "The processor vendor id is 'xxxxxxxxxxxx''\n"
.section .text
.global _start
_start:
movl $0,%eax
cpuid
movl $output,%edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
movl $1,%eax
movl $0,%ebx
int $0x80
.section .data在資料區塊裡頭宣告一個名為 output 的字串變數。
output:
.ascii "The processor vendor id is 'xxxxxxxxxxxx''\n"
movl $0,%eax其中第一行, movl $0, %eax 將 0 移至 EAX 暫存器,執行 cpuid 時,會判斷 EAX 的內容取得相對資料。EAX 為 0 時,cpuid 是取得廠商之 ID,譬如說 Intel , Geniue 等等,cpuid 執行後,會將資料分別放入 EBX , EDX , ECX 。第 3 行,將 output 字串之起始位址存至 EDI 暫存器 ( EDI 暫存器是用來存放操作目的字串指標之暫存器 ),接著將 EBX,EDX,ECX 裡面存放之結果字串放入 EDI 暫存器指向之位址加上偏移量的位置內。
cpuid
movl $output,%edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)
movl %ebx, 28(%edi)此行代表將 %ebx 內四個 Byte 之內容搬移到 EDI 存放之位址 + 28 Bytes 之位址,其 28 剛好是 xxxxxxxxxxxx 之起始的位址。因此 28,32,36 這三行搬移指令剛好將 12 個 x 補滿。
movl $4, %eax這五行為執行系統呼叫 ( 何謂系統呼叫?可參見此 ),其中 EAX 存放系統呼叫之值,EBX 存放要寫入之檔案敘述元 (STDOUT),ECX 存放字串起始位址,EDX 存放字串的長度。其等同於 write() 系統呼叫。關於系統呼叫,可以在以下定義的檔案找到:
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
/usr/include/asm/unistd.h#define __NR_write 4movl $1,%eax這三行等同於 exit(0) 系統呼叫。傳回 0 作為程式執行結果。
movl $0,%ebx
int $0x80
$ as -o cpuid.o cpuid.s$ ld -o cpuid cpuid.o./cpuidby Cornelius (c9s) (noreply@blogger.com) at June 03, 2008 03:43 PM