最讓.NET程序員苦惱的是,辛辛苦苦寫出來的.NET程序,需要客戶機上安裝了.NET才能運行。僅為一個小小的應用程序去下載上百兆的.NET安裝包,還得把它老老實實安裝到客戶機上,并占掉數百兆磁盤空間,這無疑是一件得不償失的事情。.NET程序的這個弱點,也是影響.NET應用程序普及和價值的一個重要因素。 所謂“獨立運行”,是指.NET應用程序脫離完整的.NET運行環境,像c語言編譯的程序那樣,在操作系統上直接運行。簡單地說就是:客戶電腦無需安裝任何版本的.NET框架,你的.NET程序照樣可以在他的電腦或服務器上運行。 .NET程序獨立運行的基礎是mono運行時以及它的程序集。mono是什么呢,mono是一款開源、免費、可定制的跨平臺.NET運行環境,同時,它還包含了一系列具有重要意義的實用工具,當前最新的版本號是3.0.10,本文所采用的mono,即是這個版本號的windows版。
那么,到底怎么才能讓你的.NET程序無障礙地在沒有安裝.NET平臺的客戶機“獨立運行”呢,下面直奔主題。
一,建立跨平臺的.NET環境與編譯環境: 1、下載并安裝mono的windows版,建議將它安裝到c:/mono文件夾中。 2、安裝cygwin。 A、建議將它安裝到c:/cygwin文件夾中。 B、安裝時,請將mingw-gcc、mingw-zlib、pkg-config、libiconv這幾個組件選上,這是將.NET程序轉化為本地程序的必要的編譯環境。
二,啟動cgywin并設置環境變量: 1、點擊開始菜單或桌面上的cygwin圖標,啟動且進入cygwin環境。 2、輸入下面的命令,設置或修改必要的環境變量: export PKG_CONFIG_PATH=/cygdrive/c/mono/lib/pkgconfig export PATH=$PATH:/cygdrive/c/mono/bin
三,將你的.NET程序轉化為“獨立程序”
請注意,這是本文的關鍵所在,很多地方的操作都有別于其它網文和mono官網所介紹的操作技術。
1,復制文件。把需編譯的.NET EXE文件和對應的DLL文件復制到你在cygwin的工作文件夾中,如果你的windows用戶名是xyz,那么這個文件夾就是 c:/cygwin/home/xyz/,(這一步不是必須的,如果你不怕麻煩而愿意多打字的話)。
2,轉換與打包。通過下面的命令,將.net程序和類庫打包并得到一個c程序源碼(假設你需要轉換的.NET文件是a.exe)。 mkbundle -c -o b.c -oo b.o a.exe -z 或者: mkbundle -c -o b.c -oo b.o a.exe aa.dll c://mono//lib//mono//4.5//mscorlib.dll -z 或者: mkbundle -c -o b.c -oo b.o --dept a.exe -z
3,修改得到的c文件: 這是本文的精華所在。 為什么要修改這個c文件,很簡單: A,不希望與exe文件相關的類庫全部打包到一個文件中,否則,太浪費,而且影響啟動速度。 B,這個c文件是目標程序的關鍵文件,我希望在中間加上自己的東西,讓我的程序如虎添翼。 C,我程序要在中文、日文這樣的含有非英文字母的文件夾中運行。
3.1,需要添加和修改的內容: A,用VS或記事本打開b.c,把下面的代碼復制到main函數之前,作一個準備。
#include <dir.h> #include "/usr/include/iconv.h" int gbk_utf8(char *inbuf,int inlen,char *outbuf,int outlen){ iconv_t cd; char **pin = &inbuf; char **pout = &outbuf; cd = iconv_open("utf-8","gbk"); if (cd == 0) return -1; memset(outbuf, 0, outlen); if (iconv(cd, pin, &inlen, pout, &outlen) == -1) return -1; iconv_close(cd); return 0; }
B、在main函數中,找到下面這兩行并注釋或刪除掉: if (config_dir != NULL && getenv ("MONO_CFG_DIR") == NULL) mono_set_dirs (getenv ("MONO_PATH"), config_dir); C、接著,就在這行下邊,即“mono_mkbundle_init”一行之前,輸入下邊的代碼:
const char* lib = "//lib"; const char* etc = "//etc";
char p[strlen(argv[0])]; ws l = strlen(p) + strlen(lib); char s_lib[l]; wsprintf(s_lib, "%s%s", p, lib); l = strlen(s_lib); char* s_lib_utf8 = (char*)malloc(l*2); memset(s_lib_utf8, 0, l*2); gbk_utf8(s_lib, l, s_lib_utf8, l*2); l = strlen(p) + strlen(etc); char s_etc[l]; wsprintf(s_etc, "%s%s", p, etc); l = strlen(s_etc); char* s_etc_utf8 = (char*)malloc(l*2); memset(s_etc_utf8, 0, l*2); gbk_utf8(s_etc, l, s_etc_utf8, l*2); mono_set_dirs(s_lib_utf8, s_etc_utf8); 接著在mono_mkbundle_init一行之后加入一行: chdir("c://"); 最后,找到下面三行 #ifdef _WIN32 #include <windows.h> #endif 并在“#endif”后加入一行: #undef _WIN32 改完了,存盤退出。 (有人會說“輸入這么多,為什么不寫個函數以方便我將來復用?”,我說,這不是我的事。) 3.2,編譯: 用下面這個命令生成你的目標文件“b.exe”。 gcc -mno-cygwin -o b.exe -Wall b.c `pkg-config --cflags --libs mono-2|dos2unix` b.o -lz -liconv 四,程序、類庫、配置文件的組織: 這一步,是為你的程序安一個家,讓它真的能跑起來。 1,在某個盤,比如D盤,建個文件夾,比如是“myapp” 把剛才編譯得到的目標文件b.exe復制到D:/myapp文件夾中。 同時把c:/mono/bin/文件夾中的mono-2.0.dll、zlib1.dll、iconv.dll復制到d:/myapp中。 2,組織類庫 在“d:/myapp”文件夾中,建lib和etc兩個子目錄。 在lib文件夾中,建名叫“mono”的文件夾。 在d:/myapp/lib/mono文件夾中,根據你.NET程序集版本號建一個文件夾,名字就是版本號,比如“4.5”,當然,你也可以把2.0、4.0也建好。 如果你沒有將mscorlib.dll打包到.EXE中,請將c:/mono/lib/mono/4.5/mscorlib.dll,復制到 d:/myapp/lib/mono/4.5這個文件夾中。 在d:/myall/lib/mono文件夾中,建一個名為gac的文件夾,這個文件夾是用來放你的程序需要的mono版.NET類庫的。 放些什么?放你的exe、dll文件中引用到的那些程序集的庫文件(如果你已經把這些文件打包到了.exe中,那么你就不需要放任何文件)。 比如,你引用了System名字空間,那么,將c:/mono/lib/mono/gac文件夾下的System文件夾復制到D:/myapp/lib/mono/gac中就行了。 3,組織配置文件 把c:/mono/etc文件夾中的“mono”文件夾復制到d:/myapp/etc文件夾中。 用寫字版打開config文件,找到并刪除下列三行: <dllmap dll="gdiplus" target="/tmp/install/lib/libgdiplus.so" /> <dllmap dll="gdiplus.dll" target="/tmp/install/lib/libgdiplus.so" /> <dllmap dll="gtkhtml-3.0" target="libgtkhtml-3.8-15.dll"/> 可能有讀者會說,對本文某些地方不太理解或者有異議,那么,我歡迎討論。你可以在這些地方與我取得聯系:群號為103810355的QQ群里或者網址為www.linuxdot.net的網站上。 轉自:https://www.linuxdot.net/bbsfile-3354
新聞熱點
疑難解答