博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
是否想知道节省时间的最简单方法? 使用`make`!
阅读量:2524 次
发布时间:2019-05-11

本文共 19199 字,大约阅读时间需要 63 分钟。

People have always looked for ways to make their work easier. It is a matter of debate whether using tools and automation are distinct human features. Or do we share them with other species? The fact is that we try to outsource our most mundane tasks to the machines. And that’s great!

人们一直在寻找使他们的工作更轻松的方法。 使用工具和自动化是否具有明显的人类特色,这尚有争议。 还是我们与其他物种共享它们? 事实是,我们尝试将最平凡的任务外包给机器。 太好了!

为什么要自动化? (Why automate?)

Repetition often leads to boredom and fatigue. Boredom is the first step toward burnout, while fatigue is one of the major sources of mistakes. Since we don’t want our colleagues (or ourselves) to burn out as much as we don’t want to make costly mistakes, we try to automate our everyday tasks.

重复经常导致无聊和疲劳。 厌倦是迈向倦怠的第一步,而疲劳则是错误的主要根源之一。 由于我们不希望我们的同事(或我们自己)尽自己所能,也不想犯错误的代价,因此我们尝试使日常工作自动化。

There seems to be a proliferation of software dedicated to the automation of common tasks. In the Node.JS ecosystem alone, there are (or used to be) solutions like Bower, Yeoman, Grunt, Gulp, and NPM scripts.

似乎有大量专用于自动执行常见任务的软件。 仅在Node.JS生态系统中,就有(或曾经是)诸如Bower,Yeoman,Grunt,Gulp和NPM脚本之类的解决方案。

But there is a good standard UNIX tool. By standard I mean it actually has robust documentation, that many forgot. Or never learned? I’m talking about make. More accurately, this article focuses on GNU make. It’s available on macOS, Windows, Linux and most other operating systems.

但是,有一个很好的标准UNIX工具。 按照标准,我的意思是实际上它具有强大的文档,很多人都忘记了。 还是没学过? 我说的是make 。 更准确地说,本文重点介绍GNU make。 它可在macOS,Windows,Linux和大多数其他操作系统上使用。

make is so standard you already have it installed. Type make in a command line and check yourself. This piece of software came out in 1977, which means it’s pretty much battle-tested. Is it quirky? Yup, even for the ’70s standard. But it does its job well and this is all we want from it.

make非常标准,您已经安装了它。 在命令行中键入make,然后检查一下自己。 该软件于1977年问世,这意味着它已经经受了多次考验。 这很古怪吗? 是的,即使是70年代的标准。 但是它做得很好,这就是我们想要的。

不适合使用C / C ++代码吗? (Isn’t Make for C/C++ code?)

When you read about make you probably recall that there used to be such a tool to build C/C++ projects back then. It went like this ./configure && make && make install. Yes, we are talking about exactly the same tool. And frankly, it’s not limited to compiling C/C++ code. To be honest, it can’t even compile the code.

当您读到有关make您可能会回想起当时曾经有过这样的工具来构建C / C ++项目。 它像这样./configure && make && make install 。 是的,我们正在谈论的是完全相同的工具。 坦白说,它不仅限于编译C / C ++代码。 老实说,它甚至无法编译代码。

Pretty much all make understands is files. It knows whether a file exists or not and which file is more recent. The other half of its power lies in maintaining a dependency graph. Not much, but those two features are what constitute its power.

几乎所有人make理解的是文件。 它知道文件是否存在以及哪个文件是最新的。 其功能的另一半在于维护依赖关系图。 数量不多,但是构成其功能的正是这两个功能。

In order for make to actually do anything, you write a set of recipes. Each recipe consists of a target, zero or more dependencies and zero or more rules. Targets are files that you want to obtain. Dependencies are files needed to create or update the targets. The set of rules describes the process of transforming dependencies into targets. For example imagine you want to automate installation on Node.js packages:

为了make实际执行任何操作,您编写了一组食谱。 每个配方均包含一个目标,零个或多个依赖项以及零个或多个规则。 目标是您要获取的文件。 依赖关系是创建或更新目标所需的文件。 规则集描述了将依赖关系转换为目标的过程。 例如,假设您要自动在Node.js软件包上安装:

node_modules: package.json	npm install

This means the file node_modules (yes, directories are files too) can be derived from the file package.json by running the npm install rule. Still with me?

这意味着可以通过运行npm install规则从文件 package.json派生文件 node_modules (是的,目录也是文件)。 还在我这儿?

Now, those dependencies can be other targets as well. This means we can chain different set of rules and create pipelines. For example making test results directory dependent on build directory, build directory dependent on node_modules directory and node_modules dependent on package.json. Heck, we can even create package.json dynamically making it a target of another rule.Remember when I mentioned make keeps track of which file is more recent? This is what actually saves us time. You see, without this feature, each time we run make test (following the example above) we would have to run the whole chain from the beginning (npm install, build, then test). But if nothing changed why install packages once again? Why build? Why run tests?

现在,这些依赖关系也可以成为其他目标。 这意味着我们可以链接不同的规则集并创建管道。 例如,使测试结果目录依赖于构建目录,构建目录依赖于node_modules目录,而node_modules依赖于package.json 。 哎呀,我们甚至可以动态创建package.json使其成为另一条规则的目标。记住我提到的make可以跟踪哪个文件是最新的吗? 这实际上是在节省我们的时间。 您会看到,没有此功能,每次我们运行make test (按照上面的示例)时,我们都必须从头开始运行整个链( npm install ,build,然后进行测试)。 但是,如果什么都没有改变,为什么要再次安装软件包? 为什么建造? 为什么要运行测试?

This is where make really shines. While figuring out the order of the jobs it checks the timestamps of targets and dependencies. It follows the rule only if

这是make真正发光的地方。 在确定作业的顺序时,它会检查目标和依赖项的时间戳。 只有在以下情况下遵守规则

  • one or more of dependencies is more recent than the target, and

    一个或多个依赖关系比目标更新,并且
  • the target does not exist.

    目标不存在。

One thing! As make test won’t be actually creating a file named test we need to add this target as a dependency of a .PHONY target. That’s another convention. Like this:

一件事! 由于make test实际上不会创建名为test的文件,因此我们需要将此目标添加为.PHONY目标的依赖项。 那是另一种约定。 像这样:

.PHONY: testtest: build	npm test	build: node_modules	npm build	node_modules: package.json

In our example above, a single change in package.json would result in building everything from scratch. But if we only change the code of one of the tests, make would skip all the steps prior to tests. That is, provided the dependencies are written correctly.

在上面的示例中,对package.json的单个更改将导致从头开始构建所有内容。 但是,如果我们仅更改其中一个测试的代码, make将在测试之前跳过所有步骤。 也就是说,只要正确地编写了依赖项。

但是我已经使用的语言有自己的构建系统… (But the Language I Use Already Has Its Own Build System…)

Many modern programming languages and environments come with their own build tools. Java has Ant, Maven, and Gradle, Ruby has its Rake, Python uses setuptools. And if you are worried I’m about to take those toys away from you and replace them with make, you are mistaken.

许多现代的编程语言和环境都带有自己的构建工具。 Java具有Ant,Maven和Gradle,Ruby具有Rake,Python使用setuptools。 而且,如果您担心我要把那些玩具拿走,然后用make代替它们,那就错了。

Look at it this way: how much time is needed to introduce a person to your team and make that person productive? This means setting up the development environment, installing all the dependencies, configuring every moving part, building the project, running the project, maybe even deploying the project to a development environment.

这样看:将一个人介绍给您的团队并使该人富有成效需要多少时间? 这意味着设置开发环境,安装所有依赖项,配置每个移动部分,构建项目,运行项目,甚至可能将项目部署到开发环境中。

Will a new hire start the actual work in a matter of hours? Days? Hopefully not weeks. Remember it’s not just the new hire’s time that’s wasted in the setup process. Somebody will also be bothered with lots of questions when things go wrong. And they usually do.

新员工会在几个小时内开始实际工作吗? 天? 希望不是几周。 请记住,在设置过程中浪费的不仅是新员工的时间。 当事情出错时,也会有人对很多问题感到困扰。 他们通常这样做。

There is a convention I like to use in my projects. Since it’s a convention common to multiple projects, people are free to migrate between them. Each new project or each new person that’s introduced needs to learn this convention to reach the desired outcome. This convention assumes that projects have their own Makefiles with a set of predefined targets:

我喜欢在项目中使用一个约定。 由于这是多个项目通用的约定,因此人们可以自由地在它们之间迁移。 引入的每个新项目或每个新人都需要学习此约定才能达到预期的结果。 此约定假定项目具有自己的Makefile,并带有一组预定义的目标:

  • make prepare installs all the external applications that might be needed. Normally this is done with a Brewfile and Homebrew/Linuxbrew. Since this step is optional coders can choose their own installation method at their own risk

    make prepare安装所有可能需要的外部应用程序。 通常,这是通过Brewfile和Homebrew / Linuxbrew完成的。 由于此步骤是可选步骤,因此编码人员可以自行选择安装方法,风险自负。

  • make dev sets up a local development environment. Usually, it builds and brings up Docker containers. But since make acts as a wrapper, it can be easily substituted by whatever is required (like npm serve)

    make dev建立本地开发环境。 通常,它会构建并启动Docker容器。 但是由于make充当包装器,因此可以轻松地用所需的任何内容代替(例如npm serve )

  • make deploy deploys the code to the select environment (by default its development). Under the hood, it usually runs Ansible.

    make deploy将代码部署到选择的环境中(默认情况下为development )。 在引擎盖下,它通常运行Ansible。

  • make infrastructure this is a prerequisite for make deploy as it uses Terraform to create said environments in the first place.

    make infrastructuremake deploy的先决条件,因为它首先使用Terraform创建上述环境。

  • make all produces all the artifacts required for deployment.

    make all产生部署所需的所有工件。

You know what it means? It means the mandatory README.md can focus on the business needs of the project and outline some collaboration processes. At the end, we attach the above list so everyone knows what those targets are. This means that when you enter a new project all you have to do is to make prepare and make dev. After a few CPU cycles you have a working project in front of you and you can start hacking.

你知道这是什么意思吗? 这意味着强制性README.md可以专注于项目的业务需求并概述一些协作过程。 最后,我们附上上面的列表,以便每个人都知道这些目标是什么。 这意味着,当您进入一个新项目时,您要做的只是make preparemake dev 。 经过几个CPU周期后,您面前的工作项目就可以开始黑客攻击了。

我有一个持续集成管道 (I Have a Continuous Integration Pipeline for That)

At this point, some people may notice what am I getting at. Artifacts, steps, deployment, infrastructure. That’s what our Continuous Integration/Continuous Deployment pipeline does. I’m sure it does! But remember that CI/CD is not only there to run tests each time a new commit pops up.

此时,有些人可能会注意到我在做什么。 工件,步骤,部署,基础结构。 这就是我们的持续集成/持续部署管道所要做的。 我敢肯定! 但是请记住,CI / CD不仅在每次新提交弹出时都运行测试。

Properly implemented CI/CD can help reduce debugging by making it easier to reproduce the issue and perform the root cause analysis. How? Versioned artifacts are one such means. They may help with finding the root cause, but not necessarily in fixing it.

正确实施的CI / CD可通过更轻松地重现问题和执行根本原因分析来帮助减少调试。 怎么样? 版本化工件就是这样一种手段。 他们可能有助于找到根本原因,但不一定能解决问题。

To fix the bug you need to alter the code and produce your own build. See what I’m getting at? If you CI/CD pipeline can be mirrored locally developers can test and deploy tiny changes without the need to actually use the CI/CD pipeline thus shortening the cycle. And the easiest way to make your CI/CD pipeline available locally is by making it a thin wrapper around make.

要修复该错误,您需要更改代码并生成您自己的构建。 明白我在说什么吗? 如果您可以镜像CI / CD管道,则开发人员可以测试和部署微小的更改,而无需实际使用CI / CD管道,从而缩短了周期。 使CI / CD管道在本地可用的最简单方法是使它成为make的薄包装。

Say you have a backend and a frontend and you have some tests for them as well (if not, you’re crazy running CD without tests!). This would make four distinct CI jobs. And they could be pretty much summed up as calling make backend, make test-backend, make frontend, make test-frontend. Or whatever convention you want to follow.

假设您有一个后端和一个前端,并且还对它们进行了一些测试(如果没有,那么您疯狂地运行CD而没有测试!)。 这将产生四个不同的CI作业。 他们几乎可以概括为调用make backendmake test-backendmake frontendmake test-frontend 。 或您要遵循的任何约定。

This way, no matter whether on a local machine or on CI, the code is built exactly the same way. Exactly the same steps are involved. The less commands go into your Jenkinsfile or .travis.yml (or some such) the less you rely on a Holy Build Machine.

这样,无论是在本地计算机上还是在CI上,代码都以完全相同的方式构建。 涉及的步骤完全相同。 进入Jenkinsfile.travis.yml (或类似的代码)的命令越少,您对Holy Build Machine的依赖就越少。

好的,但是有人实际使用Make吗? (Ok, But Does Anyone Actually Use Make?)

It turns out, yes. If you look around you’ll find articles like “Time for Makefiles to Make a Comeback” (by Jason Olson). “The Power Of Makefile” (by Ahmad Farag). “Rewriting our deploy tooling: from Makefile to Bash and back again” (by Paul David). Or “Makefile for Node.js developers” (by Patrick Heneise). And these are articles from the last year, not some reminiscences from the past century.

事实证明,是的。 如果环顾四周,您会发现诸如“让Makefile复出的时间”之类的文章(Jason Olson撰写)。 “ Makefile的力量”(艾哈迈德·法拉格) “重写我们的部署工具:从Makefile到Bash,然后再返回”(作者Paul David)。 或“供Node.js开发人员使用的Makefile”(作者Patrick Heneise)。 这些是去年的文章,而不是上个世纪的回忆。

Yes, I admit that make is clunky. I know about its many shortcomings and weird language features. But show me a better tool for actual development workflow automation and I’ll be glad to switch. Until then I’ll ROTFL looking at this:

是的,我承认make很笨重。 我知道它的许多缺点和奇怪的语言功能。 但是,请向我展示一个用于实际开发工作流自动化的更好的工具,我将很高兴进行切换。 在此之前,我将ROTFL看一下:

It’s , if you want to fly it.

如果您想使用它, 。

酷,现在向我展示代码 (Cool, Now Show Me the Code)

Here are some excerpts to show you what’s possible with make.

以下是一些摘录,向您展示make

.PHONY: dev.stamps:	@mkdir -p $@.stamps/git-hooks.installed: | .stamps	# This checks whether git-hooks is an executable and installs it with	# Homebrew/Linuxbrew is possible.	@if ! command -v git-hooks >/dev/null 2>&1; then \	  if command -v brew >/dev/null 2>&1; then \	    brew install git-hooks; \	  else \	    echo "You have to install https://github.com/icefox/git-hooks"; \	    exit 1; \	  fi; \	fi	@touch $@.git/hooks.old: | .stamps/git-hooks.installed	git hooks --installdev: | .git/hooks.old	pip install -e .[dev]

This snippet sets up a simple development environment. Since we want to make sure all developers use the same set of pre-commit hooks while working with Git we install those hooks for them.

此代码段建立了一个简单的开发环境。 由于我们要确保所有开发人员在使用Git时都使用同一组预提交钩子,因此我们为它们安装了这些钩子。

To do this we need to install git-hooks (that’s the name of the hooks manager). We take advantage of the knowledge that git-hooks moves the original hooks to .git/hooks.old so we check for a presence of such a file to determine whether we want to run git hooks install or not.

为此,我们需要安装git-hooks(这是钩子管理器的名称)。 我们利用git-hooks将原始钩子移动到.git/hooks.old的知识,因此我们检查是否存在这样的文件,以确定我们是否要运行git hooks install

One trick we use here is | to denote order-only dependencies. If you just want to make sure something exists, not that it change more recently than a target, order-only dependencies are the way to go. So far, so good, I suppose?

我们在这里使用的一个技巧是| 表示仅顺序依赖性。 如果您只是想确保某些东西存在,而不是它比目标更新得更近,那么只能使用顺序依赖。 我想到目前为止,一切都好吗?

Now imagine we want to build a Docker container that contains a file we cannot distribute in our source code.

现在想象一下,我们想要构建一个包含无法在源代码中分发的文件的Docker容器。

WEBAPP_SOURCES = $(sort $(notdir $(wildcard webapp/**/*)))all: webapp.stamps: Makefile	@mkdir -p $@third-party/top_secret.xml:	# WEB_USER and WEB_AUTH_TOKEN are variables that should contain credentials	# required to obtain the file.	@curl -u "$(WEB_USER):$(WEB_AUTH_TOKEN)" https://example.com/downloads/this_is_a_secret.xml -L -o $@webapp: .stamps/webapp.stamp.stamps/webapp.stamp: .stamps webapp/Dockerfile third-party/top_secret.xml $(WEBAPP_SOURCES)	docker build -t example/webapp -f webapp/Dockerfile webapp	@touch $@.PHONY: all webapp

Since we cannot use the actual file created by Docker (because images have tight permissions), we do the second best thing. We create an empty file that indicates we have successfully run docker build at one point in time.

由于我们无法使用由Docker创建的实际文件(因为图像具有严格的权限),因此我们做了第二件事。 我们创建一个空文件,指示我们已在某个时间点成功运行docker build

A common convention for such files calls them “stamps”. Our Docker image stamp depends obviously on Dockerfile, on source files and on another target, which runs curl to fetch the file obtaining credentials from environment variables.

这些文件的通用约定称它们为“邮票”。 我们的Docker映像标记显然取决于Dockerfile ,源文件和另一个目标,后者运行curl来获取文件以从环境变量中获取凭证。

Since we don’t want to print our credentials to the output we prefix the command with @. This means the rule itself is not printed to the screen. The output of the rule, however, isn’t silenced. Keep that in mind if any of the programs you want to run have a tendency of logging sensitive information to stdout or stderr.

由于我们不想将凭据打印到输出中,因此我们在命令前面加上@ 。 这意味着规则本身未打印到屏幕上。 但是,规则的输出不会被忽略。 如果要运行的任何程序倾向于将敏感信息记录到stdout或stderr,请记住这一点。

Ok, we can set up git hooks and we can build some Docker images. Why not let developers create their own environments in the cloud and deploy to them?

好的,我们可以设置git挂钩,并可以构建一些Docker映像。 为什么不让开发人员在云中创建自己的环境并进行部署?

# We include the previous Makefile so we can build the imageinclude previous.mk.stamps/webapp_pushed.stamp: .stamps/webapp.stamp        docker push example/webapp        @touch $@infrastructure: $(INFRASTRUCTURE_SOURCES)        cd deployment/terraform && terraform applydeploy: all infrastructure        cd deployment && ansible-playbook -i inventories/hosts deploy.yml.PHONY: infrastructure deploy

The actual Infrastructure as Code and Configuration Management is out of the scope of this article. Let me tell you that terraform apply manages cloud resources and ansible-playbook performs configuration on remote machines. You probably know what docker push does. In short, it pushes the local image to Docker Hub (or any other registry) so you could access it from anywhere. At this point, I’m sure you can figure out what the above snippet does.

作为代码和配置管理的实际基础架构不在本文的讨论范围之内。 让我告诉您, terraform apply管理云资源,而ansible-playbook在远程计算机上执行配置。 您可能知道docker push作用。 简而言之,它将本地映像推送到Docker Hub(或任何其他注册表),因此您可以从任何地方访问它。 至此,我确定您可以弄清楚上面的代码片段是做什么的。

那么,此工具适用于谁? (So, Who’s This Tool For?)

Even though DevOps is rising in hype recently, there is still a lot of separation between the Dev and the Ops. Some tools are used solely by Dev, some solely by Ops. There is a bit of common ground, but how far it reaches depends on any given team.

尽管最近DevOps的宣传日渐盛行,但Dev与Ops之间仍然存在许多分歧。 有些工具仅供开发人员使用,有些则仅供Ops使用。 有一些共同点,但要达到的程度取决于任何给定的团队。

Development package management, source code layout, coding guidelines are all the realms of Dev. Infrastructure as Code, Configuration Management, and orchestration are toys for the Ops. The build system and Continuous Integration pipeline might be split between the two or it might belong to either party. Can you see how the common ground is stretched thin?

开发包管理,源代码布局,编码准则都是Dev的领域。 基础架构(如代码,配置管理和业务流程)是Ops的玩具。 构建系统和持续集成管道可能会在两者之间分割,也可能属于任何一方。 您能看到共同点如何变薄吗?

make changes things, allowing for broader collaboration. Since it serves the purposes of both Dev and Ops, it is a common ground. Everyone speaks its language and everyone can contribute. But because it is so easy to use even when you want to do complex things (as in our example above) the true power of DevOps is given to the hands of every person on the team. Everyone can run make test and everyone can modify its rules and dependencies. Everyone could run make infrastructure and provision a nice cluster for development or for production. After all, they are documented in the same code!

make更改,从而实现更广泛的协作。 由于它既可以满足开发人员的需求,又可以满足运营要求,所以这是一个共同点。 每个人都说自己的语言,每个人都可以做出贡献。 但是,因为即使您想做复杂的事情,它也是如此易于使用(如上面的示例所示),DevOps的真正力量掌握在团队中每个人的手中。 每个人都可以运行make test ,每个人都可以修改其规则和依赖项。 每个人都可以运行make infrastructure并为开发或生产提供良好的集群。 毕竟,它们以相同的代码记录!

Of course, when there’s a common ground it’s good to make sure whose responsible for which part. The last thing you want is people from Dev and Ops overwriting each other’s work! But great teamwork always relies on great communication, so this could happen with or without make.

当然,如果有共同点,最好确保由谁负责哪一部分。 您想要的最后一件事是来自Dev和Ops的人员覆盖彼此的工作! 但是出色的团队合作始终取决于良好的沟通,因此无论有无make ,这都可能发生。

So it doesn’t matter if you use any of the trendy technologies associated with DevOps. You may not need and not want any Docker, Cloud, Terraform or Travis. You can write desktop applications, for what its worth, and a carefully written Makefile would still be a DevOps enabler.

因此,是否使用与DevOps相关的任何流行技术都没有关系。 您可能不需要,也不需要任何Docker,Cloud,Terraform或Travis。 您可以编写桌面应用程序,无论其价值多少,而且精心编写的Makefile仍将是DevOps的支持者。

翻译自:

转载地址:http://hfkzd.baihongyu.com/

你可能感兴趣的文章
EasyUI 搜索框
查看>>
impdp and docker install oracleXE
查看>>
入门训练 序列求和
查看>>
web前端_Vue框架_设置浏览器上方的标题和图标
查看>>
gnome3 隐藏标题栏
查看>>
duilib入门简明教程 -- 第一个程序 Hello World(3) (转)
查看>>
Visual Studio 2008下载
查看>>
hdu1712: ACboy needs your help
查看>>
[30期] 贫嘴漫谈时间
查看>>
远程连接工具SSH和linux的连接
查看>>
WPF 自定义依赖属性
查看>>
Android之Log封装
查看>>
立方体
查看>>
Python装饰器之 property()
查看>>
嵌入式Linux安装Dropbear SSH server
查看>>
消息系统避免分布式事务
查看>>
20080416
查看>>
中医养生好书
查看>>
Data Mining --- Preprocessing
查看>>
springBoot(1)启动hello world
查看>>