前言
简要总结记录一下自己学习并使用 MakeFile 文件笔记。
g++编译单文件
Linux 系统下我们写了一个简单的 C++ 程序可以分别用如下命令编译运行:
g++ test.cpp -o test -std=c++17
./test
MakeFile 简介
MakeFile 是和 make 命令一起配合使用的,很多大型项目的编译都是通过 Makefile 来组织的,。
优点使用非常广泛,通用性强,可跨平台;缺点是语法比较繁琐。要写出一个通用,便于管理,且兼容性强的makefile比较困难。
简单 MakeFile
假设有如下目录结构:
include
— demo.h
src
— demo.cpp
— test.cpp
demo.h 文件代码如下:
#ifndef DEMO
#define DEMO
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
using namespace std;
namespace demo
{
class Point
{
/**
* Point coordinate information
*/
public:
Point(const double x = 0, const double y = 0):_x(x), _y(y) {}
Point(const Point& p) : _x( p.getX() ), _y( p.getY() ) {;}
~Point() {}
const double getX() const {return _x;}
const double getY() const {return _y;}
void setX(const double x) {_x = x;}
void setY(const double y) {_y = y;}
bool operator < (const Point& p) const;
protected:
double _x, _y;
};
};
#endif
demo.cpp 文件代码如下:
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <algorithm>
#include "demo.h"
using namespace std;
namespace demo
{
bool Point::operator < (const Point& p) const
{
double eps = 1e-10;
double px = p.getX();
double py = p.getY();
if(fabs(px-_x) < eps)
{
return py < _y;
} else {
return px < _x;
}
}
};
test.cpp 文件代码如下:
#include "iostream"
#include "demo.h"
using namespace std;
using namespace demo;
int main()
{
Point p(2, 3);
cout<<"("<<p.getX()<<", "<<p.getY()<<")"<<endl;
return 0;
}
则只需在 include 和 src 的同级目录下放一个 makefile 文件,内容如下:
TARGET_EXEC := final_program
CC = g++
CXX = g++
BUILD_DIR := ./build
SRC_DIRS := ./src
# Find all the C and C++ files we want to compile
# Note the single quotes around the * expressions. Make will incorrectly expand these otherwise.
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
# String substitution for every C/C++ file.
# As an example, hello.cpp turns into ./build/hello.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
# String substitution (suffix version without %).
# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
DEPS := $(OBJS:.o=.d)
# Every folder in ./src will need to be passed to GCC so that it can find header files
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# The -MMD and -MP flags together generate Makefiles for us!
# These files will have .d instead of .o as the output.
CPPFLAGS := $(INC_FLAGS) -MMD -MP
#SHAREHOME = /User/share/
#LDFLAGS = -L${SHAREHOME}/guihun/lib -lnglib
#LDFLAGS = -std=c++17 -O3 -I${SHAREHOME}/guihun/include/netgen
SHAREHOME = /Users/guihun/computer/c++/learn_makefile
LDFLAGS = -std=c++17 -O3 -I./include
# The final build step.
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@ $(LDFLAGS)
# Build step for C source
$(BUILD_DIR)/%.c.o: %.c
mkdir -p $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
# Build step for C++ source
$(BUILD_DIR)/%.cpp.o: %.cpp
mkdir -p $(dir $@)
$(CXX) $(LDFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
# Include the .d makefiles. The - at the front suppresses the errors of missing
# Makefiles. Initially, all the .d files will be missing, and we don't want those
# errors to show up.
-include $(DEPS)
之后在此目录下输入 make 命令回车即可,最终编译连接成功的 Binary 程序会出现在 build 文件夹下,程序名为: final_program,可用./final_program 运行该程序。
后记
最初想了解 MakeFile 是为了学习一些第三方库的使用。比如我在相同的 Linux 系统下, 编译好了第三方库的 .so 文件, 则我只需再有其头问价 .h, 然后编写自己的 learn_*.cpp 文件, 最后利用如上的 MakeFile 文件,即可编译链接出 Binary 程序。
总结
makefile 学习可以参考后面的两个网址,非常详细。
本博客提到的所有代码均可到我的 GitHub 下载。