1. 前言
- 在做什么事情之前,有一个好的工具是很重要的,这可能会起到事半功倍的效果,就如同磨刀不误砍柴功,有一曲同工之妙。
- 在我们编写C/C++工程时,也许我们会选择一个流行的IDE,如vs202x / vscode, CLoin 或者 Codeblocks,使用IDE的好处是可以不用写编译程序的脚本,只需要run code 就ok,操作方便,受人青睐。
- 如上的IDE在Win上比较受欢迎,但是在工作中,基本都是在Linux下开发,拥有一个通用的Make 脚本是很重要的,需编写Makefile;另外比Make 更高级一点的还有CMake, 需要编写CMakeLists.txt。(但是在工作中,基本上makefile都是写好了的,我们仅需看得懂,能够以葫芦画瓢,能修改就好)
- 另外工作中可能会使用的很多的shell命令,简单说就是在终端输入的命令,比如简单的ls, cd等;我们可以建立一个shell脚本,比如命名为s,可以将一些复杂经常使用的命令写到s脚本中(比如,编译某某工程,pull code,push code等等),以便以后使用(./s -b xx)。
2. Make 通用模板
//Makefile
# 编译器
CC = gcc
# 编译选项
CFLAGS = -Wall
# 目标文件
TARGET = myprogram
# 源文件
# 当前目录下的.c
SRCS = $(wildcard *.c)
#其他目录下的.c
SRCS += $(wildcard path/to/directory1/*.c)
SRCS += $(wildcard path/to/directory2/*.c)
# 头文件
INC = -Ipath/to/include1
INC += -Ipath/to/include2
CFLAGS += $(INC)
# LIB
LIB = -Lpath/to/lib1
LIB += -Lpath/to/lib2
CFLAGS += $(LIB)
#添加宏定义
CFLAGS += -DANDROID_OS
#添加其他模块的make文件
include /path/xxx/makefile
# 对象文件
OBJS = $(SRCS:.c=.o)
# 默认构建目标
all: $(TARGET)
# 生成可执行文件 这里可考虑将生成的中间文件放在build中: mkdir build && mv $(OBJS) build
$(TARGET): $(OBJS)
$(CC) -o $@ $^
# 生成目标文件
%.o: %.c
$(CC) $(CFLAGS) -c $<
# 清理生成的文件
clean:
rm -f $(OBJS) $(TARGET)
编译:该文件位于工程根目录,并在当前目录下执行 make 即可编译
如果想要添加别的工程的源文件,比如当前工程需要使用curl(这个是给的源文件)工程的东西,可以在curl中建立一个makefile, 里面包含器头文件和*.c文件,但是变量名要和主工程makefile中的一致(如INC, LIB,CFLAGS等),最后在主工程makefile中 include /path/xxx/makefile
3. 关键部分解释
### 源文件
SRCS = $(wildcard *.c)
这一行使用了 wildcard 函数,它会匹配当前目录下所有以 .c 结尾的文件,
并将结果保存在变量 SRCS 中。这里假设所有的源文件都是以 .c 结尾的。
### 对象文件
OBJS = $(SRCS:.c=.o)
这一行使用了替换规则,将变量 SRCS 中的 .c 后缀替换为 .o 后缀,
并将结果保存在变量 OBJS 中。这样就得到了所有的对象文件(即将编译后的源文件)。
### 生成可执行文件
$(TARGET): $(OBJS)
$(CC) -o $@ $^
这一行定义了生成可执行文件的规则,它依赖于变量 $(OBJS),也就是所有的对象文件。
$@ 表示目标文件名,$^ 表示所有的依赖文件。这条规则使用 $(CC)
编译器将所有的对象文件链接起来生成最终的可执行文件。
### 生成目标文件
%.o: %.c
$(CC) $(CFLAGS) -c $<
这一行定义了生成目标文件的规则,它使用了模式规则。%.o 表示任意的 .o 文件,
%.c 表示与之对应的同名 .c 文件。这条规则使用 $(CC) 编译器编译对应的 .c 文件,
并使用 $(CFLAGS) 编译选项进行编译。-c 选项表示只编译成目标文件而不进行链接。
$< 表示第一个依赖文件,即对应的 .c 文件。
4. Cmake 示例
//CMakeLists.txt
# 设置最低的 CMake 版本要求
cmake_minimum_required(VERSION 3.10)
# 设置项目名称
project(MyProject)
/*
# 添加所有源文件
set(SOURCES
src/main.c
src/util.c
src/other_file.c
)
*/
# 添加所有 .c 源文件
file(GLOB SOURCES "src/*.c")
# 添加可执行文件
add_executable(myprogram ${SOURCES})
# 添加头文件搜索路径
include_directories(include)
# 添加链接库搜索路径
link_directories(lib)
# 添加链接库
target_link_libraries(myprogram mylibrary)
# 指定编译选项
set(CMAKE_C_FLAGS "-Wall -O2")
# 设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
编译:在工程根目录建立一个build 目录,然后在build目录下执行cmake …/ && make ('/'前面两个点,表示上一级目录,不是三个点哦)
5. Shell 工具脚本
#!/bin/bash
# s
#使用说明
usage() {
echo "./s -build [option] : "
echo "./s -pull [option] : "
echo "./s -push [option] : "
}
#主函数,里面可任意添加
main() {
if [ "$1" == "-build" ]; then
if [ "$2" == "-c" ]; then
echo make clean
else
echo make path/xxx/makefile
fi
elif [ "$1" == "-pull" ]; then
echo git clone www.xxxx.xxx
elif [ "$1" == "-push" ]; then
echo git add .
echo git commit
echo git push
else
usage
fi
}
# for test
#aa="-build -c"
#main $aa
# normal "$@" 表示命令行参数传入main
main "$@"