Linux 编译c/c++ makefile 通用脚本 & shell 工具脚本

6 篇文章 0 订阅
6 篇文章 0 订阅

1. 前言

  1. 在做什么事情之前,有一个好的工具是很重要的,这可能会起到事半功倍的效果,就如同磨刀不误砍柴功,有一曲同工之妙。
  2. 在我们编写C/C++工程时,也许我们会选择一个流行的IDE,如vs202x / vscode, CLoin 或者 Codeblocks,使用IDE的好处是可以不用写编译程序的脚本,只需要run code 就ok,操作方便,受人青睐。
  3. 如上的IDE在Win上比较受欢迎,但是在工作中,基本都是在Linux下开发,拥有一个通用的Make 脚本是很重要的,需编写Makefile;另外比Make 更高级一点的还有CMake, 需要编写CMakeLists.txt。(但是在工作中,基本上makefile都是写好了的,我们仅需看得懂,能够以葫芦画瓢,能修改就好
  4. 另外工作中可能会使用的很多的shell命令,简单说就是在终端输入的命令,比如简单的ls, cd等;我们可以建立一个shell脚本,比如命名为s,可以将一些复杂经常使用的命令写到s脚本中(比如,编译某某工程,pull code,push code等等),以便以后使用(./s -b xx)。

2. Make 通用模板

a. 简单工程,根目录下仅有.c和.h

#Makefile
# make -f make_base.mk
# 编译器
CC = gcc

# 编译选项
CFLAGS = -Wall

# 目标文件
TARGET = myprogram

# 源文件
# 当前目录下的.c
SRCS = $(wildcard *.c)

# 头文件
INC = -Imodule1/inc
# 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)

# 生成可执行文件 
$(TARGET): $(OBJS)
	$(CC) -o $@ $^
	mkdir -p build && mv $(OBJS) build
	mkdir -p bin && mv $(TARGET) bin

# 生成目标文件
%.o: %.c
	$(CC) $(CFLAGS) -c $<

# 清理生成的文件
clean:
	rm -f $(OBJS) $(TARGET)

b. 复杂工程,根目录下有main.c ./module1/src ./module1/inc等

#Makefile
# 编译器
CC = gcc

# 编译选项
CFLAGS = -Wall

# 目标文件
TARGET = mp
OBJ_DIR = build

# 源文件
# 当前目录下的.c
SRCS = $(wildcard *.c)
#其他目录下的.c
SRCS += $(wildcard module1/src/*.c)


# 头文件
CFLAGS += -Imodule1/inc
#CFLAGS += -Ipath/to/include2

# LIB
#CFLAGS += -Lpath/to/lib1
#CFLAGS += -Lpath/to/lib2

#添加宏定义
#CFLAGS += -DANDROID_OS

#添加其他模块的make文件
include ./module2/module.mk

# 对象文件和中间文件目录
# 将 SRCS 中的 .c 文件名转换为 $(OBJ_DIR)/%.o 格式的目标文件路径
OBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(SRCS:.c=.o)))
#OBJS = $(patsubst %.c,$(OBJ_DIR)/%.o,$(notdir $(SRCS)))

# 默认构建目标
all: $(TARGET)

# 生成可执行文件 
$(TARGET): $(OBJS)
	$(CC) -o $@ $^

# 生成根目录下的目标文件
$(OBJ_DIR)/%.o: %.c | $(OBJ_DIR)
	$(CC) $(CFLAGS) -c $< -o $@

# 生成其他目录下的目标文件
$(OBJ_DIR)/%.o: module1/src/%.c | $(OBJ_DIR)
	$(CC) $(CFLAGS) -c $< -o $@
	
# 创建中间文件目录
$(OBJ_DIR):
	mkdir -p $(OBJ_DIR)


# 清理生成的文件
clean:
	rm -rf $(OBJ_DIR) $(TARGET)

c.升级b版本的,简化了生成.o链接文件的过程,现在仅需要添加头文件和源文件即可编译ok(主要却别就是建立的一个文件夹@mkdir -p $(dir $@))

#Makefile
# 编译器
CC = g++

# 编译选项
CFLAGS = -Wall

# 目标文件
TARGET = mp
OBJ_DIR = build

# 源文件
# 当前目录下的.cpp
SRCS = $(wildcard *.cpp)
#其他目录下的.cpp
SRCS += $(wildcard module1/src/*.cpp)
SRCS += $(wildcard module2/src/*.cpp)

# 头文件
CFLAGS += -Imodule1/inc
CFLAGS += -Imodule2/inc
#CFLAGS += -Ipath/to/include2

# LIB
#CFLAGS += -Lpath/to/lib1
#CFLAGS += -Lpath/to/lib2

#添加宏定义
#CFLAGS += -DANDROID_OS

# 对象文件和中间文件目录
OBJS = $(SRCS:%.cpp=$(OBJ_DIR)/%.o)

# 默认构建目标
all: $(TARGET)

# 生成可执行文件 
$(TARGET): $(OBJS)
	$(CC) -o $@ $^

# 生成根目录下的目标文件
$(OBJ_DIR)/%.o: %.cpp | $(OBJ_DIR)
#创建文件夹很关键,不然会fail
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@

	
# 创建中间文件目录
$(OBJ_DIR):
	mkdir -p $(OBJ_DIR)


# 清理生成的文件
clean:
	rm -rf $(OBJ_DIR) $(TARGET)




编译:该文件位于工程根目录,并在当前目录下执行make 即可编译;或者指定目录:make -C <dir>, 或者指定文件make -f xx.mk

如果想要添加别的工程的源文件,比如当前工程需要使用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 文件。

### 生成其他目录下的目标文件
$(OBJ_DIR)/%.o: module1/src/%.c | $(OBJ_DIR)
	$(CC) $(CFLAGS) -c $< -o $@
# 创建中间文件目录
$(OBJ_DIR):
	mkdir -p $(OBJ_DIR)
“| $(OBJ_DIR)”是一个前置条件(order-only prerequisite),这个写法可以确保在执行其他规则之前,始终会先创建 $(OBJ_DIR) 目录,即使它已经存在也会执行创建目录的操作。

### 对象文件和中间文件目录
OBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(SRCS:.c=.o)))
#OBJS = $(patsubst %.c,$(OBJ_DIR)/%.o,$(notdir $(SRCS)))
将 SRCS 中的 .c 文件名转换为 $(OBJ_DIR)/%.o 格式的目标文件路径, 上面两句的效果是一样的;$(notdir $(SRCS:.c=.o))表示先将SRCS中的%.c转为%.o, 然后将前面的目录项去掉,如./src/tool.c -> tool.o

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 工具脚本

a. 简单示例

#!/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 "$@" 

b. 文末实际案列,用于编译运行工程

#!/bin/bash

usage() {
    echo "使用说明"
    echo "./s <-b> <project_name>	build project"
    echo "./s <-c> <project_name>	clean build & target"
	echo "./s <-r> <project_name>	run program"
}

main() {
    if [ $1 == "-b" ]; then
		if [ -n "$2" ]; then #$2有内容
        	cd $2
			make clean
			make
		else 
			usage
		fi
    elif [ $1 == "-c" ]; then
        if [ -n "$2" ]; then
        	cd $2
			make clean
		else 
			usage
		fi
	elif [ $1 == "-r" ]; then
		if [ -n "$2" ]; then  
        	./$2/mp
		else 
			usage
		fi

    else
        usage
    fi
}


main "$@"

6. 用来编译运行工程的工具示例下载

点我下载
如下是工程目录结构:包含C和C++工程, 如果要混合的工程需要自己捣鼓
在这里插入图片描述

  • 27
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值