本文主要探讨Makefile的通用模版。
项目文件结构图
模版介绍
#项目模版支持子模块动态和静态两种编译
静态编译: sh run.sh 1
静态清理: sh clean.sh 1
动态编译: sh run.sh
动态清理: sh clean.sh
默认产生可执行程序 :app
运行程序: sh app.sh
#编译默认产生的文件 : lib bin
lib 库文件
bin 可执行程序文件
#默认产生的文件目录为当前主目录,即make目录
#项目文件阐述
make 项目主目录
makefile 主makefile
makefile.mk 公共makefile
run.sh 项目编译脚本
clean.sh 项目清理脚本
app.sh 程序运行脚本
inlude 头文件目录
Math.h 子模块头文件
Thread.h 子模块头文件
Math 子模块目录
makefile 子模块makefile
Math.cpp 子模块源码
Thread 子模块目录
makefile 子模块makefile
Thread.cpp 子模块源码
App 主模块目录
makefile 主模块makefile
App.c 主模块源码
静态编译示例
静态编译结果
静态清理示例
静态清理结果
动态编译
动态编译结果
动态清理
动态清理结果
运行程序
模版文件
run.sh
#!/bin/bash
export LD_PATH
make STATIC_COMP=${1}
make STATIC_COMP=${1} install
clean.sh
#!/bin/bash
make STATIC_COMP=${1} clean
make STATIC_COMP=${1} uninstall
rm -rf $(pwd)/lib $(pwd)/bin
app.sh
#!/bin/bash
export LD_LIBRARY_PATH=$(pwd)/lib:$LD_LIBRARY_PATH
$(pwd)/bin/app 1
make/makefile
TARGET=Math Thread App
LDIR=$(shell pwd)
STATIC_COMP=0
OUT_FILE=$(shell pwd)
CTARGET=$(foreach n,$(TARGET),$(LDIR)/$n)
ITAG=_install
UTAG=_uninstall
ITARGET=$(foreach n,$(TARGET),$(LDIR)/$n$(ITAG))
UTARGET=$(foreach n,$(TARGET),$(LDIR)/$n$(UTAG))
all:$(TARGET)
$(TARGET):
$(MAKE) -C $(LDIR)/$@/ -f $(LDIR)/$@/makefile STATIC=$(STATIC_COMP)
clean:$(CTARGET)
$(CTARGET):
$(MAKE) -C $@ -f $@/makefile STATIC=$(STATIC_COMP) clean
install:$(ITARGET)
$(ITARGET):$(TARGET)
$(MAKE) -C $(subst $(ITAG),,$@) -f $(subst $(ITAG),,$@)/makefile STATIC=$(STATIC_COMP) OUT=$(OUT_FILE) install
uninstall:$(UTARGET)
$(UTARGET):
$(MAKE) -C $(subst $(UTAG),,$@) -f $(subst $(UTAG),,$@)/makefile OUT=$(OUT_FILE) STATIC=$(STATIC_COMP) uninstall
.PHONY: clean install uninstall all $(CTARGET) $(ITARGET) $(TARGET) $(UTARGET)
make/makefile.mk
ifndef TARGET
TARGET:= $(notdir $(shell pwd)) #获取当前路径
endif
CXXFLAGS:=$(CXXFLAGS) -I ../include #编译选项
LDLIBS:=$(LDLIBS) -lpthread #链库
LDFLAGS:=$(LDFLAGS) #编库选项
OUT:=/usr #输出路径
SRCS:=$(shell find $(shell pwd) -type f -name "*.cpp") #获取源码集合
OBJS:=$(patsubst %.cpp,%.o,$(SRCS)) #获取依赖集合
#编库前奏
ifeq ($(LIBTYPE),.so)
TARGET:=lib$(strip $(TARGET)).so #strip剔除空格
LDLIBS:=$(LDLIBS) -shared #共享库
CXXFLAGS:=$(CXXFLAGS) -fPIC #位置无关
endif
ifeq ($(LIBTYPE),.a)
TARGET:=lib$(strip $(TARGET)).a #strip剔除空格
endif
#编译
all:depend $(TARGET)
depend:
@$(CXX) $(CXXFLAGS) -MM $(SRCS) > .depend
-include .depend
#生成程序
#$@目标集合,$^去重依赖集合
$(TARGET):$(OBJS)
ifeq ($(LIBTYPE),.a)
$(AR) -cr $@ $^
else
$(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)
endif
define INSTALL
-mkdir -p $(2)
cp $(1) $(2)
endef
install:$(TARGET)
$(call INSTALL,$(TARGET),$(OUT)/lib)
uninstall:clean
$(RM) $(OUT)/lib/$(TARGET)
#清理
clean:
$(RM) $(TARGET) $(OBJS) .depend
.PHONY: clean all depend install uninstall
include/Math.h
#ifndef __MATH_H__
#define __MATH_H__
class Math
{
public:
Math();
Math(int num_1, int num_2):num_1(num_1),num_2(num_2){};
void get_num();
void set_num(int num_1, int num_2);
int add_num();
int dec_num();
private:
int num_1;
int num_2;
};
#endif
include/Thread.h
#ifndef __THREAD__H__
#define __THREAD__H__
#include <thread>
class Thread
{
public:
virtual void start_pthread();
virtual void wait_pthread();
virtual void pthread_task() = 0;
private:
std::thread th;
};
#endif
Math/makefile
ifeq ($(STATIC),1)
LIBTYPE=.a
else
LIBTYPE=.so
endif
include ../makefile.mk
Math/Math.cpp
#include <iostream>
#include "Math.h"
int Math::add_num()
{
return num_1 + num_2;
}
int Math::dec_num()
{
return num_1 - num_2;
}
void Math::get_num()
{
std::cout << "num_1:" << num_1 << std::endl;
std::cout << "num_2:" << num_2 << std::endl;
}
void Math::set_num(int num_1, int num_2)
{
this->num_1 = num_1;
this->num_2 = num_2;
}
Thread/makefile
ifeq ($(STATIC),1)
LIBTYPE=.a
else
LIBTYPE=.so
endif
include ../makefile.mk
Thread/Thread.cpp
#include <iostream>
#include "Thread.h"
void Thread::start_pthread()
{
std::cout << " start pthread" << std::endl;
th = std::thread(&Thread::pthread_task,this);
}
void Thread::wait_pthread()
{
th.join();
}
App/makefile
TARGET:=app
CXXFLAGS:=$(CXXFLAGS) -I ../include #编译选项
LDLIBS:=$(LDLIBS) -lMath -lThread #链库
LDFLAGS:=-L ../Thread -L ../Math #编库选项
OUT:=/usr #输出路径
SRCS:=$(shell find $(shell pwd) -type f -name "*.cpp") #获取源码集合
OBJS:=$(patsubst %.cpp,%.o,$(SRCS)) #获取依赖集合
#编译
all:depend $(TARGET)
depend:
@$(CXX) $(CXXFLAGS) -MM $(SRCS) > .depend
-include .depend
$(TARGET):$(OBJS)
$(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS) $(LDLIBS)
define INSTALL
-mkdir -p $(2)/bin
cp $(1) $(2)/bin
endef
install:$(TARGET)
$(call INSTALL,$(TARGET),$(OUT))
uninstall:clean
$(RM) $(OUT)/bin/$(TARGET)
clean:
$(RM) $(TARGET)
.PHONY: clean install uninstall
App/App.cpp
#include <iostream>
#include <chrono>
#include <thread>
#include "Thread.h"
#include "Math.h"
class Task: public Thread
{
public:
Task(int sec):sec(sec){};
void pthread_task()
{
for(int i = 0; ; i++)
{
std::cout << "Task:" << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(sec));
}
}
private:
unsigned int sec;
};
int main(int argc, char *argv[])
{
if(argc != 2)
{
std::cout << "input param error" << std::endl;
return 0;
}
Math m(1,2);
m.get_num();
std::cout << "1 + 2 = " << m.add_num() << std::endl;
std::cout << "1 - 2 = " << m.dec_num() << std::endl;
m.set_num(2,1);
m.get_num();
std::cout << "2 + 1 = " << m.add_num() << std::endl;
std::cout << "2 - 1 = " << m.dec_num() << std::endl;
Task t(atoi(argv[1]));
t.start_pthread();
t.wait_pthread();
return 0;
}