英文原文在這里:
http://digitalmars.com/d/dcompiler.html
在這里有一篇翻譯文章:
http://sofire.javaeye.com/blog/111667
不過,主要是關于windows的;我更關心Linux下的使用。
順便看看兩者有啥區別。
相關文件
注意:
Linux的dmd配置文件是dmd.conf
Windows的配置文件是sc.ini
- /dmd/bin/dmd D 編譯器的可執行文件
- /dmd/bin/dumpobj Elf file dumper
- /dmd/bin/obj2asm Elf文件反匯編器
- /dmd/bin/dmd.conf 全局配置文件(復制到 /etc/dmd.conf)
- /dmd/lib/libphobos.a D運行庫(復制到 /usr/lib/libphobos.a)
DMD的安裝
[list=1]
- 下載dmd程序:http://ftp.digitalmars.com/dmd.zip,解壓到~/dmd目錄
- 復制dmd.conf文件到/etc目錄
- cp ~/dmd/bin/dmd.conf /etc
- 給下面的文件添加執行權限
- chmod u+x ~/dmd/bin/{dmd,dumpobj,obj2asm,rdmd}
- 把~/dmd/bin添加到PATH環境變量;或者把它們復制到/usr/local/bin目錄下(不要只復制可執行程序)
- 復制庫文件到/usr/lib目錄
- cp ~/dmd/lib/libphobos.a /usr/lib
[/list]
以上安裝過程比較簡單,只有PATH環境變量設置正確了,就應該沒有什么問題
編譯參數和開關
命令的格式:
- dmd files... -switches...
[Windows]支持以下類型的文件:
- Extension File Type
- none D source files
- .d D source files
- .di D interface files
- .obj Object files to link in
- .lib Object code libraries to search
- .exe Name output executable file
- .def module definition file
- .res resource file
[Linux]支持以下類型的文件:
- Extension File Type
- none D source files
- .d D source files
- .di D interface files
- .o Object files to link in
- .a Library files to link in
好像不支持.so文件--這一點不肯定
編譯開關之一
- -debug
- 編譯調試代碼
- -debug=level
- 編譯調試代碼:code <= level
- -debug=ident
- 編譯調試代碼:標識符為ident
- -version=level
- 生成版本代碼:>=level
- -version=ident
- 生成版本代碼:==ident
- -unittest
- 編譯單元測試代碼(還有斷言)
- -cov
- 添加覆蓋率分析指令;運行程序后,會生成.lst文件
- -release
- 生成發行版本;會去掉契約和斷言等信息
-debug / -version
debug、version的使用方法很相似
- //debug.d
- import std.stdio;
- void main()
- {
- debug { writefln("debug"); }
- debug(1) { writefln("debug(1)"); }
- debug(2) { writefln("debug(2)"); }
- debug(ERROR) { writefln("debug(ERROR)"); }
- debug(WARN) { writefln("debug(WARN)"); }
- version(HOME) { writefln("version(HOME)"); }
- version(BUSINESS) { writefln("version(BUSINESS)"); }
- version(WINDOWS) {} else { writefln("version(!WINDOWS)"); }
- }
編譯并運行之:
- # dmd -debug -run debug.d
- debug
- debug(1)
- version(!WINDOWS)
- # dmd -debug=1 -run debug.d
- debug
- debug(1)
- version(!WINDOWS)
- # dmd -debug=2 -run debug.d
- debug
- debug(1)
- debug(2)
- version(!WINDOWS)
- # dmd -debug=ERROR -run debug.d
- debug(ERROR)
- version(!WINDOWS)
- # dmd -debug=WARN -run debug.d
- debug(WARN)
- version(!WINDOWS)
- # dmd -version=HOME -run debug.d
- version(HOME)
- version(!WINDOWS)
- # dmd -version=BUSINESS -version=WINDOWS -run debug.d
- version(BUSINESS)
-unittest
- //unittest.d
- import std.stdio;
- class A
- {
- int i;
- this(int v) {
- i = v;
- }
- unittest {
- A a = new A(1);
- assert(a.i == 1);
- assert(a.i != 0);
- }
- }
- int add(int a, int b)
- {
- return a - b;
- // 這里沒有unittest
- }
- void main()
- {
- // 這里沒有unittest
- }
- unittest {
- assert(add(1, 2) == 3);
- }
先正常編譯,沒有語法錯誤:
- # dmd -run unittest.d
再編譯單元測試代碼
- # dmd -unittest -run unittest.d
- Error: AssertError Failure unittest(30)
30行有錯誤?add函數寫錯了:(
-cov
看看覆蓋率分析選項:
- //cov.d
- import std.stdio;
- void main()
- {
- for (int i; i < 2; i++)
- {
- if (i < 5)
- writefln("i < 5");
- else
- writefln("i >= 5");
- }
- }
編譯并運行:
- # dmd -cov -run cov.d
- i < 5
- i < 5
得到覆蓋率分析文件:cov.lst:(注意:編譯完并不會有這個文件;運行程序后才會生成)
- |//cov.d
- |import std.stdio;
- |
- |void main()
- |{
- 6| for (int i; i < 2; i++)
- | {
- 2| if (i < 5)
- 2| writefln("i < 5");
- | else
- 0000000| writefln("i >= 5");
- | }
- |}
- cov.d is 75% covered
第6行運行了6次--自己算算是不是;
第11行運行了0次--搜索000000字符串,就能輕松找到沒有覆蓋到地方;
更多詳情參考:http://digitalmars.com/d/code_coverage.html
-release
用法很簡單,不舉例了
編譯開關之二
- -D
- 生成文檔
- -Dddocdir
- 把文檔生成到docdir目錄;注意是 -Dd
- -Dffilename
- 指定文檔的文件名;
編譯命令很簡單:
- dmd -D debug.d
關于文檔的更多信息參考:http://sofire.javaeye.com/blog/111881
編譯開關之三
- -H
- 生成.di接口文件
- -Hddir
- 把接口文件生成到dir目錄;注意是 -Hd
- -Hffilename
- 指定接口文件名;注意是 -Hf
關于接口,看一段翻譯:
當處理源文件中的import聲明時,編譯器會搜索import對應的源文件,從中提取出需要的信息。
編譯器同時也會搜索D接口文件,D接口文件中只包含模塊中需要導入的內容,而不是整個模塊。
使用D接口文件的好處是:
D接口文件更小,和D源文件相比處理起來更快。
可以隱藏源代碼。比如以接口文件和object庫的方式提供源程序,而不是提供全部源代碼。
D接口文件可以在編譯D源文件時用-H開關創建,D接口文件的后綴是.di。
當編譯器分解import聲明時,搜索尋找.di形式的D接口文件,再尋找D源文件。
D接口文件有點和C++頭文件相似,但這不是必需的,它不屬于D語言,只是編譯器的一個功能,只是用來優化程序的構建。
dmd -H生成的接口文件包括了源代碼;只是去掉了注釋,斷言等信息;具體怎么回事,待弄明白了再來改這里(TODO)
編譯開關之四
- -c
- 只編譯,不鏈接;簡單點說就是只生成.o文件,不生成可執行文件
- -Ipath
- 指定import路徑;多個路徑之間用分號(;)分割;允許有多個-I,并按照-I指定的路徑順序進行搜索
- -Jpath
- 指定D源程序中import表達式的搜索路徑;多個路徑之間用分號(;)分割;
- 允許有多個-J,并按照-J指定的路徑順序進行搜索
- -Llinkerflag
- 把linkerflag傳遞給連接程序(linker),比如: -L-L/usr/lib
- -o-
- 不生成.o文件,一般和-H、-D一起使用
- -offilename
- 指定輸出文件名;可以是可執行程序,也可以是其他文件;注意是:-of
- -odobjdir
- 把.o文件生成到objdir目錄;默認是生成到當前目錄;注意是:-od
- -op
- 默認生成的object文件(.o)會在當前目錄;添加-op參數則會生成到源文件所在目錄
-c
- dmd debug.d # 生成debug可執行文件
- dmd -c debug.d # 生成debug.o文件
dmd編譯器默認是編譯成.o文件后,再和其他庫連接成可執行文件;
某些情況下不需要編譯成可執行文件,比如沒有main函數--也編譯不成
這時就可以只編譯成.o文件
bud等程序build工具,可以自動判斷文件是否有main函數,并生成相應的文件;
但dmd編譯器不是這樣的;所以,熟悉了dmd編譯器后,可以只使用bud等工具來編譯程序
-I / -J
- import std.stdio; // -I
- void main()
- {
- auto b = import("x.d"); // -J
- }
自己體會它們的用途吧:)
注意:如果在搜索路徑下有同名文件的話,可能出現奇怪的問題;避免出現這種情況,或者改變參數的順序
-Llinkerflag
一般是-L-L 和 -L-l參數,指定lib路徑和庫文件
比如:-L-L/usr/local/lib -L-lsqlite3
對linker不熟悉,回頭在詳細寫這塊
-o-
如果只想生成文檔,連.o文件都不想要;則-o- 就是你想要的了
-offilename
默認情況下,是根據源文件名來確定后續文件的文件名;
比如foo.d 會生成 foo.o 與 foo 文件;
通過-of參數可以改變輸出文件的名字:
dmd -ofbar.exe foo.d
它不會自動添加后綴:
dmd -c -ofbar foo.d
生成文件是 bar,而不是bar.o,這可能不是你想要的
-odobjdir -op
.o文件默認生成在當前目錄下;
-od 是指定生成目錄,-od.和默認相同
-op 是把.o生成到源文件所在目錄
具體生成到什么目錄下,就看自己的愛好了;
喜歡干凈,就用-od吧;對了,-run參數能生成更干凈的代碼;)
編譯開關之五
- -O
- 優化生成的代碼,使程序運行得更快
- -g
- 添加調試信息
- -gc
- 添加C風格的調試信息(為舊的gdb)
- -inline
- 用內聯函數的方式進行優化;相當于C的inline
- -fPIC
- 生成位置無關代碼
- -d
- 允許廢棄的特征
- -profile
- profile the runtime performance of the generated code
- 參見:http://www.digitalmars.com/ctg/trace.html
這幾個參數,要么很簡單,要么不懂含義;也懶得去研究具體的意思了。
其中的-g參數涉及到使用調試器;我喜歡用writefln調試;唉,回頭再研究吧。
編譯開關之六
- --help
- 打印幫助
- -quiet
- 安靜模式,不輸出無關緊要的信息
- -v
- 顯示編譯細節
- -w
- 顯示編譯警告
編譯開關之七
- -run srcfile args...
- 編譯,鏈接,然后運行程序srcfile;args...(到命令行結束)都是程序的參數;
- 它不會保留.o和可執行程序(No .o or executable file is left behind)
文章開始就有怎么使用的例子
需要注意的是參數的順序,因為很多寫法都是錯誤的,正確的是:
- dmd 相關文件 編譯開關 -run 含main的源文件 程序參數1 程序參數2
各種參數放在-run前面,然后是含有main的源程序,再后面的內容會全部傳遞給運行程序,作為參數
鏈接Linking
在dmd編譯成功后,它會再調用連接程序;用-c參數可以不進行連接
連接的實際處理程序其實是gcc;這樣能保證和gcc編譯的模塊兼容
環境變量
CC
默認是用gcc進行連接,可以通過設置CC環境變量,使用其他連接器
DFLAGS
The value of DFLAGS is treated as if it were appended to the command line to dmd.
沒有弄明白它是怎么回事;(
dmd.conf初始化文件
dmd會按照下面的目錄順序查找
- 當前工作目錄
- 環境變量HOME指定的目錄
- dmd命令所在目錄,即bin目錄
- /etc目錄
dmd.conf的內容看起來像這樣:
- ; dmd.conf 是dmd的配置文件
- ; 分號是注釋符號
- ; %%包含的名字會用相應的環境變量替換
- ; %@P%會被本文件的路徑替換,即dmd.conf文件所在路徑
- [Environment]
- DFLAGS="-I%@P%/../src/phobos"
- DDOCFILE=candydoc/proj.ddoc
格式是 NAME=value;NAME即使是小寫,也會被處理成大寫;
里面的DFLAGS的值會覆蓋環境變量指定的值
和Windows版本的區別
- 字符串文章量是只讀的;對它寫會導致段錯誤
- 配置文件是dmd.conf,而不是sc.ini
- Windows有一個@cmdfile開關
- Windows有一個-nofloat開關
- 環境變量上有些不一樣
總結:
和gcc比起來,參數少多了 ;)
雖然可以用bud進行編譯,但理解dmd還是必要的。
反正也不復雜,花點時間學習一下還算值得。
安徽新華電腦學校專業職業規劃師為你提供更多幫助【在線咨詢】