Dmd编译器学习笔记

2024-01-17 07:48
文章标签 学习 笔记 编译器 dmd

本文主要是介绍Dmd编译器学习笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Dmd编译器学习笔记

英文原文在这里:
[url]http://digitalmars.com/d/dcompiler.html[/url]
在这里有一篇翻译文章:
[url]http://sofire.iteye.com/blog/111667[/url]
不过,主要是关于windows的;我更关心Linux下的使用。
顺便看看两者有啥区别。

[size=14][b]相关文件[/b][/size]
注意:
[color=red]
Linux的dmd配置文件是dmd.conf
Windows的配置文件是sc.ini
[/color]

[list]
[*]/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)
[/list]

[size=14][b]DMD的安装[/b][/size]
[list=1]
[*]下载dmd程序:http://ftp.digitalmars.com/dmd.zip,解压到~/dmd目录
[*]复制dmd.conf文件到/etc目录
[code]
cp ~/dmd/bin/dmd.conf /etc
[/code]
[*]给下面的文件添加执行权限
[code]
chmod u+x ~/dmd/bin/{dmd,dumpobj,obj2asm,rdmd}
[/code]
[*]把~/dmd/bin添加到PATH环境变量;或者把它们复制到/usr/local/bin目录下(不要只复制可执行程序)
[*]复制库文件到/usr/lib目录
[code]
cp ~/dmd/lib/libphobos.a /usr/lib
[/code]
[/list]

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

[size=14][b]编译参数和开关[/b][/size]
命令的格式:
[code]
dmd files... -switches...
[/code]
[Windows]支持以下类型的文件:
[code]
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
[/code]
[Linux]支持以下类型的文件:
[code]
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
[/code]
[color=red]好像不支持.so文件--这一点不肯定[/color]

[size=12][b][color=red]编译开关之一[/color][/b][/size]
[code]
-debug
编译调试代码

-debug=level
编译调试代码:code <= level

-debug=ident
编译调试代码:标识符为ident

-version=level
生成版本代码:>=level

-version=ident
生成版本代码:==ident

-unittest
编译单元测试代码(还有断言)

-cov
添加覆盖率分析指令;运行程序后,会生成.lst文件

-release
生成发行版本;会去掉契约和断言等信息
[/code]

[b]-debug / -version[/b]
debug、version的使用方法很相似
[code]
//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)"); }
}
[/code]
编译并运行之:
[code]
# 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)
[/code]

[b]-unittest[/b]
[code]
//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);
}
[/code]
先正常编译,没有语法错误:
[code]
# dmd -run unittest.d
[/code]
再编译单元测试代码
[code]
# dmd -unittest -run unittest.d
Error: AssertError Failure unittest(30)
[/code]
30行有错误?add函数写错了:(

[b]-cov[/b]
看看覆盖率分析选项:
[code]
//cov.d
import std.stdio;

void main()
{
for (int i; i < 2; i++)
{
if (i < 5)
writefln("i < 5");
else
writefln("i >= 5");
}
}
[/code]
编译并运行:
[code]
# dmd -cov -run cov.d
i < 5
i < 5
[/code]
得到覆盖率分析文件:cov.lst:(注意:编译完并不会有这个文件;运行程序后才会生成)
[code]
|//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
[/code]
第6行运行了6次--自己算算是不是;
第11行运行了0次--搜索000000字符串,就能轻松找到没有覆盖到地方;
更多详情参考:[url]http://digitalmars.com/d/code_coverage.html[/url]

[b] -release [/b]
用法很简单,不举例了

[size=12][b][color=red]编译开关之二[/color][/b][/size]
[code]
-D
生成文档

-Dddocdir
把文档生成到docdir目录;注意是 -Dd

-Dffilename
指定文档的文件名;
[/code]
编译命令很简单:
[code]
dmd -D debug.d
[/code]
关于文档的更多信息参考:[url]http://sofire.iteye.com/blog/111881[/url]

[size=12][b][color=red]编译开关之三[/color][/b][/size]
[code]
-H
生成.di接口文件

-Hddir
把接口文件生成到dir目录;注意是 -Hd

-Hffilename
指定接口文件名;注意是 -Hf
[/code]
关于接口,看一段翻译:
当处理源文件中的import声明时,编译器会搜索import对应的源文件,从中提取出需要的信息。
编译器同时也会搜索D接口文件,D接口文件中只包含模块中需要导入的内容,而不是整个模块。
使用D接口文件的好处是:
[list]
D接口文件更小,和D源文件相比处理起来更快。
可以隐藏源代码。比如以接口文件和object库的方式提供源程序,而不是提供全部源代码。
[/list]
D接口文件可以在编译D源文件时用-H开关创建,D接口文件的后缀是.di。
当编译器分解import声明时,搜索寻找.di形式的D接口文件,再寻找D源文件。
D接口文件有点和C++头文件相似,但这不是必需的,它不属于D语言,只是编译器的一个功能,只是用来优化程序的构建。
[color=red]
dmd -H生成的接口文件包括了源代码;只是去掉了注释,断言等信息;具体怎么回事,待弄明白了再来改这里(TODO)
[/color]


[size=12][b][color=red]编译开关之四[/color][/b][/size]
[code]
-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参数则会生成到源文件所在目录
[/code]

[b]-c[/b]
[code]
dmd debug.d # 生成debug可执行文件
dmd -c debug.d # 生成debug.o文件
[/code]
dmd编译器默认是编译成.o文件后,再和其他库连接成可执行文件;
某些情况下不需要编译成可执行文件,比如没有main函数--也编译不成
这时就可以只编译成.o文件

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

[b]-I / -J[/b]
[code]
import std.stdio; // -I
void main()
{
auto b = import("x.d"); // -J
}
[/code]

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

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

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

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

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

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

[size=12][b][color=red]编译开关之五[/color][/b][/size]
[code]
-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
[/code]

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


[size=12][b][color=red]编译开关之六[/color][/b][/size]
[code]
--help
打印帮助

-quiet
安静模式,不输出无关紧要的信息

-v
显示编译细节

-w
显示编译警告
[/code]

[size=12][b][color=red]编译开关之七[/color][/b][/size]
[code]
-run srcfile args...
编译,链接,然后运行程序srcfile;args...(到命令行结束)都是程序的参数;
它不会保留.o和可执行程序(No .o or executable file is left behind)
[/code]

文章开始就有怎么使用的例子
需要注意的是参数的顺序,因为很多写法都是错误的,正确的是:
[code]
dmd 相关文件 编译开关 -run 含main的源文件 程序参数1 程序参数2
[/code]
各种参数放在-run前面,然后是含有main的源程序,再后面的内容会全部传递给运行程序,作为参数

[size=14][b]链接Linking[/b][/size]
在dmd编译成功后,它会再调用连接程序;用-c参数可以不进行连接
连接的实际处理程序其实是gcc;这样能保证和gcc编译的模块兼容


[size=14][b]环境变量[/b][/size]
[b]CC[/b]
默认是用gcc进行连接,可以通过设置CC环境变量,使用其他连接器

[b] DFLAGS [/b]
The value of DFLAGS is treated as if it were appended to the command line to dmd.
没有弄明白它是怎么回事;(

[size=14][b]dmd.conf初始化文件[/b][/size]
dmd会按照下面的目录顺序查找
[list=1]
[*]当前工作目录
[*]环境变量HOME指定的目录
[*]dmd命令所在目录,即bin目录
[*]/etc目录
[/list]

dmd.conf的内容看起来像这样:
[code]
; dmd.conf 是dmd的配置文件
; 分号是注释符号
; %%包含的名字会用相应的环境变量替换
; %@P%会被本文件的路径替换,即dmd.conf文件所在路径
[Environment]
DFLAGS="-I%@P%/../src/phobos"
DDOCFILE=candydoc/proj.ddoc
[/code]

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

[size=14][b]和Windows版本的区别[/b][/size]
[list]
[*] 字符串文章量是只读的;对它写会导致段错误
[color=red][*] 配置文件是dmd.conf,而不是sc.ini[/color]

[*] Windows有一个@cmdfile开关
[*] Windows有一个-nofloat开关

[*] 环境变量上有些不一样
[/list]

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

这篇关于Dmd编译器学习笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/615345

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件