久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

實用make最佳實踐

 Runs丶SS11 2014-10-15

一、前言

Make工具最主要也是最基本的功能就是通過makefile文件來描述源程序之間的相互關(guān)系并自動維護編譯工作,。而makefile 文件需要按照某種語法進行編寫,,文件中需要說明如何編譯各個源文件并連接生成可執(zhí)行文件,,并要求定義源文件之間的依賴關(guān)系。

然而make的命令"博客精深",對于初學(xué)者來說,,真是望而生畏,,這篇文章不是make詳解,,只是講解實用makefile的編寫和使用。

在linux上,,如果用gcc一個個編譯源碼,,實在很繁瑣,尤其是隨著源代碼的增加,,這種繁瑣更是明顯,,很多人,包括我,,其實要求很簡單,,只要把頭文件和cpp或者c文件放在當前目錄或者其他目錄,直接一個命令就可以編譯了,,但是make的命令太多了,,相當打擊初學(xué)者的信心。

常用的make指令其實不多,,夠用就行了,,接下來開始講解實用makefile的編寫,看完之后大家可以直接下載make工程直接一個make命令完成編譯,。

本文相關(guān)環(huán)境:redhat 5.5 + g++ version 4.1.2 + GNU Make 3.81

g++可以支持cpp文件編譯,,gcc編譯cpp文件在鏈接時會出現(xiàn)點問題,所以這里統(tǒng)一使用g++,。

 

二,、Makefile的規(guī)則

target ... : prerequisites ...
    command
    ...
    ...

comman如果和target不是同一行,需要在第二行鍵入\t再鍵入command.

target也就是一個目標文件,,可以是Object File,,也可以是執(zhí)行文件。還可以是一個標簽(Label)

這是一個文件的依賴關(guān)系,,也就是說,,target這一個或多個的目標文件依賴于prerequisites中的文件,其生成規(guī)則定義在command中,。

prerequisites中如果有一個以上的文件比target文件要新的話,,command所定義的命令就會被執(zhí)行。這就是Makefile的規(guī)則,。也就是Makefile中最核心的內(nèi)容,。

 

三、使用make一個個編譯源代碼

 假設(shè)我們寫一個簡單的程序,,源碼位于/usr/make/main.cpp,代碼如下:

復(fù)制代碼
//main.cpp
#include 
int main(int argc, char** argv) {
    printf("app startup\n");
    printf("app stop\n");
    return 0;
}
復(fù)制代碼

make的最大好處是自動化編譯,于是我們新建/usr/make/makefile,makefile文件內(nèi)容如下:

main:   main.o
    g++ main.o -o main
main.o: main.cpp
    g++ -c main.cpp -o main.o
clean:
    rm -rf *.o main

保存之后,,直接執(zhí)行make,就可以生成main.o目標文件,main可執(zhí)行文件了。

然而我們這個程序?qū)嵲趩伪×它c,,于是我們需要加入一個App類,,控制整個程序的啟動和關(guān)閉周期,。

新建/usr/make/app.h文件,代碼如下:

復(fù)制代碼
#ifndef APP_H
#define APP_H 

class App{
    public:
        static App& getInstance();
        bool start();
        bool shutdown();
        
    private:
        App();
        App(const App&);
        App& operator=(const App&);
        bool m_stopped;
};

#endif
復(fù)制代碼



新建/usr/make/app.cpp文件,,代碼如下:

復(fù)制代碼
#include "app.h"

#include 
#include 
App& App::getInstance() {
       static App app;
       return app;
}

App::App() {
       m_stopped = false;
}
   
bool App::start() {
       printf("app startup\n");
       while (!m_stopped) {
            printf("app run\n");
            sleep(5);
       }
       return true;
}

   bool App::shutdown() {
       if (m_stopped == false) {
           m_stopped = true; 
       }
       return true;
}
復(fù)制代碼



修改/usr/make/main.cpp文件,,代碼如下:

復(fù)制代碼
//main.cpp
#include 

#include "app.h"

int main(int argc, char** argv) {
    App& app = App::getInstance();
    
    if(!app.start()) {
        printf("app start fail\n");
    }
    
    app.shutdown();
    return 0;
}
復(fù)制代碼

修改/usr/make/makefile,內(nèi)容如下:

復(fù)制代碼
main:    main.o app.o
    g++ main.o app.o -o main
main.o:    main.cpp
    g++ -c main.cpp -o main.o
app.o:    app.cpp
    g++ -c app.cpp -o app.o
clean:
    rm -rf *.o main
復(fù)制代碼




執(zhí)行make,./main,發(fā)現(xiàn)后臺會每隔5秒打印出"app run",只能ctrl+c結(jié)束.

以后我們修改了main.cpp,app.cpp,app.h文件后,我們只要輸入make,,就可以自動編譯了,,不必每次一個個g++命令去進行繁雜的編譯過程。

這種方式,,以后每添加一個源碼文件,,我們就要手工修改makefile的內(nèi)容,添加依賴和命令,,仍然顯得不自動,。


 

四、使用make自動推導(dǎo)編譯

 GNU的make很強大,,它可以自動推導(dǎo)文件以及文件依賴關(guān)系后面的命令,,于是我們就沒必要去在每一個[.o]文件后都寫上類似的命令,因為,,我們的make會自動識別,并自己推導(dǎo)命令,。

 我們的是新的makefile又出爐了:

復(fù)制代碼
CPP_SOURCES = $(wildcard *.cpp)
CPP_OBJS = $(patsubst %.cpp, %.o, $(CPP_SOURCES))

default:compile

$(CPP_OBJS):%.o:%.cpp
    g++ -c $< -o $@

compile: $(CPP_OBJS)
    g++ $^ -o main

clean:
    rm -f $(CPP_OBJS)
    rm -f main
復(fù)制代碼
下面來一步步解析這個makefie的語法.
初始化:
wildcard函數(shù)功能是展開成一列所有符合由其參數(shù)描述的文件名,,文件間以空格間隔,本例是產(chǎn)生一個所有以 '.cpp' 結(jié)尾的文件的列表,然后存入變量 CPP_SOURCES.
patsubst函數(shù)是匹配替換的函數(shù),有三個參數(shù),,第一個是一個需要匹配的式樣,,第二個表示用什么來替換它,第三個是一個需要被處理的由空格分隔的字列,本例是把
CPP_SOURCES的后綴為cpp文件列表,,替換成后綴為o的文件列表,。
生成目標文件
$(CPP_OBJS):%.o:%.cpp
    g++ -c $< -o $@

上面的例子中,指明了我們的目標從$(CPP_OBJS)中獲取,,"%.o"表明要所有以".o"結(jié)尾的目標,,也就是"main.o app.o",也就是變量$(CPP_OBJS)集合的模式.
而依賴模式"%.cpp"則取模式"%.o"的"%",,也就是"main app",,再加上后綴"cpp".于是,我們的依賴目標就是"main.cpp app.cpp",。
而命令中的"$<"和"$@"則是自動化變量,,"$<"表示所有的依賴目標集(也就是"main.cpp app.cpp"),"$@"表示目標集(也就是"main.o cpp.o"),。

展開之后是:

main.o: main.cpp
    g++ -c main.cpp -o main.o
main.o: app.cpp
    g++ -c app.cpp -o app.o

鏈接

上述的default目標是是makefile的第一個目標,,依賴compile,,compile文件不存在,也不會出現(xiàn),,所以會執(zhí)行compile目標,。

default和compile只是makefile一個普通的規(guī)則而已,沒有特殊之處,。

compile: $(CPP_OBJS)
    g++ $^ -o main

"$<"表示所有的依賴目標集,表示main.o app.o

展開之后是

compile: main.o app.o
    g++ main.o app.o -o main


這種方式,,當我們在當前目錄添加cpp文件,不用再改makefile,,只要鍵入命令make就可以完成整個編譯過程,這個時候我們可以感受到make的自動化編譯的方便,。


makeprojectv2下載

 

五、實用makefile的完善

雖然我們已經(jīng)使用了makefile的自動推導(dǎo),,但是這個makefile還有有些不足:

1.只能支持cpp文件,不支持c文件

2.生成的目標文件全放在當前目錄,,造成當前目錄混亂

3.h文件和cpp文件或者c文件沒有分離,造成目錄里的源碼文件2倍爆炸,而且也不支持多目錄

4.不支持第三方的庫文件,,包括include文件和lib文件,。

于是,有一個完善的makefile如下:

復(fù)制代碼
TARGET = main
OBJ_PATH = objs

CC = g++
CFLAGS = -Wall -Werror -g
LINKFLAGS =

#INCLUDES = -I include/myinclude -I include/otherinclude1 -I include/otherinclude2
INCLUDES = -I include
#SRCDIR =src/mysrcdir src/othersrc1 src/othersrc2
SRCDIR = src
#LIBS = -Llib -lcurl -Llib -lmysqlclient -Llib -llog4cpp
LIBS =

C_SRCDIR = $(SRCDIR)
C_SOURCES = $(foreach d,$(C_SRCDIR),$(wildcard $(d)/*.c) )
C_OBJS = $(patsubst %.c, $(OBJ_PATH)/%.o, $(C_SOURCES))

CPP_SRCDIR = $(SRCDIR)
CPP_SOURCES = $(foreach d,$(CPP_SRCDIR),$(wildcard $(d)/*.cpp) )
CPP_OBJS = $(patsubst %.cpp, $(OBJ_PATH)/%.o, $(CPP_SOURCES))

default:init compile

$(C_OBJS):$(OBJ_PATH)/%.o:%.c
    $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@

$(CPP_OBJS):$(OBJ_PATH)/%.o:%.cpp
    $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@

init:
    $(foreach d,$(SRCDIR), mkdir -p $(OBJ_PATH)/$(d);)

compile:$(C_OBJS) $(CPP_OBJS)
    $(CC)  $^ -o $(TARGET) $(LINKFLAGS) $(LIBS)

clean:
    rm -rf $(OBJ_PATH)
    rm -f $(TARGET)

install: $(TARGET)
    cp $(TARGET) $(PREFIX_BIN)

uninstall:
    rm -f $(PREFIX_BIN)/$(TARGET)

rebuild: clean compile
復(fù)制代碼



 這個makefile的功能是掃描src文件夾的c文件和cpp文件,,進行編譯,,編譯的命令是g++,編譯選項是-Wall -Werror -g,表示盡可能打印出報錯信息,,有錯誤和警告就停止編譯,,并且生成調(diào)試信息。如果是生產(chǎn)環(huán)境,,請把-g去掉,。最后連接所有目標文件為main。如果所有的c文件和cpp文件沒有main函數(shù)入口,,鏈接會報錯,。

使用這個makefile,需要注意的幾個變量是:

TARGET 表示最后生成的可執(zhí)行文件的名字,,默認生成的main可執(zhí)行文件在當前工作目錄,。
OBJ_PATH  表示編譯過程中產(chǎn)生的目標文件放在那個目錄,默認生成放在在當前目錄的objs目錄下,,無需手工mkdir,,自動生成。
CC 默認是g++,,如果是使用gcc的,,請修改,但是gcc在編譯cpp文件后,,鏈接時會出現(xiàn)問題,,請自行解決,。
INCLUDES 配置頭文件的目錄,默認是include目錄,,如果放在當前目錄,,可以改為"INCLUDES = .",如果要配置多個include目錄,,可以按照注釋,,自行配置。
SRCDIR 配置c文件和cpp文件的目錄,,默認是src目錄,,如果喜歡放在當前目錄,可以改為"SRCDIR= .",如果要配置多個源碼目錄,,可以按照注釋,,自行配置。
LIBS 配置第三方的動態(tài)鏈接庫和靜態(tài)鏈接庫,,當程序使用了第三方庫時,,我們編譯是要配置第三方的頭文件目錄,鏈接時就要配置鏈接的庫文件,,LIBS配置可以參考注釋,,如果不清楚,請看本人博客里的“gcc常用命令”文章.

來自:http://www.cnblogs.com/ggjucheng/archive/2011/12/14/2288055.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多