Linux 系统中make和makefile以及CMake如何使用

make命令

在linux系统中,make时一个用来编译的命令,项目开发和软件安装过程中我们经常会用到make或makeinstall。利用make工具我们就可以将大型开发项目分解成许多更易于管理的模块。

  • make的工作原理
    当make命令被执行时,它会扫描当前目录下Makefile或者makefile文件找到目标以及其依赖。
  1. make在当前目录下寻找“Makefile"或者”makefile“文件
  2. 若找到,查找文件中第一个目标文件.o
  3. 若目标文件不存在,根据依赖关系查找.s文件
  4. 若.s文件不存在,根据依赖关系查找.i文件
  5. 若.i文件不存在,根据依赖关系查找.c文件,此时.c文件一定存在,于是生成一个.o文件,再去执行

Makefile文件

Makefile文件有一系列的规则构成,每条规则形式如下:

<target>: <prerequisites>
[Tab]<commands>

第一行冒号前为目标,冒号后为前置条件;第二行必须由一个Tab键起首,后接命令;目标是必须的,不可省略;前置条件和命令是可选的,但是二者必须至少存在一个。

目标target

目标可以是文件名,指明make命令所要构建的对象;也可以是某个操作名称,称为伪目标

clean:
	rm *.o

以上代码的目标是clean,命令是rm*.o
执行make clean命令,实现对象文件的删除;

前置条件prerequisites

前置条件通常是一组文件名,用空格隔开;

命令commands

命令表示如何更新目标文件,由一行或多行shell命令组成;注意:shell命令一定是写在命令中,否则会被make忽略,每行命令前必须有一个Tab键;每行命令在一个独立的shell中执行,shell之间没有继承关系,因此上一行的变量赋值在下一行无效;若前后两行命令有共享数据,可以写在同一行,用分号隔开。

CMake

CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件CMakelist.txt去生成本地的Makefile文件,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile文件了,而且配置文件可以直接拿到其他平台上使用,无需修改,非常方便。

CMakelist.txt编写样例

  • 同一目录下多个源文件
    对于下面这种文件结构,适用于小型项目,文件数量较少,并不是规范的分类管理习惯。
    在这里插入图片描述
    这时CMakelist.txt内容如下:
cmake_minimum_required (VERSION 2.8)

project (demo)

add_executable(main main.c testFunc.c)

第一行的意思是要求CMake的最低版本是2.8;第二行表示本工程信息,也就是工程名叫做demo;第三行比较关键,表示最终要生成的elf文件的名字叫做main,使用的源文件是main.c,testFunc.c。在终端下切换到main.c所在的目录下,然后输入以下命令运行CMake,
cmake .
这样就会在当前目录下生成makefile文件,接着在终端输入make并回车,main.c文件就编译完成了,这时我们需要的elf文件main成功生成。
可以类推,如果在同一个目录下有多个源文件,那么只要在add_executable里把所有的源文件都添加进去即可。但是如果源文件的数量过多,cmake提供了一个命令可以把指定目录下的所有源文件存储在一个变量中,这个命令就是aux_source_directory(dir var)第一个参数是指定目录,第二个参数是存放源文件列表的变量。那么,我们的CMakelist.txt文件也可以写成下面这种形式:

cmake_minimum_required (VERSION 2.8)

project (demo)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

使用aux_source_directory把当前目录下的源文件列表存放在变量SRC_LIST中,然后在add_executable调用SRC_LIST(注意调用变量的写法)。

  • 不同目录下多个源文件
    一般情况下,当程序文件比较多时,我们会进行分类管理,根据代码的不同功能放置在不同的目录下,这样方便查找,那么这种情况下该如何编写CMakelist.txt文件呢?整理好的文件结构如下:
    在这里插入图片描述
    这时,还是在main.c目录下新建CMakelist.txt文件,内容调整为下面所示:
cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (test_func test_func1)

aux_source_directory (test_func SRC_LIST)
aux_source_directory (test_func1 SRC_LIST1)

add_executable (main main.c ${SRC_LIST} ${SRC_LIST1})

这次使用了一个新命令include_directories,该命令是用来向工程中添加多个指定头文件的搜索路径,路径之间用空格分开。因为main.c源文件中包含了testFunc.h和testFunc1.h,如果不用这个命令来指定头文件所在位置,就会无法编译,当然也可以在main.c里面使用include来指定路径,只是这种写法不太优雅,如下:

#include "test_func/testFunc.h"
#include "test_func1/testFunc1.h"
  • 正规一点的组织结构
    正规一点来说,我们会把源文件放在src目录下,把头文件放到include文件下,生成的对象文件存放在build目录下,最终输出的elf文件会放到bin目录下,这样整个结构更加清晰。比如下面这种结构:
    在这里插入图片描述
    这时,我们在最外层目录下新建一个CMakelist.txt文件,内容为:
cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (src)

这里出现了一个新的命令add_subdirectory,这个命令可以向当前工程添加存放源文件的子目录,这里指定src目录下存放了源文件,当执行cmake时就会进入src目录下取寻找src目录下的CMakelist.txt文件,所以在src目录下也建立一个CMakelist.txt:

aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

这里有出现了一个新命令set,是用于定义变量的,这里是把存放elf文件的位置设置为工程根目录下的bin目录。EXECUTABLE_OUTPUT_PATH和PROJECT_SOURCE_DIR是CMake自带的预定义变量,分别表示为:目标二进制可执行文件存放位置;工程根目录
下面来运行cmake,不过这次我们将目录切换到buid目录下,然后输入以下命令:
cmake ..
Makefile文件会在build目录下生成,然后接着在build目录下运行make,这时文件已经编译好了,回到bin目录下,发现可执行文件main已经生成。解释一下为什么要在build目录下运行cmake,从之前几个例子可以知道,如果在最外层运行cmake,运行时啥呢工程的附带文件就会和源码文件混在一起,这样会对程序的目录结构造成污染,而在build目录下运行cmake,生成的附带文件只会呆在build目录下,如果我们不想要这些文件了可以直接清空该目录,非常方便。

  • 动态库和静态库的编译控制
    有时我们只需要编译出动态库,静态库,然后等着让其他程序去使用,这种情况我们该怎么使用cmake?
    在这里插入图片描述
    我们会在build目录下运行cmake,并把生成的库文件存放在lib目录下。最外层的CMakelist.txt内容如下:
cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (lib_testFunc)

lib_testFunc目录下的CMakelist.txt如下,

aux_source_directory (. SRC_LIST)

add_library (testFunc_shared SHARED ${SRC_LIST})
add_library (testFunc_static STATIC ${SRC_LIST})

set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc")
set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc")

set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

这里有出现了新的命令和预定变量,add_library: 生成动态库或静态库(第1个参数指定库的名字;第2个参数决定是动态还是静态,如果没有就默认静态;第3个参数指定生成库的源文件);set_target_properties: 设置输出的名称,还有其它功能,如设置库的版本号等;LIBRARY_OUTPUT_PATH: 库文件的默认输出路径,这里设置为工程目录下的lib目录

  • 对库进行链接
    既然我们已经生成了库,那么就进行链接测试下。把build里的文件都删除,然后在在工程目录下新建src目录和bin目录,在src目录下添加一个main.c和一个CMakeLists.txt,整体结构如下,
    在这里插入图片描述
    工程目录下CMakelist.txt文件修改如下:
cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (lib_testFunc)
add_subdirectory (src)

src目录下的CMakelist.txt如下:

aux_source_directory (. SRC_LIST)

# find testFunc.h
include_directories (../lib_testFunc)

link_directories (${PROJECT_SOURCE_DIR}/lib)

add_executable (main ${SRC_LIST})

target_link_libraries (main testFunc)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

这里出现两个新的命令,link_directories: 添加非标准的共享库搜索路径,target_link_libraries: 把目标文件与库文件进行链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值