-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
176 lines (87 loc) · 67.7 KB
/
Copy pathatom.xml
File metadata and controls
176 lines (87 loc) · 67.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>EzraRT</title>
<subtitle>小博客</subtitle>
<link href="https://ezrart.github.io/atom.xml" rel="self"/>
<link href="https://ezrart.github.io/"/>
<updated>2023-06-26T15:10:17.000Z</updated>
<id>https://ezrart.github.io/</id>
<author>
<name>EzraRT</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>re:start</title>
<link href="https://ezrart.github.io/2023/06/26/re-start/"/>
<id>https://ezrart.github.io/2023/06/26/re-start/</id>
<published>2023-06-26T15:10:17.000Z</published>
<updated>2023-06-26T15:10:17.000Z</updated>
<content type="html"><![CDATA[<h1 id="计划重新拾起博客-别太怠惰"><a href="#计划重新拾起博客-别太怠惰" class="headerlink" title="计划重新拾起博客 别太怠惰"></a>计划重新拾起博客 别太怠惰</h1>]]></content>
<summary type="html"><h1 id="计划重新拾起博客-别太怠惰"><a href="#计划重新拾起博客-别太怠惰" class="headerlink" title="计划重新拾起博客 别太怠惰"></a>计划重新拾起博客 别太怠惰</h1></summary>
</entry>
<entry>
<title>使用CMake来构建项目</title>
<link href="https://ezrart.github.io/2020/11/21/cmake/"/>
<id>https://ezrart.github.io/2020/11/21/cmake/</id>
<published>2020-11-21T07:46:58.000Z</published>
<updated>2020-11-21T07:46:58.000Z</updated>
<content type="html"><![CDATA[<h1 id="Cmake的使用"><a href="#Cmake的使用" class="headerlink" title="Cmake的使用"></a>Cmake的使用</h1><h2 id="CMake是什么"><a href="#CMake是什么" class="headerlink" title="CMake是什么"></a>CMake是什么</h2><p>Cmake是一种跨平台的项目构建工具,它使用<strong>符合CMake要求的项目</strong>来<strong>生成平台原生的项目</strong>,从而利用平台原生的工具来构建你的项目。</p><p>例如:</p><table><thead><tr><th align="center">平台类型</th><th align="center">生成的项目类型</th></tr></thead><tbody><tr><td align="center">UNIX/LINUX</td><td align="center">Makefile构建的项目</td></tr><tr><td align="center">Windows</td><td align="center">Visual Studio项目</td></tr><tr><td align="center">Mac OS</td><td align="center">XCode项目</td></tr></tbody></table><h2 id="CMake的用法"><a href="#CMake的用法" class="headerlink" title="CMake的用法"></a>CMake的用法</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">cmake [路径] </span><br></pre></td></tr></table></figure><p>即可生成对应的项目,以Linux平台为例,cmake可以为我们制作出Makefile项目,再执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">make</span><br></pre></td></tr></table></figure><p>即可得到我们想要的可执行文件</p><h2 id="CMake构建的项目"><a href="#CMake构建的项目" class="headerlink" title="CMake构建的项目"></a>CMake构建的项目</h2><p>何为CMake构建的项目?CMake构建的项目使用<strong>CMakeLists.txt</strong>文件来描述项目的组织情况,一个CMakeLists.txt应该具有如下要素</p><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION 构建此项目所需的最低cmake版本)</span><br><span class="line"><span class="keyword">project</span>(项目名)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加一个可执行文件</span></span><br><span class="line"><span class="keyword">add_executable</span>(可执行文件名 组成该可执行文件的所有源代码文件名的列表)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加一个静态库</span></span><br><span class="line"><span class="keyword">add_library</span>(库名 STATIC 组成该库的所有源代码文件名的列表)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将两个或多个target[s]链接起来</span></span><br><span class="line"><span class="keyword">target_link_libraries</span>(生成的<span class="keyword">target</span>[可执行文件名/库名] 它所需链接的<span class="keyword">target</span>[s]列表) </span><br></pre></td></tr></table></figure><p>第一句,制定了此项目所需的最低cmake版本,一般地,此版本应设置为<strong>3.0.0</strong>;</p><p>第二句,设定了该项目的名称;</p><p>第三句,设定了一个可执行文件作为target(目标),即此句话的目的是生成该目标,而为了生成该目标,需要对它进行一些描述,一般是指构建它所需的所有源文件名;</p><p>第四句,设定了一个库作为target(目标),即此句话的目的是生成该目标;</p><p>第五句,用于在需要链接外部库或自己定义的库的时候,用于将它们<a href="/2020/11/18/compile/">链接</a>起来。</p><h2 id="一些实例"><a href="#一些实例" class="headerlink" title="一些实例"></a>一些实例</h2><h3 id="HelloWorld"><a href="#HelloWorld" class="headerlink" title="HelloWorld"></a>HelloWorld</h3><p>俗话说得好,不知道写什么的时候就写Hello,World!<del>其实是我说的</del></p><p>项目中文件如下</p><ul> <li>main.c</li> <li>CMakeLists.txt</li></ul><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="comment"># CMakeLists.txt</span></span><br><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.0</span>.<span class="number">0</span>)</span><br><span class="line"><span class="keyword">project</span>(helloworld)</span><br><span class="line"></span><br><span class="line"><span class="keyword">add_executable</span>(hello main.c) </span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// main.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Hello,World!\n"</span>);</span><br><span class="line">} </span><br></pre></td></tr></table></figure><p>再执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="comment"># .代表当前目录,..代表上级目录</span></span><br><span class="line">cmake .</span><br><span class="line">make </span><br></pre></td></tr></table></figure><p>即可得到可执行文件hello了</p><h3 id="多文件项目"><a href="#多文件项目" class="headerlink" title="多文件项目"></a>多文件项目</h3><p>项目中文件如下</p><ul> <li>main.c</li> <li>add.h</li> <li>add.c</li> <li>CMakeLists.txt</li></ul><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="comment"># CMakeLists.txt</span></span><br><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.0</span>.<span class="number">0</span>)</span><br><span class="line"><span class="keyword">project</span>(<span class="keyword">add_test</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">add_executable</span>(add_test_exec main.c add.c) </span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// add.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> __FUNC_H__</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __FUNC_H__</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// __FUNC_H__ </span></span></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// add.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"add.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line">} </span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// main.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"add.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, add(<span class="number">1</span>, <span class="number">2</span>));</span><br><span class="line">} </span><br></pre></td></tr></table></figure><h3 id="库项目"><a href="#库项目" class="headerlink" title="库项目"></a>库项目</h3><p>库是什么?库是程序的一部分,但它不可以直接执行,通常库中包含了库所编写的函数的实现,但并没有main函数,即它不能自己执行,需要别的程序来调用它才能执行。从链接方式上来看,库分为静态库(static)和动态库(dynamic)。</p><p>静态库类似多文件项目中,某源文件编译过程中生成的二进制文件,它保留了函数入口及实现。将在链接后被<strong>包含到</strong>可执行文件中;</p><p>动态库在链接时仅告诉可执行文件一些<strong>函数的信息</strong>,而不告诉它具体的实现,而在运行时,可执行文件会在某些规则下寻找动态库文件并将其载入内存中进行函数调用。</p><p>不难看出,动态库的优点在于节省了可执行文件的体积,而且多个不同的可执行文件可以共享一份动态库文件,从而有效节约硬盘资源。但其也有弊端,比如程序在别的计算机上运行时,可能那台计算机并没有所需的动态库,则需要将动态库也拷贝一份,否则程序将无法执行,而使用静态库的程序只要拷贝一个可执行文件就可以运行了。</p><p>此处我们使用一个静态库项目来举例</p><p>项目中文件如下</p><ul> <li>add.h</li> <li>add.c</li> <li>CMakeLists.txt</li></ul><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="comment"># CMakeLists.txt</span></span><br><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.0</span>.<span class="number">0</span>)</span><br><span class="line"><span class="keyword">project</span>(add)</span><br><span class="line"></span><br><span class="line"><span class="comment"># static是指生成静态库</span></span><br><span class="line"><span class="keyword">add_library</span>(add STATIC add.c) </span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// add.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> __FUNC_H__</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __FUNC_H__</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// __FUNC_H__ </span></span></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// add.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"add.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line">} </span><br></pre></td></tr></table></figure><p>Linux平台下构建得到<strong>libadd.a</strong>文件,a是指archive,译为档案,就是静态库的意思,add是我们生成的库名,通过执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">ar -t ./libadd.a </span><br></pre></td></tr></table></figure><p>可以得到这个档案中所包含的内容,此处为add.c.o,正是我们add.c在编译时产生的二进制文件!也就是称<strong>库与源文件编译过程中生成的二进制文件类似</strong>的原因。</p><p>同理Windows下会得到后缀名为lib的库文件,lib是library的意思。</p><h3 id="使用库的项目"><a href="#使用库的项目" class="headerlink" title="使用库的项目"></a>使用库的项目</h3><p>我们写好了一个库,那就要给别人/自己用啊。如何利用cmake来将库加入自己的项目中呢?</p><p>项目中文件如下</p><ul> <li>add.h</li> <li>main.c</li> <li>libadd.a</li> <li>CMakeLists.txt</li></ul><figure class="highlight cmake"><table><tr><td class="code"><pre><span class="line"><span class="comment"># CMakeLists.txt</span></span><br><span class="line"><span class="keyword">cmake_minimum_required</span>(VERSION <span class="number">3.0</span>.<span class="number">0</span>)</span><br><span class="line"><span class="keyword">project</span>(test_lib_add)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 此处指定了库所在的目录,如果不指定的话,系统会在系统设置的环境变量中遍历寻找</span></span><br><span class="line"><span class="keyword">link_directories</span>(.)</span><br><span class="line"></span><br><span class="line"><span class="keyword">add_executable</span>(test_lib_add main.c)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将add库与测试add的项目链接起来</span></span><br><span class="line"><span class="keyword">target_link_libraries</span>(test_lib_add add) </span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// add.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> __FUNC_H__</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __FUNC_H__</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// __FUNC_H__ </span></span></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">// main.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"add.h"</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span></span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, add(<span class="number">1</span>, <span class="number">2</span>));</span><br><span class="line">} </span><br></pre></td></tr></table></figure><p>想要使用库文件,必须知道我们需要使用的函数的定义,即拥有上例add库的头文件<strong>add.h</strong></p><p>而在链接时需要函数实现,故还需add库生成的<strong>libadd.a</strong>文件</p><p>我们与<a href="#%E5%A4%9A%E6%96%87%E4%BB%B6%E9%A1%B9%E7%9B%AE">多文件项目</a>相比可谓是多此一举,但使用库有什么意义呢?</p><p>答案是隐藏了你的源码。在使用库的项目测试中,无需add.c来告诉编译器add函数如何实现,只是借add.h告诉了编译器:“我有个函数叫add,使用两个int做参数,使用int做返回值,你看着办!” 而编译器会在链接时,尝试找到所有未实现的函数并把它们的定义和其实现(在库文件中)进行关联,从而生成可执行程序。</p><p>而且用户无需考虑你的具体实现,只要调用它即可。现在很多项目都是使用这种方法来提供自己的API(Application Programming Interface,类似于此处的函数定义)的。</p><h3 id="其他实例"><a href="#其他实例" class="headerlink" title="其他实例"></a>其他实例</h3><p>更多实例请看这个<a href="https://github.com/ttroy50/cmake-examples">开源项目</a></p>]]></content>
<summary type="html"><h1 id="Cmake的使用"><a href="#Cmake的使用" class="headerlink" title="Cmake的使用"></a>Cmake的使用</h1><h2 id="CMake是什么"><a href="#CMake是什么" class="head</summary>
<category term="编译工具" scheme="https://ezrart.github.io/categories/%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7/"/>
<category term="C/C++" scheme="https://ezrart.github.io/tags/C-C/"/>
<category term="编译" scheme="https://ezrart.github.io/tags/%E7%BC%96%E8%AF%91/"/>
<category term="cmake" scheme="https://ezrart.github.io/tags/cmake/"/>
</entry>
<entry>
<title>自动化编译流程</title>
<link href="https://ezrart.github.io/2020/11/18/makefile/"/>
<id>https://ezrart.github.io/2020/11/18/makefile/</id>
<published>2020-11-18T14:16:31.000Z</published>
<updated>2020-11-18T14:16:31.000Z</updated>
<content type="html"><![CDATA[<h1 id="自动化编译流程"><a href="#自动化编译流程" class="headerlink" title="自动化编译流程"></a>自动化编译流程</h1><h2 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h2><h3 id="C-x2F-C-语言的编译过程"><a href="#C-x2F-C-语言的编译过程" class="headerlink" title="C/C++语言的编译过程"></a>C/C++语言的编译过程</h3><p>不妨查看<a href="/2020/11/18/compile/">这里</a></p><h2 id="为什么要自动化编译"><a href="#为什么要自动化编译" class="headerlink" title="为什么要自动化编译"></a>为什么要自动化编译</h2><p>用命令行一条指令地执行来编译也未尝不可,但对于大型项目,尤其是较多文件的项目来说,每次编译都要输入一大串命令是不可忍受的,聪明的孩子可能会想到:“那我写一个脚本来执行编译命令不就皆大欢喜了吗?”确实是这样。</p><p>对于一个简单的项目,我们可以编写一个脚本,在其中按顺序设定好编译所需的所有指令,每次编译只要执行它就好了,但如果你更改了其中一个文件,重新编译便要把所有文件重新编译一遍再链接,如果其它文件没有改动,那这不是白白浪费了时间?</p><h2 id="使用makefile来管理我们的编译流程"><a href="#使用makefile来管理我们的编译流程" class="headerlink" title="使用makefile来管理我们的编译流程"></a>使用makefile来管理我们的编译流程</h2><p>makefile是一种特殊的脚本标记语言,它文件名就叫做makefile[或Makefile]</p><p>我们在项目的根部录下创建一个makefile文件</p><p>makefile的语法如下:</p><figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">target1 : dependency1 [dependency2] ...</span><br><span class="line">Command</span><br><span class="line"></span><br><span class="line">target2 : dependency1 [dependency2] ...</span><br><span class="line">Command</span><br><span class="line"></span><br><span class="line">...... </span><br></pre></td></tr></table></figure><p>这是什么意思呢?</p><p>直接举一个例子</p><p>我们有一个多文件的项目,源代码为main.c、add.c、add.h,其中main.c,add.c都include了add.h</p><p>我们编译需要执行的命令有三条</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line"><span class="comment">#编译main.c</span></span><br><span class="line">gcc -c -o main.o ./main.c </span><br><span class="line"><span class="comment">#编译add.c</span></span><br><span class="line">gcc -c -o add.o ./add.c</span><br><span class="line"><span class="comment">#链接得到可执行文件</span></span><br><span class="line">gcc -o main ./main.o ./add.o </span><br></pre></td></tr></table></figure><p>其中第一条命令是得到main.c编译后得到的main.o,其中,main.o就是makefile中的target,而得到main.o所需的依赖为main.c文件,而main.c中引入了add.h头文件,故add.h也是main.o的依赖。所以makfile中,得到main.o所需的标记如下</p><figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">main.o : main.c add.h</span><br><span class="line">gcc -c -o main.o ./main.c</span><br><span class="line"><span class="comment">#注意上一行开头是一个tab符 </span></span><br></pre></td></tr></table></figure><p>同理,得到add.o的标记如下</p><figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">add.o : add.c add.h</span><br><span class="line">gcc -c -o add.o ./add.c</span><br><span class="line"><span class="comment">#注意上一行开头是一个tab符 </span></span><br></pre></td></tr></table></figure><p>而最终想得到的可执行文件main的标记如下</p><figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line"><span class="comment">#使用all来指示target,这是执行make时默认生成的target</span></span><br><span class="line">all : main.o add.o </span><br><span class="line">gcc -o main ./main.o ./add.o</span><br><span class="line"><span class="comment">#注意上一行开头是一个tab符 </span></span><br></pre></td></tr></table></figure><p>将它们写在同一个makefile文件中,便得到了我们所需的makefile文件</p><figure class="highlight makefile"><table><tr><td class="code"><pre><span class="line">all : main.o add.o </span><br><span class="line">gcc -o main ./main.o ./add.o</span><br><span class="line"></span><br><span class="line">main.o : main.c add.h</span><br><span class="line">gcc -c -o main.o ./main.c</span><br><span class="line"></span><br><span class="line">add.o : add.c add.h</span><br><span class="line">gcc -c -o add.o ./add.c </span><br></pre></td></tr></table></figure><p>Windows下安装了gcc之后,有一个make.exe供我们使用,它便是用来解析并执行makefile文件中的命令的程序。(Linux使用make来构建更方便)</p><p>我们在makefile同一目录下执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">make </span><br></pre></td></tr></table></figure><p>短短的四个字,为我们带来了无尽的方便。</p><h2 id="makefile的优势"><a href="#makefile的优势" class="headerlink" title="makefile的优势"></a>makefile的优势</h2><p>但和普通脚本相比,makefile文件多写了很多字啊,这不是反而麻烦了吗?</p><p>其实不然,上文说到普通脚本会暴力的执行每一步操作,而makefile标记的编译过程,每次执行make,make会检查每一个target及其dependency。</p><p>如果target不存在,好的,执行下一行的Command来得到target;</p><p>如果target依赖于某个or某些dependency,好的,先去检查这些dependency的获取方式;</p><p>如果dependency不存在,好的,先去搜索如何得到dependency;</p><p>如果dependency被改变了,好的,重新构建该target。</p><p>这时makefile的优势便体现了出来,本例中,假设我已经编译了程序,结果发现我add.c中的add函数有bug!我把它写成减法了!我改动了add.c文件使其能完成正确的操作。再次执行make时,它进行检查:</p><p>all 依赖于 main.o 与 add.o,先去检查它们</p><p>main.o 依赖于 main.c 与 add.h,这两个文件都没有改变(相比与上一次make),且make.o已经存在(上一次make生成的),所以main.o是已经生成好了的。(跳过此target指示的Command)</p><p>add.o 依赖于 add.c 与 add.h,发现add.c被改变了!将重新生成add.o。(执行下一行的Command)</p><p>对all的依赖检查结束,发现至少有一个依赖不存在或已经改变。(此处为add.o)重新生成all(执行下一行的Command)</p><p>对于简单地执行脚本,我们少执行了一条编译main.c的指令。在此处优势还不太明显,但在大型项目组织中,这无疑是最好的构建方法,对于单个文件的改动,不会重复地去编译其他的源代码,从而大大减少了编译时间。(C/C++编译速度慢也是它们常年来被诟病的一个点) </p>]]></content>
<summary type="html"><h1 id="自动化编译流程"><a href="#自动化编译流程" class="headerlink" title="自动化编译流程"></a>自动化编译流程</h1><h2 id="前置知识"><a href="#前置知识" class="headerlink" titl</summary>
<category term="编译工具" scheme="https://ezrart.github.io/categories/%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7/"/>
<category term="C/C++" scheme="https://ezrart.github.io/tags/C-C/"/>
<category term="编译" scheme="https://ezrart.github.io/tags/%E7%BC%96%E8%AF%91/"/>
</entry>
<entry>
<title>C与C++的编译</title>
<link href="https://ezrart.github.io/2020/11/18/compile/"/>
<id>https://ezrart.github.io/2020/11/18/compile/</id>
<published>2020-11-18T14:16:30.000Z</published>
<updated>2020-11-18T14:16:30.000Z</updated>
<content type="html"><![CDATA[<h1 id="C-x2F-C-的编译过程"><a href="#C-x2F-C-的编译过程" class="headerlink" title="C/C++的编译过程"></a>C/C++的编译过程</h1><p><code>以GCC编译器为例</code></p><h2 id="总览"><a href="#总览" class="headerlink" title="总览"></a>总览</h2><img src="/2020/11/18/compile/1475571-20190715205533181-2142975310.png" class="" title="1475571-20190715205533181-2142975310"><p>使用gcc命令行一步一步编译的命令为:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">gcc [option] -o 用于保存结果的文件名 输入文件名 </span><br></pre></td></tr></table></figure><p>其中option即为图中的-E -S -c<br>一个源代码文件要经过上述过程才能被编译成可执行文件,下面对其中每个步骤做一些介绍</p><h2 id="预处理"><a href="#预处理" class="headerlink" title="预处理"></a>预处理</h2><p>一个源代码中包含了#include、#ifdef等预处理语句以及宏定义等内容,而在编译时,它们都会被展开,例如如下的源程序</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">//main.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"add.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PI 3.14</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> <span class="type">const</span>* argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">char</span> temp[<span class="number">80</span>];</span><br><span class="line"> <span class="type">double</span> ss = PI;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Hello,World!\n"</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, add(<span class="number">1</span>, <span class="number">2</span>));<span class="comment">//此add函数在add.c中实现</span></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">} </span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">//add.h</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> __ADD_H__</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __ADD_H__</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span>;<span class="comment">//仅函数声明</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">// __ADD_H__ </span></span></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">//add.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"add.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line">} </span><br></pre></td></tr></table></figure><p>我们include了stdio.h,add.h这些头文件,宏定义了一个PI,并在main函数中进行了一些简单的操作,在add.c中实现了一个简单的加法函数,而对main.c预处理之后,它变成了这样</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">//main.i</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"./main.c"</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"<built-in>"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*此处省略一万个stdio.h中的类型重名*/</span></span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">char</span> *__mingw_get_crt_info (<span class="type">void</span>);</span><br><span class="line"># <span class="number">11</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">2</span> <span class="number">3</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">pragma</span> pack(push,_CRT_PACKING)</span></span><br><span class="line"># <span class="number">35</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">3</span></span><br><span class="line">__extension__ <span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span> <span class="type">size_t</span>;</span><br><span class="line"># <span class="number">45</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">3</span></span><br><span class="line">__extension__ <span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> <span class="type">ssize_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">size_t</span> <span class="type">rsize_t</span>;</span><br><span class="line"># <span class="number">62</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">3</span></span><br><span class="line">__extension__ <span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> <span class="type">intptr_t</span>;</span><br><span class="line"># <span class="number">75</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">3</span></span><br><span class="line">__extension__ <span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">long</span> <span class="type">long</span> <span class="type">uintptr_t</span>;</span><br><span class="line"># <span class="number">88</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">3</span></span><br><span class="line">__extension__ <span class="keyword">typedef</span> <span class="type">long</span> <span class="type">long</span> <span class="type">ptrdiff_t</span>;</span><br><span class="line"># <span class="number">98</span> <span class="string">"D:/Tools/GCC/x86_64-w64-mingw32/include/crtdefs.h"</span> <span class="number">3</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">wchar_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">wint_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">wctype_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int</span> <span class="type">errno_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*此处省略一万个stdio.h中的函数声明*/</span></span><br><span class="line"></span><br><span class="line"># <span class="number">2</span> <span class="string">"./main.c"</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line"># <span class="number">1</span> <span class="string">"./add.h"</span> <span class="number">1</span></span><br><span class="line"></span><br><span class="line"># <span class="number">4</span> <span class="string">"./add.h"</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span>;</span><br><span class="line"># <span class="number">4</span> <span class="string">"./main.c"</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> <span class="type">const</span>* argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="type">char</span> temp[<span class="number">80</span>];</span><br><span class="line"> <span class="type">double</span> ss = <span class="number">3.14</span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Hello,World!\n"</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, add(<span class="number">1</span>, <span class="number">2</span>));</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//此文件实际共有894行 </span></span><br></pre></td></tr></table></figure><p>这种看着像C语言,但又有些不同的语法,便是编译器对源文件预处理后得到的中间产物。对比源文件我们可以发现,我们#include进来的<stdio.h> “add.h” 文件的内容被替换在引入头文件的位置了,且add.h中的预处理命令#ifndef、#define、#endif等等都被处理完了。</p><p>而add.c在预处理后变成了这样</p><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="comment">//add.i</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"./add.c"</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"<built-in>"</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"<command-line>"</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"./add.c"</span></span><br><span class="line"># <span class="number">1</span> <span class="string">"./add.h"</span> <span class="number">1</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span>;</span><br><span class="line"># <span class="number">2</span> <span class="string">"./add.c"</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span></span><br><span class="line">{</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//此文件没有省略,因为add.c和其include进来的add.h头文件都没有再include其他文件,故仅有这些内容 </span></span><br></pre></td></tr></table></figure><h2 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h2><p>此处的编译是将预处理后的那种带有奇怪标记的中间文件编译成汇编语言文件</p><p>此处得到的结果为</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">//main.s</span><br><span class="line">.file"main.c"</span><br><span class="line">.text</span><br><span class="line">.def__main;.scl2;.type32;.endef</span><br><span class="line">.section .rdata,"dr"</span><br><span class="line">.LC1:</span><br><span class="line">.ascii "Hello,World!\0"</span><br><span class="line">.LC2:</span><br><span class="line">.ascii "%d\12\0"</span><br><span class="line">.text</span><br><span class="line">.globlmain</span><br><span class="line">.defmain;.scl2;.type32;.endef</span><br><span class="line">.seh_procmain</span><br><span class="line">main:</span><br><span class="line">pushq%rbp</span><br><span class="line">.seh_pushreg%rbp</span><br><span class="line">movq%rsp, %rbp</span><br><span class="line">.seh_setframe%rbp, 0</span><br><span class="line">addq$-128, %rsp</span><br><span class="line">.seh_stackalloc128</span><br><span class="line">.seh_endprologue</span><br><span class="line">movl%ecx, 16(%rbp)</span><br><span class="line">movq%rdx, 24(%rbp)</span><br><span class="line">call__main</span><br><span class="line">movsd.LC0(%rip), %xmm0</span><br><span class="line">movsd%xmm0, -8(%rbp)</span><br><span class="line">leaq.LC1(%rip), %rcx</span><br><span class="line">callputs</span><br><span class="line">movl$2, %edx</span><br><span class="line">movl$1, %ecx</span><br><span class="line">calladd</span><br><span class="line">movl%eax, %edx</span><br><span class="line">leaq.LC2(%rip), %rcx</span><br><span class="line">callprintf</span><br><span class="line">movl$0, %eax</span><br><span class="line">subq$-128, %rsp</span><br><span class="line">popq%rbp</span><br><span class="line">ret</span><br><span class="line">.seh_endproc</span><br><span class="line">.section .rdata,"dr"</span><br><span class="line">.align 8</span><br><span class="line">.LC0:</span><br><span class="line">.long1374389535</span><br><span class="line">.long1074339512</span><br><span class="line">.ident"GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"</span><br><span class="line">.defputs;.scl2;.type32;.endef</span><br><span class="line">.defadd;.scl2;.type32;.endef</span><br><span class="line">.defprintf;.scl2;.type32;.endef </span><br></pre></td></tr></table></figure><p>没学过汇编语言的人可能会想:“这啥啊,看都看不懂,我写的不是C语言吗,怎么变成这样了”</p><p>在编译过程中,将C语言编译成汇编语言,我们的工作就成功大半了。因为汇编语言与机器语言(计算机可以识别、执行的命令)是一一对应的,接下来再进行一些小步骤,就能把我们的文本文件变成计算机可以执行的文件了。</p><p>不过这里让我们略微看一看这个汇编代码,在这里</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">callputs</span><br><span class="line">movl$2, %edx</span><br><span class="line">movl$1, %ecx</span><br><span class="line">calladd</span><br><span class="line">movl%eax, %edx</span><br><span class="line">leaq.LC2(%rip), %rcx</span><br><span class="line">callprintf </span><br></pre></td></tr></table></figure><p>是不是看到了一些熟悉的字眼?puts、printf这些都是C语言提供的函数,而add函数是我们自己定义的。call的意思就是去调用这些函数。</p><h2 id="汇编"><a href="#汇编" class="headerlink" title="汇编"></a>汇编</h2><p>得到了汇编代码就可以简单地把它翻译成机器语言了</p><p>编译得到main.o文件,使用著名反汇编分析程序IDA打开它,可以发现,它已经不再是简单的文本文件,但当使用软件将它从机器语言再翻译回汇编语言</p><img src="/2020/11/18/compile/image-20201118205614228.png" class="" title="image-20201118205614228"><p>还是能从中发现一些端倪,比如main函数调用了puts、add、printf函数等</p><p>但当我们追踪下去,却发现</p><img src="/2020/11/18/compile/image-20201118205804785.png" class="" title="image-20201118205804785"><img src="/2020/11/18/compile/image-20201118205826577.png" class="" title="image-20201118205826577"><img src="/2020/11/18/compile/image-20201118205843698.png" class="" title="image-20201118205843698"><p>它们无一例外地,全都只是一个空入口,此时,编译得到的文件虽然已经是计算机认识的代码了,但有些函数调用只是在原地留了个坑,程序还不知道如何去调用这些程序。</p><p>而汇编add.s文件后,得到了add函数。</p><img src="/2020/11/18/compile/image-20201118210652468.png" class="" title="image-20201118210652468"><p>那么如何让我们main.o与add.o以及printf、puts函数的实现文件联合起来呢?快进到链接。</p><h2 id="链接"><a href="#链接" class="headerlink" title="链接"></a>链接</h2><p>链接不需要加额外参数,只要执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">gcc -o main ./main.o ./add.o </span><br></pre></td></tr></table></figure><p>便可以得到可执行文件main.exe了,执行试试</p><img src="/2020/11/18/compile/image-20201118211322248.png" class="" title="image-20201118211322248"><p>嗯,不错。<br>此时我们再用IDA来分析main.exe文件</p><img src="/2020/11/18/compile/image-20201118210520236.png" class="" title="image-20201118210520236"><p>找不同时间到,这与刚刚得到的main.o文件有什么不同呢?</p><p>答案是,几乎没有区别,但是!puts、add、printf等字眼变成蓝色了,此时我们再追踪这些函数,终于找到了它们真实的函数入口</p><p>例如add函数</p><img src="/2020/11/18/compile/image-20201118210952029.png" class="" title="image-20201118210952029"><p>至此,我们便完成了一个分文件的项目的编译,由于项目简单,仅有两个源文件,采用gcc命令行编译&链接的方式也不算繁琐。但当项目变得庞大起来,这种方法还靠谱吗?</p>]]></content>
<summary type="html"><h1 id="C-x2F-C-的编译过程"><a href="#C-x2F-C-的编译过程" class="headerlink" title="C&#x2F;C++的编译过程"></a>C&#x2F;C++的编译过程</h1><p><code>以GCC编译器为例</code></summary>
<category term="编译工具" scheme="https://ezrart.github.io/categories/%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7/"/>
<category term="C/C++" scheme="https://ezrart.github.io/tags/C-C/"/>
<category term="编译" scheme="https://ezrart.github.io/tags/%E7%BC%96%E8%AF%91/"/>
<category term="makefile" scheme="https://ezrart.github.io/tags/makefile/"/>
</entry>
<entry>
<title>Git的使用</title>
<link href="https://ezrart.github.io/2020/11/18/Git_Usage/"/>
<id>https://ezrart.github.io/2020/11/18/Git_Usage/</id>
<published>2020-11-18T09:34:05.000Z</published>
<updated>2020-11-18T09:34:05.000Z</updated>
<content type="html"><![CDATA[<h1 id="Git"><a href="#Git" class="headerlink" title="Git"></a>Git</h1><h2 id="Git是什么"><a href="#Git是什么" class="headerlink" title="Git是什么"></a>Git是什么</h2><p>Git是一种源代码版本控制系统(VCS),什么叫版本控制系统呢?</p><p>假设你写了一个Word文档,叫做《我的idea》.docx。</p><p>第一天,你blahblah写了不少点子,把它保存了下来;</p><p>第二天,你发现昨天的点子有一些纰漏,你将其更改了一些;</p><p>第三天,你发现第二天干坏事了,不小心删除了一个重要的点子,然而你已经想不起来那个点子了!</p><p>这时就体现出版本控制系统的重要性了,版本控制系统可以记录你每一次的文件更改,如果你用了版本控制系统的话,你可以将你的文件还原到任意一次更改时的状况。</p><p>PS:git版本控制系统实际上不适合docx这类非纯文本文件,在此处只是举例,源代码(纯文本文件)才是git大放光彩的地方。</p><h2 id="Git的用法"><a href="#Git的用法" class="headerlink" title="Git的用法"></a>Git的用法</h2><p>详细用法不在此介绍<del>我也不会</del></p><p>常见操作如下:</p><ol><li><p>克隆服务器上的git项目</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> xxxxx.git [可选:文件夹名] </span><br></pre></td></tr></table></figure><p>其中“xxxxx.git”为你的项目地址。</p><p>执行完成后会看到当前目录下多出了一个文件夹,其名为[你克隆来的git项目名]/[你指定的文件夹名]。</p><p>比如我克隆一个测试仓库,执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/EzraRT/testgit.git</span><br></pre></td></tr></table></figure><img src="/2020/11/18/Git_Usage/image-20201118143958792.png" class="" title="image-20201118143958792"><p>一番翻云覆雨后,就把代码仓库克隆下来了,得到一个如下的文件夹</p><img src="/2020/11/18/Git_Usage/image-20201118161025755.png" class="" title="image-20201118161025755"><p>进入该文件夹,里面存放了此代码仓库的最新代码,还有一个特殊的文件夹</p><img src="/2020/11/18/Git_Usage/image-20201118145746643.png" class="" title="image-20201118145746643"><p>这个.git文件夹,便是git仓库的数据文件,一般它是一个隐藏文件夹,需要手动开启“显示隐藏的项目”才能看到它。</p><p>对于其中的内容我们暂且不深入,只要知道它储存了一些git的数据即可。</p><p>这是我不久前创建的代码仓库,仅有一个说明文件(README.md)和一个.gitignore文件。</p><p>接下来我们要介绍如何参与到代码改动的工作中去,让我们仔细地观察这张图</p><img src="/2020/11/18/Git_Usage/git_man.jpg" class="" title="img"><p>服务器:Remote</p><p>本地仓库:Repository</p><p>工作区:workspace</p><p>目录:Index</p><p>其中,本地仓库、工作区,目录都位于你的电脑上,只有服务器位于服务器上<del>废话</del>,而你编辑代码时所做的更改都位于你的工作区,如何一步一步地提交代码改动并上传到服务器呢?</p></li><li><p>提交更改</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git add 文件名 [文件名1] [文件名2] [...] </span><br></pre></td></tr></table></figure><p>这个指令是告诉git你更改的文件,git会将这几个文件于此时此刻保存起来(将某些信息保存在.git文件夹中),注意,之后你对该文件执行了更改,需要<strong>重新执行一遍add命令</strong>,不然git认为它还是上一次执行add时的模样。</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git commit -m <span class="string">"提交信息"</span> </span><br></pre></td></tr></table></figure><p>这便提交了你的代码更改操作,你应在[提交信息]中简明扼要地说明你对代码进行了何种改动。</p><p>如果你进行了很多文件的更改,不想一个一个add它们,也可以执行:</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git commit -a -m <span class="string">"提交信息"</span> </span><br></pre></td></tr></table></figure><p>这个-a选项即是让git把所有未add、但发生了更改的文件记录下来准备提交。一般地,使用此种方法可以快速地提交你的代码更改。</p></li><li><p>获取服务器上的最新版本代码</p><p>在你克隆下来的git项目的目录下执行(先别执行!)</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git pull</span><br></pre></td></tr></table></figure><p>但git常常用在团队合作中,如果有人在你之前更改了服务器上的代码,而你浑然不知,改了一些代码,准备提交到服务器上,傻傻地获取最新代码然后提交你的改动,这时会发生什么状况呢?</p><p>情况1:你和他改动的代码并无冲突(你们更改的不是同一个文件或是同一个文件的不同部分)</p><p>情况2:你和他的改动有git难以处理的冲突,此时强行pull会造成很多的问题,比如你的改动被覆盖(白干半天)。</p><p>关于这几种情况处理起来比较复杂(虽然git是有处理方法的),我们介绍一种比较好的处理方式。</p><p>先执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git fetch</span><br></pre></td></tr></table></figure><p>获取服务器上的最新代码,但不合并到你本地的代码中。如何理解这句话?让我们回到这张图</p><img src="/2020/11/18/Git_Usage/git_man.jpg" class="" title="img"><p>你add&commit操作都是在本地进行的操作,服务器浑然不知你的工作,而你不想白干活,因此要从服务器上fetch(拉取)服务器上的最新改动,并以此判断是否需要提交你的更改,同时也可以完成一些冲突的处理。但如果执行了pull操作,便会把代码改动直接应用到你的工作区,如果正好有人在你之前提交了某文件的更改,而你恰好也更改了它,这就是悲剧的开始。</p><p>因此,先fetch下代码改动并利用diff工具(代码比较工具)查看改动,确认没有冲突之后再pull并提交代码改动。</p></li><li><p>提交代码更改给服务器</p><p>终于到了这一激动人心的一刻,你的工作将被记录下来并保存到服务器上,执行</p><figure class="highlight sh"><table><tr><td class="code"><pre><span class="line">git push</span><br></pre></td></tr></table></figure><p>便可以将你此前提交的代码更改(commit)告诉服务器了。如果执行push时git告诉你:“你的代码不是最新版本”,那想必是你又慢人一步了,请从第2点重新操作。</p></li></ol><p> 总结:参与到某git项目的代码维护工作中,你需要做的事有:</p><p> 首先,clone对应的项目;</p><p> 参与代码的改动工作,进行代码改动的基本流程如下:</p><p> fetch服务器的更改、仔细比较并确认、pull拉取最新的代码更改到你的工作区,commit提交你的代码改动、push上传你的代码改动到服务器。</p><h2 id="日常使用的Git用法(利用软件集成的版本控制系统)"><a href="#日常使用的Git用法(利用软件集成的版本控制系统)" class="headerlink" title="日常使用的Git用法(利用软件集成的版本控制系统)"></a>日常使用的Git用法(利用软件集成的版本控制系统)</h2><p>生活在现代的我们,往往不用操作如此繁琐的命令,此处介绍VSCode的图形化git工具,它可以帮助我们完成大部分的工作。</p><p>有关VSCode安装的相关教程可以查看<a href="/2020/11/16/VSCode-C-C-Config/">这个</a></p><p>首先用VSCode打开我们git项目的目录,进行一番改动后,界面如下</p><img src="/2020/11/18/Git_Usage/image-20201118163423675.png" class="" title="image-20201118163423675"><p>对于这几处,与你平常编写代码时不一样的显示,我们从左到右进行说明。</p><ol><li><p>文件改动列表(版本控制栏)</p><p>最左边,标记了一个数字,这是VSCode集成的版本管理系统(git工具),其界面如下图</p><img src="/2020/11/18/Git_Usage/image-20201118163445738.png" class="" title="image-20201118163445738"><p>你对文件进行的更改都会罗列在此处,本例中,我们改动了test.cc文件、新建了main.cc文件、删除了README.md文件,在此处点击它,便可以在右侧看到它与上一次提交的变化</p><img src="/2020/11/18/Git_Usage/image-20201118162326544.png" class="" title="image-20201118162326544"><p>左侧为改动前的文件,右侧为改动后的文件,此处我们将一句感叹编写成了一个可以编译执行的感叹。</p></li><li><p>某文件改动情况</p><p> 对于有所改动的文件,它会在文件名右方显示改动的类型</p><p> 蓝色的<font color=#0099ff>M</font>是modified的意思,译为已被更改,说明我们对此文件进行了更改操作;</p><p> 绿色的<font color=#2baf2b>U</font>,untracked,说明你新建了该文件且没有提交;</p><p> 红色的<font color=#c41411>D</font>(可以在1:文件改动列表中查看),deleted,说明你删除了该文件。</p></li><li><p>每一行的改动情况</p><p> 对应颜色与上述文件改动类型对应</p><p>这时我们如何利用图形界面进行commit、pull、push操作呢?</p><p>在版本控制栏中,点击文件名后面的小加号可以把它提交到舞台上<code>(OnStage)</code>,接着在上方的Message栏输入你的提交说明,最后点击这个勾,便将你<code>[提交到Stage]</code>的改动commit完成了。</p><img src="/2020/11/18/Git_Usage/image-20201118164556879.png" class="" title="image-20201118164556879"><p>最后,将你的代码改动push到服务器上去</p><p>等等!pull、fetch操作呢?说好的代码安全呢?</p><p>在VSCode的左下角,有一个循环模样的小按钮</p><img src="/2020/11/18/Git_Usage/image-20201118165034207.png" class="" title="image-20201118165034207"><p>其旁边的数字指示了你比服务器落后了多少个commit(下载箭头指示,可能是别人提交的)、你比服务器领先多少个commit(上传箭头指示,你想要提交的代码更改)。</p><p>点击它,便会执行pull&push操作,且在与服务器有冲突时会询问你该怎么办。具体情况具体对待,此处不做延伸。</p><p>这便是我们日常使用中对git的使用,相比命令行,对文件的改动变得显而易见,你可以利用图形化的diff工具比较每一处改动、用版本控制工具查看文件历史<code>(该文件的每次更改情况)</code>等等。</p></li></ol><p><code>附录:.gitignore文件是什么呢?ignore的意思是忽略,此文件是一个文本文件,里面罗列了git进行代码比较、提交更改时忽略的文件、文件类型、文件夹等等。</code></p>]]></content>
<summary type="html"><h1 id="Git"><a href="#Git" class="headerlink" title="Git"></a>Git</h1><h2 id="Git是什么"><a href="#Git是什么" class="headerlink" title="Git是什么"><</summary>
<category term="软件教程" scheme="https://ezrart.github.io/categories/%E8%BD%AF%E4%BB%B6%E6%95%99%E7%A8%8B/"/>
<category term="Git" scheme="https://ezrart.github.io/tags/Git/"/>
<category term="教程" scheme="https://ezrart.github.io/tags/%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>Windows下使用VSCode和GCC的C++开发环境配置</title>
<link href="https://ezrart.github.io/2020/11/16/VSCode-C-C-Config/"/>
<id>https://ezrart.github.io/2020/11/16/VSCode-C-C-Config/</id>
<published>2020-11-16T14:22:11.000Z</published>
<updated>2020-11-17T07:54:20.000Z</updated>
<content type="html"><![CDATA[<h1 id="C-环境配置"><a href="#C-环境配置" class="headerlink" title="C++环境配置"></a>C++环境配置</h1><ul><li><p>下载软件</p><ul><li>下载<a href="https://code.visualstudio.com/Download">vscode安装程序</a>与<a href="https://r2.ezrart.workers.dev/gcc.7z">gcc的压缩包</a>。</li></ul></li></ul><h2 id="安装软件"><a href="#安装软件" class="headerlink" title="安装软件"></a>安装软件</h2><ol><li>安装vscode</li></ol><ul><li><img src="/2020/11/16/VSCode-C-C-Config/image-20201011183659353.png" class="" title="image-20201011183659353"></li><li><p>选择安装目录:推荐安装在:</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">D:\Program Files\Microsoft VS Code</span><br></pre></td></tr></table></figure><img src="/2020/11/16/VSCode-C-C-Config/image-20201011183804611.png" class="" title="image-20201011183804611"></li><li><p>一路next,记得勾选这两项(还有勾选创建桌面图标,方便寻找)</p><img src="/2020/11/16/VSCode-C-C-Config/image-20201011183907932.png" class="" title="image-20201011183907932"></li><li><p>一路next,安装完成后进入下一步</p></li><li><p>安装GCC编译环境</p><ul><li><p>解压7z后缀的压缩包,得到名叫mingw64的文件夹</p></li><li><p>创建GCC安装文件夹,推荐</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">D:\Program Files\GCC</span><br></pre></td></tr></table></figure><img src="/2020/11/16/VSCode-C-C-Config/image-20201011184244365.png" class="" title="image-20201011184244365"></li><li><p>将解压得到的文件夹中的所有东西复制到此GCC文件夹中,效果如下</p><img src="/2020/11/16/VSCode-C-C-Config/image-20201011184358624.png" class="" title="image-20201011184358624"></li><li><p>GCC至此安装完成,进入下一步</p></li></ul></li></ul><h2 id="环境变量设置"><a href="#环境变量设置" class="headerlink" title="环境变量设置"></a>环境变量设置</h2><ol><li>打开控制面板</li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011184513447.png" class="" title="image-20201011184513447"><ol start="2"><li>依次进入 <strong>系统与安全</strong>——<strong>系统</strong>——<strong>高级系统设置</strong>(位于左侧)</li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011184801912.png" class="" title="image-20201011184801912"><ol start="3"><li>在弹出的窗口中点击<strong>环境变量</strong></li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011184842887.png" class="" title="image-20201011184842887"><ol start="4"><li>在下方的小窗口中寻找变量<strong>Path</strong>,点击<strong>编辑</strong></li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011184945024.png" class="" title="image-20201011184945024"><ol start="5"><li>在新弹出的窗口中,点击<strong>新建</strong>,接着输入</li></ol><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">你安装GCC的目录\bin</span><br></pre></td></tr></table></figure><p>如果你一路顺着我的教程安装完GCC,那么你应该输入的是</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">D:\Program Files\GCC\bin</span><br></pre></td></tr></table></figure><ol start="6"><li><p>输入完成后依次点击所有窗口的OK(确定),来保存环境变量设置,若中途任意一个窗口点击了Cancel(取消),请从<strong>环境变量设置</strong>章节开始重新设置。</p></li><li><p>测试环境设置是否正确/生效</p><p>按下键盘上的Windows键+R,弹出运行窗口</p></li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011185459450.png" class="" title="image-20201011185459450"><p> 输入cmd,点击OK(确定)</p><p> 弹出一个黑窗口</p><img src="/2020/11/16/VSCode-C-C-Config/image-20201011185550713.png" class="" title="image-20201011185550713"><p> 输入</p><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">gcc -v</span><br></pre></td></tr></table></figure><p> 敲击回车执行,将会看到以下输出</p><img src="/2020/11/16/VSCode-C-C-Config/image-20201011185651683.png" class="" title="image-20201011185651683"><p> 恭喜你,环境变量设置完成了,进入下一步</p><p>PS:若看到<strong>“gcc”不是一个blahblah</strong>,说明上述步骤设置错误,请重新设置环境变量</p><h2 id="配置vscode环境"><a href="#配置vscode环境" class="headerlink" title="配置vscode环境"></a>配置vscode环境</h2><ol><li>打开安装好的vscode</li><li>点击左侧Extension(插件)按钮</li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011190024628.png" class="" title="image-20201011190024628"><ol start="3"><li>搜索以下插件并安装</li></ol><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">C/C++</span><br><span class="line">Code Runner</span><br></pre></td></tr></table></figure><p>如果你看不懂英文界面可以安装中文插件,大概是叫Chinese Simplified</p><p>上述插件安装完成后,关闭vscode,再打开,使插件生效</p><ol start="4"><li>打开设置</li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011190339543.png" class="" title="image-20201011190339543"><p>PS:若打开设置显示的是一个文本文件,自请查阅<strong>“如何打开vscode设置UI“</strong></p><ul><li>搜索并设置<strong>Default Intelli Sense Mode</strong>选项,将其设置为<strong>gcc-x64</strong></li></ul><img src="/2020/11/16/VSCode-C-C-Config/image-20201011190610975.png" class="" title="image-20201011190610975"><ul><li>搜索<strong>Code-runner:Run In Terminal</strong>选项,勾选它</li></ul><img src="/2020/11/16/VSCode-C-C-Config/image-20201011191917490.png" class="" title="image-20201011191917490"><ul><li>搜索<strong>Code-runner: Save All Files Before Run</strong>选项,勾选它</li></ul><img src="/2020/11/16/VSCode-C-C-Config/image-20201022172527167.png" class="" title="image-20201022172527167"><p>PS:此选项是为了防止运行前忘记保存代码。</p><p><font color=#ff0000 size=5>请从现在开始,养成随手按Ctrl+S保存文件的好习惯。</font></p><p>(同样适用于Office、Adobe全家桶等软件)</p><p>退出设置</p><h2 id="编写代码来测试你的环境配置"><a href="#编写代码来测试你的环境配置" class="headerlink" title="编写代码来测试你的环境配置"></a>编写代码来测试你的环境配置</h2><ol><li>点击左上角的<strong>文件——打开文件夹</strong></li></ol><p>选择你用来保存代码的目录</p><ol start="2"><li>创建一个新的代码文件如<strong>main.c</strong>,输入你的测试代码</li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011191020656.png" class="" title="image-20201011191020656"><figure class="highlight c"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> <span class="type">const</span> *argv[])</span></span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Hello World!\n"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="3"><li>点击<strong>右上角的三角形按钮</strong></li></ol><img src="/2020/11/16/VSCode-C-C-Config/image-20201011191216450.png" class="" title="image-20201011191216450"><p>下方终端会显示一系列命令,左侧工作目录中增加了编译生成的<strong>exe可执行文件</strong>,最终在下方终端中<strong>自动运行你的程序</strong>。</p><p>你应该可以看到程序所输出的Hello World!</p><p>至此vscode+gcc的开发环境配置完毕,你还可以探索<a href="https://code.visualstudio.com/docs">更多的vscode的用法</a></p>]]></content>
<summary type="html"><h1 id="C-环境配置"><a href="#C-环境配置" class="headerlink" title="C++环境配置"></a>C++环境配置</h1><ul>
<li><p>下载软件</p>
<ul>
<li>下载<a href="https://code.v</summary>
<category term="环境配置" scheme="https://ezrart.github.io/categories/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
<category term="C/C++" scheme="https://ezrart.github.io/tags/C-C/"/>
<category term="环境配置" scheme="https://ezrart.github.io/tags/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
</entry>
</feed>