MonoDevelop on Windows

Cygwin 要裝些什麼可以參考這篇:CodeProject 上的文章:Building Mono on Windows: the final battle.
不過 Mono 可以直接用官方提供的,不需要自己 build。

首先進 Cygwin shell,設定 PATH 與 PKG_CONFIG_PATH,讓 Cygwin 能找到 Mono

export PATH=/cygdrive/c/Progra~1/Mono-1.9.1/bin:$PATH
export PKG_CONFIG_PATH=/usr/lib/pkgconfig/:/usr/local/lib/pkgconfig/:/cygdrive/c/Progra~1/Mono-1.9.1/lib/pkgconfig

再把 Mono 目錄下的 pkg-config 更名,因為這個版本的 pkg-config 太舊。

接著要 build Mono-Addin-0.3.1,這簡單,很快就 build 過了。(./configure && make && make install )

再來就麻煩了,1.0 無法 build,它會要求裝 monodoc, gtksourceview-sharp-2.0.0;monodoc 其實已經有了,但卻沒有給 pkg-config 用的 .pc 檔,所以補上一個自製的 monodoc.pc。接著,gtksourceview-sharp 則需要裝 gnome-sharp、gtk-sharp 與實體的 gtk+、gnome 函式庫,所以我放棄 1.0,改用 1.9。1.9 是比較順利了,順利的原因是,MonoDevelop team 本來就有打算要出 Windows 版本,只是能不能用還在未知之數。

在 build 的過程中,發現 gmcs 無法載入 Mono.Addin.Setup assembly 的問題,這是由於 gacutil 跟 Cygwin 相處的不太好,gacutil 收的 path separator 是反斜線 ‘\’,但 Cygwin 只能給 ‘/’,所以安裝 Mono.Addin 時,並沒有依照 Makefile 的指定,將 .dll 註冊到 gac 所以在編譯(make)、安裝(make install)後,你必須要手動將 .dll 註冊到 gac 裡:

cd bin;find . -name '*.dll' -exec gacutil -i {} \;

接著,MonoDevelop 就 build 成功了。不過,MonoDevelop 還是不能執行 🙁 MonoDevelop.Core.Gui.Services 這邊會丟出例外。

Banshee 的 PlayQueue

1.0 版以後多了一個新功能-PlayQueue,我很喜歡這功能,因為你可以一直把想聽的歌丟進去,Banshee會播放這個Queue裡的歌直到Queue沒有歌為止。
本來以為這是內建的功能,後來看了之後,才發現這是一個 Extension。
它主要繼承 PlaylistSource、IBasicPlaybackController,把自己實作成一個 Playlist 來源,在Banshee播放時,實際上來源已經不是原來的 Music library 了。
所以如果要取得這個 Source,應該是利用 ServiceManager.SourceManager 來取得,要加入 PlayQueue 的話,則是使用 AddSelectedTracks()。
目前我還沒研究出如何在 Extension 裡面呼叫其他 Extension 的方法…

.NET framework essential Chapter 5

這一章主要講 ADO.Net。
DataSet、DataTable、DataRow、DataRelation… 這一組類別完全是一個抽離實體層的類別,所以有 DataAdapter 這一組與 Connection、Command、DataReader …等類別溝通。

  • GetChildRows[] 可以依據 Relationship 來取得子Table與父Table相關的資料列。
  • 一個 DataAdapter 基本上對應一個 DataTable,但他不管所在的 DataSet,所以你可以都塞到同一個 DataSet 裡面去。另外 DataAdapter 不處理 Relationship,所以用 Fill 取得資料並放到 DataSet 裡的 DataTable 之後,得自己加上 Relationship。
  • 由於 DataSet 與 XML 有一定的關係,第五章最後簡單地介紹了 XML 的相關函數。

.NET framework essential Chapter 4

Chapter 3 主要是講各種語言的介紹與互相操作,大致都已經知道,沒什麼要紀錄的。
接著記 Chapter 4 的一些東西。

  • 只要在 .config 裡面使用 bindingRedirect,就可以重新導向相依的assembly到新版本的assembly。.config 裡的 attribute:runtime / assemblyBinding / dependentAssembly
  • Remoting object 的程式真的出乎意料地簡單,以前從沒研究過,有機會來試試效能,看看傳一堆物件或是 Dataset 的效能如何。
  • 有一個 Attribute 的簡單範例…
  • 支援 Transaction 的要件:
    1. 繼承 ServicedComponent
    2. 使用正確的 Transaction attribute

    接著就可用 System.EnterpriseServices.ContextUtil。此外最好也指定 ApplicationName、ApplicationActivation 等組件attribute。.NET 會在編譯時自動把組件加入 COM+ Service 裡,無須自己動手註冊。這邊還有 Object pooling、Role base、Message Queuing 的例子,很淺顯易懂。這部份在 Mono 裡都沒有被實作出來,主要是因為 COM+ 在 Linux 下沒有替代品的關係。

.NET essential 第二章 CLR 筆記

主要是紀錄以前不知道或是看過沒深入了解的一些東西:

  1. Managed C++ 編譯出來的執行檔無法用mono執行,可能是因為 Native code 跟 IL code 放到一起的關係。
  2. 從 stack-based 的 value type 轉成 heap-based 的 reference type 的過程稱作 boxing,反之稱作 unboxing。
    int i=1;
    object obj = i; // boxing
    int j = (int)obj; // unboxing
    
  3. 為了要讓各種語言能在 CLR 上執行,有 Common Language Specification 的 ECMA 標準 – Standard ECMA-335
  4. NGen 可以預先將 IL code 轉為 Native executable code,省掉 JIT compiler 的工作(pre-JITting),因此可以加速。mono裡似乎是用
    mono -O=all --aot your-assembly

    來替代的樣子。

ILMerge

這工具可以讓你把 .Net 不同語言編譯出來的 Assembly (組件)合併在一起。
官方網址:ILMerge
安裝以後,用法很簡單:

"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:library /out:[輸出檔名] /lib:[Assembly搜索路徑] [要合併的 Assembly 1] [要合併的 Assembly 2] ...

只想給客戶一個可執行檔,不想給一堆其他組件的時候,這樣作也行:

"c:\Program Files\Microsoft\ILMerge\ILMerge.exe" /t:[exe或winexe] /out:[輸出檔名] /lib:[Assembly搜索路徑] [執行檔] [要合併的 Assembly 1] [要合併的 Assembly 2] ...

對,合併以後,檔案絕對變大,然後千萬不要忘記了,要測試。另外,ILMerge 文件(ILMerge.doc)裡面有些限制以及問題,甚至是用法都有詳細描述,要記得閱讀…

包在 Mono Windows 版裡的東西

再隨手記下一些:

  • VisualPng.exe,可以看 png 的軟體
  • webshot.bat,可以抓取網頁當作圖片的 console 程式,不過在 Windows 跑不起來,會丟出需要 gtkembedmoz 的錯誤訊息
  • ipy、ipy2,是的,有把 IronPython 包進來,不過互動模式怪怪的。
  • ikvm,這是之前就有的,詳情請參考ikvm官方網頁說明,是可以讓 Java 程式在 mono 上執行的程式(甚至是互轉)
  • jay,類似 yacc 的 parser,是的,c# compiler 就是以此為基礎
  • xulrunner,好像是這一版才加入的,印象中之前並沒有,用途不明…
  • cilc,用途不明,help 是寫:Mono CIL-to-C binding generator
  • monop、monop2,把類別的公開介面列出來的 console 程式
  • monolinker,可以只把需要的類別抽取出來或是把一些程式安插進去的程式。

pythonw 與 monow

Windows 版的 Python 在安裝以後,你會發現目錄下除了 python.exe 以外,還有一個 pythonw.exe,這是做什麼的呢?
簡單的說,python.exe 是一個 console 程式,執行 Python 程式的時候,在建立捷徑的時候,你會這樣寫:python your_app.py,但是執行時會出現一個黑色的 console 視窗。
pythonw.exe 作用則在於,不出現那個黑色的 console 視窗。
好,那 monow 的作用為何,你應該也能了解了吧~
特別指出這個的原因,是因為我這幾天在看 Mono 裝了什麼東西時發現的,其實我陸續還有看到一些東西,慢慢再介紹。

亂碼 1/2

此亂碼非彼亂馬啊~
家裏 Server 的 Mono 升級到 1.9 以後,ASP.Net 網頁裡的中文突然都變成了亂碼,可是我什麼都沒改啊~
由於個人因素 (就是懶啦),一直都沒去管,今天看開了,決定找出真兇…
首先試著直接跑 xsp2 之後,用 Browser 去看結果,正常,沒有亂碼。很好,那麼應該是 mod_mono 跟 Apache 的問題囉~
再看看有亂碼的網頁,看看送出來的網頁與 Response header 是否正確,送出來網頁的中文都變成了 ?,可是從資料庫撈出來的字卻又都沒問題,可以正常顯示,網頁的 Response header 也沒問題。很好,那真的是 mod_mono 與 Apache 的問題了。
仔細看了 mod_mono 的設定,唯一我覺得有問題的,就是 MonoSetEnv,可是我確實地已經設定了 MonoSetEnv “LANG=en_US.UTF-8″,應該不會有問題才對。
好,那麼就寫個簡單的網頁把所有環境變數列出來看看,果不其然,LANG = C,這表示LANG並沒有被設定,那麼會出現亂碼也是很正常的了。LANG 對 Linux 來說,是很重要的環境變數,沒有這個,很多應用程式將無法判斷目前所在的語系與編碼。
那麼是 mod_mono 問題囉?可是看過 source code 之後,發現沒有特別針對 MonoSetEnv 做什麼修正,再回頭看看列出來的環境變數,我發現我在設定檔裡面設定的 TEMP 環境變數有生效,那麼?!
再仔細看一次 mod_mono 的說明,原來如果你要設定多個環境變數時,要加上 ‘;’,所以在我改寫為 MonoSetEnv “LANG=en_US.UTF-8;TEMP=/var/tmp”,重新啟動之後,問題就解決了。
p.s. 那…為啥以前沒錯?! 我想可能是 Apache 的 apr 行為有改變吧~

c# Iterator

這裡沒有要解說什麼,下面這段程式是從 c# specification 來的,而程式本來是不能執行的,是的,範例有問題。問題點:

  1. 原本的 IEnumerator<T> GetEnumerator() 應該加上 IEnumerable<T>.,成為 IEnumerator<T> IEnumerable<T>.GetEnumerator()
  2. 少繼承了 IEnumerable 介面並實做 IEnumerable.GetEnumerator()

我查了很久,才找到問題點,另外還參考 Bertrand Le Roy 的文章,精簡了 IEnumerable.GetEnumerator() 的代碼。

Iterator 就類似 Python/Boo Generator 的概念,目前我認知到最大的好處是,不一定要讓迴圈全部跑完,就可以先傳回一個值去處理。

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
public class Tree<T>: IEnumerable<T>, IEnumerable
{
T value;
Tree<T> left;
Tree<T> right;
public Tree(T value, Tree<T> left, Tree<T> right) {
this.value = value;
this.left = left;
this.right = right;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
if (left != null) {
foreach (T x in left)
yield return x;
}
yield return value;
if (right != null) {
foreach (T x in right)
yield return x;
}
}
// Yield and generics rock! - Tales from the Evil Empire <http://weblogs.asp.net/bleroy/archive/2004/08/31/223531.aspx>
IEnumerator IEnumerable.GetEnumerator() {
return (IEnumerator)(((IEnumerable<T>)this).GetEnumerator());
}
}
public class Program
{
static Tree<T> MakeTree<T>(T[] items, int left, int right) {
if (left > right)
return null;
int i = (left + right) / 2;
return new Tree<T>(items[i],
MakeTree(items, left, i - 1),
MakeTree(items, i + 1, right));
}
static Tree<T> MakeTree<T>(params T[] items) {
return MakeTree(items, 0, items.Length - 1);
}
// The output of the program is:
// 1 2 3 4 5 6 7 8 9
// Mon Tue Wed Thu Fri Sat Sun
public static void Main() {
Tree<int> ints = MakeTree(1, 2, 3, 4, 5, 6, 7, 8, 9);
foreach (int i in ints)
Console.Write("{0} ", i);
Console.WriteLine();
Tree<string> strings = MakeTree(
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
foreach (string s in strings)
Console.Write("{0} ", s);
Console.WriteLine();
Console.ReadLine();
}
}

額外的收穫是,發現 mono gmcs 編譯出來的代碼比 Microsoft csc 編譯出來的代碼要多出約四百多個 bytes。