1. 程式人生 > >手動建立makefile簡單例項解析!

手動建立makefile簡單例項解析!

假設我們有一個程式由5個檔案組成,原始碼如下:

/*main.c*/

#include 
"mytool1.h"
#include 
"mytool2.h"int main()
{
        mytool1_print(
"hello mytool1!");
        mytool2_print(
"hello mytool2!");
        
return0;
}
/*mytool1.c*/

#include 
"mytool1.h"
#include 
<stdio.h>void mytool1_print(char*print_str)
{
        printf(
"This is mytool1 print : %s ",print_str);
}
/*mytool1.h*/

#ifndef _MYTOOL_1_H
#define _MYTOOL_1_Hvoid mytool1_print(char*print_str);
#endif /*mytool2.c*/

#include 
"mytool2.h"
#include 
<stdio.h>void mytool2_print(char*print_str)
{
        printf(
"This is mytool2 print : %s ",print_str);
}
/*mytool2.h
*/

#ifndef _MYTOOL_2_H
#define _MYTOOL_2_Hvoid mytool2_print(char*print_str);
#endif

    首先了解一下make和Makefile。GNU make是一個工程管理器,它可以管理較多的檔案。我所使用的RedHat 9.0的make版本為GNU Make version 3.79.1。使用make的最大好處就是實現了“自動化編譯”。如果有一個上百個檔案的程式碼構成的專案,其中一個或者幾個檔案進行了修改,make就能夠自動識別更新了的檔案程式碼,不需要輸入冗長的命令列就可以完成最後的編譯工作。make執行時,自動尋找Makefile(makefile)檔案,然後執行編譯工作。所以我們需要編寫Makefile檔案,這樣可以提高實際專案的工作效率。

    在一個Makefile中通常包含下面內容:

1、需要由make工具建立的目標體(target),通常是目標檔案或可執行檔案。
2、要建立的目標體所依賴的檔案(dependency_file)。
3、建立每個目標體時需要執行的命令(command)。

格式如下:

 target:dependency_files
<TAB>command

target:規則的目標。通常是程式中間或者最後需要生成的檔名,可以是.o檔案、也可以是最後的可執行程式的檔名。另外,目標也可以是一個make執行的動作的名稱,如目標“clean”,這樣的目標稱為“偽目標”。

dependency_files:規則的依賴。生成規則目標所需要的檔名列表。通常一個目標依賴於一個或者多個檔案。


command:規則的命令列。是make程式所有執行的動作(任意的shell命令或者可在shell下執行的程式)。一個規則可以有多個命令列,每一條命令佔一行。注意:每一個命令列必須以[Tab]字元開始,[Tab]字元告訴make此行是一個命令列。make按照命令完成相應的動作。這也是書寫Makefile中容易產生,而且比較隱蔽的錯誤。命令就是在任何一個目標的依賴檔案發生變化後重建目標的動作描述。一個目標可以沒有依賴而只有動作(指定的命令)。比如Makefile中的目標“clean”,此目標沒有依賴,只有命令。它所指定的命令用來刪除make過程產生的中間檔案(清理工作)。


在Makefile中“規則”就是描述在什麼情況下、如何重建規則的目標檔案,通常規則中包括了目標的依賴關係(目標的依賴檔案)和重建目標的命令。make執行重建目標的命令,來建立或者重建規則的目標(此目標檔案也可以是觸發這個規則的上一個規則中的依賴檔案)。規則包含了目標和依賴的關係以及更新目標所要求的命令。
Makefile中可以包含除規則以外的部分。一個最簡單的Makefile可能只包含規則描述。規則在有些Makefile中可能看起來非常複雜,但是無論規則的書寫是多麼的複雜,它都符合規則的基本格式。

下面就可以寫出第一個Makefile了。

main:main.o mytool1.o mytool2.o
        gcc 
-o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
        gcc 
-c main.c
mytool1.o:mytool1.c mytool1.h
        gcc 
-c mytool1.c
mytool2.o:mytool2.c mytool2.h
        gcc 
-c mytool2.c

clean:
        rm 
-*.o main

在shell提示符下輸入make,執行顯示:

gcc -c main.c
gcc 
-c mytool1.c
gcc 
-c mytool2.c
gcc 
-o main main.o mytool1.o mytool2.o

執行結果如下:

[[email protected] makefile-easy]$ ./main
This 
is mytool1 print : hello mytool1!
This 
is mytool2 print : hello mytool2!

這只是最為初級的Makefile,現在來對這個Makefile進行改進。

改進一:使用變數

一般在書寫Makefile時,各部分變數引用的格式如下:
1. make變數(Makefile中定義的或者是make的環境變數)的引用使用“$(VAR)”格式,無論“VAR”是單字元變數名還是多字元變數名。
2. 出現在規則命令列中shell變數(一般為執行命令過程中的臨時變數,它不屬於Makefile變數,而是一個shell變數)引用使用shell的“$tmp”格式。
3. 對出現在命令列中的make變數同樣使用“$(CMDVAR)” 格式來引用。

OBJ=main.o mytool1.o mytool2.o

make:$(OBJ)
        gcc 
-o main $(OBJ)
main.o:main.c mytool1.h mytool2.h
        gcc 
-c main.c
mytool1.o:mytool1.c mytool1.h
        gcc 
-c mytool1.c
mytool2.o:mytool2.c mytool2.h
        gcc 
-c mytool2.c

clean:
        rm 
-f main $(OBJ)

改進二:使用自動推導

讓make自動推導,只要make看到一個.o檔案,它就會自動的把對應的.c檔案加到依賴檔案中,並且gcc -c  .c也會被推匯出來,所以Makefile就簡化了。

CC = gcc
OBJ 
= main.o mytool1.o mytool2.o

make: $(OBJ)
        $(CC) 
-o main $(OBJ)

main.o: mytool1.h mytool2.h
mytool1.o: mytool1.h
mytool2.o: mytool2.h

.PHONY: clean
clean:
        rm 
-f main $(OBJ)

改進三:自動變數($^  $<  [email protected])的應用

Makefile 有三個非常有用的變數,分別是[email protected]、$^、$<。代表的意義分別是:
[email protected]目標檔案,
$^--所有的依賴檔案,
$<--第一個依賴檔案。

CC = gcc
OBJ 
= main.o mytool1.o mytool2.o

main: $(OBJ)
        $(CC) 
-[email protected] $^

main.o: main.c mytool1.h mytool2.h
        $(CC) 
-c $<
mytool1.o: mytool1.c mytool1.h
        $(CC) 
-c $<
mytool2.o: mytool2.c mytool2.h
        $(CC) 
-c $<

.PHONY: clean
clean:
        rm 
-f main $(OBJ)

     這些是最為初級的知識,現在至少可以減少編譯時的工作量。細節方面的東西還需要在以後的工作和學習中不斷的總結,不斷的深化理解。可以 參考GNU Make手冊,這裡講解的比較全面。

相關推薦

手動建立makefile簡單例項解析

假設我們有一個程式由5個檔案組成,原始碼如下: /*main.c*/ #include "mytool1.h" #include "mytool2.h"int main() {         mytool1_print("hello mytool1!");         mytool2_print("

makefile 簡單例項

文章目錄 1 makefile 基本結構 2 Makefile 例項 2.1 專案檔案 2.2 makefile 編寫(不生成庫) 2.3 makefile 編寫(生成動態庫) 2.4 makefile

SAXReader簡單例項解析HTML

轉載自:http://blog.csdn.net/seayqrain/article/details/5024068# 使用SAXReader需要匯入dom4j-full.jar包。 dom4j是一個Java的XML API,類似於jdom,用來讀寫XML檔案的。dom4

MapReduce簡單例項解析map、reduce、combiner、partition一條龍

需求:通過MapReduce對紅樓夢TXT檔案統計笑、喜、哭、怒在全書的數量,使用combiner減少IO,通過partition輸出到兩個檔案中。 通過MapReduce外掛建立MapReduce project,這樣需要的包都會自動匯入 主函式:

Makefile簡單編寫例項

介紹一下Makefile的簡單編寫例子。 編寫Makefile的規則就是: 目標檔案:依賴檔案 (tab)編譯規則 現在我有一個檔案目錄結構為: 解釋一下這幾個檔案。首先我建立makefile目錄,底下有一個include目錄和src目錄。include目錄存放一個head.h標頭檔案,是我們sr

簡單例項開始,學會寫Makefile(一)

 不會寫Makefile雖然還不至於影響到專案進度,從別的地方拷貝一份過來稍加修改就可以用了,但是,對於咱們“程式猿”來說這實在是一件讓人感覺很不爽的事。於是,百度,谷歌(PS:吐槽一下,不XX的話Google已經完全不能用了,Bing的效果都要比百度好一些),各種看資料,看

Java簡單的繼承例項解析

面向物件程式語言具有封裝、繼承、多型三個基本特徵,本文就繼承舉例詳談 程式碼中有一個父類person1類,表示“這個人”,person1的一個子類為student,表示“這個人是學生”。 perso

aix下新建例項手動建立資料庫

**********************************字元下新建資料庫1. 建立相關目錄:$mkdir /oracle/app/oracle/admin/test$mkdir /oracle/app/oracle/admin/test/bdump$mkdir /oracle/app/oracle

Scala 解析檔案內容簡單例項

import scala.io.Source  //操作檔案的類 if(args.length > 0){   for(line <- Source.fromFile(args(0)).getLines())     println(line.

linux手動建立oracle例項全過程

先理解幾個概念 oracle跟mysql和mssql的不同,提出了例項和表空間等的概念例項:即一個執行的服務,不含任何物理資料和內容資料庫:依託於例項執行,資料庫和例項可以使1對1的關係,也可以是一對多的管理,即可以有不同例項載入資料庫,但是一個例項只能載入一個數據庫一個作業

Java技術_每天掌握一種設計模式(002)_使用場景及簡單例項建立型:單例模式)

1.模式描述 一個類有且僅有一個例項,並且自行例項化並向整個系統提供。 2.模式作用 保證某個類在系統中只有一個例項物件,對於特殊需求來說非常必要。 限制了例項個數有利於GC的回收。

Java技術_每天掌握一種設計模式(006)_使用場景及簡單例項建立型:原型模式)

1.模式描述 用原型例項指定建立物件的種類,並且通過拷貝來建立新的物件。 2.模式作用 可以一定程度上解耦,消費者和物件的構造過程隔離開,物件如何構造與消費者完全無關。 可以一定程度提升效率,複雜物件的構造往往需要較長的時間(中間可能會進行復雜運算或者資料庫

建立一個簡單spring例項,spring單例與多例,初始化與銷燬

(1)在配置完spring提示框架後(上一遍文章有介紹),首先建立一個專案,匯入sprig所需的jar包然後書寫主配置檔案applicationContext.<?xml version="1.0" encoding="UTF-8"?> <beans xml

Centos7手動部署Openstack Mitaka版安裝配置--(八)命令建立並使用例項

使用命令建立一臺虛擬機器例項 1、在控制節點上,載入 admin 憑證來獲取管理員能執行的命令訪問許可權 #source /root/admin-openrc 2、建立網路介面 #neutron net-create --shared --pro

tp3 上傳圖片出現上傳根目錄不存在請嘗試手動建立:./Public/Uploads/ 錯誤解決思路

下面看我的程式碼 方法一 我指定的路徑是在 ` public function upload( &data)      {data)      {upload = new \Think\Upload();// 例項化上傳類

利用navicat建立儲存過程、觸發器和使用遊標的簡單例項

建立儲存過程和觸發器 1、建表 首先先建兩張表(users表和number表),具體設計如下圖: 2、儲存過程 寫一個儲存過程,往users表中插入資料,建立過程如下:     程式碼如下: BEGIN #Routine body goes here... d

Java技術_每天掌握一種設計模式(003)_使用場景及簡單例項建立型:工廠方法)

1.模式描述 提供一個用於建立物件的介面(工廠介面),讓其實現類(工廠實現類)決定例項化哪一個類(產品類),並且由該實現類建立對應類的例項。 2.模式作用 可以一定程度上解耦,消費者和

MyBatis簡單例項及配置檔案解析

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/

MySQL新增觸發器簡單例項全程操作(包含建立表部分)

~~語法~~ CREATE TRIGGER <觸發器名稱>  --觸發器必須有名字,最多64個字元,可能後面會附有分隔符.它和MySQL中其他物件的命名方式基本相象.{ BEFORE | AFTER }  --觸發器有執行的時間設定:可以設定為事件發生前或後。{ INSERT | UPDATE 

java--通過sax方式解析xml檔案的簡單例項

1.重寫的繼承自DefaultHandler的方法,部分程式碼如下: @Override public void startElement(String uri, String localName, String qName, Attributes attribut