【Linux系】第6回 Linux自動ビルドツール - make/makefile

1.メイクとメイクファイルの違い

makeはコマンドで、makefileはファイルです

2. 依存関係と依存メソッド

依存関係:依存関係は、2 つのファイル間の依存関係を示します。たとえば、test.o ファイルの生成は、test.s ファイルに依存します。

従属メソッド:従属メソッドは、この関係に依存するために必要なことです。たとえば、test.o を構成するには、test.s をアセンブルする必要があります。つまり、gcc -c test.s -o test.o です。

3. make/Makefile の使用

 #include <stdio.h>
 
 int main()
 {
    
    
	printf("hello Makefile\n");                                                                                                           
	return 0;
}

上記のコード列の場合、実行可能プログラムを生成するために Linux で記述する必要がある場合、以前は長い命令列を入力する必要がありましたが、makefile を学習した後は、gcc test.c -o testこの長い命令列を入力する必要がなくなりました。必要なものは 1 つだけです。make コマンドで十分です。

1. makefile を書く

  1. 最初に、ソース ファイルのディレクトリに Makefile または Makefile を作成します (最初の文字は大文字にすることができますが、他の文字は大文字にすることはできません)。
    ここに画像の説明を挿入

  2. 次にmakefileを開いてルールを編集します。1
    ここに画像の説明を挿入
    ここに画像の説明を挿入
    行目のコロンの左側のオブジェクトファイルmycodeが対象ファイルで、コロンの右側に応じて対象ファイルが生成されるmycode.cので、1行目は依存関係を書きますが、 2 行目はタブ キーを使用する必要があります。次に、2 つのファイルの依存メソッドを記述します。

  3. 次に、makeコマンドを直接使用します。このようにして
    ここに画像の説明を挿入
    、必要な実行可能プログラム ファイルが作成されます。

2. 一時ファイルをクリーンアップする

上記の書き込みが完了したら、必要な実行可能ファイルを生成できますが、生成された一時的な実行可能プログラム ファイルをクリーンアップする必要がある場合は、次のように記述できます。
ここに画像の説明を挿入

.PHONYこのキーワードで修飾されたオブジェクトが疑似ターゲットであることを示します。(この疑似ターゲットは常に実行可能です)

使用:以下に示すように:
ここに画像の説明を挿入

質問:コンパイル時に make を直接使用できるのに、クリーニングには clean が必要なのはなぜですか?

実際、make の後に mycod を続けることもできますが、make はデフォルトで、makefile の最初のターゲット ファイルの名前を省略できます。

3. makefile の動作原理

  1. make は、現在のディレクトリで「Makefile」または「makefile」という名前のファイルを探します。
  2. デフォルトでは、Makefile の最初のターゲットが最終ターゲットです。
      つまり、デフォルトでは、メイクファイルは実行可能なターゲット ファイルのみを形成します. 形成後、後続の依存関係と依存メソッドは実行されなくなります (デフォルトでは、常に上から下へのスキャンが実行され、最初のメソッドのみが形成されます)デフォルトは指定されていません。)
  3. all: デフォルトでは、Makefile はコンパイルを完了する最初のターゲット ファイルのみを生成しますが、すべてのターゲット ファイルを生成するように指定できます。
  4. 指定した関数を完成させる必要がある場合は、make コマンドの後に makefile に記述したコマンドを追加するだけです。

4.ファイルの3回

前述のように、.PHONY疑似ターゲットは変更され、疑似ターゲットはいつでも実行できます。どういう意味ですか?図に示すように、
ここに画像の説明を挿入
最初の make を実行すると、実行可能プログラム ファイルをコンパイルして生成できますが、2 回目の make を実行すると実行できず、mycode が最新であることを確認するプロンプトが表示され、いつでも変更でき.PHONYますclean。実行されます。


では、なぜ gcc コンパイルは mycode が最新であることを認識しているのでしょうか? 次に、ファイルの 3 つの時間を知りましょう。

[wyt@VM-20-4-centos lesson3]$ stat mycode.c
  File: ‘mycode.c’
  Size: 81        	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 794005      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1001/     wyt)   Gid: ( 1001/     wyt)
Access: 2023-02-11 17:08:52.893235379 +0800 //文件最近访问时间
Modify: 2023-02-04 13:21:39.841893206 +0800 //内容被修改时间
Change: 2023-02-04 13:21:39.841893206 +0800 //属性被修改时间
 Birth: -

4.1、アクセス: ファイルが最後にアクセスされた時刻

ファイルの内容を読み取り、ファイルの内容を変更すると、アクセスが変更されます。

ファイルの内容を変更すると、アクセス時刻はすぐに更新されますが、ファイルの読み取り時刻はすぐには更新されません。
ここに画像の説明を挿入
ここに画像の説明を挿入

cat、find などのファイルの読み取りや表示は頻度の高い操作ですが、これらのコマンドを頻繁に使用すると、アクセス時間が頻繁に更新され、Linux の処理速度が低下する可能性があります。

新しい Linux カーネルでは、この問題が最適化されており、ファイルが読み取られた後、アクセス時刻はすぐには更新されず、一定の時間間隔が経過すると、OS が自動的に時刻を更新します。

4.2、変更: ファイルの内容が最後に変更された時刻

ファイルの内容が変更される限り、変更時間は更新されます. これは頻度の低い操作と見なされるため、ファイルの内容を変更するとすぐに更新されます.

ただし、ファイルの内容を変更すると、途中でファイルの属性が変更される場合があります.たとえば、新しいコンテンツを追加すると、ファイルのサイズが変更されます (ファイルのサイズはファイルの属性に属します)。
ここに画像の説明を挿入

4.3. 変更: ファイル属性が最後に変更された時刻

ファイル属性の変更も頻度の低い操作と見なされ、ファイル属性を変更するとすぐに変更時刻が更新されます。

ファイル属性を変更するだけでは、変更およびアクセスの時間には影響しません。

ここに画像の説明を挿入

4.4、「xxx」が最新の問題

したがって、上記で遭遇した make の問題は非常に簡単に解決できます。
ここに画像の説明を挿入
最初のmakeの後、実行可能なターゲットファイルが生成され、makeの後、実行可能なターゲットファイルmycodeとソースファイルmycode.cの変更時刻を比較する必要があります

ここに画像の説明を挿入

実行可能オブジェクト ファイルmycodeの変更時刻がmycode.cソース ファイルの変更時刻よりも新しいため、コンパイルできなくなります。

ソースファイルの時刻が変更されたら、make を再度コンパイルできます。
ここに画像の説明を挿入

要約:

ソース ファイルの変更時刻がターゲット ファイルの変更時刻よりも新しい場合は、make を使用して再度コンパイルできます。

第四に、makefileの導出規則

次の図に示すように、makefile がスキャンされると、上から下にスキャンされます。
ここに画像の説明を挿入

make は、最初のターゲット ファイルが最終的にコンパイルされるまで、レイヤーごとにファイルの依存関係を見つけます。

上の図を例にとります。
ここに画像の説明を挿入
上記のように、mycode.i オブジェクト ファイルが最後に見つかった後、レイヤーごとに上に移動し、最終的に実行可能なオブジェクト ファイルを形成します。

上記の導出プロセスはスタック構造のようなもので、先入れ後出しです。

5.プログレスバーアプレット

1. ラインバッファの問題

まず、コード実行の次の 2 つの文字列の現象を見てください:
コード 1:
ここに画像の説明を挿入
現象:
写真の説明を追加してください

コード 2:
ここに画像の説明を挿入

現象:

写真の説明を追加してください

2 つのコード列の違いは\n、コード 1 にはあるのにコード 2 にはないということです。では、なぜ別の現象が発生するのでしょうか?

まず、コードがシーケンシャルに構成されていることを明確にする必要があります。つまり、上から下に実行されるため、printf が最初に実行され、次に sleep が実行されます。なぜ異なる現象があるのか​​というと、次のようになります。

、ここにラインバッファの概念があります。C 言語レベルのバッファーの場合、文字列は最初にこのバッファーに格納され、表示が更新されるのを待ちます。ただし、表示の更新は行の更新に属します。つまり、'\n' に遭遇したときに更新されます。これで、コード 2 には '\n' がなく、出力される文字列は C 言語レベルでバッファーに格納されており、これらの文字列はプログラムがほぼ終了したときにのみ画面上で更新されることがわかりました。 .

では、コード 2 の printf をすぐにモニターに表示するにはどうすればよいでしょうか。

#include <stdio.h>    
#include <unistd.h>    
int main()    
{
    
        
    printf("hello LInux");
    fflush(stdout);//fflush会立即刷新缓冲区
    sleep(2);    
    return 0;    
}   

2. キャリッジリターンとラインフィード (\r と \n)

理解:

  • \r: 入力。現在の行の先頭に戻る
  • \n: 改行。次の行に変更しますが、列は変更しません

言語レベルでは、\nキャリッジ リターンとライン フィードです。

3.カウントダウン機能

#include <stdio.h>    
#include <unistd.h>    
int main()    
{
    
        
    int cnt=10;    
    while(cnt)    
    {
    
        
        printf("%2d\r",cnt);//2d控制刷新两位,\r表示回车                                                                                   
        fflush(stdout);//手动刷新缓冲区   
        sleep(1);    
        --cnt;    
    }    
    return 0;    
}  

3.プログレスバーの実現

複数のファイル形式:
ここに画像の説明を挿入

ヘッドファイルprocess.h

#pragma once
 
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define NUM 101
extern void ProncessOn(); //函数的声明 

ソースファイルprocess.c

#include "process.h"

void ProncessOn() //函数的定义
{
    
    
    int cnt = 0;
    char bar[NUM];
    memset(bar, '\0', sizeof(bar));

    const char *lable = "|\\-/";
    while(cnt <= 100)
    {
    
    
        printf("[%-100s][%d%%][%c]\r", bar, cnt, lable[cnt%4]);
        fflush(stdout);//立即打印
        bar[cnt++] = '#';                                                                                                               
        //sleep(1);//单位是秒,太慢了
        usleep(50000); //微妙  5S/100 == 0.05S == 50000
    }
    printf("\n");
}

効果は次のとおりです。

写真の説明を追加してください

おすすめ

転載: blog.csdn.net/m0_58124165/article/details/128880757