番外14:make和cmake了解及小项目实现

文章目录

一、makefile

0.make零散知识补充

  • 原因:

因为以前是只用过makefile所以,复习下,顺便总结cmake怎么写

  • 1)makefile三个要素:依赖、目标、命令
  • 2)对于make ⼯具,⼀个⽂件是否改动不是看⽂件⼤⼩,⽽是其时间戳
  • 3)在现实中也难免存在所定义的⽬标与所存在的⽂件是同名的,可以用.PHONY

1.第一个makefile

.PHONY: test #用 .PHONY),这就告诉 make 不用检查它们 是否存在于磁碟
test: #echo 前⾯必须只有 TAB, echo功能是打印字符串到终端上
	@echo "hello test"
all: test
	@echo "hello all"
#运⾏“make all”命令,这告诉 make ⼯具,我要⽣成⽬标 all
#第一个目标是默认生成的

2.第二个makefile

//main.c
extern void foo();
int main()
{
    foo();
    return 0;
}

//foo.c
#include <stdio.h>
void foo()
{
    printf ("This is foo ()!\n");
}

//makefile
#第一个目标是默认生成的
.PHONY: clean
all: main.o foo.o			#生成simple执行文件,依赖两个文件
	gcc -o simple main.o foo.o 
main.o:
	gcc -o main.o -c main.c
foo.o:
	gcc -o foo.o -c foo.c
clean:						#删除.o文件和执行文件
	rm simple main.o foo.o
  • 依赖树
    在这里插入图片描述

3.第三个makefile

.PHONY: all
all: first second third
	@echo "\$$@ = $@"
	@echo "$$^ = $^"
	@echo "$$< = $<"
first: #生成一个bin目录
	mkdir bin
second third:

# $@用于标识一个规则中的目标,当我们的一个规则中有多个目标时,$@指的是其中任何造成命令被运行的目标
# $^表示的是规则中的所有先决条件(依赖)
# <表示的是规则中的第一个先决条件	
# 想采⽤ echo 输出‘$’,则必需⽤两个连着的‘$’
# $@对于 Shell 也有特殊的意思,我们需要在“$$@”之前再加⼀个脱字符‘\’

在这里插入图片描述

4.第四个makefile

.PHONY: clean
CC = gcc 	  #CC⽤于保存编译器名
RM = rm  	  #RM⽤于指示删除⽂件的命令
EXE = simple  #EXE⽤于存放可执⾏⽂件名
# SRCS = main.c foo.c
SRC$ = $(wildcard *.c)  			#wildcard搜索所有.c文件
# patsubst把.c换成对应的.o
# OBJS = foo.o foo2.o main.o 
OBJS = $(patsubst %.c,%.o,$(SRCS)) # OBJS⽤于放置所有的⽬标⽂件名(.c、.o文件)

$(EXE): $(OBJS)		#生成EXE需要OBJS,OBJS需要SRC
	$(CC) -o $@ $^
%.o: %.c            #.c生成点.o,$@表示.o文件,$^表示.c文件
	$(CC) -o $@ -c $^
clean:
	$(RM) $(EXE) $(OBJS)
# $@⽤于表示⼀个规则中的⽬标。当我们的⼀个规则中有多个⽬标时,$@所指的是其中任何造成命令被运⾏的⽬标
# $^则表示的是规则中的所有先择条件
# $<表示的是规则中的第⼀个先决条件

5.第五个makefile

.PHONY: all clean

MKDIR = mkdir
RM = rm 
RMFLAGS = -fr
CC = gcc
DIR_OBJS = objs
DIR_EXES = exes
DIRS = $(DIR_OBJS) $(DIR_EXES)

EXE = complicated
#让生成的执行文件放到exes目录
EXE := $(addprefix $(DIR_EXES)/,$(EXE))

SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
#让生成的.o放在objs目录
OBJS := $(addprefix $(DIR_OBJS)/,$(OBJS))

all: $(DIRS) $(EXE)

$(DIRS):
	$(MKDIR) $@

$(EXE)
	$(CC) -o $@ $^

$(DIR_OBJS)/%.o: %.c foo.h
	$(CC) -o $@ -c $<

clean:
	$(RM) $(RMFLAGS) $(DIRS)

二、cmake

1)cross-platform development

跨平台不用cmake(需要做四项修改)
在这里插入图片描述
使用Cmake之后:(只需要修改cmakelist.txt)

在这里插入图片描述

2)语法特性介绍

  • 基本语法格式

在这里插入图片描述

  • 指令是大小写无关的,参数和变量大小是大小写相关的

在这里插入图片描述

  • 变量使用${}方式取值,但是再IF控制语句中是直接使用变量名

3)Cmake重要指令

(1)cmake_minimum_required

在这里插入图片描述

(2)project 定义工程名称,并指定工程支持的语句

这里可选项【。。。】一般都不用在这里插入图片描述

(3)set 显示的定义变量

在这里插入图片描述

(4)include_directories 向工程添加多个特定的头文件搜索路径

在这里插入图片描述

(5)link_directories-向工程添加多个特定的库的文件搜索路径(只是提供路径)

在这里插入图片描述

(6)add_library-生成库文件

前面定义的SRC为两个.c文件(默认生成静态库,生成动态库需要加SHARED)
在这里插入图片描述

(7)add_compile_options-添加编译参数

在这里插入图片描述
在这里插入图片描述

(8)add_executable-生成可执行文件

在这里插入图片描述

(9)add_executable-生成可执行文件

在这里插入图片描述

(10)target_link_libraries-为target添加需要链接的共享库

hello就是库的名字,main是可执行文件,这里是给可执行文件链接库
在这里插入图片描述

(11)add_subdirectory-向当前工程添加存在源文件的子目录,并可以指定中间二进制和目标二进制存放的位置(添加子目录)

在这里插入图片描述

(12)aux_source_directory-发现一个目录下所有的源代码文件并将列表存储再一个变量中,这个指令临时被用来自动构建源文件列表(用来做库的命令,等等添加当前目录的.c和.h文件)

把当前目录下的.c和.cpp文件都放到SRC这个目录中
()
在这里插入图片描述

(13)MESSAGE 往屏幕打印信息

在这里插入图片描述
在这里插入图片描述

(14)INSTALL 安装二进制、动态库、链接库或文件目录等等到对应目录

INSTALL指令⽤于定义安装规则,安装的内容可以包括⽬标⼆进制、动态库、静态库以及⽂件、⽬录、脚本等。INSTALL指令包含了各种安装类型,我们需要⼀个个分开解释:

安装可执行的目标文件

在这里插入图片描述

普通文件

在这里插入图片描述

目录

在这里插入图片描述

  • 例子

顶级目录

在这里插入图片描述

子目录
在这里插入图片描述

  • 目录结构
    在这里插入图片描述
(15)SET_TARGET_PROPERTIES生成名字相同的静态库和动态库

在这里插入图片描述

  • 但还是有潜在问题
    在这里插入图片描述
(16)SET(LIBRARY_OUTPUT_PATH <路径>)指定⼀个新的位置给生成的库文件

在这里插入图片描述

下⾯我们⽤这个指令再来添加静态库:
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

(17)SET_TARGET_PROPERTIES设置动态库版本号

在这里插入图片描述

4)Cmake常用变量

(1)CMAKE_C_FLAGS gcc编译选项

c语言的编译选项

(2)CMAKE_CXX_FLAGS g++编译选项
#在g++编译选项后追加-std=c++11
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 " ) 
(3)CMAKE_BUILD_TYPE 编译类型(Debug , Release)
#设置编译类型为debug
set(CMAKE_BUILD_TYPE  Debug)
#设置编译为release
set(CMAKE_BUILD_TYPE Release)
(4)CMAKE_BINARY_DIR 和 CMAKE_SOURCE_DIR

在这里插入图片描述

(5)CMKAE_C_COMPILER: 指定C编译器
(6)CMAKE_CXX_COMPILER:指定C++编译器
(7)EXECUTABE_OUTPUT_PATH:可执行文件输出的存放路径
(8)LIBRARY_OUTPUT_PATH:库文件出输出的存放路径
(9)CMAKE_BUILD_TYPE设置cmake编译是debug还是release

在这里插入图片描述

编译指令
在这里插入图片描述

5)CMake编译工程

CMake目录结构:项目主目录存在一个CMakeLists.txt文件

(1)两种方式设置编译规则:

1.包含源文件的子文件包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可
2.包含原文件的子文件未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt文件中

(2)linux平台使用CMake构建C/C++工程的流程如下

1.编写CMakeLists.txt
2.执行cmake path生成makefile(PATH是顶层CMakeLists.txt文件所在的路径)
3.使用make进行编译

(3)两种构建方式
1)内部构建:不推荐使用

在这里插入图片描述

2)外部构建:推荐使用

在这里插入图片描述

6)【实战】CMake代码实践

(1)二级目录

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

(2)多个目录实现
1)子目录编译成库文件

这里的aux_source_directory相当于set

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述CMAKE_CURRENT_SOURCE_DIR表示当前源码目录,就是src里面的目录

  • 完整版cmakelists.txt
    在这里插入图片描述
2)对应子目录没有cmakelists.txt(第二种方法3.2.1,不需要链接库文件)

在这里插入图片描述

(3)生成库文件(详细版)

补充:

PROJECT_SOURCE_DIR 跟着最近工程的目录

1)静态库和动态库生成

在这里插入图片描述

在这里插入图片描述

把路径拼起来
在这里插入图片描述

2)调用库去install

在这里插入图片描述

install后
在这里插入图片描述

(4)链接库文件
1)链接静态库

在这里插入图片描述

2)链接动态库

在这里插入图片描述

(5)调用库
1)调用动态库

在这里插入图片描述

2)调用静态库

在这里插入图片描述

(6)编译指定debug还是release版本

在这里插入图片描述

三、其他编译稀奇古怪的问题

1)gcc编译为什么要加-g选项

加上-g 选项,会保留代码的文字信息,便于调试下面两幅图是有无 -g 选项调试的区别

(我是用的是cgdb,比gdb稍微好用一点,文章结束附带cgdb下载教程)

先来一段简单的代码:
在这里插入图片描述
如果使用 gcc test.c, 再使用cgdb调试时的效果是这样的:
在这里插入图片描述
如果使用 gcc -g test.c, 再使用cgdb调试时的效果是这样的:

在这里插入图片描述
在这里插入图片描述
cgdb安装教程

2)linux找不到动态链接库 .so文件的解决方法

传送门

3)/usr/bin/ld: cannot find -lc错误原因及解决方法

  • 问题
    在运行asapp书中第7章链接例子时,在使用gcc -static -o prog main.o ./libvector.a 命令进行链接时出现以下错误:
/usr/bin/ld: 找不到 -lc
collect2: 错误:ld 返回 1
  • 原因
    在新版本的linux 系统下安装 glibc-devel、glibc和gcc-c++时,都不会安装libc.a. 只安装libc.so. 所以当使用-static时,libc.a不能使用。只能报找不到libc了。

  • 解决方法
    安装 glibc-static
    sudo yum install glibc-static

4)GCC编译过程与动态链接库和静态链接库

传送门

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值