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