文章目录
为什么Linux会有自动化构建工具呢?一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂
的功能操作,makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建
make会在当前目录下找名字叫“Makefile”或“makefile”的文件,然后开始自动化构建,下面我们先来看一个例子。

Makefile文件由一系列规则(rules)构成。每条规则的形式如下:
<target> : <prerequisites>
[tab] <commands>
上述例子中形成的可执行文件myfile就是target,而myfile.c就是prerequisites,下面一行commands就是"命令",第二行必须以tab键起首
我们在构建之前必须清楚:构建目标的前置条件是什么,以及怎么构建
一个目标(target)就构成一条规则。目标通常是文件名,指明Make命令所要构建的对象,比如上文的 myfile 。目标可以是一个文件名,也可以是多个文件名,之间用空格分隔

关于目标我们还得注意以下几点:
我们将Makefile文件修改为如下:

这时我们键入make

除了文件名,目标还可以是某个操作的名字,这称为"伪目标"(phony target),例如:
clean:
rm -rf myflie
如果这样的话那么make每次需要检查clean是否是一个文件,我们可以用.PHONY来声明clean是个伪目标,这样make就不会检查clean是否是个文件,而是直接执行以下的命令.
我们还可以查询手册知道其它关于makefile的关键字:makefile关键字手册
前置条件通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),"目标"就需要重新构建。



这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
Makefile:
a.txt:
echo "a.txt" > a.txt
m.txt:
echo "b.txt" > m.txt
t.txt:
echo "t.txt" > t.txt
source: a.txt m.txt t.txt

命令(commands)表示如何更新目标文件,由一行或多行的Shell命令组成。它是构建"目标"的具体指令,它的运行结果通常就是生成目标文件。
.RECIPEPREFIX声明其它键.RECIPEPREFIX = >
myfile:myfile.c
>gcc myfile.c -o myfile
.PHONY:clean
clean:
>rm -rf myfile
我们用>号代替了tab键,每个命令前用>就可以了
#在Makefile中表示注释。
# 这是注释
myfile: myfile.c
# 这是注释
gcc myfile.c -o myfile # 这也是注释
正常情况下我们每次执行make命令时,系统都会打印相应的命令再执行

我们在命令前加上@就可以关闭回声。
.PHONT:source
source:
@echo "这是第二次" > test.c
@cat test.c

注意:由于我们具体要看我们到底执行了哪些命令,所以我们一般只在注释和纯echo显示命令前加上@
通配符(wildcard)用来指定一组符合条件的文件名。Makefile 的通配符与 Bash 一致。
- 星号
*:可以使用星号代替零个、单个或多个字符- 问号
?:可以匹配任意一个字符- 中括号
[]:匹配中括号任意一个字符,如[ljk]代表匹配一个l,j或k的字符[-]:匹配范围,[0-9]代表匹配任一个数字[!]:匹配不是中括号的一个字符,[!0-9]表示不匹配a-z中任意字符
关于通配符更详细的讲解:Linux通配符
Makefile 允许使用=自定义变量。
ret = hello world
test:
@echo $(ret)
上面代码中,变量 ret 等于 Hello World。调用时,变量需要放在 $( ) 之中。此时会打印出hello world
有时变量的值可能会指向另外一个变量。
a1 = $(a2)
这时就出现了问题,a1 的值到底在定义时扩展(静态扩展),还是在运行时扩展(动态扩展)?如果 a2 的值是动态的,这两种扩展方式的结果可能会差异很大。
为了解决类似问题,makefile提供了四个运算符:
a1 := $(a2)
# 在执行时扩展,允许递归扩展。
a1 := $(a2)
# 在定义时扩展。
a1 ?= $(a2)
# 只有在该变量为空时才设置值。
a1 += $(a2)
# 将值追加到变量的尾端。
Make命令提供一系列内置变量,比如,(CC) 指向当前使用的编译器,(MAKE) 指向当前使用的Make工具。这主要是为了跨平台的兼容性,详细的内置变量清单见手册。
output:
$(CC) -o output input.c
Make命令还提供一些自动变量,它们的值与当前规则有关。主要有以下几个:
@指代当前目标,就是Make命令当前构建的那个目标。比如,make clean的@ 就指代clean。a.txt b.txt:
touch $@
等同于下面的写法
a.txt:
touch a.txt
b.txt:
touch b.txt
<指代第一个前置条件,比如规则为 a.txt: b.txt c.txt,那么$<就指代b.txta.txt: b.txt c.txt
cp $< $@
等同于下面的写法
a.txt: b.txt c.txt
cp b.txt a.txt
$ ?
?指代比目标时间戳更新的所有前置条件,例如t:p1 p2 p3,p1,p2时间戳新于t,则$?指代p1,p2
$ ^
^指代所有前置条件,例如t:p1 p2 p3,p1,p2时间戳新于t,则$^指代p1,p2,p3
Makefile还可以使用函数,格式如下:
$(function arguments)
Makefile提供了许多内置函数,可供调用。下面是几个常用的内置函数。
1. shell函数
shell 函数用来执行 shell 命令。
srcfiles := $(shell echo src/{00..99}.txt)
2. wildcard函数
wildcard 函数用来在 Makefile 中,替换 Bash 的通配符。
srcfiles := $(wildcard src/*.txt)
3. subst函数
subst 函数用来文本替换,格式如下:
$(subst from,to,text)
下面的例子将字符串"feet on the street"替换成"fEEt on the strEEt"。
$(subst ee,EE,feet on the street)
4. patsubst函数
patsubst 函数用于模式匹配的替换,格式如下。
$(patsubst pattern,replacement,text)
下面的例子将文件名"x.c.c bar.c",替换成"x.c.o bar.o"。
$(patsubst %.c,%.o,x.c.c bar.c)
5. 替换后缀名
替换后缀名函数的写法是:变量名 + 冒号 + 后缀名替换规则。它实际上patsubst函数的一种简写形式。
min: $(OUTPUT:.js=.min.js)
上面代码的意思是,将变量OUTPUT中的后缀名 .js 全部替换成 .min.js
我们利用printf函数进行输出的时候,实际上编译器会将我们的输出内容写到缓冲区,等到系统刷新缓冲区的时候,屏幕上才会输出相应内容,同时清空缓冲区
所以我们进行输出的时候会带上/n等选项,因为那会帮我们自动刷新缓冲区,但是加上/r,会将光标移动到行开头,然后刷新缓冲区,我们的结果就会被新打印出来的结果给覆盖掉,所以我们应该在之前刷新缓冲区,我们有一个刷新缓冲区的函数fflush,以下为test.c用例

此时会观察到屏幕先打印了结果,并且光标移动到了行首,因此接下打印出的命令行将原结果覆盖掉了

#include "proc.h"
#define SIZE 102
#define STYLE '='
#define ARR '>'
// "|/-\\"
void process()
{
const char *lable = "|/-\\";
char bar[SIZE];
memset(bar, '\0', sizeof(bar));
int i = 0;
while( i <= 100 )
{
printf("[%c][\033[42;32;31m%-100s\033[0m][%d%%]\r", lable[i%4], bar, i);
fflush(stdout);
bar[i++] = STYLE;
if(i != 100) bar[i] = ARR;
usleep(100000);
}
printf("\n");
}
我们还可以自己添加颜色输出:printf颜色输出
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
我们目前正在为ROR3.2开发自定义cms引擎。在这个过程中,我们希望成为我们的rails应用程序中的一等公民的几个类类型起源,这意味着它们应该驻留在应用程序的app文件夹下,它是插件。目前我们有以下类型:数据源数据类型查看我在app文件夹下创建了多个目录来保存这些:应用/数据源应用/数据类型应用/View更多类型将随之而来,我有点担心应用程序文件夹被这么多目录污染。因此,我想将它们移动到一个子目录/模块中,该子目录/模块包含cms定义的所有类型。所有类都应位于MyCms命名空间内,目录布局应如下所示:应用程序/my_cms/data_source应用程序/my_cms/data_ty
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功