這個真正的控制臺程序來自corefxlab,名叫CoreClrHelloWorld,是一個跨平臺的.NET控制臺演示程序,可以顯示微軟、Linux、蘋果的logo。
CoreClrHelloWorld代碼如下(代碼中省略了拼接logo的字符串,完整代碼見這里):

using System; internal class Program { private static void Main(string[] args) { if (args.Length == 1 && args[0] == "linux") { DrawLinux(); } else if (args.Length == 1 && args[0] == "mac") { DrawMac(); } else { DrawWindows(); } Console.WriteLine(); Console.WriteLine("Press ENTER to exit ..."); Console.ReadLine(); } private static void DrawWindows() { Console.WriteLine("Hello, Windows..."); const int squareSize = 20; var colors = new[] { ConsoleColor.Red, ConsoleColor.Green, ConsoleColor.Blue, ConsoleColor.Yellow }; for (int row = 0; row < 2; row++) { for (int i = 0; i < squareSize / 2; i++) { Console.WriteLine(); Console.Write(" "); for (int col = 0; col < 2; col++) { Console.BackgroundColor = colors[row * 2 + col]; Console.ForegroundColor = colors[row * 2 + col]; for (int j = 0; j < squareSize; j++) Console.Write('@'); Console.ResetColor(); } } } Console.WriteLine(); } private static void DrawLinux() { Console.WriteLine("Hello, Linux..."); const string Penguin = @"..."; foreach (char c in Penguin) { if (c == '\n') { Console.ResetColor(); Console.WriteLine(); } else { ConsoleColor cc = c == '*' ? ConsoleColor.Blue : c == '@' ? ConsoleColor.Black : c == '-' ? ConsoleColor.Yellow : ConsoleColor.White; Console.BackgroundColor = cc; Console.ForegroundColor = cc; Console.Write(" "); } } Console.ResetColor(); Console.WriteLine(); } private static void DrawMac() { Console.WriteLine("Hello, Mac..."); const string Apple = @"..."; Console.ForegroundColor = ConsoleColor.White; Console.Write(Apple); Console.ResetColor(); Console.WriteLine(); } }
在之前的博文在Mac OS X上用自己編譯出的CoreCLR運行.NET程序中,當時的控制臺演示程序只是用到了mscorlib.dll,并沒有用到.NET Core Framework(CoreFx)中的程序集。而CoreClrHelloWorld用到了CoreFx中的System.Console.dll,所以如果將CoreClrHelloWorld在Mac上跑起來,就可以進一步體驗跨平臺的.NET Core。
在Mac上折騰CoreClrHelloWorld的過程中,主要遇到了3個問題,問題出在System.Console中的ConsolePal.Unix.cs代碼對Mac OS X的支持上:
1)Interop.libc.open64需要改為Interop.libc.open,open64不是POSIX標準中定義的。(詳見corefx#715)
2)在Mac OS X中讀取terminfo的問題:在Linux中,文件路徑是/lib/terminfo/x/xterm-256color;在Mac中是/usr/share/terminfo/78/xterm-256color。78是x的16進制ASCII碼,而ConsolePal.Unix.cs中只根據x去讀就讀取不到。(詳見corefx#723)
3)Interop.libc.lseek64需要改為Interop.libc.lseek,原因與問題1一樣。(詳見corefx#733)
當這3個問題被修復并合并到corefx的主分支之后,就可以在Mac上成功運行CoreClrHelloWorld了。(詳見corefx/pull#716,#725,#736)
下面分享一下詳細的操作步驟,操作有些繁瑣。
如果你嫌麻煩,可以從GitHub簽出已經配置好的CoreClrHelloWorld,然后直接運行:
git clone https://github.com/cnblogs-dudu/CoreClrHelloWorld.git
cd CoreClrHelloWorld
runtime_mac/corerun app/HelloWorld.exe mac
最好自己一步一步操作一下,這樣會有不一樣的體會。具體操作步驟如下:
(一)
【準備CoreClrHelloWorld文件】
1)創建CoreClrHelloWorld文件夾:mkdir CoreClrHelloWorld;cd $_
2)創建app文件夾:mkdir app;cd $_
3)下載CoreClrHelloWorld.cs至app文件夾:
curl -O https://raw.githubusercontent.com/dotnet/corefxlab/master/demos/CoreClrConsoleApplications/HelloWorld/HelloWorld.cs
(二)
【準備CoreCLR】
運行CoreCLR需要三大組件:corerun, libcoreclr.dylib, mscorlib.dll。
1)git簽出最新版的coreclr代碼庫:git clone https://github.com/dotnet/coreclr.git
2)編譯coreclr:./build.sh
3)編譯成功之后,在CoreClrHelloWorld中創建runtime_mac文件夾:mkdir ../CoreClrHelloWorld/runtime_mac
4) 將編譯出來的corerun與libcoreclr.dylib復制到CoreClrHelloWorld/runtime_mac文件夾
cp binaries/Product/amd64/debug/corerun binaries/Product/amd64/debug/libcoreclr.dylib ../CoreClrHelloWorld/runtime_mac
5) 下載之前博文中用到的mscorlib.dll文件至CoreClrHelloWorld/runtime_mac(該文件由@kangaroo提供,在運行CoreClrHelloWorld時使用,詳見這里)
cd ../CoreClrHelloWorld/runtime_mac curl http://files.cnblogs.com/files/dudu/mscorlib.dll.zip | tar -xf- -C . rm -r __MACOSX
這2步之后CoreClrHelloWorld的文件夾結構如下:
(三)
【準備編譯時需要引用的程序集】
1)在CoreClrHelloWorld中創建compile_r_lib文件夾:mkdir compile_r_lib; cd $_
2)下載nuget.exe:curl -L -O https://nuget.org/nuget.exe
3)安裝nuget中的System.Console包包:
mono nuget.exe install System.Console -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease
4)將子文件夾中的System.Console.dll與System.Runtime.dll文件復制到compile_r_lib文件夾:
find . -wholename '*/aspnetcore50/System.Console.dll' -exec cp {} \. \; find . -wholename '*/aspnetcore50/System.Runtime.dll' -exec cp {} \. \;
5)下載編譯時要引用的mscorlib.dll至compile_r_lib文件夾(該文件也由@kangaroo提供,在編譯HelloWorld.cs時使用,詳見這里):
curl http://files.cnblogs.com/files/dudu/mscorlib_contract.dll.zip | tar -xf- -C . rm -r __MACOSX
(四)
【編譯HelloWorld.cs文件】
用mono的mcs命令進行編譯。
1)回到CoreClrHelloWorld文件夾:cd ..
2)運行編譯命令:
mcs -nostdlib -r:compile_r_lib/mscorlib.dll -r:compile_r_lib/System.Runtime.dll -r:compile_r_lib/System.Console.dll app/HelloWorld.cs
如果你不想用mono,也可以將項目復制到Windows中用csc命令進行編譯:
csc /nostdlib /r:compile_r_lib/mscorlib.dll /r:compile_r_lib/System.Runtime.dll /r:compile_r_lib/System.Console.dll app/HelloWorld.cs
編譯成功后,就會在app文件夾中看到HelloWorld.exe文件。
(五)
【準備運行HelloWorld.exe所需的程序集】
1)由于System.Console還依賴一些其他程序集,都得要通過nuget下載下來,下載到compile_r_lib文件夾中。
mono nuget.exe install System.Diagnostics.Contracts -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Diagnostics.Debug -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Diagnostics.Tools -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Globalization -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.IO.FileSystem.Primitives -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Reflection -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Resources.ResourceManager -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Runtime.Extensions -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Runtime.Handles -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Runtime.InteropServices -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Text.Encoding.Extensions -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease mono nuget.exe install System.Threading -Source https://www.myget.org/F/dotnet-corefx/ -Prerelease
2)將compile_r_lib中所有通過nuget下載的包包的aspnetcore50文件夾中的程序集復制到runtime_mac文件夾中。
find . -wholename '*/aspnetcore50/*' -exec cp -n {} ../runtime_mac \;
3)刪除compile_r_lib中所有的nuget包包文件夾
find . -type d -exec rm -rf {} \;
(注:感謝@問天何必提供了更簡單的刪除命令:rm -r -- */ )
于是最新的CoreClrHelloWorld文件夾結構如下:
大功告成?沒有,但即將告成。現在如果運行程序,會出現下面的錯誤:
Unable to continue due to missing library.
當前的System.Console.dll是從nuget上取下來的,并不支持Mac OS X。我們需要從corefx中自己編譯出System.Console.dll,這就是接下來的一項重要工作。
(六)
【編譯System.Console】
這一步操作要在Windows上進行。
1)簽出corefx的代碼庫:git clone https://github.com/dotnet/corefx.git
2)打開Visual Stuiod的命令行(為了能運行msbuild命令)
3)進入corefx所在的文件夾,運行msbuild命令:
msbuild src\System.Console\src\System.Console.csproj /p:OS=Unix;DefineConstants=TRACE /t:clean,build
(注:一定要加上DefineConstants=TRACE,這樣在debug模式下編譯時會去除代碼中的Debug.Assert。因為Debug.Assert在運行時會引發CoreCLR出現"UNIXTODO: Implement string loading from resources"錯誤)
4)編譯成功之后,將Windows中的corefx\bin\Debug\System.Console\System.Console.dll文件復制到Mac的Coreclrhelloworld\runtime_mac文件夾中,替換已有的System.Console.dll。
(七)
【用CoreCLR運行HelloWorld.exe】
回到Mac中,進入CoreClrHelloWorld文件夾,運行如下命令:
runtime_mac/corerun app/HelloWorld.exe mac
激動人心的時刻到來了!運果結果如下:
接著運行命令 runtime_mac/corerun app/HelloWorld.exe linux :
企鵝只出來了上半身,這地方有點問題,暫且不管了。(這個問題后來被解決了,詳見corefx#761)
再接著運行命令 runtime_mac/corerun app/HelloWorld.exe windows :
搞定!Mac.NET之路正一步一步向前邁進。
文章列表