2011年12月31日 星期六

阿班私房菜- 初探 Networking debug Logging (網路偵錯日誌)

tcpdump-with-cap

(註: 筆者愛用 nc(netcat) + tcpdump 來做網路實驗,上圖即其結果。 )

記得許久前,某人問我一個問題,有比較好的遠端偵錯的方法嗎?

首先,我先定義所謂"遠端偵錯":
  • 無法利用即時偵錯
    • 你的程式可能在數百公里外執行。簡言之,你沒辦法到現場去查臭蟲。
    • 24X7伺服端程式,你不能停止它來使用單步偵錯。
筆者先談談針對網路相關問題偵錯心得:

排除法:先簡化錯誤發生的因素。

案例:某公司開發用伺服器上的網站,使用手機(Android Phone)或較慢的機器(如:Eeepc),時常發生連線逾時的情形;但手機連線至他站均無問題。
  • 先檢查,區網內的硬體是否有問題?(無線Access Point (AP)及Router 檢查,甚至網路線更換,無改善。)
  • 再查,AP的DNS是否有問題。(無發現)
  • 查看google 大神,是否Eeepc 網路卡有相容性問題。(無發現)
  • 拿出無敵大絕招,使用擷取網路封包方法。(注意:要擷取封包時,請同時抓取,Server 及 Client 端。)
    • Server 遠端使用tcpdump 擷取封包並儲存為Wireshark 可開啟的檔案.cap
    • Client 端使用Wireshark來擷取封包。
    • 在Client 重現連線網路問題。
    • 比對封包 (其中發現Server端收到3個SYN 封包,卻無回應到client 端)
    • 範圍縮小至Server端
    • 利netstat –na | grep TIME_WAIT‘ , 發現TCP TIME_WAIT 很快被系統移除。
小結:

  到此階段,筆者有很高的把握,應該是系統網路優化設定所造成。

再和朋友試一下,網路相關設定才發現與tcp_tw_recycle有關;關閉後一切正常。

$ grep recycle /etc/sysctl.conf
net.ipv4.tcp_tw_recycle=1   --> net.ipv4.tcp_tw_recycle=0


結論:

對於網路程式的偵錯而言,看懂封包的協定是十分必要的,
另外在撰寫網路相關的程式,若能瞭解所使用標準協定(如:TCP TimeWait RFC793, HTTP RFC2616),將有莫大的幫助,以避免所開發程式與其它第三方程式發生不相容情事。

(有任何誤謬,請不吝指正。)


2011年12月30日 星期五

阿班私房菜-Design Pattern(DP)初探使用Python (1)


Design Patterns: Elements of Reusable Object-Oriented Software

最近使用Python 寫程式,心血來潮,使用 (DP) 套用看看。
以 Factory worker 為例。
首先建立一個物件Worker 包含姓名、屬性等等。
class Worker:
    def __init__(self, name=None):
        self.name = capfirst(name) if name else "The worker"
    def getName(self):
        return self.name
    def attrib(self):        return "Worker"
    def lookandfeel(self):
        print "%s is a %s" % (self.name, self.attrib())

Designer與Engineer繼承它,並覆寫attrib() Method。
class Designer(Worker):
    def attrib(self):        return "Designer"
class Engineer(Worker):
    def attrib(self):        return "Engineer"

當使用各自物件來建立,並執行lookandfeel() 時,會呼叫各自的attrib method。
以下使用 factory pattern 來實作僱用workers 的容器物件。
# factory pattern
class Factory:
    type_designer = 1
    type_engineer = 2
    def __init__(self):
        self.workers = []
    def employ(self, worker_type, name=None):
        if worker_type == Factory.type_designer:
            self.workers.append(Designer(name))
        elif worker_type == Factory.type_engineer:
            self.workers.append(Engineer(name))
    def workerCount(self):
        return len(self.workers)
    def browse(self):
        for a in self.workers:
            a.lookandfeel()
z = Factory()
z.employ(Factory.type_designer)
z.employ(Factory.type_designer, 'bill')
z.employ(Factory.type_engineer, 'sue')
z.browse()

執行結果:
$ python factory_dp1.py
The worker is a Designer
Bill is a Designer
Sue is a Engineer

承上篇重構一文:我們來重構一下它,並加入singleton pattern(利用@staticmethod 來實作)。
class Factory:
    # class static variable
    type_designer = "1"
    type_engineer = "2"
    _Factoryself = None
    _factorydict = {
           type_designer: Designer,
           type_engineer: Engineer,
        }
    def __init__(self):
        self.workers = []

    @staticmethod
    def singleton():
        if Factory._Factoryself == None:
            Factory._Factoryself = Factory()
        return Factory._Factoryself



    def employ(self, worker_type, name=None):
        caller = Factory._factorydict.get(worker_type)
        if caller:
            self.workers.append(caller(name))
        return None



    def workerCount(self):
        return len(self.workers)

    def browse(self):
        i = 0
        for a in self.workers:
            print " - Worker[%s]:%s" % (i, a.getLookandfeel())
            i+=1

def main():
    f = Factory.singleton()
    f2 = Factory.singleton()
    if f == f2:
        print "* Singleton pattern of Factory"



    print "* Factory pattern to employ"
    f.employ(Factory.type_designer)
    f.employ(Factory.type_designer, 'Bill')
    f.employ(Factory.type_engineer, 'Sue')
    print "* Factory pattern to browse"
    f.browse()
    print "* The factory has %s workers." % f.workerCount()

if __name__ == "__main__":
    main()

小結

使用python 來寫DP程式,功能強大,自由度高;
但這意味,寫其程式時,要有其紀律,遵守一定規範(coding convention)來寫;
不然程式會變得非常難讀及維護。 最近上列範例程式均可在github-class_dp中找到。
上述範例還可進一步,重構或修改為工廠人員管理系統的雛形,留待有興趣的讀者們來添加!

2011年11月30日 星期三

阿班私房菜-重構(Refactoring)的小技巧(1)


最近在看一本書"The Pragmatic Programmer",裡有不少與重構相關的範例,值得參考,有與趣人可以買來看看。因此書,筆者心血來潮,分享一下自己的開發經驗。


在專案開發程式的過程,常會因時間壓力或市場考量,不得不加入很多非計畫中的程式碼。
開發時間越久,就漸漸難以維護,增加新功能更為秏時;當人力不足以達成出貨時程,便開始增加人力,最後日積月累,專案程式變成一個大怪物;直至某一日砍掉重練。


而筆者近年來,使用重構方法,使得自己不用一直為解專案bug而加班。

重構(Refactoring) 英文是一個現在進行式,表示這個動作需要一直不斷發生。


其中,"重構"的最重要的基石就是自動化測試程式,如每當重構程式碼中重覆的部分時,執行一下自動化測試程式,便可很快的確認程式修改後的正確性。

接下來我們來看一些筆者常用的小技巧,以下範例使用Python語言。

def show_animal_info0(animal):
    if animal == 'dog':
        print("The dog has four legs")
    elif animal == 'chick':
        print("The chick has two legs")
    else:
        print("There is an unknown animal")
show_animal_info0("dog")
show_animal_info0("chick")
show_animal_info0("cat")


重構if-else

通常if-else會越加越長,慢慢變得難以除錯。
animal_info_dict = {
        "dog":   "four legs",
        "chick": "two legs"
        }
def show_animal_info1(animal):
    try:
        info = animal_info_dict[animal]
        print("The %s has %s." % (animal, info))
    except:
        print("There is unknown animal")
用dict結構表格取代if-else, 也可用來取代switch


重構重覆呼叫函式

這種函式大部分由copy and paste而來。
show_animal_info0("dog")
show_animal_info0("chick")
show_animal_info0("cat")
def main():
    animals = ["dog", "chick", "cat"]
    for name in animals:
        show_animal_info1(name)
if __name__== "__main__":
    main()

重構屬性
紅色legs部分也是重覆程式碼的狀況之一
animal_info_dict = {
        "dog":   "four legs",
        "chick": "two legs"
        }
def show_animal_info1(animal):
    try:
        info = animal_info_dict[animal]
        print("The %s has %s." % (animal, info))
    except:
        print("There is unknown animal")
animal_info_dict = {
        "dog":   {"leg": "four"},
        "chick": {"leg": "two"},
        "cat":   {"leg": "four"}
        }
def show_animal_info1(animal):
    try:
        info = animal_info_dict[animal]
        legs = info['leg']
        print("The %s has %s legs." % (animal, legs))
    except:
        print("There is unknown animal.")


自動化測試程式

要進行自動化測試,以本範例為例:

1. 將邏輯與資料顯示動作分離

def show_animal_info1(animal):
    try:
        info = animal_info_dict[animal]
        legs = info['leg']
        print("The %s has %s legs." % (animal, legs))
    except:
        print("There is unknown animal.")
def get_animal_info1(animal):
    try:
        info = animal_info_dict[animal]
        legs = info['leg']
        msg = "The %s has %s legs." % (animal, legs)
    except:
        msg = "There is unknown animal."
    return msg

2. 比對預期函式回傳值結果

使用pyunit 來實作自動測試
import unittest
from code_for_automation import *
class DefaultTestCase(unittest.TestCase):
    def testTestDog(self):
        sample="The dog has four legs."
        msg = get_animal_info1('dog')
        assert msg == sample , 'test dog message'
    def testTestChick(self):
        sample="The chick has two legs."
        msg = get_animal_info1('chick')
        assert msg == sample , 'test chick message'
    def testTestCat(self):
        sample="The cat has four legs."
        msg = get_animal_info1('cat')
        assert msg == sample , 'test cat message'
if __name__ == '__main__':
    myTestSuite = unittest.makeSuite(DefaultTestCase,'test')
    runner = unittest.TextTestRunner()
    runner.run(myTestSuite)

3. 統計測試結果
$ python 05_automation.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
以上範例程式均可由tip1下載

結論

當有了自動化測試程式之後,可提高自行重構的信心,又不用花費手動一個個輸入測試的時間。
本文雖以python為例,但觀念是相通的,其他語言也有其自動測試函式庫可供使用,歡迎不吝指教。


django i18n 實戰 (二)


續上篇django i18n 實戰,筆者作了一些小實驗,以方便中文翻譯的進行。

整段文章中文化


在前篇提到的使用django.po 來編修翻譯的方法,在此處便不太適用。
因為這類文字時常修修補補,非常不易維護。
目前使用的解決方法,使用不同locale目錄來放置不同語言版本template。
en test.html
test2.html
zh-tw test.html
test2.html

取得目錄及template名稱
from django.utils import translation
def getLocaleResourcePathName(templateName):
    cur_language = None
    try:
        cur_language = translation.get_language()
    except:
        logger.exception('getLocaleResourcePath')
    if cur_language == 'zh-tw':
        return "%s/%s" % (cur_language, templateName)
    return “en/%s”  % templateName
其中translate.get_language() ,傳會目前要求取用此頁瀏灠器所使用的語系。


在javascript中需翻譯的文字

解法1: 為將瀏灠器目前所使用的語系,存入cookie中,以便javascript實作中文化。
def setLangCookie(request):
    params = {}
    c = Context(params)
    t = loader.get_template(pageForJS)
    response = HttpResponse(t.render( c ))
    try:
        cur_language = translation.get_language()
        response.set_cookie('lang', cur_language)
    except:
        logger.exception('set_cookie')
    return response

解法2: 同上一解法為將所需要翻譯文字集中至同一檔案,依瀏灠器目前所使用的語系,代換為i18n.js所在路徑。

簡易bash腳本檔案i18n.sh


續前篇,將相關命令包裝為腳本檔以方便使用。

如: sh  i18n.sh  u
 (即更新django.po檔案,附加新增文字)

#!/bin/sh


ACTION="$1"
TARGET="$2"

usage() {
        echo "syntax: |update|compile>"
}

case $ACTION in
initial)
        django-admin.py makemessages -l zh_TW "$TARGET"
        ret=$?
;;
u*|update)
        django-admin.py makemessages -a
        ret=$?
;;
c*|compile)
        django-admin.py compilemessages
        ret=$?
;;
*)
        usage
        ret=1
;;
esac
exit $ret

備註:其中django-admin.py,如使用環境在Mac OS X 使用brew install gettext卻找不到xgettext 和 msgfmt相關檔案時,請使用下列命令產生正確連結:
 brew link gettext


2011年11月29日 星期二

django i18n 實戰

image

最近在為的上線前專案做中文化的處理,在此留下一心得記錄。
就django 中文化相關工具而言,主要是將gettext中的兩個命令:
  • xgettext包裝成django-admin.py makemessages, 用以將程式及腳本檔中所定義的Key字串取出放入至django.po
  • msgfmt包裝成django-admin.py compilemessages, 用來把django.po 轉為二進位的django.mo檔案。
Key 字串
以底線(_)為常見的gettext key字串
在下列命令為常使用的兩種:
from django.utils.translation import gettext_lazy as _
筆者使用下列語法:
from django.utils.translation import ugettext as _
為什麼筆者不使用 gettext_lazy呢?
django 在更新po檔案時,會將相近字詞直接複製到附加的詞組中,時常牛頭不對馬嘴,不如手動編修。

demo 專案為例
請進入與settings.py同層的專案目錄
$ django-admin.py makemessages –l zh_TW
processing language zh_TW
正確產生自動下列檔案django.po
locale/zh_TW/LC_MESSAGES/django.po
如出現下列錯誤:
$ django-admin.py makemessages -l zh_TW
Error: This script should be run from the Django SVN tree or your project or app tree. If you did indeed run it from the SVN checkout or your project or application, maybe you are just missing the conf/locale (in the django tree) or locale (for project and application) directory? It is not created automatically, you have to create it by hand if you want to enable i18n for your project or application.
請建立locale目錄,再試一次。

更新po檔案
每當新增一些個需要中文化字串,並不需要將它們動手加入django.po
可使用下列指令,直接將新字串附加至原有的django.po:
$ django-admin.py makemessages –a
編譯mo
$ django-admin.py compilemessages
註:在測試時,如有重新mo檔案,請重新執行django。

附錄
  • 在使用 blocktrans 及 endblocktrans時,因為採用python 內建dict 變數代換功能,所以只能使用-層。範例如下:
{% blocktrans %} {{user.username}} 進行統
統操作中,… {% endblocktrans %}
其中 {{user.username}}將無法正確代換,需改為 {{username}} 一層dict 結構。對照python 原字串展開範例:
userinfo={'username': _('Bill')}
"%(user.username)s 進行統
統操作中,…" % userinfo


結論


gettext 廣泛使用在開源軟體之中,而django-admin加以包裝,讓它在使用上更加方便。
若對如何包裝gettext有興趣,可參閱python腳本檔如下:
/usr/lib/python2.7/site-packages/django/core/management/commands/makemessages.py
/usr/lib/python2.7/site-packages/django/core/management/commands/compilemessages.py

2011年11月3日 星期四

Vagrant+virtualbox (2): 實戰封裝自制package.box

image

續上篇執行lucid32.box 使用 jRuby + vagrant在Windows XP
Vagrantfile 範例
Vagrant::Config.run do |config|
  config.vm.box = "gold"
  # config.vm.forward_port("web", 80, 8080)
end


添加所需應用程式及設定,如安裝django套件:
sudo easy_install pip
sudo pip install django
使用此檔案執行 vagrant up後,使用 putty (參考執行lucid32.box 使用 jRuby + vagrant在Windows XP


若要附加自己的說明檔案,請使用—include
vagrant package --vagrantfile .vagrant --include README.txt


若要附加自己的說明檔案,請使用--
vagrant package --vagrantfile .vagrant --


執行結果
C:\Documents and Settings\vagrant\SRC\vagrant\gold>vagrant package --vagrantfile .vagrant --
[default] Attempting graceful shutdown of linux...
[default] Clearing any previously set forwarded ports...
[default] Cleaning previously set shared folders...
[default] Creating temporary directory for export...
[default] Exporting VM...
Progress: 0%Progress: 1%Progress: 4%Progress: 9%Progress: 10%Progress: 14%Progre
ss: 19%Progress: 24%Progress: 28%Progress: 34%Progress: 39%Progress: 42%Progress
: 44%Progress: 49%Progress: 54%Progress: 69%
[default] Compressing package to: C:/Documents and Settings/vagrant/SRC/vagrant/gold/package.box[default] Packaging additional file: .vagrant


加入本機檔案package.box 為mygold box
vagrant box add mygold package.box


執行結果
C:\Documents and Settings\vagrant\SRC\vagrant\gold>vagrant box add mygold package.box[vagrant] Downloading with Vagrant::Downloaders::File...
[vagrant] Copying box to temporary location...
[vagrant] Extracting box...
[vagrant] Verifying box...
[vagrant] Cleaning up downloaded box...

在新增之後,看看目前有的boxes:
C:\Documents and Settings\vagrant\SRC\vagrant\mygold>vagrant box list
gold
lucid32
mygold


修改新的Vagrantfile 來使用 mygold
Vagrant::Config.run do |config|
  config.vm.box = "mygold"
  # config.vm.forward_port("web", 80, 8080)
end

執行vagrant up 啟動
C:\Documents and Settings\vagrant\SRC\vagrant\mygold>vagrant up
There is a syntax error in the following Vagrantfile. The syntax error
message is reproduced below for convenience:
C:/Documents and Settings/vagrant/.vagrant.d/boxes/mygold/include/_Vagrantfile:1: syntax error, unexpected ':'
{"active":{"default":"f5a2c996-a70b-4c2c-8928-a85127a26863"}}

發生錯誤,移除include/_Vagrantfile ,再執行一次,啟動成功。
C:\Documents and Settings\vagrant\SRC\vagrant\mygold>vagrant up
[default] Importing base box 'mygold'...
[default] The guest additions on this VM do not match the install version of
VirtualBox! This may cause things such as forwarded ports, shared
folders, and more to not work properly. If any of those things fail on
this machine, please update the guest additions and repackage the
box.
Guest Additions Version: 4.1.2
VirtualBox Version: 4.1.4
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- ssh: 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Running any VM customizations...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
C:\Documents and Settings\vagrant\SRC\vagrant\mygold>vagrant ssh
`vagrant ssh` isn't available on the Windows platform. The
vagrant.ppk file for use with Putty is available at:
  C:/jruby-1.6.5/lib/ruby/gems/1.8/gems/vagrant-0.8.7/keys/vagrant.ppk
To use this create a new Putty session for `vagrant@localhost`
on port `2222`, in the Connection>SSH>Auth
configuration section navigate to the vagrant.ppk file,
select it, save the session for later use, and connect.
For a more detailed guide please consult:
http://vagrantup.com/docs/getting-started/setup/windows.html
C:\Documents and Settings\vagrant\SRC\vagrant\mygold>

使用 putty連入,檢查之前在gold box所產生的測試用檔案[my.box],OK。
image


停止啟動mygold box

vagrant halt


刪除啟動後的mygold box
C:\Documents and Settings\vagrant\SRC\vagrant\mygold>vagrant destroy
[default] Forcing shutdown of VM...
[default] Destroying VM and associated drives...


結論
利用封裝已安裝及設定好的軟體的Box,可大大減少啟動後所需的安裝時間。
且可使用不同版本的gold box 來進行軟體自動化測試,並方便管理。


附註
多人共用mygold.box
可將編寫腳本檔案 mygold_update.bat 中加入如下設定:
@echo off
REM 刪除已存在的mygold_xxxx, 視情況決定是否執行destory, 或由使用者自行決定
vagrant destroy
REM 移除舊的mygold
vagrant box remove mygold
REM 加入新的mygold
vagrant box add mygold http://yourwebserver:port/mygold.box
註:請記得將所產生的package.box檔案更改並放到自行架設的web server 上。

可與ssh 搭配使用
vagrant ssh 等於
ssh -i <vagrant private key> vagrant@localhost –p <vagrant port>
(ex: ssh -i /cygdrive/c/jruby-1.6.5/lib/ruby/gems/1.8/gems/vagrant-0.8.7/keys/vagrant vagrant@localhost -p 2222)

下列為使用cygwin + ssh + vagrant key
$ ssh -i /cygdrive/c/jruby-1.6.5/lib/ruby/gems/1.8/gems/vagrant-0.8.7/keys/vagrant vagrant@localhost -p 2222
Could not create directory '/home/vagrant/.ssh'.
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
ECDSA key fingerprint is 36:28:64:97:6c:a4:dd:2a:4e:1a:0e:db:3a:db:d4:66.
Are you sure you want to continue connecting (yes/no)? yes
Failed to add the host to the list of known hosts (/home/vagrant/.ssh/known_hosts).
Welcome to Ubuntu 11.04 (GNU/Linux 2.6.38-8-server x86_64)
* Documentation:  http://www.ubuntu.com/server/doc
  System information as of Thu Nov  3 01:22:58 CST 2011
  System load:  0.0               Processes:           71
  Usage of /:   3.1% of 38.15GB   Users logged in:     0
  Memory usage: 6%                IP address for eth0: 10.0.2.15
  Swap usage:   0%
  Graph this data and manage this system at https://landscape.canonical.com/
New release 'oneiric' available.
Run 'do-release-upgrade' to upgrade to it.
Last login: Thu Nov  3 00:49:19 2011 from 10.0.2.2
vagrant@vagrant-ubuntu-natty:~$

2011年10月31日 星期一

Python+Django 輕鬆寫Web AP


近期工作需要在較短時間內,開發出Web端的程式,因筆者擅長Python,最後決定使用python+django 的組合。
另外在FreeNas 8 中也是使用 python+django來實作Web 控制介面,所以學會django,也可日後若為FreeNas添加新功能做準備。

(註:Google App Engine也採用django,但內建的版本已封裝一層,但有網上教學如何使用原來的django套件方法。)

環境設定

本次採用python 2.7+django 1.3.1
django 授權BSD License(筆者愛用BSD授權)

Cygwin
  • 下載python-2.7.2 重新編繹
  • 開啟Cygwin Terminal 或Mintty for Cygwin
  • 安裝pip
    • easy_install pip
  • 使用pip來管理python套件
    • pip install django

Mac OS X Lion
  • 內建python 2.7.1
  • 開啟Terminal
  • 安裝pip
    • sudo easy_install pip
  • 使用pip來管理python套件
    • sudo pip install django

如何建立專案?

此部分主要參考django文件(原文),加入筆者心得
Django首次使用產生主網站(如:mystie)

django-admin.py startproject mysite

註:在Mac OS X使用django-admin.py startproject 如出permission denied, 請將修改權限

chmod +x django-admin.py

mysite 目錄結構
manage.pydjango命令列工具
settings.pydjango專案設定腳本
urls.py用來設定urls 對應網頁進入點(可參原文說明
__init__.py空的內容則用來告訴python這是一個module,並可用來指定mysite模組初始化動作


啟動mystie專案

若只要本機內可供取用,請執行下行命令(server 會啟動在127.0.0.1:8000)
python manage.py runserver

參數語法
python manage.py runserver [:]

若欲使外部可連接請指定IP為0.0.0.0,表所有外部電腦均可使用此server系統IP連接。
python manage.py runserver 0.0.0.0:8080

註:不可單獨指定IP而沒有指定port
$ python manage.py runserver 0.0.0.0
Error: "0.0.0.0" is not a valid port number or address:port pair.


執行結果
~ mysite$ python manage.py runserver 0.0.0.0:8080
Validating models...

0 errors found
Django version 1.3.1, using settings 'mysite.settings'
Development server is running at http://0.0.0.0:8080/
Quit the server with CONTROL-C.


使用瀏覽器連接到localhost:8080










結論

與之前試過nodejs+express,有異曲同工之妙;只在使用的語言不同。
若網友想寫類似Web應用程式,可選擇慣用,產能倍增。
除此之外,便是主機代管服務的選擇,也將會影響你的可用的組合。
因筆者較熟悉python,用django較為得心應手,而nodejs 到處使用callback的方式不太習慣。
最近django網站首頁所列一句話:
"Django makes it easier to build better Web apps more quickly and with less code."
也是筆者採用的主因之一。
本篇旨在記錄一下,學習心得,歡迎交流。


2011年10月30日 星期日

執行lucid32.box 使用 jRuby + vagrant在Windows XP

image

最近朋友有在Windows環境中使用vagrant的需求,
而筆者有時要用windows xp來使用vagrant,
故寫了本篇,便是介紹如何安裝vagrant及其環境。

安裝 Ruby
  • 實驗使用cygwin+ruby,但最後有相容性臭蟲問題而成殘念。
/usr/lib/ruby/gems/1.8/gems/virtualbox-0.9.2/lib/virtualbox/com/mscom_interface.rb:28:in `initialize': failed to create WIN32OLE object from `VirtualBox.VirtualBox' (WIN32OLERuntimeError)
    HRESULT error code:0x80004005
C:\Documents and Settings\vagrant>set PATH=C:\jruby-1.6.5\bin;%PATH%
C:\Documents and Settings\vagrant>gem install vagrant
Fetching: archive-tar-minitar-0.5.2.gem (100%)
Fetching: erubis-2.7.0.gem (100%)
Fetching: json-1.5.4-java.gem (100%)
Fetching: net-ssh-2.1.4.gem (100%)
Fetching: net-scp-1.0.4.gem (100%)
Fetching: i18n-0.6.0.gem (100%)
Fetching: thor-0.14.6.gem (100%)
Fetching: ffi-1.0.10-java.gem (100%)
Fetching: virtualbox-0.9.2.gem (100%)
Fetching: vagrant-0.8.7.gem (100%)
Successfully installed archive-tar-minitar-0.5.2
Successfully installed erubis-2.7.0
Successfully installed json-1.5.4-java
Successfully installed net-ssh-2.1.4
Successfully installed net-scp-1.0.4
Successfully installed i18n-0.6.0
Successfully installed thor-0.14.6
Successfully installed ffi-1.0.10-java
Successfully installed virtualbox-0.9.2
Successfully installed vagrant-0.8.7
10 gems installed
C:\Documents and Settings\vagrant>cd SRC
C:\Documents and Settings\vagrant\SRC>cd vagrantTest
C:\Documents and Settings\vagrant\SRC\vagrantTest>vagrant up
JRuby limited openssl loaded. http://jruby.org/openssl
gem install jruby-openssl for full support.
[default] Importing base box 'lucid32'...
[default] The guest additions on this VM do not match the install version of
VirtualBox! This may cause things such as forwarded ports, shared
folders, and more to not work properly. If any of those things fail on
this machine, please update the guest additions and repackage the
box.
Guest Additions Version: 4.1.0
VirtualBox Version: 4.1.4
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- ssh: 22 => 2222 (adapter 1)
[default] -- web: 80 => 8080 (adapter 1)
[default] Creating shared folders metadata...
[default] Running any VM customizations...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] Forcing shutdown of VM...
[default] Destroying VM and associated drives...
[default] Destroying unused networking interface...
LoadError: OpenSSL::BN requires the jruby-openssl gem
出現OpenSSL錯誤,在安裝下表的jruby-openssl後,此問題已排除。
C:\Documents and Settings\vagrant\SRC\vagrantTest>gem install jruby-openssl
Fetching: bouncy-castle-java-1.5.0146.1.gem (100%)
Fetching: jruby-openssl-0.7.4.gem (100%)
Successfully installed bouncy-castle-java-1.5.0146.1
Successfully installed jruby-openssl-0.7.4
2 gems installed

啟動lucid32版本
此版本由http://files.vagrantup.com/lucid32.box下載:
(使用vagrant add lucid32 下載,
便已發生無法正在驗證的問題,
筆者直接將box檔案用tar xvf lucid32.box解壓縮至.vagrant.d\boxes\lucid32\目錄中)
C:\Documents and Settings\vagrant\SRC\vagrantTest>vagrant up
[default] Importing base box 'lucid32'...
[default] The guest additions on this VM do not match the install version of
VirtualBox! This may cause things such as forwarded ports, shared
folders, and more to not work properly. If any of those things fail on
this machine, please update the guest additions and repackage the
box.
Guest Additions Version: 4.1.0
VirtualBox Version: 4.1.4
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- ssh: 22 => 2222 (adapter 1)
[default] -- web: 80 => 8080 (adapter 1)
[default] Creating shared folders metadata...
[default] Running any VM customizations...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] Failed to connect to VM!
Failed to connect to VM via SSH. Please verify the VM successfully booted
by looking at the VirtualBox GUI.
由最後發現啟動lucid32已成功,但SSH連線失敗,對照本文一開始的左圖(vagrantTest_1319904659, Ubuntu)
接著使用vagrant ssh 命令查看相訊息。
C:\Documents and Settings\vagrant\SRC\vagrantTest>vagrant ssh
`vagrant ssh` isn't available on the Windows platform. The
vagrant.ppk file for use with Putty is available at:
  C:/jruby-1.6.5/lib/ruby/gems/1.8/gems/vagrant-0.8.7/keys/vagrant.ppk
To use this create a new Putty session for `vagrant@localhost`
on port `2222`, in the Connection>SSH>Auth
configuration section navigate to the vagrant.ppk file,
select it, save the session for later use, and connect.
For a more detailed guide please consult:
  http://vagrantup.com/docs/getting-started/setup/windows.html
(註:在Mac OS X 中,因terminal環境有ssh 指令,所以可直接啟動ssh連線至虛擬機器)

使用PuTTY 


啟動PuTTY
(筆者愛用Pietty,由PuTTY改版以支援中文)

Auto-login username
在Connection->Data中,Auto-login username一欄,輸入使用者名稱 vagrant,如下:
image

輸入私密金鑰
在Connection->SSH->Auth中,Private key file for authentication一欄,輸入私密金鑰ppk所在路徑及檔名,如下:
C:\jruby-1.6.5\lib\ruby\gems\1.8\gems\vagrant-0.8.7\keys\vagrant.ppk
image

主機名稱及Port
使用主機名稱localhost 及port 2222 來連接,卻無法使用ssh 來連接 lucid32,有未知的問題存在,網上此問題討論
image
筆者使用另一個朋友所製作gold.box, 使用主機名稱localhost 及port 2200 來連接成功,如下圖:
image image
如欲按儲存以保留設定,輸入 Saved sessions 名稱: <自訂名>。

結論
就筆者使用vagrant在windows來說,設定環境很多小問題,需要花時間去調整。整體而言,在Mac OS X 環境,設定vagrant就比windows 容易許多。
記得使用完要關機,在啟動目錄中,輸入vagrant halt,便會關閉虛擬機。一點小經驗,望有所助益。
如有網友成功直接在cygwin 中成功設定vagrant 環境,請不吝分享。

附註
  • 請先行安裝VirtualBox
  • 為求方便使用,可將jruby安裝路徑(如:C:\jruby-1.6.5\bin)加入系統環境變數
  • 請確定有將C:\Program Files\Oracle\VirtualBox 路徑加入至系統環境變數中。(與cygwin 環境整合使用)
  • 若有使用Python,也可將環境變數加入,以便在Windows命令提示字元終端中使用。
setup_globalvarsetup_globalvar_selectpathsetup_globalvar_edit  


  • 成功關閉gold vm 的訊息


C:\Documents and Settings\vagrant\SRC\gold>vagrant halt
[default] Attempting graceful shutdown of linux...

C:\Documents and Settings\vagrant\SRC\gold>

2011年10月14日 星期五

在Mac OS X初次使用Arduino實驗板

今天在HackingThursday 聚會,朋友借了一塊Arduino Mega 2560實驗板,現場測試。本文便是將開發設定相關心得做個紀錄。
當然可參考原文的說明手冊
首先至http://arduino.cc/en/Main/Software此下載Mac OS X安裝檔http://arduino.googlecode.com/files/arduino-0022.dmg
arduino_install1
開啟dmg檔案後,便會出現上列,將Arduino 圖示,拖曳到Applications(應用程式目錄),再安裝USB 序列埠驅動程式,如下,依指示安裝。
  arduino_Install_FTD_Driver
先使用USB連接線,連接Mac及2560實驗板,會出現偵測到新網路介面,按cancel 取消即可,不需進行此項設定。
IMG_1442Arduino Mega 2560 Modem in usb detected
再來到Applications 目錄中,找到並執行Arduino整合開發應用程式。
Arduino_in_Applications_dir
Arduino 整合開發環境是以Java開發而成,加上AVR gcc/g++ …的跨平台編譯器及相關設定所組成。
在Arduino設定,注意事項中,先由選單,選擇[Tools] –> [Board] –> [Arduino Mega 2560] (請依網友們的開發板型號,挑選)
arduino_select_hardware
緊接著設定USB 序列埠,先由選單,選擇[Tools] –>[Serial Port]->[/dev/tty.usbmodemfd121] (請依網友們的開發板型號,挑選)
 Arduino_select_the_serial_port
好戲上場,在Arduino中,已準備許多範例程式可供參考,選取視窗上方按鈕[Open]->[1.Basics]->[Blink],
 Arduino_selected_1.Basics_Blink.sample
即出現下方畫面,中央為範例程式碼。最後執行[Upload]鈕(右方數來第二按鈕),立刻編譯並上傳到開發板。(在傳送過程式中,TX燈會閃爍,完成後,即啟動閃爍程式,令13腳位LED每隔一秒閃爍一次。
arduino_Blink_LED_Uploading
若無其他3.3V LED可連13及GND腳位時,可參考下圖,USB Port右方,紅色燈號亦作用與在13pin插LED相同。
 IMG_1445 IMG_1448
結論
Arduino設計非常易於使用,並且有相當多的相容擴充元件可供使用,很適合不太熟悉程式設計及硬體的人來使用。

2011年10月1日 星期六

ARM Linux 開發環境設定指南

debian-arm-booting 
最近在工作上,需要用到ARM相關平台,所以花時間研究 ARM CPU 架構的開發環境,
其中硬體商(目前開發板:Friendly ARM Tiny6410)提供的部分程式必須在Windows 上才可執行。
故筆者想能不能在windows 及ubuntu-linux 中,也可各有一個模擬arm 的開發平台,可直接編譯程式而不需要使用cross-compiler(簡言之,如在windows平台上,使用ARM虛擬機器編譯arm執行檔)。
經過搜尋網上資料後,發現有一套件debian armel可供使用,且很貼心的提供可利用qemu arm來直接載入使用,大大減少重新編譯的時間。

設定步驟


安裝QEMU
下載debian-armel
檔案所在位置:http://people.debian.org/~aurel32/qemu/armel/
 a3853606c5762d41bb245aaeb8823996  debian_lenny_armel_desktop.qcow2
  dce9f0d2855d57b79b63bcf3a9ecd51d  debian_lenny_armel_standard.qcow2
  a6d0dde54fb27254e2b8d94736889462  initrd.img-2.6.26-2-versatile
  1969e2a0ffc571ccf6024dc7c842d4dd  vmlinuz-2.6.26-2-versatile
  c5f9039b463e07852055071ac118320a  debian_squeeze_armel_desktop.qcow2
  b7807306c4c79aaa9a423119f4633ffb  debian_squeeze_armel_standard.qcow2
  f73e83b8e48bd422457dafeb8afe7fc6  initrd.img-2.6.32-5-versatile
  8b33324f99d13dc71d6ad060db2fd60a  vmlinuz-2.6.32-5-versatile

筆者所使用的檔案組合如下表:
下載檔案說明
initrd.img-2.6.32-5-versatile初始化並啟動附加檔案
vmlinuz-2.6.32-5-versatile系統啟動用linux 核心
debian_squeeze_armel_standard.qcowdebian squeeze 標準系統映像檔(可寫入更新資料)


執行debian arm linux
開機完成後,預設登入帳號及密碼皆為root。
debian-arm-login

執行腳本檔
此腳本用來執行debian-armel,及相關必要參數。
run.sh
#!/bin/sh
export PATH="$PATH:/usr/local/qemu/bin"
PLATFORM="`uname -s | cut -d'_' -f1`"
QEMUEXE="qemu-system-arm"
if [ "$PLATFORM" = "CYGWIN" ] ; then
    QEMUEXE=${QEMUEXE}.exe
fi
img=debian_squeeze_armel_standard.qcow2
$QEMUEXE -M versatilepb  -kernel vmlinuz-versatile -initrd initrd.gz -m 256 -hda $img -append 'root=/dev/sda1' -redir tcp:2200::22

使用腳本檔案前用先將,下列檔案更名:

  • initrd.img-2.6.32-5-versatile  改為 initrd.gz
  • vmlinuz-2.6.32-5-versatile 改為 vmlinuz-versatile

進入到run.sh 所在目錄,並執行下列腳本檔

sh run.sh

註一:當在使用apt-get install gcc g++ 時,發生找不到檔案的情形。
解決方法: apt-get update –fix-missing
註二:因為qemu 網路架構原設計,需使用-redir 參數用來將Guest OS(debian-arm) 的ssh 22 port 轉到本機2200port。(記得debian-arm中,執行 apt-get install openssh-server來安裝ssh server)

結論
當筆者完成所有步驟後,等於擁有一台虛擬ARM機器,且為一包含完整開發軟體的LINUX系統。
若網友們所寫的程式無特別額外ARM硬體需求,則可直接在上面開發偵錯,可減少arm程式複製到arm 板子上的時間。

2011年9月16日 星期五

自製免費軟體:超軟中文直式閱瀏器sviewer 0.27.1001更新

sviewer027


主要修正 2.7.1001
* 解決無BOM標頭UTF8檔案,顯示亂碼問題。
* 狀態列顯示檔案類型UTF8, BOM UTF8, ASCII等等
* 工具字型大小選擇: 字型加大為大24, 中20, 小16

檔案下載
由此下載sviewer-027-1001.zip檔案
a073cfa82d621593c49fc26b6972e7bf *sviewer-027-1001.zip

2011年9月14日 星期三

Go 程式語言再探

go_webs_qrcode
  從官網中範例程式找到一段Go程式碼WebServer,加入我的編譯腳本檔如下:
GOCC=6g
GOLD=6l
PROJECT=webserver
all: $(PROJECT)
$(PROJECT).6: $(PROJECT).go
        $(GOCC) $(CFLAGS) $^
$(PROJECT): $(PROJECT).6
        $(GOLD) -o $@ $^
run: $(PROJECT)
        ./$^
clean:
        rm -f $(PROJECT).6 $(PROJECT)
當你輸入,make run 時,如果設定無誤(詳設定請參閱Go語言初探),將會啟動一個Web Server 在localhost:1718。
如上圖,筆者輸入本站網址,點按[Show QR],輕輕鬆鬆產生本站QRCode圖像。
結語
短短50行程式碼,其中包含20行網頁腳本,使用掛載flag, http, io, log, template等等套件大幅提高程式生產力。
若要學習Go,不容錯過Effective Go一文。

2011年9月7日 星期三

Go 程式語言初探

from http://golang.org



最近寫多篇與OS開發相關超硬的文章,來學習Go 語言換換口味輕鬆一下吧!參考英文說明,寫了以下心得:

使用平台為Mac OS X 10.6.8 + Xcode 4.2

前言

Go 程式語言是一個開放源碼的專案,以BSD-style授權發佈。
它以通用語言作為系統設計基礎想法。在強調於型別、垃圾回收及明確定義支持Concurrent程式設計的語言功能等等。並提供大量套件 ,提高寫程式效率。目前支援x86及ARM處理器,一個64位元及32位元x86的編譯套件(6g和8g),及支援ARM的編譯套件(5g)。


開發環境設定

安裝 Mercurial (hg)
 sudo easy_install mercurial
(註:easy_install 是python所內附一個好用安裝第三方工具的python腳本)

Mercurial versions 1.7.x 需要設定檔來指定憑證授權 Certification Authorities (CAs). 在筆者機器遇到下列警示訊息:
warning: go.googlecode.com certificate with fingerprint 28:92:... not verified (check hostfingerprints or web.cacerts config setting)

這表示你所使用的Mercurial沒有正確設定CAs. 參考configure the CAs一文,進行設定。
以下是OSX 10.6以上版本的設定

openssl req -new -x509 -extensions v3_ca -keyout /dev/null -out dummycert.pem -days 3650

使用openssl命令建立替代憑證(設定內容隨意打)
接著使用下列指令將dummycert.pem複製到/etc

sudo cp dummycert.pem /etc/hg-dummy-cert.pem

最後在~/.hgrc 或go/.hg/hgrc內容加入下列兩行。

[web]
cacerts = /etc/hg-dummy-cert.pem

下載Go 正式發佈版本源碼


 hg clone -u release https://go.googlecode.com/hg/ go


編譯Go

你將需要安裝Xcode,其中包含GCC, C libraries ...

$ cd go/src
$ ./all.bash
如果沒任何錯誤發生,訊息如下:


ALL TESTS PASSED

---
Installed Go for darwin/amd64 in /Users/you/go.
Installed commands in /Users/you/Go/bin.
*** You need to add /Users/you/Go/bin to your $PATH. ***
The compiler is 6g.

最後幾行顯示你的系統資訊,硬體架構,和所安裝的目錄,你需要將此目錄加到搜尋路徑中。詳請參閱英文文章環境變數environment variables.


使用Go來編Hello範例
$ make
6g hello.go
hello.go:2: can't find import: fmt
錯誤發生原因沒有指定環境變數。
筆者指定下列環境變數後,總算編譯成功。

export PATH=~/Go/bin:$PATH
export GOROOT=$HOME/Go
export GOARCH=386
export GOOS=darwin
export GOBIN=$HOME/Go/bin

$ make
6g hello.go
6l -o hello hello.6


執行結果
$ make run
./hello
hello, world


hello 範例可由此下載

歡迎留言分享心得。

2011年9月5日 星期一

啟用e100 (i82559er)網路卡在自製Bos

bos_i82559er_enabled 續上篇自製BenOS支援lspci 命令,參考MIT OSE Lab6: Network Driver 及其中各項文件,且參照相關Linux網路驅動程式設計,目前已整合實作82559er網路卡驅動至BOS v0.21中。
新增及修改下列檔案:
pcireg.h PCI相關參數標頭檔,引用自NetBSD,源自MIT OSE LAB
pci.c 移植Lab6 kern/pci.c
net_e100.h 參考Lab6相關實作資料
net_e100.c 參考Lab6相關實作資料
teset/Makefile   已修改以i82559er為參數,啟動qemu :
qemu -fda "../bos.img" -net user -net nic,model=i82559er
執行後結果,如文頭畫面。

啟用e100
其中pci.c,如何啟用e100 82559er 簡略原始碼如下:
pci_func_enable(pci_pdata_t f) {
        pci_conf_write(f, PCI_COMMAND_STATUS_REG,
                       PCI_COMMAND_IO_ENABLE |
                       PCI_COMMAND_MEM_ENABLE |
                       PCI_COMMAND_MASTER_ENABLE);
        for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
             bar += bar_width)
        {
                uint32_t oldv = pci_conf_read(f, bar);
                bar_width = 4;
                pci_conf_write(f, bar, 0xffffffff);
                uint32_t rv = pci_conf_read(f, bar);
                if (rv == 0)   continue;
                int regnum = PCI_MAPREG_NUM(bar);
                if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) {
                        if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT)
                                bar_width = 8;
                        size = PCI_MAPREG_MEM_SIZE(rv);
                        base = PCI_MAPREG_MEM_ADDR(oldv);
                } else {
                        size = PCI_MAPREG_IO_SIZE(rv);
                        base = PCI_MAPREG_IO_ADDR(oldv);
                }
       pci_conf_write(f, bar, oldv);
       f->addr_base[regnum] = base;
       f->addr_size[regnum] = size; }

net_e100.c
啟用後,這時便用使用到 io region 1: 0xc040,長度為64位元組,參考Intel 82559,來進行下列操作。
需要將e100 做軟體重置(可參e100_reset函式),因使用DMA Rings,
所以接著要掛上傳送的緩衝區Control Block List(CBL)及接收用的緩衝區Receive Frame Area(RFA),可參考cbl_init()及rfa_init()。



net 命令
在起動Bos v0.21後,輸入net 指令,可看到下列結果:
bos$ net
PCI function 00:18.0 (8086:1209) enabled
mem region 0: 4096 bytes at 0xf2020000
io region 1: 64 bytes at 0xc040
cbl avail = 9, wait = 1, slot = 0x420000, irq=11
rfa avail = 10, wait = 0, slot = 0x420050
其中黃色標記三項資訊,在對網路卡設備進行操作時,會使用到。


結語
原使用e100設備序號,並不生效;後來研究OSE資料後,發現必須在qemu參數中設定,之後再使用設備序號1209來啟用e100(i82559er),如此才能正確執行在qemu環境。
MIT OSE Lab6十分具有挑戰性,筆者經幾天的努力才把這網路卡驅動部分實作完成;但大約只完成Lab6的三分之二,其餘部分,待9/6社群活動後,再來討論後面部分旳細節。本次程式碼可由此下載

2011年8月29日 星期一

自製BenOS支援lspci 命令

image
在實現網路支援之前,必須先能使用PCI Bus來找到網路卡相關資訊,
參考OSDev.org的"Where I can find Programming Info on PCI?”一文後,
筆者已在Bos實現了lspci 命令,參考"Configuration Mechanism #1”完成,下列程式,
其實一開始,最先遇到問題部分是如何讀取PCI?
原文使用sysOutLong() 和sysInLong(), 對照MIT OSE Lab相關資料,實作如下:
static __inline uint32_t inl(int port)
{
        uint32_t data;
        __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
        return data;
}
static __inline void outl(int port, uint32_t data)
{
        __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
}
筆者也試了一下NASM的寫法如下:
        global _inl, _outl
;uint32_t _intl(int port)
_inl:
        mov  edx, [esp+4]
        mov  eax, 0
        in eax, dx
        ret
;void _outl(int port, uint32_t data)
_outl:
        mov  edx, [esp+4]  ; io port
        mov  eax, [esp+8]  ; data
        out  dx, eax
        ret
之後,實作pci_conf_readl與pci_conf_readw,先試作讀取的部分:
完整程式碼請參照kernel/pci.ckernel/osfunc.s,從GitHub 上bos下載。

結論

在程式實作過程中,只要依照PCI所定義的資料表,將所需要的資料取出,存到一個PCI資訊的陣列中。
當有需要時,再從PCI 資訊陣列中取出相對應的記錄一一列出便可得到文章開頭的螢幕畫面。
其中一筆如下:
vendor:0x8086, devid:0x100E, class:0200(Network Controller), rev=3
0x100E指得便是e100的Intel網路卡。而它便是筆者正在研究議題的網路卡資訊來源之一, 提供網路實作使用。

(註一:軟語錄:"提高程式設計功力的方法無它,便是不斷地實作與追踪偵錯。")
(註二:此次9/6活動,筆者將分享最近在研究網路實作的心得,歡迎來切磋指教。)

2011年8月25日 星期四

在Cygwin中設定並使用Qemu

mintty_cygwin_qemu
在看完前三篇編繹BOS文章之後,眼尖的讀者,應該有發現在Linux和MAC OS X平台都是使用qemu 來執行;可是一到Windows 怎麼變成VMWare Player呢!其實筆者曾試著編繹cygwin版的qemu, 卻有太多問題要解決,為求效率;使用其他虛擬機軟體來代替。
這篇算是補完"自製開發BenOS支援Windows+Cygwin"一文。

1. 下載所需qemu工具

在使用谷歌大神後,Qemu.org的友站連結中的非官方版已預先編繹好的程式,找到qemu 0.13版,由此下載 。(感謝他的分享,筆者少花數小時生命。)


2. 安裝Qemu
在下載完qemu-0.13.0-windows.zip後,將它解壓縮到cygwin安裝目錄中。
就筆者環境來說,路徑為C:\cygwin\usr\local\qemu
3. 開啟cygwin命令視窗
加入下列指令到 /etc/bash.bashrc
export PATH=/usr/local/qemu:$PATH
4. 重新開啟cygwin命令視窗
下載最新版bos,執行下列指令,便可看到如上所示執行畫面:
make run
本次在程式碼的編繹腳本修改所使用命令為qemu,主因是此版本qemu-system-x86_64.exe無法正常運作,但qemu卻是正常工作。
@@ -9,7 +9,7 @@ endif
all: run
run:
-ifeq ($(KNAME),CYGWIN)
+ifeq ($(KNAME),$(KNAME_CYGWIN))
        qemu -fda "$(IMG_NAME)"
else
        qemu-system-x86_64 -boot a -M $(MACHINE) -fda "$(IMG_NAME)"
結語

筆者歸納了最近使編繹流程跨平台的經驗,列出幾點供大家參考:
  1. 先到網上花5分鐘找看看,有無編繹好的開發用軟體;
  2. 如果沒有,看看有無編繹經驗分享,
  3. 也無經驗分享,最後才是自己編繹一版。
保持分享的美德,把編繹好的工具,公布出來。如此一來,基於眾人成果,大家互相會受益於時間成本的大大縮短。
當然這也筆者撰文的原因之一。

註:此次報名網址已建置好,請由此報名9/6星系主題活動

更新0825

Dennis 有提出:
我覺得應該找qemu for win32, 用vc++或mingw compile。因為cygwin有些posix api模擬,並沒有做得很好,用native win32 api比較順。而且我很久以前有試過這個 http://www.h7.dion.ne.jp/~qemu-win/ ,它應該可以work。

ben 想:
不過這個qemu-win網址編繹的版本0.9.0有點老而且已停止更新,其實我文章中所用Qemu 可能同一人所維護,只是文中使用連結是較新的版本。若要最新版本,需要的人就要自行編繹了


2011年8月23日 星期二

在Mac OS X上編繹BenOS並使用Qemu執行

bos_run_at_osx

續上篇自製開發BenOS支援Windows+Cygwin後,發現Mac上的使用者(當然筆者也是其中之一,不才也是半個蘋果迷)也想能直接編繹(另一個原因是,不想再開另一個Linux 虛擬機,太耗資源及電力,環保一下吧),於是乎有了這篇文章。

編繹環境設定

筆者的Mac 是Snow Leopard 10.6.8

1. 安裝Xcode

http://developer.apple.com/下載並安裝Xcode (筆者用的是4.0.2)

2. 安裝HomeBrew

請參考把常用的UNIX 環境重建到MAC OS X (1) 一文。

3. 使用brew 安裝 nasm 和qemu

sudo brew install nasm qemu git

4.安裝cross gcc

測試使用Xcode 的gcc,並發現不能做完整靜態連結。也不能輸出ELF檔案。

正想把最後殺手鐧拿來,自己編繹gcc時,心血來潮google 一下,

發現下列的站台,有專門編繹給Mac OS X,二話不說,馬上拿來用,節省不少時間。

可從此處下載http://crossgcc.rts-software.org/doku.php

dmg 安裝至目錄

gcc-4.5.2-for-linux32.dmg (65.2 MB)

/usr/local/gcc-4.5.2-for-linux32/
gcc-4.5.2-for-linux64.dmg (71.7 MB) /usr/local/gcc-4.5.2-for-linux64/

筆者安裝是64位元版,但在編繹時需要加上-m32, 因為目前bos 尚未相容64位元模式。

5. 安裝mtools

在編繹過程,只有一個小問題,便是找不到iconv,極可能是script 的bug,加上-liconv,即可通過編繹。

另外為求保險,去除不必要的變數,故加上-arch i386,產生mtools i386 版。

env CFLAGS="-arch i386" LDFLAGS="-arch i386 -liconv" ./configure
make
sudo make install

結語

如此一來,便可在OSX上編繹及執行,可參考開頭畫面。

再則,感謝google 大神,讓我能省去編繹 toolchain時間。相對windows 來說,Mac OS X 對Unix-like開發者,較為友善。

然後,到本文筆者便寫完三個主要平台的OS開發環境Linux、Windows、OSX上設定。

希望對大家有所幫助,少走一彎路。

最後,筆者因為以前工作屬工友級,所以需要什麼,就學什麼。

想請問大家最常使用什麼平台和工具來進行程式開發呢?

說不定有更好的組合提高您的生產力;一人技窮,二人技長;快提出來大家討論,集思廣益吧。

註一:下次的大聚會9/6,有重量級的OS長老駕到,可來吸收一甲子功力,請大家踴躍參加。

註二:此次9/6活動已加入TOSSUG行程(請參閱http://www.tossug.org/2011)

2011年8月21日 星期日

自製開發BenOS支援Windows+Cygwin


vmplayer_bos_run
繼上篇"自製作業系統原始碼公佈"後,發現讀者們使用Windows系統比例高達7成。
筆者便在想,讓自製的小系統也能直接在Windows 裡編繹並使用其虛擬機器執行。
1. 安裝Cygwin
(但Cygwin 所附的bash login console 介面,限制頗多,不太方便,所以下載mintty來使用 (它以putty程式碼修改而來)。
在安裝過程中,請記得選取並安裝gcc 和nasm套件,用來編繹主程式及組合語言部分。
2. 安裝mtools
在Bos v0.2後,使用了mcopy。可參考 英文原文此文下載安裝。
3. 安裝 git + pagent.exe
因為要使用github,而其中需要使用上傳檔案的key,
所以利用pagent.exe 將key提供給git 使用。(試過使用ssh,但不能正常工作)
目前筆者在使用github 前,使用下列命令將key載入,
bash file: load_pagent_with_key
/cygdrive/c/yourpath/pageant.exe "c:\\youpath\\your_key_generate_by_puttygen.ppk" &
接著pagent.exe 會跳出輸入密碼的視窗,輸入後便載入完成。
記得使用完github,要將下列PAgent 圖示,按滑鼠右鍵,選Exit結束程式。




4. 下載 BOS v0.2 原始碼
使用git 前,請確認GIT_SSH環境變數:
$ export | grep GIT
declare -x GIT_SSH="C:\\yourpath\\plink.exe"
註:可在Windos 系統內容->進階->環境變數->系統變數 中修改GIT_SSH。
請下載最近原始碼
$ git clone git@github.com:benwei/bos.git
Initialized empty Git repository in C:/src/
github/bos/.git/
remote: Counting objects: 65, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 65 (delta 5), reused 63 (delta 3) KiB/s
Receiving objects: 100% (65/65), 32.73 KiB | 31 KiB/s, done.
Resolving deltas: 100% (5/5), done.
5. 編繹Bos
$ make
… ignored
nasm -f elf32 kernel/main.s -o kernel/main.o -Iinclude/ # -l kernel/main.lst
nasm -f elf32 kernel/osfunc.s -o kernel/osfunc.o -Iinclude/ # -l kernel/osfunc
.lst
ld -nostdlib -static -e _start --no-undefined -X -T ld-script.lds -Map MYOS.map
-o myos.elf kernel/init.o kernel/kthread.o lib/describtbl.o lib/fifo.o lib/file.
o lib/floppy.o lib/interrupt.o lib/keyboard.o lib/memory.o lib/mtask.o lib/timer
.o blibc/screen.o blibc/stdio.o blibc/string.o apps/bshell.o kernel/main.o kerne
l/osfunc.o
ld: cannot perform PE operations on non PE output file 'myos.elf'.
make: *** [myos.elf] Error 1
在編繹過程發現原本由CYGWIN所安裝的gcc 只支援PE 格式,所編繹出來的obj file 格式為 Windows coff @.@。
但main.s同時包含16位元與32位元程式碼用以進入32位元保護模式, 所以會產生下列錯誤。
$ make CYGWIN=1
nasm -f win32 kernel/main.s -o kernel/main.o -Iinclude/ # -l kernel/main.lst
begdt.inc:24: error: COFF format does not support non-32-bit relocations
kernel/main.s:75: error: COFF format does not support non-32-bit relocations
kernel/main.s:89: error: COFF format does not support non-32-bit relocations
make: *** [kernel/main.o] Error 1
目前編繹obj檔案格式參照
$ file bos/kernel/init.o
bos/kernel/init.o: MS Windows COFF Intel 80386 object file
$ file bos/kernel/main.o
bos/kernel/main.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
目前解決方法有二:
1. 改寫main.s 將進保護模式部分移到開機程式中,使其能順利使用 nasm –f win32 編繹。
2. 使用cross compiler, 參考OSDev.og文章GCC Cross Compiler
筆者選擇使用方法二,主因是BOS可能會支援ARM或其他平台。看了此篇Cross-Compiler Successful Builds
使用binutils-2.20 + gcc-4.4.3 的組合,編繹了一版ToolChain,由此下載。
cygwin_toolchain4_bos0821.tgz (md5sum: e06bdccb2c44c4cc65097399e8722d95)
$ cd /
$ tar zxvf <your download path>/cygwin_toolchain4_bos0821.tgz
已修改使用新的Toolchain, 下列為編繹成功範例。
$ make
nasm -o bootldr.elf boot/bootldr.s -I include
nasm -f elf32 kernel/main.s -o kernel/main.o -Iinclude/ # -l kernel/main.lst
nasm -f elf32 kernel/osfunc.s -o kernel/osfunc.o -Iinclude/ # -l kernel/osfun
.lst
building [kernel/init.c] -> [kernel/init.o]
building [kernel/kthread.c] -> [kernel/kthread.o]
building [lib/describtbl.c] -> [lib/describtbl.o]
building [lib/fifo.c] -> [lib/fifo.o]
building [lib/file.c] -> [lib/file.o]
building [lib/floppy.c] -> [lib/floppy.o]
building [lib/interrupt.c] -> [lib/interrupt.o]
building [lib/keyboard.c] -> [lib/keyboard.o]
building [lib/memory.c] -> [lib/memory.o]
building [lib/mtask.c] -> [lib/mtask.o]
building [lib/timer.c] -> [lib/timer.o]
building [blibc/screen.c] -> [blibc/screen.o]
building [blibc/stdio.c] -> [blibc/stdio.o]
building [blibc/string.c] -> [blibc/string.o]
building [apps/bshell.c] -> [apps/bshell.o]
/usr/local/cross/bin/i586-elf-ld -nostdlib -static -e _start -s -Ttext 500 -Map
MYOS.map -o myos.elf kernel/main.o kernel/osfunc.o kernel/init.o kernel/kthrea
.o lib/describtbl.o lib/fifo.o lib/file.o lib/floppy.o lib/interrupt.o lib/keyb
ard.o lib/memory.o lib/mtask.o lib/timer.o blibc/screen.o blibc/stdio.o blibc/s
ring.o apps/bshell.o
echo "convert myos.elf MYOS.BIN"
convert myos.elf MYOS.BIN
/usr/local/cross/bin/i586-elf-objcopy -I elf32-i386 -O binary -R .pdr -R .note
R .note.gnu.build-id -R .comment -S myos.elf MYOS.BIN
$ make package
dd if=./bootldr.elf of=bos.img seek=0 count=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.000172887 s, 3.0 MB/s
dd if=/dev/zero of="bos.img" seek=1 count=2879
2879+0 records in
2879+0 records out
1474048 bytes (1.5 MB) copied, 0.011148 s, 132 MB/s
mcopy -i "bos.img" "MYOS.BIN" ::
mdir -i "bos.img"
Volume in drive : has no label
Volume Serial Number is A0A1-A2A3
Directory for ::/
MYOS BIN 19576 2011-08-21 21:07
1 file 19 576 bytes
1 437 696 bytes free
在windows 上使用VMware Player來執行, 請建立一新的虛擬機器,
在使用磁片檔部分填入所產生的bos.img 的檔案路徑及名稱,如下所示,
vmplayer_bos
接著執行,便可看到本文開頭的執行畫面。
讀者們若對編繹及執行BOS系統在windows+cygwin上有任何問題?
另外筆者最近寫了許多新文章,這裡有個小問題,請問一下讀者們,有什麼想看的技術主題?
歡迎留言交流。
註:此次9/6活動已加入TOSSUG行程(請參閱http://www.tossug.org/2011)