開発者ドキュメント

HowToUseMakefilestoAutomateRepetitiveTasks

序章

Linuxサーバーにソースコードからソフトウェアをインストールした経験がある場合は、おそらく make utility. This tool is primarily used to compile and build programs. It allows the source code’s author to lay out the steps required to build that specific project.

Although make was created to automate software compilation, the tool was engineered in a flexible enough fashion that it can be used to automate almost any task that you can accomplish from the command line. このガイドでは、makeを再利用して、順番に発生する反復タスクを自動化する方法について説明します。

Prerequisites

A Linux environment of any kind will work for this tutorial. Package install instructions are provided for both Ubuntu/Debian Linux and for Red Hat/Rocky Linux.

Installing Make

Most Linux distributions allow you to install a compiler with a single command, but do not provide one by default.

On Ubuntu, you can install a package called build-essential that will provide all the packages needed for a modern, well-supported compiler environment. Update your package sources and install the package with apt:

  1. sudo apt update
  2. sudo apt build-essential

On Rocky Linux or other Red Hat derivatives, you can install a group of packages called Development Tools to provide the same compiler functionality. Install the packages with dnf:

  1. dnf groups mark install "Development Tools"
  2. dnf groupinstall "Development Tools"

You can verify that a compiler is available by checking for the existence of the make command on your system. In order to do that, use the which command:

  1. which make
Output
/usr/bin/make

これで、通常の容量でもmakeを利用できるツールができました。

Makefileを理解する

makeコマンドが命令を受け取る主な方法は、 Makefile.

Makefiles are directory specific, meaning that make will search in the directory where it was called to find these files. We should put the Makefile in the root of whatever the task that we are going to be performing, or where it makes most sense to call the scripts we will write.

Inside the Makefile, we follow a specific format. Makeは、ターゲット、ソース、およびコマンドの概念を次のように使用します。

Makefile
target: source
    command

The alignment and format of this is very important. ここでは、これらの各コンポーネントの形式と意味について説明します。

目標

The target is a user-specified name to refer to a group of commands. Think of it as similar to a function in a programming language.

ターゲットは左側の列に配置され、連続した単語(スペースなし)であり、コロン(:)で終わります。

makeを呼び出すときは、次のように入力してターゲットを指定できます。

  1. make target_name

次に、MakeはMakefileをチェックし、そのターゲットに関連付けられたコマンドを実行します。

ソース

Sources are references to files or other targets. これらは、関連付けられているターゲットの前提条件または依存関係を表します。

For instance, you could have a section of your Makefile that looks like this:

Makefile
target1: target2
    target1_command

target2:
    target2_command

この例では、次のようにtarget1を呼び出すことができます。

  1. make target1

Make would then go to the Makefile and search for the target1 target. 次に、指定されたソースがあるかどうかを確認します。

It would find the target2 source dependency and jump temporarily to that target.

From there, it would check if target2 had any sources listed. It does not, so it would proceed to execute target2_command. At this point, make would reach the end of the target2 command list and pass control back to the target1 target. It would then execute target1_command and exit.

Sources can be either files or targets themselves. Make uses file timestamps to see if a file has been changed since its last invocation. If a change to a source file has been made, that target is re-run. それ以外の場合は、依存関係が満たされているとマークされ、次のソース、またはそれが唯一のソースである場合はコマンドに進みます。

The general idea is that by adding sources, we can build a sequential set of dependencies that must be executed before the current target. You can specify more than one source, separated by spaces, after any target. 手の込んだ一連のタスクを指定する方法を理解し始めることができます。

コマンド

What gives the make command such flexibility is that the command portion of the syntax is very open-ended. You can specify any command to run under the target. You can add as many commands as needed.

Commands are specified on the line after the target declaration. They are indented by one tab character. makeの一部のバージョンは、コマンドセクションをインデントする方法に柔軟性がありますが、一般に、makeが意図を認識できるように、単一のタブを使用する必要があります。

Make considers every indented line under the target definition to be a separate command. You can add as many indented lines and commands as you would like. Make will go through them one at a time.

コマンドの前に配置して、makeにそれらを異なる方法で処理するように指示できるものがいくつかあります。

追加機能

いくつかの追加機能は、Makefileでより複雑なルールチェーンを作成するのに役立ちます。

変数

Make recognizes variables (or macros), which behave as placeholders for substitution in your makefile. これらはファイルの先頭で宣言するのが最善です。

The name of each variable is completely capitalized. Following the name, an equal sign assigns the name to the value on the right side. たとえば、インストールディレクトリを次のように定義する場合 /usr/bin, we could add INSTALLDIR=/usr/bin at the top of the file.

Later in the file, we can reference this location by using the $(INSTALLDIR) syntax.

改行をエスケープする

私たちができるもう1つの便利なことは、コマンドが複数の行にまたがることを許可することです。

We can use any command or shell functionality within the command section. This includes escaping newline characters by ending the line with \:

Makefile
target: source
    command1 arg1 arg2 arg3 arg4 \
    arg5 arg6

if-thenステートメントなど、シェルのよりプログラム的な機能のいくつかを利用する場合、これはより重要になります。

Makefile
target: source
    if [ "condition_1" == "condition_2" ];\
    then\
        command to execute;\
        another command;\
    else\
        alternative command;\
    fi

This will execute this block as if it were a one line command. 実際、これを1行で書くこともできますが、このように分解すると読みやすさが大幅に向上します。

If you are going to escape end of line characters, be certain to not have any extra spaces or tabs after the \, or else you will get an error.

ファイルサフィックスルール

An additional feature that you can use for file processing is file suffixes. これらは、拡張子に基づいてファイルを処理する方法を提供する一般的なルールです。

たとえば、ディレクトリ内のすべての.jpgファイルを処理し、ImageMagickスイートを使用してそれらを.pngファイルに変換する場合、Makefileに次のようなものを含めることができます。

Makefile
.SUFFIXES: .jpg .png

.jpg.png:
    @echo converting $< to $@
    convert $< $@

ここで確認する必要があることがいくつかあります。

最初の部分は .SUFFIXES: declaration. This tells make about all of the suffixes we will use in file suffixes. Some suffixes that are used often in compiling source code, like .c and .o files are included by default and do not need to be labeled in this declaration.

The next part is the declaration of the actual suffix rule. This takes the form of original_extension.target_extension:.

これは実際のターゲットではありませんが、2番目の拡張子を持つファイルの呼び出しと一致し、最初の拡張子のファイルからそれらを構築します。

In our case, we can call make like this to build a file called file.png if there is a file.jpg in our directory:

  1. make file.png

make will find the png file in the .SUFFIXES declaration and see the rule for creating .png files. It will then look for the target file with the .png replaced by .jpg in the directory. その後、次のコマンドを実行します。

The suffix rules use some variables that we have not been introduced to yet. これらは、プロセスの現在の部分に基づいて、さまざまな情報を置き換えるのに役立ちます。

変換メイクファイルを作成する

画像操作を行うMakefileを作成し、ファイルをファイルサーバーにアップロードして、Webサイトで表示できるようにします。

If you would like to follow along, before you begin, ensure that you have the ImageMagick packages installed. These are command line tools for manipulating images and we will make use of them in our script.

On Ubuntu or Debian, update your package sources and install with apt:

  1. sudo apt-get update
  2. sudo apt-get install imagemagick

On Red Hat or Rocky, you’ll need to add the epel-release repo to get extra packages like this one, then install the package using dnf:

  1. dnf install epel-release
  2. dnf install ImageMagick

現在のディレクトリに、というファイルを作成します Makefile:

  1. nano Makefile

このファイル内で、コンバージョンターゲットの実装を開始します。

すべてのJPGファイルをPNGに変換する

Our server has been set up to serve .png images exclusively. このため、アップロードする前に.jpgファイルを.pngに変換する必要があります。

As we learned above, a suffix rule is a great way of doing this. まずは .SUFFIX declaration that will list the formats we are converting between: .SUFFIXES: .jpg .png.

Afterwards, we can make a rule that will change .jpg files into .png files. これは、 convert command from the ImageMagick suite. The convert command syntax is convert from_file to_file.

このコマンドを実装するには、開始する形式と終了する形式を指定するサフィックスルールが必要です。

Makefile
.SUFFIXES: .jpg .png

.jpg.png:           ## This is the suffix rule declaration

一致するルールができたので、実際の変換ステップを実装する必要があります。

Because we don’t know exactly what filename will be matched here, we need to use the variables that we learned about. 具体的には、参照する必要があります $< 元のファイルとして、および $@ as the file we are converting to. これをconvertコマンドについて知っていることと組み合わせると、次のルールが得られます。

Makefile
.SUFFIXES: .jpg .png

.jpg.png:
    convert $< $@

Let’s add some functionality so that we can be told explicitly what is happening with an echo statement. We will include the @ symbol before the new command and the command we already had in order to silence the actual command from being printed when it is executed:

Makefile
.SUFFIXES: .jpg .png

.jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

この時点で、ファイルを保存して閉じ、テストできるようにする必要があります。

Get a jpg file into the current directory. If you don’t have a file on hand, you can download one from the DigitalOcean website by using wget:

  1. wget https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/PoweredByDO/DO_Powered_by_Badge_blue.png
  2. mv DO_Powered_by_Badge_blue.png badge.jpg

makeファイルを作成するように依頼することで、これまでにmakeファイルが機能しているかどうかをテストできます。 badge.png ファイル:

  1. make badge.png
Output
converting badge.jpg to badge.png using ImageMagick... conversion to badge.png successful!

MakeはMakefileに移動します。 .SUFFIXES declaration and then go to the suffix rule that matches. 次に、リストされているコマンドを実行します。

ファイルリストを作成する

この時点で、そのファイルが必要であることを明示的に指定すると、makeは.pngファイルを作成できます。

It would be better if it just created a list of .jpg files in the current directory and then converted those. これを行うには、変換するすべてのファイルを保持する変数を作成します。

The best way to do this is with the wildcard directive like JPG_FILES=$(wildcard *.jpg).

We could just specify a target with a bash wildcard like JPG_FILES=*.jpg, but this has a shortcoming. If there are no .jpg files, this actually tries to run the conversion commands on a file called *.jpg, which will fail.

上記のワイルドカード構文は、現在のディレクトリにある.jpgファイルのリストをコンパイルします。存在しない場合は、変数を何にも設定しません。

While we are doing this, we should try to handle a slight variation in .jpg files that is common. These image files are often seen with the .jpeg extension instead of .jpg. To handle these in an automated way, we can change their name in our program to .jpg files.

上記の行の代わりに、次の2つを使用します。

Makefile
JPEG=$(wildcard *.jpg *.jpeg)     ## Has .jpeg and .jpg files
JPG=$(JPEG:.jpeg=.jpg)            ## Only has .jpg files

最初の行は、現在のディレクトリにある.jpgファイルと.jpegファイルのリストをコンパイルし、それらをという変数に格納します。 JPEG.

The second line references this variable and does a name translation to convert the names in the JPEG variable that end with .jpeg into names that end with .jpg. This is done with the syntax $(VARNAME:.convert_from=.convert_to).

これらの2行の終わりに、という新しい変数があります。 JPG which contains only .jpg filenames. Some of these files may not actually exist on the system, because they are actually .jpeg files (no actual renaming took place). このリストを使用して、作成する.pngファイルの new リストを作成するだけなので、これは問題ありません。

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)

これで、変数に要求するファイルのリストができました。 PNG. This list contains only .png filenames, because we did another name conversion. これで、このディレクトリ内の.jpgまたは.jpegファイルであったすべてのファイルを使用して、作成する.pngファイルのリストをコンパイルしました。

また、更新する必要があります .SUFFIXES 宣言とサフィックスのルールは、現在.jpegファイルを処理していることを反映しています。

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)
.SUFFIXES: .jpg .jpeg .png

.jpeg.png .jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

ご覧のとおり、サフィックスリストに.jpegを追加し、ルールに一致する別のサフィックスも含めました。

いくつかのターゲットを作成する

We have quite a lot in our Makefile right now, but we don’t have any normal targets yet. それを修正して、合格できるようにしましょう PNG サフィックスルールのリスト:

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)
.SUFFIXES: .jpg .jpeg .png

convert: $(PNG)

.jpeg.png .jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

All this new target does is list the .png filenames that we gathered as a requirement. 次に、Makeは、.pngファイルを取得する方法があるかどうかを確認し、サフィックスルールを使用して取得します。

Now, we can use this command to convert all of our .jpg and .jpeg files to .png files:

  1. make convert

Let’s add another target. Another task that is generally done when uploading images to a server is to resize them. Having your images the correct size will save your users from having to resize images on the fly when they request them.

と呼ばれるImageMagickコマンド mogrify can resize images in the way that we need. Let’s say the area where our images will be displayed on our site is 500px wide. 次のコマンドを使用して、この領域に変換できます。

  1. mogrify -resize 500\> file.png

This will resize any images larger than 500px wide to fit this area, but will not touch smaller images. This is what we want. ターゲットとして、次のルールを追加できます。

Makefile
resize: $(PNG)
    @echo resizing file...
    @mogrify -resize 648\> $(PNG)
    @echo resizing is complete!

これを次のようにファイルに追加できます。

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)
.SUFFIXES: .jpg .jpeg .png

convert: $(PNG)

resize: $(PNG)
    @echo resizing file...
    @mogrify -resize 648\> $(PNG)
    @echo resizing is complete!

.jpeg.png .jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

これで、これら2つのターゲットを別のターゲットの依存関係としてつなぎ合わせることができます。

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)
.SUFFIXES: .jpg .jpeg .png

webify: convert resize

convert: $(PNG)

resize: $(PNG)
    @echo resizing file...
    @mogrify -resize 648\> $(PNG)
    @echo resizing is complete!

.jpeg.png .jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

You may notice that resize implicitly will run the same commands as convert. We are going to specify them both though in case that is not always the case. 変換には、将来、より複雑な処理が含まれる可能性があります。

webifyターゲットは、画像を変換およびサイズ変更するようになりました。

リモートサーバーにファイルをアップロードする

Now that we have our images ready for the web, we can create a target to upload them to the static images directory on our server. これを行うには、変換されたファイルのリストをに渡します scp:

ターゲットは次のようになります。

Makefile
upload: webify
    scp $(PNG) root@ip_address:/path/to/static/images

This will upload all of our files to the remote server. ファイルは次のようになります。

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)
.SUFFIXES: .jpg .jpeg .png

upload: webify
    scp $(PNG) root@ip_address:/path/to/static/images

webify: convert resize

convert: $(PNG)

resize: $(PNG)
    @echo resizing file...
    @mogrify -resize 648\> $(PNG)
    @echo resizing is complete!

.jpeg.png .jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

掃除

リモートサーバーにアップロードされた後、すべてのローカル.pngファイルを削除するためのクリーニングオプションを追加しましょう。

Makefile
clean:
    rm *.png

Now, we can add another target at the top, that calls this one after we upload our files to the remote server. これが最も完全なターゲットであり、デフォルトにしたいターゲットです。

To specify this, we will put it as the first target available. This will be used as the default. We will call it all by convention:

Makefile
JPEG=$(wildcard *.jpg *.jpeg)
JPG=$(JPEG:.jpeg=.jpg)
PNG=$(JPG:.jpg=.png)
.SUFFIXES: .jpg .jpeg .png

all: upload clean

upload: webify
    scp $(PNG) root@ip_address:/path/to/static/images

webify: convert resize

convert: $(PNG)

resize: $(PNG)
    @echo resizing file...
    @mogrify -resize 648\> $(PNG)
    @echo resizing is complete!

clean:
    rm *.png

.jpeg.png .jpg.png:
    @echo converting $< to $@ using ImageMagick...
    @convert $< $@
    @echo conversion to $@ successful!

これらの最後の仕上げで、Makefileと.jpgまたは.jpegファイルを使用してディレクトリに入ると、引数なしでmakeを呼び出してファイルを処理し、サーバーに送信してから、アップロードした.pngファイルを削除できます。

  1. make

As you can see, it is possible to string together tasks and also to cherry pick a process up to a certain point. For instance, if you only want to convert your files and need to host them on a different server, you can just use the webify target.

結論

At this point, you should have a good idea of how to use Makefiles in general. 具体的には、ほとんどの種類の手順を自動化するためのツールとしてmakeを使用する方法を知っておく必要があります。

While in some cases it may work better to write a script, Makefiles are a way of setting up a structured, hierarchical relationship between processes. Learning how to leverage this tool can help make repetitive tasks more manageable.

モバイルバージョンを終了