|
華麗的 c++ 與華麗的娃衣 |
cfront 是幹麻的? c++ 程式員應該不陌生, 他是把 c++ 程式轉成 c, 再用 c 編譯器編譯出最後執行檔的轉譯程式。知道的 c++ 開發者應該很多, 但看過、甚至執行過 cfront 的人應該就很少了。
我一直都在找 cfront 的 source code, 希望可以編譯/執行起來看看, 這樣可以很清楚的知道, virtual function, 繼承的 class, template 到底是怎麼轉成 c code 的, cfront 不支援 exception, 因為這功能複雜到超過 cfront 的能力了。
Comeau C/C++ 也可以做到類似的事情, 不過要錢, 沒免費版可以試用。
這個
https://github.com/seyko2/cfront-3 就是 cfront source code 了, 我想在 linux 下編譯, 之前嘗試過一次, 失敗了, 這次有新版再來挑戰一次, 向 bjarne stroustrup 博士致敬, 感謝他發明出 c++ 這麼複雜的語言, 整死開發 c++ 編譯器的開發人員, 當然還有學習 c++ 的程式員。
我修改過的版本在
https://github.com/descent/cfront-3, 切到 can_build_in_linux branch 即可, 你得先會用 git 才行, 好吧! git checkout can_build_in_linux 就可以了。
Makefile L20
all: libC.a munch cfront
總共有 3 個部份要編譯, libC.a, munch, cfront 我分 3 次手動編譯, 為了避免奇怪的錯誤, 請按以下次序編譯。
[cfront]
編譯 cfront 會用到 yacc, can_build_in_linux branch 除了修改程式碼與編譯參數, 還有 yacc 需要改為使用 byacc (Berkeley YACC, 修改 Makefile), 使用 apt-get 來安裝 byacc。
apt-get install byacc
用 bison 會有以下錯誤訊息:
編譯指令:
cd src
make CC=gcc CCFLAGS="-Os -fpermissive -I../incl-master/incl-linux32/"
很奇怪, 在 gcc 9 之下, 不能使用 -Os, 會有 list 1 的錯誤。
看到以下錯誤免著驚, 這是藥氣等待行, cfront 其實已經編譯出來了。
g++ -o cfront Bits.o alloc.o block.o dcl.o dcl2.o dcl3.o dcl4.o del.o discrim.o error.o expand.o expr.o expr2.o expr3.o find.o hash.o lalex.o lex.o main.o norm.o norm2.o print.o print2.o repr.o simpl.o simpl2.o size.o table.o template.o tree_copy.o tree_walk.o typ.o typ2.o y.tab.o _stdio.o
Makefile:23: recipe for target 'cfront' failed
make: [cfront] Error 1 (ignored)
cp cfront ..
cfront 編好了。
[munch]
使用 cfront 編譯時, 需要用到的一個叫 munch 的工具程式。
gcc -o munch _munch/munch.c
這麼簡單, 不需要說明, 這是 .c 不用出動 cfront。
[libC.a]
cd lib/mk
make CC=gcc CCFLAGS="-Os -I../../incl-master/incl-linux32/"
不建議用 gcc 編譯 libC.a。 建議用 cfront 編譯, 不過先要編出 cfront 才行, CC3 就會使用 cfront 來編譯。後面會提到怎麼使用 cfront 編譯出一個可以執行的檔案, 這邊的 libC.a 就需要用 cfront 來編譯, 否則會有奇怪的 link 錯誤。
編出 cfront 之後 (需要複製到 cfront-3 目錄下), 在 cfront-3 目錄下打 make libC.a 即可。
建議使用 cfront 編譯 libC, 避免出現奇怪的錯誤 (因為這樣, 出現很多靈異現象讓我找了老半天)。
cd pt
make CC=gcc
pt 目錄有一些工具程式是編譯用到 string class 的時候會用到的。
ref: cfront-3/demo/string/
string class 我沒成功編譯出來。
也可以用 cfront 編譯 cfront 自己, 不過先要編出 cfront 才行, CC3 就會使用 cfront 來編譯, 不過有些問題, 得手動修改, 我懶的改, 沒成功用 cfront 編譯 cfront 自己。
終於 build 出來了, 執行一下, 感動阿!
用 cfont 編譯 demo/hello/hello.C
有點難度, 步驟如下:
cp hello.C incl-master/incl-linux32
gcc -I. -E hello.C > hh.c
../../cfront < hh.c > h3.c
有沒很感動, 輸出一個 c 的 c++ 程式, bjarne 有你的。
只有這樣還不能滿足吧, 希望可以讓這個 c 檔案透過 gcc 編譯出可執行檔案, 這就會需要那個 libC.a 了, cout 在 libC.a 中。
上面那個是我自己亂試的, 後來我參考了 cfront-3/demo/hello/hello.sh, 知道整個使用 cfront 的編譯步驟。
我們來看看怎麼編譯在平常不過的 hello world c++ 程式。
在 cfront-3 目錄中執行:
cpp -Iincl-master/incl-linux32/ hello.C > hello.i # 處理 header files
./cfront +a1 +L +fhello.C < hello.i > hello..c # 將 cpp 檔 (.C) 轉成 .c 檔
gcc hello..c ./libC.a -o hello.tmp # 不知道
nm hello.tmp | ./munch > hello.cdts..c # 不知道
gcc hello..c hello.cdts..c ./libC.a -o hello # 輸出可執行檔
./hello # 執行
看到印出來的 Hello, World 真是感動。
後來我測試了, template function, class template 都沒有問題。
用 cfront 編譯 cfront 時, alloc.C 遇到的問題:
CC3 L608
eval 'gcc -Du3b -U__GNUC__ -D__cfront__ -D__cplusplus=1 -D__signed__= -D__null=0 -E' ' -I../incl-master/incl-linux32/ -D__CFRONT_ANSI_OPT' '-Dc_plusplus=1' '-D__cplusplus=1' '' ' -I/media/work/git/cfront-3/incl' 'alloc.C' \>/media/work/git/cfront-3/tmpdir/CC.25638/cpptmp
用 llvm 也可以作到 c++ 轉 c code, 參考
Can I use LLVM to convert C++ code to C code? 不過要 3.1 版才能用, 我的系統最低是 3.6。
不過 llvm 用的方式是先轉成 .bc 再將 .bc 轉成 c, 其實和 cfront 不太一樣。
ref:
[LLVMdev] How to enable cbe as a supported target?
至於很常用到的 vector, 這個版本付的 vector 用法和 std::vector 的用法很不同:
demo/generic/Vector.C
vectordeclare(int)
vectordeclare(float)
vectorimplement(int)
vectorimplement(float)
vector(int) iv(VectorSize);
看起來很類似 macro 的用法, 而不是 class template 的用法, 後來將我那個 myvec.h 修改一下, 可以用在 cfront。
是可以用的。
ref:
另外一個 cfront 版本
release 1.0:
http://www.softwarepreservation.org/projects/c_plus_plus/cfront/release_1.0/src/cfront.tar.gz/view
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。