概念
代码变成可执行文件,叫做编译(compile);
先编译这个,还是先编译那个(即编译的顺序安排),叫做构建(build)。
Make是最常用的构建工具。也就是将编译的顺序写在一个叫Makefile的文件中。Make命令依赖这个文件进行构建。
构建规则都写在Makefile文件里面,要学会如何Make命令,就必须学会如何编写Makefile文件。
常规gcc编译运行过程
gcc -c test.cpp test1.cpp test2.cpp
进行编译可以生成.o文件
test1.cpp test1.o test2.cpp test2.o test.cpp test.o
gcc -o app test1.o
链接生成可执行文件
然后运行该程序
./app
makefile的出现(选择性编译)
https://www.cnblogs.com/lfri/p/9693545.html
我们编译链接三个文件成可执行文件,可以执行下面两步
gcc -c test.cpp test1.cpp test2.cpp
gcc -o main test.o test1.o test2.o
这样的话我们也可以产生main程序,并不复杂。
但是如果我们考虑一下如果我们修改了其中的一个文件那么我们难道还要重新输入上面的命令?
也许你会说,这个很容易解决啊,我写一个 SHELL脚本,每次执行一下就可以了。对于这个简单程序来说,是没问题。但,如果我们的程序有几百个源程序的时候,那么我们编译器会一个一个源文件重新编译?每次这个编译时间就很长了。
而make正是帮我们解决这个问题的,当我们修改某个文件的时候他只会编译其中修改了的文件,而不会编译其他文件。大大缩短了编译时间。
makefile使用示例
下面我们编写一个最简单的Make file文件。
先编写好源文件(.c文件),然后在同一目录下新建名为Makefile(之前首字母必须大写,现在大小写都行)的文本文件。
hello: test.cpp
gcc -c test.cpp
gcc -o app test.o
然后执行make,编译完成后生成可执行文件,我们再运行程序
可以使用一些变量来精简语法
#定义变量并赋值
CC = gcc
CFLAGS = -lm -Wall -g
hello: test.cpp
$(CC) $(CFLAGS) test.cpp -o app #引用前面定义的变量,$(变量名),这种形式
makefile递归过程
CC = gcc
CFLAGS = -O -Wall -m64 -std=gnu89
LIBS = -lm
all: main_max #必须写成all这样的形式,否则只会生成前一个可执行文件main_max,
#前置条件是两个文件,他不执行语句
# 然后我们看前置条件main_max,他需要三个文件, .c在目录中存在,而其他两个前置条件我们继续向下搜索
# 所以说这个前置条件的查找类似于一个递归的过程
main_max: main_max.c bar.o foo.o # 前置条件是有main_max.c bar.o foo.o,如果前置条件存在,则可以执行下一行的命令
$(CC) main_max.c bar.o foo.o -o main_max
# 下面两个文件的两个前置条件是这两个.c文件存在,如果存在则编译生成.o文件
foo.o: foo.c
$(CC) -c foo.c
bar.o: bar.c
$(CC) -c bar.c
# 下面是防止重命名
.PHONY: clean
clean:
rm *.o main_max
执行make 可以看到,我们这个是从下往上执行的gcc语句
makefile更多语法
更多语法可以参照阮老师教程
http://www.ruanyifeng.com/blog/2015/02/make.html
CmakeList.txt
makefile是在Linux编译c或者c++代码的时候的一种脚本文件,但是每一个功能都要写一个makefile文件,这样如果这个工程很大,而且相关性比较强的话,makefile的书写就会变得相对繁琐,看起来就会特别麻烦;
简单的解释就是cmake是为了生成makefile 脚本文件,这样我们就不需要再去写makefile了,只需要写简单的CMakeLists.txt即可。
cmake之后就会产生我们想要的makefile文件,然后再直接make就可以编译出我们需要的结果了。
一个简单例子
#include <stdio.h>
int main()
{
printf("Hello World Test!\n");
return 0;
}
添加一个CmakeList.txt文件
project(hello_jelly)
set(APP_SRC main.c)
add_executable(${PROJECT_NAME} main.c)
#print message
message(${PROJECT_SOURCE_DIR})
然后将以上两个文件放在统一目录下面,注意编译产生时候分为两种:
- 一种是直接在当前源码目录执行cmake命令
cmake ./
,但是这样会在当前目录下产生很多临时文件和目录 - 另一种方式就是在当前目录新建一个build目录,然后我门进入到build目录,执行命令
cmake ../
,这样产生的所有临时文件都会生成在build目录下,而不影响源码目录的代码,
然后在该项目的目录下新建build文件夹,那么我门进入到build目录,执行命令 cmake ../
这样产生的所有临时文件都会生成在build目录下,而不影响源码目录的代码。
可以看到生成了很多文件,主要的是生成makefile文件
然后我们执行make就可以编译,并生成可执行文件了。
最后运行可执行文件
语法
https://www.elecfans.com/d/2024564.html
cmake_minimum_required(VERSION 3.0)
# 指定项目名称
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加编译选项
add_compiler_options("-g")
# 现阶段,你只需要了解 SET 指令可以用来显式的定义变量即可
# 将 hello.cpp 赋值给 SRC_LIST 变量,也可以指定多个源文件,用空格隔开
SET(SRC_LIST hello.cpp add.cpp sub.cpp)
# 输出打印构建目录
MESSAGE(STATUS "This is HELLO_BINARY_DIR " ${HELLO_BINARY_DIR})
# 指定源文件或者动态库头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# ## 下面为链接过程
# 指定要链接的动态库的搜索路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 生成动态库
add_library(app SHARED ${SRC_LIST})
# 根据源文件生成一个可执行程序名字为app
add_executable(app ${SRC_LIST})
# 指定要链接的库
target_link_libraries(app pthread calc)
上面过程都是编译链接阶段。
因为动态库是运行时需要,所以在程序运行时需要将指定动态库的位置,程序运行默认会到编译目录下寻找动态库,如果找不到则需要指定LD_LIBRARY_PATH来找。
target_link_libraries并不区分动态库和静态库,都可以在这里指定链接库的名称,注意这里可以写全称,也可以写简称。写简称的时候,会在名称前面自动加一个lib
注意下面是target link libraries的详解。
https://blog.csdn.net/qq_37805392/article/details/139721270