資訊技術 – Computer Science

以「中央儲存庫 (Centralized Repository)」的方式建立 Mercurial 儲存庫

  1. 建立存放 central repositories 的目錄。(例:D:\hg_repos)
  2. 在其中建立存放專案 central repository 的目錄。(例:D:\hg_reposprj1)
  3. 使用 hg init,在步驟 2 的目錄中建立儲存庫。
  4. 切換到工作目錄下。(例:D:\working)
  5. 使用 hg clone,clone 一份 repository 到工作目錄中。
  6. 在工作目錄中,使用 hg add 建立第一版的 source tree。
  7. hg commit
  8. 使用 hg push,將 local 端的變更 push 回 central repository。

在 Windows 下將 Subversion 的 repo 由 BDB 格式轉為 FSFS 格式

我用 Subversion 管理工作用的程式碼已經好幾年了,不過最近我越來越討厭它。討厭它的原因並不是因為它變得難用,而是開發團隊對於舊版本使用者表現的那種傲慢態度。

其中一個例子:我前一陣子在研究 Subversion 和 Apache 協同運作時遇到版本搭配的問題。在網路上搜尋答案,卻看到一個像是 project team 成員的人跳出來說:「你就用我們提供的、已經和 Subversion 緊密搭配的 Apache 版本就好了嘛!」問題是並不是所有人都有這樣的權限啊!(像我就是)

另一個例子就是今天這篇文章想要解決的問題。Subversion 在建立 repository 時提供兩種不同的格式讓使用者選擇:Berkley DB (BDB) 和 FSFS。早期的 TortoiseSVN 和 CollabNet 的 Subversion for Win32 都提供這兩種格式讓使用者選擇。但從 1.6.0 版開始,TortoiseSVN 突然就不支援 BDB 了!也沒有提供任何轉換的工具!請問一下:那我之前那些用 BDB 建立的 repository 怎麼辦?有一種被拋棄的感覺… 🙁

最近我開始用 Mercurial 管理我新開的專案……不過那是另外一個故事了。但舊的 repository 還是得救回來,不然之前的心血都白費了。

將 repo 由 bdb 轉成 fsfs 說起來不算太難,只要利用 svnadmin 下幾個指令就行了。但問題是:要選對 Subversion 的版本!前面說過,Subversion 沒有提供任何轉換的工具。一般人常用的的 Subversion 版本(CollabNet 和 VisualSVN 等)也都不支援 BDB (wtf –_-)!我試了好幾套,最後找到由 David Darj 維護的 Subversion for Windows 有支援 BDB(嗯… 至少 1.6.13 有支援;而且在 SourceForge 上能 download 舊版。

下載安裝就不多提了。安裝完後,先建立一個新的 repo,準備接轉出來的資料——當然,這個新的 repo 的格式要選 fsfs。你可以用 TortoiseSVN 建,或是直接利用 svnadmin create 建(假設你的 repos 都放在 D:SVN_DB;然後要轉的 repo 叫做 MyProject :

svnadmin create –fs-type=fsfs MyProject_fsfs

接著我們用 svnadmin dump 把舊的 repo 內容倒出來,再用 svnadmin load 傳進新的 repo 中:

svnadmin dump MyProject | svnadmin load MyProject_fsfs

最後我們把舊的 repo 改名、備份;用新的 repo 取代舊有的 repo:

move MyProject MyProject_old
move MyProject_fsfs MyProject

這樣應該就可以了。

在 64-bit 的 Linux 中,用 32-bit 的 gcc 產生 32-bit 的 binary…

噢!這個標題真是個亂七八糟的組合……XDD

看起來很好笑,但實際遇到就很難笑出來了。

在這樣的組合下,若是我們直接執行 gcc 的話,會有下列的錯誤訊息:

$ gcc test.c
/tmp/cc7YTML2.s: Assembler messages:
/tmp/cc7YTML2.s:13: Error: suffix or operands invalid for push'
/tmp/cc7YTML2.s:14: Error: suffix or operands invalid for '
/tmp/cc7YTML2.s:16: Error: suffix or operands invalid for push'
/tmp/cc7YTML2.s:25: Error: suffix or operands invalid for '
/tmp/cc7YTML2.s:26: Error: suffix or operands invalid for pop'</pre>
<p>會有這樣的錯誤訊息,主要是因為 gcc 產生了 32-bit 的 assembly file,餵給 as (assmebler);但此時系統裝的 as 卻是 64-bit 版的,因此預設會用 64-bit 的方式去組譯 32-bit 的 assembly,結果當然是出不來。</p>
<p>as 有個參數 -32’,可以強制 as 用 32-bit 的方式去組譯。我們可以把原本 gcc 幫我們做的動作拆成下列的分解動作,手動編譯 test.c:

$gcc -S test.c            # 編譯,產生 test.s
$as -32 -o test.o test.s  # 以 32-bit 模式組譯,產生 test.o
$gcc -o test.out test.o   # 產生執行檔

但每個程式這樣做不是很麻煩嗎(笑)?還好,gcc 另外提供了一個方法,可以把參數送給 as:

$gcc -Wa,-32 -o test.out test.c

要注意 32 前面的減號不能省略。這樣做就 ok 了。

[筆記] FreeBSD 設定上的相關問題…

問題:
更新 port tree 之後,安裝 port 出現下列的錯誤訊息:
X11BASE is now deprecated.  Unset X11BASE in make.conf and try again.
*** Error code 1
Stop.
解決方法:
/etc/make.conf 中加入下列一行:
X11BASE=${LOCALBASE}

參考網站:http://forums.freebsd.org/showthread.php?t=13030


問題:
在 private network 中的機器,執行 apachectl start 後,沒有錯誤訊息,但 httpd 沒有起來。查看 /var/log/httpd-error.log 看到下面的錯誤訊息:

[Sat Jun 05 00:20:46 2010] [alert] (EAI 8)hostname nor servname provided, or not known: mod_unique_id: unable to find IPv4 address of "host.name.and.domain"
Configuration Failed

其中 host.name.and.domain 是 host 的 domain name。

解決方法:
原因是 httpd 找不到該 domain name 的 IP。在 /etc/hosts 中加入下列兩行:
10.1.1.203              host.name.and.domain host
10.1.1.203              host.name.and.domain.

記得將 10.1.1.203 代換成這台機器的虛擬 IP。


問題:
啟動 Apache2.x 時都會出現錯誤訊息 :Failed to enable the 'httpready' Accept Filter

解決方法:
原因是沒有安裝 accf_http 這個 kernel module。手動動態安裝的方法是在 shell 中鍵入以下指令:

> kldload accf_http

再 restart apache 即可。若要開機時自動載入,請在 /boot/loader.conf 加入下面這行:

accf_http_load="YES"

參考資料:

【書評】現代嵌入式系統開發專案實務

本書作者邱毅凌先生後來又出版了一本「嵌入式系統開發之道:菜鳥成長日誌與專案經理的私房菜」。雖然書名有些不同,但其實就是這本書的第二版。第二版頁數大幅增加至 900 餘頁,內容雖然更為充實,但閱讀所需的精力稍微多了些。

兩個版本其實都值得嵌入式系統的從業人員們閱讀。只可惜年份已久,兩個版本都已絕版。想找到它們,可能得在二手市場碰碰運氣了……

2021/11/15 更新

雖然很少資訊系的學生會立志當個嵌入式系統的程式員;但事實上,在台灣從事這方面工作的程式員不在少數。因為我們日常生活會遇到太多的嵌入式系統了:冷氣機、洗衣機、電冰箱、電磁爐……什麼冠上「微電腦」的幾乎都有嵌入式系統;電視機有一個嵌入式系統,電視機遙控器裡也有一個嵌入式系統;DVD player、遊樂器也算是嵌入式系統;電子錶、手機、PDA、電子字典、電子雞……所有你想得到的電子產品幾乎都屬於嵌入式系統的範疇。

正因為人才需求高,市面上和嵌入式系統程式設計相關的書籍、補習班課程等亦多如牛毛。這些書大多是學院派的,從理論出發。偶有書名冠上「實作」的,也僅只於列出程式的範例。很少書籍從現實出發,告訴你在職場上會到什麼樣的問題、該朝什麼樣的方法解決。很幸運的是,《現代嵌入式系統開發專案實務》(以下簡稱《實務》)就是一本這樣的書;而且更幸運的是,這本書是台灣人寫成的、土生土長的中文原創書(相信曾被劣質翻譯書或是中國大陸電腦術語荼毒過的人都能了解這件事情有多重要)。

《實務》最大的特點,就是從目前台灣業界的現實面出發,點出專案團隊人力缺乏、內部各小組互有摩擦、老闆客戶常有無理要求……等真相。這點要歸功於作者擁有的十數年專案開發經驗(而非數十篇學術論文)。書中提到的要點及案例,字字璣珠,句句血淚。只要曾在業界有些經驗的人,讀這本書應會不時露出會心的微笑(或是苦笑)。

也許是想要突顯出「實務」的特性,也許是希望讀者能更輕鬆地消化書中的觀念,《實務》的內文採用技術書籍少見的「劇情對話式」文體,描述一位剛從學校畢業的資訊科系碩士從無到有,學習嵌入式系統開發流程的經過。全文的主要內容,就是這位「菜鳥」和「專案經理」及各小組的「老鳥」間的對話。菜鳥所代表的是學院派、主流電腦系統的思維(動輒上 GHz 的 32/64-bit CPU、數百 MB 甚至上 GB 的記憶體、還有用不完的硬碟空間);而老鳥們則代表了業界和嵌入式系統的現實(微處理只有數十 MHz、資料記憶體只有幾 KB、讀寫 NAND ROM 還要考慮效率問題)。藉由菜鳥和老鳥之間的對話,我們可以清楚地看到「學院 vs 實務」以及「PC vs 嵌入式系統」的不同之處。再加上詼諧不艱澀的文筆,讀者們可以快速而專注地了解嵌入式系統的特性。

書中的這位「菜鳥」以成為全才為目標,因此隨著書中專案的進行,被派到各個不同的部門了解學習……作者藉由這個方法帶領讀者了解專案團隊中每個小組的工作內容,也同時大略地介紹了專案開發的流程。書中提到一件重要的觀念:學硬體的人不要怕軟體,學軟體的人也不要怕硬體。在專案人數普遍不足的情況下,軟體人員遇到簡單的硬體問題需要澄清時,最快的方法是靠自己做簡單的實驗,不要等枯等別人來幫忙。相同的,其他小組人員的工作,我們也不是永遠不會碰到。所以了解每個專案人員負責扮演的角色不僅是專案經理的工作,了解這些知識對每個專案成員都有好處。

而本書最最重要的一個觀念,就是作者不斷強調的:「一法通,萬法通」。嵌入式系統使用的處理器種類繁多,再加上不同的單晶片 (SoC) 實作,是永遠學不完的。因此一個嵌入式系統的工程師學習的目標並不是把手中的晶片研究透徹(那是賣你晶片的廠商的工作),而是要了解「嵌入式系統有什麼特性」;等到真的把晶片和 data sheet(有人喜歡叫它 "data shit"....)拿到手後,再把觀念套上去。作者在書中舉出案例時,也不忘提醒讀者什麼是重要的,什麼是旁枝末節大概看懂就好。

對於專案開發的細節而言,《實務》稍嫌深度不足;但一本五百多頁的書要顧及廣度,深度本來就不能苛求。況且這本書著重的是觀念,細節方面書中列出不少經典書籍供參考。我認為這本書可以當成進入嵌入式系統開發的引門磚,看完之後再看書單上的書,應該更有感覺。

由此衍生出來的另一個尷尬問題是:這本書的主要目標讀者應該是嵌入式系統的生手,尤其是資訊本科系畢業的學生,但他們對嵌入式系統了解得太少,讀起來可能沒什麼感覺(而且還可能會有「我才不會去寫這種低階的程式呢!」這樣的自傲);而對有經驗的人來說,它讀起來又比較像是小說,列出我們已經知道的事,還有我們無力解決的現實。到最後可能只有那些糊里糊塗踏進這個業界的新手從中獲益最多。

當然,這本書不是聖經,有些觀念應用上還是要考慮現實的狀況和個人/公司的習慣,不是不能改變的。像是書中提到 memory-mapped registers 是否要用 register 的名稱做為 symbol 的問題,我個人的看法就和作者不同。另外書中還有一些小錯誤,或是跟業界用語不同的地方(例如業界通常以 micro processor/uP 稱呼嵌入式系統的處理單元,而非稱之為 CPU)。不過瑕不掩瑜,無損這本書的價值。(但若是作者能在這本書的官方網頁中提供 errata 的話,那就更完美了)

總而言之,這本書是中文計算機原創書中難得一見的好書!強力推薦給正在這個業界中努力求生存、以及將要進入這個業界的勇士們。另外,我也要推薦給資訊科系的學弟妹們。書中描述的情景可能就是你們的未來工作上會遇到的問題。即使將來不走這條路,書中的內容也可以和課本上的微電腦組織架構互相比較驗證。而且這本書寫得那麼輕鬆,就算是當故事書看也不錯啦!

[筆記] Visual C++ 的 Struct Memeber Alignment 問題與解決方法

在 Visual C++ 中,default 的 data alignment 是 4 bytes。舉例來說,這樣的一個 struct:

struct TestStruct
{
    char c;
    short s;
};

sizeof() 得到的結果是 4 而不是 3。這樣的特性是為了資料處理的速度;但若是我們直接把 object 內容當成 raw data 處理時,就會出現問題。

要更改 VC++ 對 struct member alignment 的處理方式有兩種方法。其一是更改 compile option "/Zp[num]",把 [num] 換成想要的 alignment boundary(可以選擇的數字有 1, 2, 4, 8, 16)。若是使用 IDE 的話,這個選項在 "Project -> Properties -> Configuration Properties -> C/C++ -> Code Generation -> Struct Member Alignment"。

但上述方法會影響到整個 project。如果只是希望某個 struct 不要 align 的話,可以在 struct 宣告的前後加上下列的 pragma:

#pragma pack(push,1)
struct TestStruct
{
    char c;
    short s;
};
#pragma pack(pop)

其中 push 的意思是先將原來的設定(可能是 4)暫存起來;而 pop 則是恢復原來的設定。

[筆記] About the dependency of Win32 executables compiled by Visual C++ 2005/2008….

  1. The Win32 executables (non-managed) compiled by VC++ 2005/2008 (Express) cannot be executed on all Windows PC's, if default project settings are used. This is because, by default, the executables are configured to use the dynamic version of C run-time (CRT) library. Each version of VC++ provides its version of CRT DLL, which is not guaranteed to presents on every Windows PC.

    This can be solved by asking VC++ to link CRT libraries statically, instead of using DLLs:

    Project -> (project name) Properties... -> Configuration Properties -> C/C++ -> Code Generation. Set Runtime Library to "Multi-Threaded (/MT)" or "Multi-Threaded Debug (/MTd)".

  2. Another solution is to distribute necessary DLL's along with the executable. Two tools can help to check the DLL dependencies of an executable. One is "depends.exe", located in <VisualStudio_Folder>Common7Tools, if installed. The other is dumpbin.exe, located in <VisualStudio_Folder>VCbin, with the /DEPENDENTS option.

[筆記] Subversion directory structure strategy

公司裡只有我一個人在玩 Subversion(目前公司用的是 CVS),而且真的拿 Subversion 來管理自己改的 sources 也只是這一、兩個月的事。拿之前玩 Version Manager, ClearCase & CVS 的經驗和觀念來玩 Subversion,跌跌撞撞了一段時間。下面是我在 Windows 下撞出來的心得,若是有更好的方法歡迎討論。

  1. 安裝完後,建立一個目錄做為存所有的 repositories。例:E:svn_reps
  2. 以 project 名稱在 repositories directory 中建 sub-directory。例:E:svn_repsbd1
  3. 在以 project 命名的 directory 中建立 repository。
  4. Import project. 不要把 project files 直接 import 到以 project 命名的 repository 中;把它們 import 到 repository 中的 trunk 目錄。URL 範例:file:///E:/svn_reps/bd1/trunk/
  5. 建立一個空的目錄,把它 import 到 repository 中的 branches 目錄。URL 範例:file:///E:/svn_reps/bd1/branches/
    (其實這兩步可以一次搞定:先在 local 硬碟上把目錄結構建好,然後再一次 import)
  6. 大功告成。以後 trunk 就是 baseline,branches 則 create 在 branchesbranch_name 下面。

其實上面的說明寫得很爛……沒有 Subversion 概念的人大概還是不能了解我在說啥 XD

用慣了每個檔案有不同版號、利用 tag/label 來控制 snap-shot 的版本控制系統後,一下子切到 Subversion,實在有些不習慣,覺得想貼個 label/tag 都礙手礙腳的。尤其一開始目錄規劃沒弄好,現在想要 create branches/tag 都不知道該怎麼辦……

不過基本上還是蠻好玩的啦!尤其是在 Windows 上搭配 TortoiseSVN 使用更是方便。TortoiseCVS 也還不錯,至少比那該死的 WinCVS 好用一萬倍。 -_-