码迷,mamicode.com
首页 > 其他好文 > 详细

【学习记录】关于makefile而进行的互联网学习技巧练习及学习笔记和学习心得记录(vs2010)

时间:2015-11-13 00:51:37      阅读:324      评论:0      收藏:0      [点我收藏+]

标签:

我也不知道作为一个完全的windows平台下的不怎么专业的软件工程学生,看到《Accelerated C++》的源代码,第一反应是:哦!我应该用make生成工程文件。然后我愉快的用AOL开始搜索相关资料。

然并卵!我一定是被什么奇怪的生物附身了。我应该直接用vs创建项目->导入文件。然后……ctrl+F5。多么完美。

可是……以下:

 

【教程】来自于云风大大的blog(云风的 BLOG)

IDE 不是程序员的唯一选择(一)

以及后面的(二)(三)(四)

 

以及大大写了一篇半,只为了说明用cl来编译和链接程序的步骤做引出make工具的引子。我……【手动面无表情

其实我猜想应该是大大突发奇想写一篇如何用cl命令来编译程序,给那些好奇心重,不按常理出牌,然并卵并没有很屌的学习能力的新手一些引导。然后……就一发不可收拾了。所以才会有这么诡异的篇幅结构?好吧我承认这只是我的脑补,最近越来越觉得做程序员好寂寞的,机器不会跟我说话。每次它跟我说话的时候就是我的代码有问题的时候了><,以及我确实是已经点亮在无聊环境下可以靠着哼歌和自我脑补完美调节心情的技能。当然以上都是废话。

 

相关错误以及修正方法在后续文章中说明。下面,let‘s jump.噢,入了奇怪的戏,下面是我的学习记录。

 

【part.1】vs2010自带的cl进行编译链接工作以及路径设置和问题解决


步骤记录:

命令行(win+R,输入cmd空格召唤)模式下,输入

cl foo.c

系统会生成foo.obj,foo.exe两个文件,编译原理的老师说,程序生成是先编译,再链接的过程。如果没记错编译是生成中间代码形式,貌似是汇编?然后再链接生成二进制程序,也就是exe,executive的缩写,如果我没拼错。嗯。记错或者拼错求不打脸QAQ。

云风大大说,cl这个命令就是给编译,链接这个过程加个壳,或者我们应该时髦一点说,封装一下?

嗯,如果提示你任何错误,请先检查你的foo.c是否存在。

以下是错误记录

  1. 输入cl提示缺少mspdb.dll错误。
  2. 输入命令后提示iostream:缺少文件支持
  3. 输入命令后提示无法打开文件“kernel32.dll”

相关的解决方法链接在问题上。

当然你可能会因为然并卵我的室友在玩游戏/用迅雷我的网速是豆腐渣并不想跳转,当然也许你跳转了之后发现太长不看。好吧,下面是……我的解决方法。

  1. 云风大大的解决方法是运行:VS安装目录/Common7\Tools\vsvars32.bat(或者vsvarsll.bat)  脚本,会设置vs运行需要的环境变量。我用的是在环境变量path中加入: VS安装目录\Common7\IDE。(环境变量使用 我的电脑(右键)-> 属性 -> 高级系统设置 ->环境变量 打开)
  2. 环境变量总新建LIB和INCLUDE变量,(LIB)C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib;C:/Program Files/Microsoft SDKs/Windows/v5.0/Lib;VS安装目录/VC/lib    (INCLUDE)VS安装目录/VC/include(说好的vsvarsall.bat解决所有问题呢!!!)
  3. 将  C:\Program Files\Microsoft SDKs\Windows\v7.0A\Lib  目录下的  kernel32.lib  拷贝到  VS安装目录\VC\lib目录 下。
cl foo.c bar.c // 多文件链接生成,默认生成EXE名称为第一个源文件名称

  

cl /Fefoobar foo.c bar.c // 生成foobar.exe,/Fe和foobar之间没有空格。

 

cl /Fefoobar foo.obj bar.obj
link /out:foobar.exe foo.obj bar.obj // 二者等价

调试:

cl /Zi foo.c

接下来,云风将传授一门关于调试的独门秘籍。

知道调试器是如何实现断点这个功能的吗?其实它偷偷的在你的程序要设置断点的位置放置了一条调试中断指令。在 x86 32 位系统上,这是一条单字节指令,汇编代码是 int 3 。cpu 运行程序的时候,碰到 int 3 就会把控制权交给调试器,当你在调试器中选择继续运行的时候,调试器再将被替换的程序机器指令换回去,让程序继续运行。

知道了这个细节,我们就可以自己提前设置调试断点了。我称它为硬断点。只要程序运行到,就一定会停下来。如果你想在运行期屏蔽硬断点,需要在源码上做一些工作了。

现在在你刚才的 foo.c 的程序入口处加一行 __asm int 3 ( 如果你在用 gcc 可以加 asm ("int $3"); ) 重新用 cl /Zi foo.c 编译一次。然后在命令行直接运行 foo.exe 。

马上,你将会看到一个熟悉的关于程序崩溃的对话框。没关系,它是由你插入的硬断点 (int 3) 造成的。如果你正确安装了 vs ,vs 应该已经把自己设置成系统默认的调试器了。点对话框上的按钮,便将启动 vs 的 ide ,我们会发现程序正好停在了 int 3 那行汇编的地方。现在你可以尽情的单步跟踪了。

http://blog.codingnow.com/2008/09/replacement_of_ide_1.html

其实就是报错->vs调试,然而vs调试用的并不熟练……。 

 

【part2】make工具


 云风大大推荐使用MinGW的gmake。关键字 MinGW GNU make

编程之道在于,让机器做机器的事,人专注于人的思考。如果真的靠手键入每条编译指令,无疑让程序员去做了机器之事。把编译指令写入批处理(脚本)文件,仅仅只是节省了每次编译的重复劳动,并没有从根本上解脱。

在从 C 的源代码构建最终的执行文件这个流程中,哪些是人的创造,哪些是机器应行之事?显而易见,程序员应该做的是:

  1. 教会机器,如何把一个 .c 文件编译成 .obj 文件。

  2. 教会机器,如何把若干个 .obj 文件链接成 .exe 文件。

  3. 告诉机器,你的项目由那些 .c 文件构成,最终你想生成一个叫什么名字的 .exe 文件。

其中前两步,对于大多数类似的项目来说是共同的,所以我们只用也只应该教机器一次。而第三步,提供一个文件列表和一个目标文件名给机器即可。

 编写makefile

all :// 必须以all开头
    echo Hello World            // 行前必须是一个tab

  

然后gmake,over。

我的gmake默认只执行第一个命令,即只执行echo Hello World。如果要执行后面的foobar.exe,必须使用gmake foobar.exe。

 

上一篇开篇,我们讲到了,如何用命令行分开编译 .c 文件,并把它们链接起来。这样做,可以使每次修改都可以让机器做最少的编译任务。对于小工程,这样做的意义不大。但是大工程,可能就能帮我们节约不少时间了。记住这一点,永远没有通用的最优方案。因为实施方案本身也是有成本的。我们只需要找到最直接最简单的方法就可以了。比如项目一开始,可以写一个最简单的 Makefile 文件,随着项目规模的扩大再逐步完善。

分开编译再链接这件事,人做起来都比较繁琐,把它教给机器去做,当然也会更繁琐。所以我没有在上一篇中详解。好学的同学应该会自己弄了,今天,我也来写写自己的方案。但在此之前,我们先梳理一下对 Make 的理解。

Make 是一个工作于非常简单的模式下的工具。它的内部有一张表,记录了目标文件之间的依赖关系。Makefile 就是用来描述这张依赖关系表的。对于依赖关系表的描述,用了一种非常简单的语法:

目标 : 依赖

这表示,"目标" 的构建依赖于 "依赖" 先构建出来。这里,"目标" 和 "依赖" 都是文件系统中的文件,而"依赖"本身也可以是一个"目标"。如果 "依赖" 的文件时间新于 "目标" 的文件时间,表示 "目标" 需要重新构建。如果 "目标" 文件不存在,也会触发这种构建过程。

一个目标可以有多个依赖,可以在 : 后以空格分开写上多个,比如:

目标 : 依赖1 依赖2 依赖3

这在我们前一篇中已经多次见过了。其实还有另一个规则,我们可以写:

目标 : 依赖1

目标 : 依赖2

这样分两行写,即,每次写 "目标 : 依赖" 都在依赖关系的依赖关系表中添加了一项。(关于同名的依赖添加的问题,以后我们在讨论)

举个例子:

a : b c

a : b
a : c

其实是等价的。

每个目标的构建方法并不是由 Make 内置功能完成的,Make 只是简单调用写在 "目标" 定义的下一行的若干命令行脚本而已。而每一行命令行脚本必须以 Tab 键开头。

注意,如果你把目标的依赖关系分成若干行实现,只可以有一个地方定义构建脚本。

举例:

all : a
all : b

a :
    echo $@

b :
    echo $@

这样一个 Makefile 用 Make 运行后,会显示:

echo a
a
echo b
b

为什么呢?因为 Make 会找 Makefile 中定义的第一个目标,做为它这次的终极目标。在这里是 all 。all 依赖于 a 和 b 两个目标。由于你的工作目录下没有 a 和 b 两个文件,所以触发了 a 以及 b 的构建。而 a 的构建指令是 echo $@ ,$@ 指代了当前目标 "a" ,结果就执行了 echo a 。同样,b 文件的不存在,导致了 b 的构建,执行了 echo b 。

需要强调的是,echo 并不是 Make 的内置功能。echo 是 Windows 命令行指令(在 *nix 系统上,称为 shell 指令)。Make 只管忠实的执行那些相关的以 Tab 开始行内描述的命令行指令。目标的构建成功也不以目标文件是否正确生成为依据。而是以命令执行的结果是否为 0 。记得学 C 语言的时候,老师教你,main 函数得到正确结果时,应该 return 0 吧。这个 main 的 return 0 就是返回给系统用的。Make 通过检查这个返回值来觉得命令行指令是否被正确的执行。如果收到非 0 的返回值,整个 Make 的过程会被中断。当然,echo 这样的指令,一般都会返回 0 的。

注意,一个目标是否被正确构建,只取决于构建它的命令行指令是否正确的返回 0 ,而不取决于文件是否被创建出来或是被更新到最新的时间。在一次构建中,每个目标最多只会被构建一次。这是由于 Make 只对依赖关系表做一次简单的拓扑排序,然后就开始工作了。

同样,我们还可以让多个目标依赖同样的东西:

a b : c d

就等价于

a : c d
b : c d

现在我们可以看到,在 Makefile 里写 : 定义,其实就是在填写一张依赖关系表。每次的一个 : 都向表里追加一些项目。Make 工作的时候,先读完整个文件,把完整的依赖关系表建立好,再根据命令行指定的目标开始工作,如果在命令行不指定目标,默认就是 Makefile 里写的第一个目标了。

这样我们就好理解,除了 Makefile 里的第一个目标定义之外,所有的依赖关系描述都是无所谓书写的先后次序的。Make 只管向依赖关系表里添加表项,不会删除。原则上也不保证按依赖表中的次序先后来构建,如果你需要一个目标一定先于另一个目标构建,就需要显式的描述出依赖关系。

 

http://blog.codingnow.com/2008/09/replacement_of_ide_3.html

 

  

 

 【part3】这理应成为一个神作(zuō)


 在我等MinGW下载的时候,突发奇想为什么不用nmake,然后经过细致的,仔细地,耐心的看完并没有几行的makefile,我觉得我可以尝试以下输入:

nmake test

之后,刷刷刷刷刷刷刷刷刷刷刷刷刷刷刷刷,什么obj,什么exe都出来了。嗯。我想静静。

顺带之前不知道安装了什么自带了cygwin……这酸爽。

看完了其实可以参考这个实践:http://www.cnblogs.com/youngzii/p/3395055.html

 

【学习记录】关于makefile而进行的互联网学习技巧练习及学习笔记和学习心得记录(vs2010)

标签:

原文地址:http://www.cnblogs.com/ma-mama/p/4924429.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!