1.Cmake常用模板
常用模板
/*
cmake版本
必选项。放在第一行,指定cmake最低版本。
*/
cmake_minimum_required(VERSION 3.10) # 必须
/*
指定语言版本
这里其实是用set给默认变量CMAKE_CXX_STANDARD & CMAKE_C_STANDARD 赋值。
*/
set(CMAKE_CXX_STANDARD 14) # C++14
/*
设置工程名字
这个应该可以必选项。工程名后面可选 加 语言类型。
指定的工程名,在后面可以通过变量${PROJECT_NAME}获取此值。
project(HelloWorld CXX) # 可选指明是C++
project(HelloWorld C CXX) # C & C++
*/
project(HelloWorld) #工程名
/*
指定头文件目录
include_directories后可以可以加SYSTEM标志,这个标志是告诉编译器将此目录视为系统目录,跳过某些编译检查。
一般不用加SYSTEM。
include_directories("../third-party/include/")
include_directories(SYSTEM "/usr/local/include/") # 可选SYSTEM
*/
include_directories("/usr/local/include/") # 头文件目录
/*
指定链接库目录
动态库或者静态目录
我查到了有两个函数link_libraries和target_link_libraries,这两者区别是 前者需放生成目标之前,后者放在生成目标之后。
link_libraries(pthread) # 在add_executable前面
add_executable(${PROJECT_NAME} main.cpp)
或者
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} pthread) # 在add_executable后面,且第一参数为目标名。
Clion工程采用的是第一种方式。要是按照 编译-链接 的顺序,还是后者比较好理解。
*/
link_directories("/usr/local/lib/") # 链接库目录
/*
指明源码文件
可以用aux_source_directory(目录名 变量)来检索此目录下所有源文件。
或者使用FILE()函数检索。
aux_source_directory(. SRCS) # 当前目录
aux_source_directory(../common/ SRCS) # 上级目录
FILE(GLOB SRCS ${PROJECT_SOURCE_DIR}/*.cpp) # 匹配源码目录所有.cpp文件
FILE(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/*.cpp ) # 递归搜索匹配源码目录和其子目录下的.cpp文件
*/
aux_source_directory(. SRCS) # 源文件
aux_source_directory(./abc SRCS)
/*
生成可执行文件
add_executable(可执行文件名 源文件),源文件可以是变量形式,或者后面加了一串源文件名。
*/
add_executable(${PROJECT_NAME} ${SRCS}) # 生成可执行文件,这里程序名即为功能名
/*
见上
*/
target_link_libraries(${PROJECT_NAME} pthread) # 链接库
/*
一般开源项目需要安装的,都有make install命令,这个命令是通过install函数实现的。
安装的时候一般都需要指定安装路径,cmake里面通过设置CMAKE_INSTALL_PREFIX来实现的,可以在执行cmake的时候直接指定,
比如cmake .. -DCMAKE_INSTALL_PREFIX=./local,Linux环境默认是/usr/local目录。
# 安装动态库到lib目录
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib) # 安装在 /usr/local/lib目录
install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION lib) # 多用于静态库
# 安装对外头文件
install(TARGETS ${XXXX} PUBLIC_HEADER DESTINATION include)
*/
# 下面使用install作为项目打包使用
set(CMAKE_INSTALL_PREFIX ./dist) # 自定义安装目录,打包使用
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) # 打包二进制文件,安装在 /usr/local/bin目录
set(CONFIGS ${PROJECT_SOURCE_DIR}/hello.cf)
install(FILES ${CONFIGS} DESTINATION config) # # 安装其他文件,比如配置文件
===============其他==============
/*
多级目录多个工程
可以使用add_subdirectory编译子目录中的cmake工程。
*/
add_subdirectory(subdir)
/*
输出方式
message函数输出,可以指定输出消息类型STATUS WARNING DEBUG等。
*/
message("hello")
message(STATUS ${PROJECT_NAME})
/*
常见宏(默认变量)
*/
宏 说明
PROJECT_NAME project()设置的工程名
PROJECT_SOURCE_DIR 工程源码目录,例如 ~/Hello/
PROJECT_BINARY_DIR 生成文件目录,例如 ~/Hello/build
使用方法
- cmake工程一般都不在源码目录直接编译,通常新建目录进行编译,配置失败可以直接删除新目录再重新配置。
比如有个hello工程
cd hello
mkdir build
cd build
cmake ..
make
2.makefile常用模板
单文件项目
- 假设有hello.c文件。
all: Hello
Hello:
gcc -o Hello hello.c
clean:
rm -rf Hello
====单文件项目进阶版(多文件)====
.PHONY:clean all
CC=gcc
CPP=g++
CFLAGS=-Wall -g
BIN=codedump_OSSPopLogque ip const_cpp:const_cpp
CFLAGS_MORE=-pthread
all:$(BIN)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
%.o:%.cpp
$(CPP) $(CFLAGS) -c $< -o $@
codedump_OSSPopLogque:codedump_OSSPopLogque.o
$(CC) ${$(CFLAGS_MORE)} $^ -o $@
ip:ip.o
$(CC) $(CFLAGS) $^ -o $@
const_cpp:const_cpp.o
$(CPP) $(CFLAGS) $^ -o $@
clean:
rm -f $(BIN) *.o
多文件项目
- 假设一个工程下,有main.c和有多个.c源文件以及同名的.h头文件
# .PHONE伪目标,具体含义百度一下一大堆介绍
.PHONY:all clean
# 方便起见一般都会先定义编译器链接器
CC = gcc
LD = gcc
# -I指定头文件目录
INCLUDE = -I./include
# -L指定库文件目录,-l指定静态库名字(去掉文件名中的lib前缀和.a后缀)
LIB = -L./libs -ltomcrypt
# 开启编译warning和设置优化等级
CFLAGS = -Wall -O2 -g
# 可执行文件的名字
TARGET = Hello
# 要生成的目标文件
all: $(TARGET)
#链接
# 第一行依赖关系:冒号后面为依赖的文件,相当于Hello: main.o a.o b.o
# 第二行规则:$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
$(TARGET): $(OBJS)
$(LD) $^ -o $@ $(LIB)
##下面两个等价
## 正则表达式表示目录下所有.c文件,相当于:SRCS = main.c a.c b.c
#SRCS = $(wildcard *.c)
## OBJS表示SRCS中把列表中的.c全部替换为.o,相当于:OBJS = main.o a.o b.o
#OBJS = $(patsubst %c, %o, $(SRCS))
## 上一句目标文件依赖一大堆.o文件,这句表示所有.o都由相应名字的.c文件自动生成
##编译
%.o:%.c
$(CC) ${INCLUDE} $(CFLAGS) -c $< -o $@
# make clean删除所有.o和目标文件
clean:
rm -f $(OBJS) $(TARGET)
多个文件,多个程序(建议使用单文件的进化版)
- 把a.c/b.c/d.c都要编译成可执行文件a/b/c
C_SRC = $(wildcard *.c)
C_OBJ = $(patsubst %c, %o, $(C_SRC))
# 目标文件也是多个
TARGETLIST = $(patsubst %.c, %, $(C_SRC))
.PHONY:all clean
# 这句不写规则的语句可以自动把相应的a.c b.c编译成a b
all:${TARGETLIST}
clean:
rm -f ${TARGETLIST} *.o
遍历执行子目录下的Makefile
- 有这么个应用场景,当前目录下有多个子目录,且每个子目录下都有独立的Makefile文件,相当于目录下有多个独立的工程,现在需要执行make把各个子目录下的工程全部编译
- 赋值符号,=基本赋值,:=覆盖之前的指,?=如果没有值则赋值,+=继续添加后面的值
.PHONY:all clean
# 排除目录
exclude_dirs := .git
# 显示深度为1的子目录
dirs := $(shell find . -type d -maxdepth 1)
# 去掉获取到目录名称前面的./
dirs := $(basename $(patsubst ./%, %, $(dirs)))
# 过滤指定目录
dirs := $(filter-out $(exclude_dirs), $(dirs))
all:
$(foreach N,$(dirs),make -C $(N);)
clean:
$(foreach N,$(dirs),make -C $(N) clean;)