`
mjun2001
  • 浏览: 9179 次
  • 性别: Icon_minigender_1
  • 来自: 宁夏
文章分类
社区版块
存档分类
最新评论

Dmd编译器学习笔记

阅读更多
Dmd编译器学习笔记

英文原文在这里:
http://digitalmars.com/d/dcompiler.html
在这里有一篇翻译文章:
http://sofire.iteye.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的安装


  1. 下载dmd程序:http://ftp.digitalmars.com/dmd.zip,解压到~/dmd目录
  2. 复制dmd.conf文件到/etc目录
    代码
    1. cp ~/dmd/bin/dmd.conf /etc   
    <script>render_code();</script>
  3. 给下面的文件添加执行权限
    代码
    1. chmod u+x ~/dmd/bin/{dmd,dumpobj,obj2asm,rdmd}   
    <script>render_code();</script>
  4. 把~/dmd/bin添加到PATH环境变量;或者把它们复制到/usr/local/bin目录下(不要只复制可执行程序)
  5. 复制库文件到/usr/lib目录
    代码
    1. cp ~/dmd/lib/libphobos.a /usr/lib   
    <script>render_code();</script>

 

以上安装过程比较简单,只有PATH环境变量设置正确了,就应该没有什么问题

编译参数和开关
命令的格式:

代码
  1. dmd   files...  -switches...    
<script>render_code();</script>
[Windows]支持以下类型的文件:
代码
  1. Extension      File Type     
  2. none           D source files     
  3. .d             D source files     
  4. .di            D interface files     
  5. .obj           Object files to link in     
  6. .lib           Object code libraries to search     
  7. .exe           Name output executable file     
  8. .def           module definition file     
  9. .res           resource file     
<script>render_code();</script>
[Linux]支持以下类型的文件:
代码
  1. Extension      File Type   
  2. none           D source files   
  3. .d             D source files   
  4. .di            D interface files   
  5. .o             Object files to link in   
  6. .a             Library files to link in   
<script>render_code();</script>
好像不支持.so文件--这一点不肯定

 

编译开关之一

代码
  1. -debug   
  2.     编译调试代码   
  3.   
  4. -debug=level   
  5.     编译调试代码:code <= level   
  6.   
  7. -debug=ident   
  8.     编译调试代码:标识符为ident   
  9.   
  10. -version=level   
  11.     生成版本代码:>=level   
  12.   
  13. -version=ident   
  14.     生成版本代码:==ident   
  15.        
  16. -unittest   
  17.     编译单元测试代码(还有断言)   
  18.   
  19. -cov   
  20.     添加覆盖率分析指令;运行程序后,会生成.lst文件   
  21.   
  22. -release   
  23.     生成发行版本;会去掉契约和断言等信息   
<script>render_code();</script>

 

-debug / -version
debug、version的使用方法很相似

代码
  1. //debug.d   
  2. import std.stdio;   
  3.   
  4. void main()   
  5. {   
  6.     debug    { writefln("debug"); }   
  7.     debug(1) { writefln("debug(1)"); }   
  8.     debug(2) { writefln("debug(2)"); }   
  9.   
  10.     debug(ERROR) { writefln("debug(ERROR)"); }   
  11.     debug(WARN)  { writefln("debug(WARN)"); }   
  12.   
  13.     version(HOME)      { writefln("version(HOME)"); }   
  14.     version(BUSINESS)  { writefln("version(BUSINESS)"); }   
  15.   
  16.     version(WINDOWS) {} else { writefln("version(!WINDOWS)"); }   
  17. }   
<script>render_code();</script>
编译并运行之:
代码
  1. # dmd -debug -run debug.d   
  2. debug   
  3. debug(1)   
  4. version(!WINDOWS)   
  5.   
  6. # dmd -debug=1 -run debug.d   
  7. debug   
  8. debug(1)   
  9. version(!WINDOWS)   
  10.   
  11. # dmd -debug=2 -run debug.d   
  12. debug   
  13. debug(1)   
  14. debug(2)   
  15. version(!WINDOWS)   
  16.   
  17. # dmd -debug=ERROR -run debug.d   
  18. debug(ERROR)   
  19. version(!WINDOWS)   
  20.   
  21. # dmd -debug=WARN -run debug.d   
  22. debug(WARN)   
  23. version(!WINDOWS)   
  24.   
  25. # dmd -version=HOME -run debug.d   
  26. version(HOME)   
  27. version(!WINDOWS)   
  28.   
  29. # dmd -version=BUSINESS -version=WINDOWS -run debug.d   
  30. version(BUSINESS)   
<script>render_code();</script>

 

-unittest

代码
  1. //unittest.d   
  2. import std.stdio;   
  3.   
  4. class A   
  5. {   
  6.     int i;   
  7.     this(int v) {   
  8.         i = v;   
  9.     }      
  10.   
  11.     unittest {   
  12.         A a = new A(1);   
  13.         assert(a.i == 1);    
  14.         assert(a.i != 0);    
  15.     }      
  16. }   
  17.   
  18. int add(int a, int b)   
  19. {   
  20.     return a - b;   
  21.     // 这里没有unittest   
  22. }   
  23.   
  24. void main()   
  25. {   
  26.     // 这里没有unittest   
  27. }   
  28.   
  29. unittest {   
  30.     assert(add(12) == 3);    
  31. }   
<script>render_code();</script>
先正常编译,没有语法错误:
代码
  1. # dmd -run unittest.d   
<script>render_code();</script>
再编译单元测试代码
代码
  1. # dmd -unittest -run unittest.d    
  2. Error: AssertError Failure unittest(30)   
<script>render_code();</script>
30行有错误?add函数写错了:(

 

-cov
看看覆盖率分析选项:

代码
  1. //cov.d   
  2. import std.stdio;   
  3.   
  4. void main()   
  5. {   
  6.     for (int i; i < 2; i++)   
  7.     {   
  8.         if (i < 5)   
  9.             writefln("i < 5");   
  10.         else  
  11.             writefln("i >= 5");   
  12.     }   
  13. }   
<script>render_code();</script>
编译并运行:
代码
  1. # dmd -cov -run cov.d   
  2. i < 5  
  3. i < 5  
<script>render_code();</script>
得到覆盖率分析文件:cov.lst:(注意:编译完并不会有这个文件;运行程序后才会生成)
代码
  1.        |//cov.d   
  2.        |import std.stdio;   
  3.        |   
  4.        |void main()   
  5.        |{   
  6.       6|    for (int i; i < 2; i++)   
  7.        |    {   
  8.       2|        if (i < 5)   
  9.       2|            writefln("i < 5");   
  10.        |        else  
  11. 0000000|            writefln("i >= 5");   
  12.        |    }   
  13.        |}   
  14. cov.d is 75% covered   
<script>render_code();</script>
第6行运行了6次--自己算算是不是;
第11行运行了0次--搜索000000字符串,就能轻松找到没有覆盖到地方;
更多详情参考:http://digitalmars.com/d/code_coverage.html

 

-release
用法很简单,不举例了

编译开关之二

代码
  1. -D   
  2.     生成文档   
  3.   
  4. -Dddocdir   
  5.     把文档生成到docdir目录;注意是 -Dd   
  6.        
  7. -Dffilename   
  8.     指定文档的文件名;   
<script>render_code();</script>
编译命令很简单:
代码
  1. dmd -D debug.d   
<script>render_code();</script>
关于文档的更多信息参考:http://sofire.iteye.com/blog/111881

 

编译开关之三

代码
  1. -H   
  2.     生成.di接口文件   
  3.   
  4. -Hddir   
  5.     把接口文件生成到dir目录;注意是 -Hd   
  6.   
  7. -Hffilename   
  8.     指定接口文件名;注意是 -Hf   
<script>render_code();</script>
关于接口,看一段翻译:
当处理源文件中的import声明时,编译器会搜索import对应的源文件,从中提取出需要的信息。
编译器同时也会搜索D接口文件,D接口文件中只包含模块中需要导入的内容,而不是整个模块。
使用D接口文件的好处是:

    D接口文件更小,和D源文件相比处理起来更快。
    可以隐藏源代码。比如以接口文件和object库的方式提供源程序,而不是提供全部源代码。

D接口文件可以在编译D源文件时用-H开关创建,D接口文件的后缀是.di。
当编译器分解import声明时,搜索寻找.di形式的D接口文件,再寻找D源文件。
D接口文件有点和C++头文件相似,但这不是必需的,它不属于D语言,只是编译器的一个功能,只是用来优化程序的构建。

dmd -H生成的接口文件包括了源代码;只是去掉了注释,断言等信息;具体怎么回事,待弄明白了再来改这里(TODO)

 

编译开关之四

代码
  1. -c   
  2.     只编译,不链接;简单点说就是只生成.o文件,不生成可执行文件   
  3.   
  4. -Ipath   
  5.     指定import路径;多个路径之间用分号(;)分割;允许有多个-I,并按照-I指定的路径顺序进行搜索   
  6.   
  7. -Jpath   
  8.     指定D源程序中import表达式的搜索路径;多个路径之间用分号(;)分割;   
  9.     允许有多个-J,并按照-J指定的路径顺序进行搜索   
  10.   
  11. -Llinkerflag   
  12.      把linkerflag传递给连接程序(linker),比如: -L-L/usr/lib   
  13.   
  14. -o-   
  15.     不生成.o文件,一般和-H、-D一起使用   
  16.   
  17. -offilename   
  18.     指定输出文件名;可以是可执行程序,也可以是其他文件;注意是:-of   
  19.   
  20. -odobjdir   
  21.     把.o文件生成到objdir目录;默认是生成到当前目录;注意是:-od   
  22.   
  23. -op   
  24.     默认生成的object文件(.o)会在当前目录;添加-op参数则会生成到源文件所在目录   
<script>render_code();</script>

 

-c

代码
  1. dmd debug.d     # 生成debug可执行文件   
  2. dmd -c debug.d  # 生成debug.o文件   
<script>render_code();</script>
dmd编译器默认是编译成.o文件后,再和其他库连接成可执行文件;
某些情况下不需要编译成可执行文件,比如没有main函数--也编译不成
这时就可以只编译成.o文件

 

bud等程序build工具,可以自动判断文件是否有main函数,并生成相应的文件;
但dmd编译器不是这样的;所以,熟悉了dmd编译器后,可以只使用bud等工具来编译程序

-I / -J

代码
  1. import std.stdio;               // -I   
  2. void main()   
  3. {   
  4.     auto b = import("x.d");     // -J   
  5. }   
<script>render_code();</script>

 

自己体会它们的用途吧:)
注意:如果在搜索路径下有同名文件的话,可能出现奇怪的问题;避免出现这种情况,或者改变参数的顺序

-Llinkerflag
一般是-L-L 和 -L-l参数,指定lib路径和库文件
比如:-L-L/usr/local/lib -L-lsqlite3
对linker不熟悉,回头在详细写这块

-o-
如果只想生成文档,连.o文件都不想要;则-o- 就是你想要的了

-offilename
默认情况下,是根据源文件名来确定后续文件的文件名;
比如foo.d 会生成 foo.ofoo 文件;
通过-of参数可以改变输出文件的名字:
dmd -ofbar.exe foo.d

它不会自动添加后缀:
dmd -c -ofbar foo.d
生成文件是 bar,而不是bar.o,这可能不是你想要的

-odobjdir -op
.o文件默认生成在当前目录下;
-od 是指定生成目录,-od.和默认相同
-op 是把.o生成到源文件所在目录
具体生成到什么目录下,就看自己的爱好了;
喜欢干净,就用-od吧;对了,-run参数能生成更干净的代码;)

编译开关之五

代码
  1. -O   
  2.     优化生成的代码,使程序运行得更快   
  3.   
  4. -g   
  5.     添加调试信息   
  6.   
  7. -gc   
  8.     添加C风格的调试信息(为旧的gdb)   
  9.   
  10. -inline   
  11.     用内联函数的方式进行优化;相当于C的inline   
  12.   
  13. -fPIC   
  14.     生成位置无关代码   
  15.   
  16. -d   
  17.     允许废弃的特征   
  18.   
  19. -profile   
  20.     profile the runtime performance of the generated code    
  21.     参见:http://www.digitalmars.com/ctg/trace.html   
<script>render_code();</script>

 

这几个参数,要么很简单,要么不懂含义;也懒得去研究具体的意思了。
其中的-g参数涉及到使用调试器;我喜欢用writefln调试;唉,回头再研究吧。

编译开关之六

代码
  1. --help   
  2.     打印帮助   
  3.   
  4. -quiet   
  5.     安静模式,不输出无关紧要的信息   
  6.   
  7. -v   
  8.     显示编译细节   
  9.   
  10. -w   
  11.     显示编译警告   
<script>render_code();</script>

 

编译开关之七

代码
  1. -run srcfile args...   
  2.     编译,链接,然后运行程序srcfile;args...(到命令行结束)都是程序的参数;   
  3.     它不会保留.o和可执行程序(No .o or executable file is left behind)   
<script>render_code();</script>

 

文章开始就有怎么使用的例子
需要注意的是参数的顺序,因为很多写法都是错误的,正确的是:

代码
  1. dmd 相关文件 编译开关 -run 含main的源文件 程序参数1 程序参数2  
<script>render_code();</script>
各种参数放在-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会按照下面的目录顺序查找


  1. 当前工作目录
  2. 环境变量HOME指定的目录
  3. dmd命令所在目录,即bin目录
  4. /etc目录

 

dmd.conf的内容看起来像这样:

代码
  1. ; dmd.conf 是dmd的配置文件   
  2. ; 分号是注释符号   
  3. ; %%包含的名字会用相应的环境变量替换   
  4. ; %@P%会被本文件的路径替换,即dmd.conf文件所在路径   
  5. [Environment]   
  6. DFLAGS="-I%@P%/../src/phobos"  
  7. DDOCFILE=candydoc/proj.ddoc   
<script>render_code();</script>

 

格式是 NAME=value;NAME即使是小写,也会被处理成大写;
里面的DFLAGS的值会覆盖环境变量指定的值

和Windows版本的区别


  • 字符串文章量是只读的;对它写会导致段错误

     

     

  • 配置文件是dmd.conf,而不是sc.ini
  • Windows有一个@cmdfile开关
  • Windows有一个-nofloat开关

     

     

  • 环境变量上有些不一样

 

总结:
和gcc比起来,参数少多了 ;)
虽然可以用bud进行编译,但理解dmd还是必要的。
反正也不复杂,花点时间学习一下还算值得。

分享到:
评论

相关推荐

    编译器源代码之:DMD(D语言)dmd.2.026

    DMD的源代码不仅对于编译器开发者具有学习价值,也为D语言的爱好者和实践者提供了深入研究语言实现的机会。通过阅读和理解DMD的源代码,开发者可以学习到编译原理的实际应用,了解语言特性的底层实现,这对于提升...

    D语言编程参考手册 2.036-3.1.pdf

    - **rdmd**:除了传统的编译器之外,D语言还提供了rdmd工具,这是一个用于实时预览和执行D语言代码的工具,非常适合快速测试代码片段或学习新的语言特性。 #### 四、示例代码分析 D语言中有一段经典的筛法算法示例...

    dmd:dmd D编程语言编译器

    DMD:D编程语言编译器详解 DMD(D Mangle Daemon)是D编程语言的主要官方编译器,由Walter Bright创建并维护。...通过学习和使用DMD,不仅可以掌握D语言,还能深入理解编译器的工作原理,提升软件开发技能。

    DMD.zip_DMD_DMD模态_dmd特征值_selectps3_动态模态分解

    动态模态分解(Dynamic Mode Decomposition,简称DMD)是一种数据驱动的方法,广泛应用于流体动力学、信号处理和工程领域,用于分析复杂系统的行为。在这个“DMD.zip”压缩包中,包含的是一个关于DMD应用的具体实例...

    DMD-code_matlab_DMD_

    动态模态分解(Dynamic Mode Decomposition,简称DMD)是一种数据驱动的分析方法,主要用于处理时间序列数据,特别是...通过深入学习和比较这些代码,我们可以更好地理解DMD的原理,并能够根据具体需求进行定制和优化。

    esdl:电子系统描述语言

    并且由于该语言是基于D编程语言构建的,因此您需要最新版本的DMD编译器来编译Vlang源文件。 ESDL与2.081或更高版本的DMD编译器一起使用。 可以从页面下载DMD编译器。 目前,Vlang仅在64位Linux计算机上进行了测试。

    DMD2-master_DMD_

    【DMD2-master_DMD_】是一个与动态模式分解(DMD, Dynamic Mode Decomposition)相关的源代码库。...通过学习和应用DMD2-master,不仅可以掌握DMD算法的实现细节,还可以进一步提升在动态系统建模和预测方面的能力。

    DMD.rar_DMD 代码_dmd matlab程序_dmd分解_matlab dmd_分解

    动态模式分解的matlab 代码,有注释

    DMD2-master_DMD_源码.zip

    DMD2,全称 Digital Mars D Compiler,是D语言的主要编译器之一,由Walter Bright创建并维护。DMD2源码包含了编译器的...如果你对编译器技术感兴趣,或者想要深入D语言的底层机制,DMD2源码无疑是一个绝佳的学习材料。

    DMD.zip_DMD_DMD时间积分_dmd 编程_dmd编程

    通过深入学习这些资料,开发者可以熟练掌握DMD编程技巧,从而在实际项目中发挥DMD的优势,创造出高质量的投影效果。 总的来说,DMD编程涉及多个方面,包括时间积分、帧频和画面大小等关键参数的设定。理解和熟练...

    POD_DMD-master.zip_CFD_DMD_POD_模态分析_降阶

    在本资源"POD_DMD-master.zip"中,包含的是一套针对CFD数据进行处理和分析的方法,主要涉及两种关键的技术:主成分分析(PCA,Principal Component Analysis)也称为POD( Proper Orthogonal Decomposition)和动态...

    PODandDMD_本征正交分解_动模态分解_POD和DMD_

    标题中的“PODandDMD”指的是两种在流体力学和信号处理领域广泛使用的数据分析方法:本征正交分解( Proper Orthogonal Decomposition,简称POD)和动态模态分解(Dynamic Mode Decomposition,简称DMD)。...

    乐创自动化 DMD403及DMD403A步进电机细分驱动器使用手册.pdf

    乐创自动化生产的DMD403及DMD403A步进电机驱动器是一款高性能、价格低廉的产品,适合于驱动两相或四相的混合式步进电机。该驱动器采用了双极性恒流斩波技术,能较其他驱动方式输出更大的功率。同时,它还具有细分...

    DMD402及DMD402A-B使用手册.pdf

    DMD402及DMD402A-B使用手册pdf,DMD402及DMD402A-B使用手册

    DMD15/DMD15L

    ### 一、DMD15/DMD15L卫星调制解调器概述 **标题**: DMD15/DMD15L **描述**: 该设备为一种卫星调制解调器(Satellite Modem),型号为DMD15/DMD15L,适用于IBS/IDR通用系统。它提供了安装与操作手册(Installation...

    DFL for DMD2.031

    在本篇文章中,我们将探讨DFL的最新版本——DFL for DMD2.031,以及它如何与DMD(D语言的官方编译器)的这一特定版本相结合,提升开发体验。 首先,我们需要了解DMD2.031。DMD是D语言的主要编译器,由Walter Bright...

    Schematic-FLD3 DMD Board.pdf

    根据提供的文档信息,我们可以提取出以下有关DMD(Digital Micromirror Device)板的相关知识点,主要用于DLP(Digital Light Processing)技术,该技术是由TI(德州仪器)公司开发的。 首先,DMD板是DLP系统中的...

Global site tag (gtag.js) - Google Analytics