前言
本文以實用爲第一目標,將給出一個 編譯 ++ 工程的固定模板,以便讀者可以迅速上手!
文章主要如下分爲三部分:
- 爲什麼需要 ?
- 如何編寫 ?
- 下編譯 ++ 工程的固定模板
如果覺得文章對你有幫助,請點個贊再走!(•̀ᴗ•́)و ̑̑
爲什麼需要 ?
的出現主要是由於在大型的 ++ 工程中,經常會出現文件相互依賴的情況。舉個例子, 文件調用了 文件中的 類 / 函數,因此我們需要將 文件統一鏈接在一起形成最終的可執行文件。
正是由於上述情況的存在,使得我們必須將工程中所有文件鏈接在一起,而手工一條一條命令敲又非常費時,因此我們需要 ,在我們給定編譯順序後自動幫助我們完成編譯。
我們將以下面的三份代碼爲例來介紹在 下使用 的方法。
#include <iostream>
#include "B.h"
using namespace std;
int main() {
cout << add(1, 2) << endl;
return 0;
}
#ifndef B_H
#define B_H
int add(int a, int b);
#endif
#include <iostream>
#include "B.h"
int add(int a, int b) {
return a + b;
}
由此不難發現,想要讓 文件能夠正確執行,我們需要將這三個文件統一鏈接在一起!如果一條一條命令輸的話,我們需要依次執行下述命令。
g++ -c A.c
g++ -c B.c
g++ -o main A.o B.o
顯然一條一條命令輸非常麻煩,因此我們需要 來簡化這個過程!
如何編寫 ?
我們以上述的例子爲例,簡要介紹我們的固定模板!
- 文件結構
- 兩個大文件夾:、
- 分爲兩個小文件夾,、
- 放最終的可執行文件
- 放 中的文件所生成的 文件
- 工程文件
- 最外層:、(最終可執行文件的鏈接文件)
- 語法規則
$@:
目標文件$^:
所有依賴文件$<
第一個依賴文件- 編譯語法規則
targets:
文件名,以空格分開,可以使用通配符command:
命令行,如果其不與 在一行,則必須以 鍵卡頭,如果和 在一行,則可以用分號作爲分隔prerequisites:
目標所依賴的文件,如果其中某個文件要比目標文件要新,則目標就被認爲是 “過時的”,被認爲是需要重新生成的- 《跟我一起寫 》
targets: prerequisites
command
- 定義變量
- 文件路徑
- 編譯命令參數
- 最終目標文件
dest_dir = build
src_dir = src
obj_dir = $(dest_dir)/objects
bin_dir = $(dest_dir)/bin
CC = g++
RESULT = main
CFLAGS = -Wall -O3 -std=c++14
CFILES = A.cpp B.cpp
ofiles = $(CFILES:%.cpp=$(obj_dir)/%.o)
program = $(bin_dir)/$(RESULT)
$(program): $(ofiles)
- 產生 文件
- 第一句:輸出編譯信息
- 第二句:如果不存在路徑上的文件夾,則創建文件夾
- 第三句:執行
g++ -c xxx.c
命令
# src 中所有 cpp 文件
$(obj_dir)/%.o: $(src_dir)/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
# src 所有子文件夾中 cpp 文件
$(obj_dir)/%.o: $(src_dir)/*/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
- 將所有 文件鏈接在一起生成可執行文件,並在最外層生成可執行文件的鏈接文件
- 第一句:輸出編譯信息
- 第二句:如果不存在路徑上的文件夾,則創建文件夾
- 第三句:執行
g++ -o 目標可執行文件 xxx1.o xxx2.o ...
命令 - 第四句:將目標可執行文件鏈接到最外層
$(bin_dir)/%:
@echo ">>> Linking" $@ "<<<"
@if [ ! -d $(bin_dir) ]; then mkdir -p $(bin_dir); fi;
$(CC) -o $@ $^
ln -sf $@ $(notdir $@)
- 命令
- 當我們需要重新編譯時,我們想要快速地刪除上一次編譯所產生的文件
- 我們可以自定義 命令,實現對上一次編譯生成文件的快速清理
.PHONY: clean
clean:
rm -rf $(dest_dir)
rm -f $(RESULT)
下編譯 ++ 工程的固定模板
至此,我們實現了一個簡易的編譯 ++ 工程的 的固定模板。
每次需要編譯,則先執行 ,再執行
工程: ,++ 工程: ++
增加需要編譯的文件: 在 變量後面繼續添加即可
# $@: 目標文件, $^: 所有依賴文件, $<: 第一個依賴文件
# 語法規則:
# targets: prerequisites
# command
dest_dir = build
src_dir = src
obj_dir = $(dest_dir)/objects
bin_dir = $(dest_dir)/bin
CC = g++
RESULT = main
CFLAGS = -Wall -O3 -std=c++14
CFILES = A.cpp B.cpp
ofiles = $(CFILES:%.cpp=$(obj_dir)/%.o)
program = $(bin_dir)/$(RESULT)
$(program): $(ofiles)
$(bin_dir)/%:
@echo ">>> Linking" $@ "<<<"
@if [ ! -d $(bin_dir) ]; then mkdir -p $(bin_dir); fi;
$(CC) -o $@ $^
ln -sf $@ $(notdir $@)
$(obj_dir)/%.o: $(src_dir)/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
$(obj_dir)/%.o: $(src_dir)/*/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -rf $(dest_dir)
rm -f $(RESULT)
後記
本文的主要目標就是幫助讀者快速迅速上手 下 ++ 工程的 文件編寫,因此並沒有太多涉及 的高階用法,有興趣的朋友可以仔細研讀陳皓所寫的《跟我一起寫 》!
技術水平的不斷提高在於不斷實踐,不斷記錄,持續精進!💪💪💪