CMake
开发环境准备:
系统环境:Ubuntu18.04 LTS 虚拟机
开发语言:C++
开发IDE:Clion
Linux系统介绍
什么是Linux系统:Linux是开源的操作系统
多用户多任务:
- 单用户:一个用户,在登录计算机(操作系统),只能允许同时登录一个用户
- 单任务:一个任务,允许用户同时进行的操作任务数量
- 多用户:多个用户,在登录计算机(操作系统),允许同时登录多个用户进行操作
- 多任务:多个任务,允许用户同时进行多个操作任务
Windows属于:单用户,多任务
Linux属于:多用户,多任务
Linux一切皆文件,对于文件操作一般有:创建文件、编辑文件、保存文件、关闭文件、重命名文件、删除文件、恢复文件
目录结构
- bin:全称binary,含义是二进制文件。该目录中存储的都是一些二进制文件,文件是可以被运行的
- dev:该目录中主要存放的是外接设备,例如磁盘、其他光盘等。在其中的外接设备是不能直接被使用的,需要挂载(类似Windows下的分配盘符)
- etc:该目录主要存储一些配置文件
- home:表示”家”,表示除了root用户以外其他用户的家目录,类似于Windows汇总User/用户目录
- proc:全称process,表示进程,该目录中存储的是Linux运行时候的进程
- root:该目录是root用户自己的家目录
- sbin:全称super binary,该目录也是存储一些可以被执行的二进制文件,但是必须得有super权限的用户才能执行
- tmp:表示”临时”的,当系统运行时产生的临时文件会在这个目录存着
- usr:存放的是用户自己安装的软件。类似于Windows下的program files
- var:存放的程序/系统的日志文件的目录
- mnt:当外接设备需要挂载的时候,就需要挂载到mnt目录下
指令与选项
指令含义:Linux的指令是在Linux终端(命令行)中输入的内容
指令格式:
- 完整指令的标准格式:
命令 [选项] [操作对象]
- 选项和操作对象都可以没有,也可以是多个
ls -l -a -h /home ./ |
重要指令
pwd
Print current working directory作用:打印当前终端所在的目录
用法:pwd
pwd
ls
List directory contents作用:列出当前工作目录下的所有文件/文件夹的名称
用法1:ls
含义:列出当前工作目录下的文件/文件夹名称
ls
用法2:ls [路径]
含义:列出指定路径下的所有文件/文件夹的名称
- 绝对路径:相对根目录的路径
- 相对路径:相对当前目录的路径
# 相对路径
ls ./ # 表示当前目录下
ls ../ # 上一级目录下
# 绝对路径
ls /home
- 用法3:ls [选项]
含义:在列出指定的路径下的文件/文件夹的名称,并以指定的格式进行显示
```sh
# ls 选项 路径
ls -lah /home
# 选项解释
-l # 表示list,表示以详细列表的形式进行展示
-a # 表示显示所有的文件/文件夹(包含隐藏文件/文件夹)
-h # 表示以可读性较高的形式显示
# ls -l中第一位"-"表示对应的文档为文件,"d"表示对应的文档为文件夹cd
Change directory作用:切换当前的工作目录
用法1:cd ~或cd
# cd ~与cd等价,表示进入当前用户的家目录下
cd
cd ~用法2:cd [相对路径]
# 进入到上级目录下
cd ..
# 进入到上级目录中的local目录下
cd ../local用法3:cd [绝对路径]
# 进入到/usr/local目录下
cd /usr/local
mkdir
Make diretcory作用:创建目录
用法1:mkdir 路径
# 在当前路径下创建出目录"myfolder"
mkdir myfolder用法2:mkdir -p 路径
含义:一次性创建多层不存在目录
# 创建~/a/b/c目录
mkdir -p ~/a/b/c用法3:mkdir 路径1 路径2
含义:一次性创建多个目录
# 在当前目录下分别创建a, b, c三个文件夹
mkdir a b c
touch
Change file timestamps作用:创建新文件
用法1:touch [路径]
# 在当前目录下创建linux.txt文件
touch linux.txt
# 在上一级目录下创建linux.txt
touch ../linux.txt
# 在/home/santidadday目录下创建myfile
touch /home/santidadday/myfile用法2:touch 路径1 路径2
# 在当前目录下创建file file.txt两个文件
touch file file.txt
rm
remove files or directories作用:删除文件/目录
用法1:rm [选项] 需要移除的文件路径
# 删除当前路径下的myfile问阿金
rm myfile
# 删除/usr路径下的myfile文件
rm /usr/myfile用法2:rm [选项] 需要移除的目录
# 删除当前路径下的abc文件
rm -rf abc
# 删除/usr路径下的abc文件
rm -rf abc
cp
Copy files and directories作用:复制文件/文件夹到指定的位置
用法1:cp 被复制的文件路径
# cp命令来赋值一个文件
cp /home/santidadday/myfile ./用法2:cp -r 被复制的文件路径
含义:-r表示递归复制,复制文件夹时需要加-r
# cp命令来赋值一个文件夹中所有文件
cp /home/santidadday ./
mv
Move(remove)files作用:移动文件到新的位置,或者重命名文件
用法:mv 需要移动的文件路径
# 移动当前目录下myfile文件到跟目录下
mv myfile /myfile
# 移动当前目录下myfolder文件夹到根目录下
mv myfolder /myfolder
# 移动当前目录下myfile到根目录下,并重命名为myfile01
mv myfile /myfile01
man
An interface to the system reference manuals作用:包含了Linux中全部命名手册
用法:man [命令]
含义:查看命令使用手册,按q退出
# 查看ls使用手册
man ls
reboot
Reboot the machine作用:重启linux系统
用法:reboot
# 立即重启
reboot
shutdown
power off the machine作用:关机
用法:shut -h [时间]
# 立即换季
shutdown -h now
vim文件编辑
vim [file]
- 所有的Linux系统都会内建vi/vim编辑器,其他的编辑器则不一定会存在
- vim是所有Unix和Linux系统下标准的编辑器
- vim具有程序开发的能力,也可以用来对文件进行简单的编辑
开发环境搭建
编辑器和调试器安装
安装GCC,GDB
sudo apt update
# 通过一下命令安装编辑器和调试器
sudo apt install build-essential gdb确认安装成功
# 以下命令确认可以确认每个软件是否安装成功
# 如果成功显示版本号
gcc --version
g++ --version
gdb --version
CMake安装
安装cmake
# 通过以下命令安装cmake
sudo apt install cmake确认安装成功
# 如果成功显示版本号
cmake --version
GCC编译器
前言:
- GCC编译器支持编译Go、Objective-C、Objective-C++、Fortran、Ada、D和BRIN(HSAIL)等程序
- Linux开发C/C++一定要熟悉GCC
- Clion默认使用MinGW,我们可以将其修改为GCC来实现C/C++的编译工作
实际使用中:
- GCC指令编译C代码
- G++指令编译C++代码
编译过程
预处理Pre Processing
# -E选项指示编译器仅对输入文件进行预处理
g++ -E test.cpp -o test.i
# .i文件编译Compiling
# -S编译选项告诉g++在c++代码产生了汇编语言文件后停止编译
# g++产生的汇编语言文件的缺省扩展名是.s
g++ -S test.i -o test.s汇编Assembling
# -c选项告诉g++仅把源代码编译为机器语言的目标代码
# 缺省时g++建立的目标代码文件有一个.o
g++ -c test.s -o test.o链接Linking
# -o编译选项来为将产生的可执行文件用指定的文件名
g++ test.o -o test
G++重要编译参数
- -g 编译带调试信息的可执行文件(如果需要可执行文件被GDB调试需要添加-g选项)
- -O[n] 优化源代码(n可以取值0,1,2,3)
- -l和-L 指定库文件 | 指定库文件路径
- -I 指定头文件搜索目录
- -Wall 打印警告信息
- -w 关闭警告信息
- -std=c++11 设置编译标准
- -o 指定输出文件名
- -D 定义宏
实际使用
include
swap.h
src
swap.cpp
main.cpp
直接编译:
g++ main.cpp src/swap.cpp -Iinclude -o test
生成库文件并编译:
链接静态库生成可执行文件:
# 进入src目录下
cd src
# 汇编,生成swap.o文件
g++ swap.cpp -c -I../include
# 生成静态库libswap.a
ar rs libswap.a swap.o
# 回到上一级
cd ..
# 链接,生成可执行该文件:staticmain
g++ main.cpp -Iinclude -Lsrc -lswap -o staticmain链接动态库生成可执行文件:
# 进入src目录下
cd src
# 生成动态库libswap.so
g++ swap.cpp -c -I../include -fPIC -shared -o libswap.so
# 等价于g++ swap.cpp -I../include -c -fPIC g++ -share -o libswap.so swap.o
# 回到上一级
cd ..
# 链接,生成可执行该文件:staticmain
g++ main.cpp -Iinclude -Lsrc -lswap -o sharemain
静态库生成的可执行文件可以直接执行./staticmain
动态库生成的可执行文件需要另外的执行方式LD_LIBRARY_PATH=src ./sharemain
GDB调试器
前言:
- GDB(GNU Debugger)是一个用来调试C/C++程序的功能强大的调试器,是Linux系统开发C/C++最长使用的调试器
- 程序员可以使用GDB来跟踪程序中的错误,从而减少程序员的工作量
- Linux开发C/C++一定需要熟练使用GDB
- Clion是通过调用GDB调试器来实现C/C++调试工作的
GDB主要功能:
- 设置断点(断点可以是条件表达式)
- 使程序在指定的代码行上暂停执行,便于观察
- 单步执行程序,便于调试
- 查看程序中变量值的变化
- 动态改变程序的执行环境
- 分析崩溃程序产生的core文件
GDB是什么
GDB, the GNU Project debugger, allows you to see what is going on `inside’ another program while it executes – or what another program was doing at the moment it crashed.
GDB 调试器,可以允许你在程序运行时检查里面到底发生了什么
GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:
GDB可以做以下四个事情:
- Start your program, specifying anything that might affect its behavior.开始并设置可能影响你的程序行为的参数
- Make your program stop on specified conditions.可以在特殊情况下停止
- Examine what has happened, when your program has stopped.当你的程序停止时,检查发生了什么
- Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.
Those programs might be executing on the same machine as GDB (native), on another machine (remote), or on a simulator. GDB can run on most popular UNIX and Microsoft Windows variants, as well as on Mac OS X.跨平台
GDB支持哪些语言
GDB supports the following languages (in alphabetical order):
- Ada
- Assembly汇编
- C
- C++
- D
- Fortran
- Go
- Objective-C
- OpenCL
- Modula-2
- Pascal
- Rust
搭建实验环境
安装GDB:yum install gdb
检查GDB是否成功安装:gdb --version
快速上手
|
gcc -g test.c
进行编译
gcc ./a.out
进入GDB
r
运行程序
quit
退出GDB
list
查看源代码
b 函数名或行号
打断点
info b
查看断点位置
p 变量
查看变量值
|
s
进入被调用的程序
GDB小技巧:
- 可以通过shell调用终端命令
- 日志功能
set logging on
- 观察变量是否变化
watchpoint
调试core文件
ulimit |
gdb 二进制文件 core文件
查看挂掉文件
调试正在运行的进程
搭建一个后台运行的实验环境
后台gdb -p 进程号
CMake
前言:
- CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)
- CMake可以说已经成为大部分C++开源项目标配
Cross-platform development
语法特性介绍
基本语法格式:指令(参数1 参数2 …)
- 参数使用括弧括起
- 参数之间使用空格或分号分开
指令与大小写无关的,参数和变量与大小写相关
set(HELLO hello.cpp)
add_executable(hello main.cpp hello.cpp)
ADD_EXECUTABLE(hello main.cpp ${HELLO})变量使用${}方式取值,但是在IF控制语句中是直接使用变量名
重要指令
重要指令:
cmake_minimum_required - 指定CMake的最小版本要求
语法:cmake_minimum_required(VERSION versionNumber [FATAL_ERROR])
# CMake最小版本要求为2.8.3
cmake_minimum_required(VERSION 2.8.3)project - 定义工程名称,并可指定工程支持的语言
语法:project(projectname [CXX] [C] [JAVA])
# 指定工程名称为HELLOWORLD
project(HELLOWPRLD)set - 显示的定义变量
语法:set(VAR [VALUE] [CACHE TYPE DOCSTRING] [FORCE])
# 定义SRC变量,其值为sayhello.cpp hello.cpp
set(SRC sayhello.cpp hello.cpp)include_directories - 向工程添加多个特定的头文件搜索路径 —> 相当于指定g++编辑器的-I参数
语法:include_directories([AFTER|BEEFORE] [SYSTEM] dir1 dir2 …)
# 将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径
include_directories(/usr/include/myincludefolder ./include)link_directories - 向工会曾添加多个特定的库文件搜索路肩 —> 相当于指定g++编辑器的-L参数
语法:link_directories(dir1 dir2 …)
# 将/usr/lib/mylibfolder 和 ./lib 添加到库文件搜索路径
link_directories(/usr/lib/mylibfolder ./lib)add_library - 生成库文件
语法:add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
# 通过变量SRC生成libhello.so共享库
add_library(hello SHARED ${SRC})acc_compile_options - 添加编译参数
语法:add_compile_options(<option> …)
# 添加编译参数 -Wall -std=c++11
add_compile_options(-Wall -std=c++11 -o2)acc_executable - 生成可执行文件
语法:add_executable(exename source1 source2 … sourceN)
# 编译main.cpp生成可执行文件main
add_executable(main main.cpp)target_link_libraries - 为target添加需要链接的共享库 —> 相当于指定g++编译器-l参数
语法:target_link_libraries(target library1<debug | optimized> library2 …)
# 将hello动态库文件链接到可执行文件main
target_link_libraries(main hello)add_subdirectory - 向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
语法:add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# 添加src子目录,src中需要一个CMakeLists.txt
add_subdirectory(src)aux_source_directory - 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表
语法:aux_source_directory(dir VARIABLE)
# 定义SRC变量,其值为当前目录下所有的源代码文件
aux_source_directory(. SRC)
# 编译SRC变量所代表的源代码文件,生成main可执行文件
add_executable(main ${SRC})
CMake常用变量
CMAKE_C_FLAGS gcc编译选项
CMAKE_CXX_FLAGS g++编译选项
# 在CMAKE_CXX_FLAGS编译选项后追加-std=c++11
set(CAMKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")CMAKE_BUILD_TYPE 编译类型(Debug,Release)
# 设定编译类型为debug,调试时需要选择debug
set(CMAKE_BUILD_TYPE Debug)
# 设定编译类型为release,发布时需要选择release
set(CMAKE_BUILD_TYPE Release)CMAKE_BINARY_DIR
PROJECT_BINARY_DIR
<projectname>_BINARY_DIR
这三个变量指代的内容是一致的。如果是in source build,值的就是工程顶层目录;如果是out of source编译,指的是工程编译发生的目录;PROJECT_BINARY_DIR跟其他指令稍有区别
CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
<projectname>_SOURCE_DIR
这三个变量指代的内容是一致的。不论采用何种编译方式,都是工程顶层目录
CMAKE_C_COMPILER 指定C编译器
CMAKE_CXX_COMPILER 指定C++编译器
EXECUTABLE_OUTPUT_PATH 可执行文件输出的存放路径
LIBRARY_OUTPUT_PATH 库文件输出的存放路径
CMake编译工程
CMake目录结构:项目主目录存在一个CMakeLists.txt文件
两种方式设置编译规则:
- 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可
- 包含源文件的子文件夹不包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中
编译流程
在Linux平台下使用CMake构建C/C++工程流程如下:
- 手动编写CMakeLists.txt
- 执行
cmake PATH
生成MakeFile(PATH是顶层CMakeLists.txt所在的目录) - 执行命令
make
进行编译
两种构建方式
内部构建(不推荐使用)
外部构建:将编译输出文件与源文件存放到不同目录中
# 外部构建 |