开发环境准备:

系统环境: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 ./
ls -lah /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具有程序开发的能力,也可以用来对文件进行简单的编辑
vim编辑器
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

快速上手

#include <stdio.h>

int main() {
int arr[4] = {1, 2, 3, 4};
for (int i = 0; i < 4; i++) {
printf("%d\n", arr[i]);
}

return 0;
}

gcc -g test.c进行编译

gcc ./a.out进入GDB

r运行程序

quit退出GDB

list查看源代码

b 函数名或行号打断点

info b查看断点位置

p 变量查看变量值

#include <stdio.h>

void hello() {
printf("hello world\n");
}

int main() {
int arr[4] = {1, 2, 3, 4};
for (int i = 0; i < 4; i++) {
printf("%d\n", arr[i]);
}
hello();
return 0;
}

s进入被调用的程序

GDB小技巧:

  • 可以通过shell调用终端命令
  • 日志功能set logging on
  • 观察变量是否变化watchpoint

调试core文件

ulimit
-a  显示目前资源限制的设定。
-c <core文件上限>  设定core文件的最大值,单位为区块。
-d <数据节区大小>  程序数据节区的最大值,单位为KB。
-f <文件大小>  shell所能建立的最大文件,单位为区块。
-H  设定资源的硬性限制,也就是管理员所设下的限制。
-m <内存大小>  指定可使用内存的上限,单位为KB。
-n <文件数目>  指定同一时间最多可开启的文件数。
-p <缓冲区大小>  指定管道缓冲区的大小,单位512字节。
-s <堆叠大小>  指定堆叠的上限,单位为KB。
-S  设定资源的弹性限制。
-t <CPU时间>  指定CPU使用时间的上限,单位为秒。
-u <程序数目>  用户最多可开启的程序数目。
-v <虚拟内存大小>  指定可使用的虚拟内存上限,单位为KB。

gdb 二进制文件 core文件查看挂掉文件

调试正在运行的进程

搭建一个后台运行的实验环境

后台gdb -p 进程号

CMake

前言:

  • CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)
  • CMake可以说已经成为大部分C++开源项目标配

Cross-platform development

CMake

语法特性介绍

  • 基本语法格式:指令(参数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进行编译

两种构建方式

内部构建(不推荐使用)

外部构建:将编译输出文件与源文件存放到不同目录中

# 外部构建
# 在当前目录下,创建build文件夹
mkdir build
# 进入build文件夹
cd build
# 编译上一级目录的CMakeLists.txt,生成MakeFile和其他文件
cmake ..
# 执行make命令,生成target
make