CMakeLists.txt

26 篇文章 1 订阅

摘要:本系统基于CentOS7.6,x86_64环境下操作;关键词:Linux、VSCode、CMake、C/C++、GCC/GDB

适用范围:

想从Windows转Linux开发的者

想深入了解并掌握GCC编译器语法和规则者

想深入了解并掌握GDB调试器命令行调试者

想学习使用CMake构建C/C++工程者

想学习Linux下使用VSCode进行C/C++开发者

第一讲:Linux系统介绍

1.1目录结构

1.2指令与选项

1.3重要指令讲解

​ 目录、文件创建、查看、编辑、修改、删除等

1.4文件编译(vim/vi)

第二讲 开发环境搭建

2.1编译器、调试器安装

为方便起见,以下命令行操作均在root(管理员)用户登录操作

安装GCC,GDB

  [root@localhost ~]# yum update
  # 通过以下命令安装编译器和调试器
  s[root@localhost ~]# yum  -y install build-essential gdb

安装成功确认

  
  以下命令确认每个软件是否安装成功,如果成功,则显示版本号
  [root@localhost ~]#gcc --version
      gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
  [root@localhost ~]#g++ --version
      g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
  [root@localhost ~]#gdb --version
      GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7

2.2CMake安装

安装cmake

  
  # 通过以下命令安装编译器和调试器
  [root@localhost ~]# yum -y  install cmake

安装成功确认

  
  # 确认是否安装成功 如果成功,则显示版本号
  [root@localhost ~]# cmake --version
      cmake version 3.20.5
      CMake suite maintained and supported by Kitware (kitware.com/cmake).

第三讲 GCC/g++编译器

前言:

1.GCC编译器支持编译GO、Objective-C、Objective-C++、Fortran等程序

2.Linux开发从C/C++一定要熟悉GCC

3.VSCode是通过GCC编译器来实现C/C++的编译工作的

实际使用中:

使用gcc指令编译C代码

使用g++指令编译C++ 代码

3.1编译过程

1.预处理-Pre=Processing //.i文件

  
  # -E 选项指示编译器仅对输入文件进行预处理
  [root@localhost ~]#g++  -E  test.cpp  -o  test.i    //.i文件

2.编译-Compiling //.s文件

  
  -S 编译选项告诉 g++在为c++ 代码产生了汇编语言文件后停止编译
  g++产生的汇编语言文件的缺省扩展名是.s
  [root@localhost ~]#g++ -S test.i -o test.s

缺省扩展名:任何文件都是有扩展名的,扩展名决定了文件的属性,缺省就是按系统默认的情况执行,(添加新建文件的扩展名,运行相关程序),通常也就不显示了,如果想知道扩展名,可以右击文件属性查看

3.汇编-Assembling // .o文件

  
  # -c 选项告诉 g++ 仅把源代码编译为机器语言的目标代码 缺省时 g++ 建立的目标代码文件有一个 .o 的扩展名
  [root@localhost ~]#g++  -c  test.s  -o  test.o

4.链接-Linking //bin文件

  
  # -o 编译选项来为将产生的可执行文件用指定的文件名
  [root@localhost ~]#g++  test.o  -o  test

3.2 g++重要文件编译参数

1.-g 编译带调试信息的可执行文件

  
  # -g 选项告诉 GCC 产生能被 GNU 调试器GDB使用的调试信息,以调试程序。
  # 产生带调试信息的可执行文件test
  [root@localhost ~]#g++ -g test.cpp

2.-O[n] 优化源代码

  
  #所谓优化,例如省略掉代码中从未使用过的变量、直接将常量表达式用结果值代替等等,这些操作会缩减目标文件所包含的代码量,提高最终生成的可执行文件的运行效率。
  # -O 选项告诉 g++ 对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。 -O2 选项告诉 g++ 产生尽可能小和尽可能快的代码。 如-O2,-O3,-On(n 常为0–3)
  # -O 同时减小代码的长度和执行时间,其效果等价于-O1
  # -O0 表示不做优化
  # -O1 为默认优化
  # -O2 除了完成-O1的优化之外,还进行一些额外的调整工作,如指令调整等。
  # -O3 则包括循环展开和其他一些与处理特性相关的优化工作。
  # 选项将使编译的速度比使用 -O 时慢, 但通常产生的代码执行速度会更快。
  # 一般使用 -O2优化源代码,并输出可执行文件
  [root@localhost ~]#g++ -O2 test.cpp

案例展示:未做优化和做优化的效果

1.文件大

  
  未优化:
  [root@localhost LinuxC++]# g++ test.cpp   -O2 -o O2_test
  优化:
  [root@localhost LinuxC++]# g++ test.cpp    -o no_O2_test
  -rwxr-xr-x 1 root root 9024 10月  5 08:58 no_O2_test
  -rwxr-xr-x 1 root root 8888 10月  5 08:57 O2_test

2.执行速度

  
  未优化
  [root@localhost LinuxC++]# time  ./no_O2_test
  real    0m1.067s
  user    0m0.005s
  sys     0m0.004s
  优化:
  [root@localhost LinuxC++]# time  ./O2_test
  real    0m0.071s
  user    0m0.002s
  sys     0m0.005s

通过上述可知,优化后的可执行文件明显比未做优化的文件小,执行速度上优化后的速度(0.071s)未优化的速度(1.067s)有明显的提升。

3.-l和-L 指定库文件 | 指定库文件路径

  
  -l参数(小写)就是用来指定程序要链接的库,-l参数紧接着就是库名,在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接
  链接glog库
  [root@localhost LinuxC++]#g++ -lglog test.cpp
  如果库文件没放在上面三个目录里,需要使用-L参数(大写)指定库文件所在的目录
  -L参数跟着的是库文件所在的目录名
  #链接mytest库,libmytest.so在/home/目录下
  [root@localhost LinuxC++]#g++  -L/home/LinuxC++  -lmytest  test.cpp

4.-I(大写i) 指定头文件搜索目录

-I

  
  /usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件在/home/LinuxC++目录里,那编译命令就要加上-I/home/LinuxC++ 参数了,如果不加你会得到一个xxxx.h: No such file or directory的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.指定。上面我们提到的-cfalgs参数就是用来生成-I参数的。

5.-Wall 打印告警信息

  
  打印出gcc提供的告警信息
  [root@localhost LinuxC++]#g++ -Wall test.cpp

6.-w 关闭告警信息

  
  [root@localhost LinuxC++]#g++   -w test.cpp

7.-std=c++11 设置编译标准,不设置有可能默认其他的标准如C++98等

  
  使用c++11标准编译标准
  [root@localhost LinuxC++]#g++ -std=c++ test.cpp
  1. -o指定文件名

  
  指定即将产生的文件名
  指定输出可执行文件名test,如果不写的默认a.out
  不指定:
  [root@localhost LinuxC++]# g++  test.cpp
  -rwxr-xr-x 1 root root 8.9K 10月  5 10:52 a.out
  指定:
  [root@localhost LinuxC++]# g++  test.cpp  -o  no_test
  -rwxr-xr-x 1 root root 8.9K 10月  5 10:54 no_test
  -rw-r--r-- 1 root root  300 10月  5 10:04 test.cpp

9.-D宏定义

  
  在使用gcc/g++编译的时候定义宏
  常用场景:
  -DDEBUG  定义DEBUG宏,可能文件中有DEBUG部分的相关信息,用DDEBUG来选择开启或者关DEBUG

示例代码:

  
  // -Dname 定义宏name,默认定义内容为字符串“1”
   #include <stdio.h>
   int main()
   {
      #ifdef DEBUG
         printf("DEBUG LOG\n");
      #endif
         printf("in\n");
  }
  // 1. 在编译的时候,使用gcc -DDEBUG main.cpp
  // 2. 第七行代码可以被执行

注:使用 man gcc命令可以查看gcc英文使用手册

3.3【实战】g++命令编程

安装tree目录结构查看指令3 directories, 4 files

  
  [root@localhost LinuxC++]#yum  -y   install tree
  [root@localhost LinuxC++]# tree .
  .
  ├── bin
  │   └── O2_test
  ├── include
  │   └── Swap.h
  └── src
      ├── Swap.cpp
      └── test.cpp

3.3.1直接编译

最简单的直接编译,并运行

  
  # 将 main.cpp src/Swap.cpp 编译为可执行文件
  [root@localhost LinuxC++]#g++ main.cpp src/Swap.cpp -Iinclude
  # 运行a.out
  ./a.out

增加参数编译,并运行

  
  # 将 main.cpp src/Swap.cpp 编译为可执行文件 附带一堆参数
  [root@localhost LinuxC++]#g++ main.cpp src/Swap.cpp -Iinclude -std=c++11 -O2 -Wall -o b.out
  # 运行 b.out
  [root@localhost LinuxC++]#./b.out

3.3.2 生成库文件并编译

链接静态库生成可执行文件1:关键字ar rs .a

  
  ## 进入src目录下
  $cd src
  # 汇编,生成Swap.o文件
  [root@localhost LinuxC++]#g++ Swap.cpp -c -I../include
  # 生成静态库libSwap.a
  [root@localhost LinuxC++]#ar rs libSwap.a Swap.o
   ## 回到上级目录
  [root@localhost LinuxC++]#cd ..
  # 链接,生成可执行文件:staticmain
  [root@localhost LinuxC++]#g++ main.cpp -Iinclude -Lsrc -lSwap -o staticmain

链接动态库生成可执行文件2:关键字: -fPIC -shared .so

-shared 参数时,目的是使源码编译成动态库 .so 文件

-fPIC的作用是 告知编译器 生成位置无关代码(编译产生的代码没有绝对位置,只有相对位置);从而可以在任意地方调用生成的动态库。

  
  ## 进入src目录下
  [root@localhost LinuxC++]#cd src
  # 生成动态库libSwap.so
  [root@localhost LinuxC++]#g++ Swap.cpp -I../include -fPIC -shared -o libSwap.so
  ## 上面命令等价于以下两条命令
  #[root@localhost LinuxC++]# gcc Swap.cpp -I../include -c -fPIC
  #[root@localhost LinuxC++]#gcc -shared -o libSwap.so Swap.o
  ## 回到上级目录
  [root@localhost LinuxC++]#cd ..
  # 链接,生成可执行文件:sharemain
  [root@localhost LinuxC++]#g++ main.cpp -Iinclude -Lsrc -lSwap -o sharemain

3.3.3 运行可执行文件,两种方式

动态库和动态库最大区别,在编译过程中。静态库文件直接被编译到可执行文件中,意味着运行可执行文件不需要执行静态库的路径等;相反,动态库需要指定库文件的路径。下面的是两种运行的方式:

静态库方式1:

  
  #直接运行
  [root@localhost LinuxC++]#./staticmain

动态库方式2:

  # 运行可执行文件
  ​
  [root@localhost LinuxC++]#LD_LIBRARY_PATH=src ./sharemain

第四讲 GDB调试器

前言

  • GDB(GUN Debugger)是一个用来调试C/C++程序的功能强大的调试器,是Linux系统开发C/C++最常用的调试器;

  • 程序员可以使用GDB来跟踪程序中的错误,从而减少程序员的工作量

  • Linux开发C/C++一定要熟悉GDB

  • VSCode是通过调用调试器来实现C/C++ 的调试工作的;

延伸:

  • Windows 系统中,常见的集成开发环境(IDE),如 VS、VC等,它们内部已经嵌套了相应的调试器

    GDB主要功能:

  • 设置断点(断点可以是条件表达式)

  • 使程序员指定的代码上暂停执行,便于观察

  • 单步执行程序,便于调试

  • 查看程序中变量值的变化

  • 分析奔溃程序产生的core文件

4.1常用调试命令参数

调试开始:执行gdb[exefilenme],进入gdb调试程序,其中exefilename为要调试的可执行文件名

  
  以下命令后括号为命令的简化使用,比如run(r),直接命令r就代表命令run
  $(gdb)help(h) #查看命令帮助,具体命令查询在gdb中输入help+命令
  $(gdb) run(r)  #重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件)
  $(gdb) start 单步执行   运行程序,停在第一条执行语句
  $(gdb) list(l)  查看源代码(list-n,从第n行开始查看代码,list+函数名:查看具体函数)
  $(gdb) set 设置变量的值
  $(gdb) next(n)单步调试(逐过程。函数直接执行)
  $(gdb) step (s)  单步调试(逐语句:跳入自定义函数内部执行)
  $(gdb) backtrace(bt)查看函数的调用的栈帧和层级关系
  $(gdb) frame(f)切换函数的栈帧
  $(gdb) info(i) 查看函数内部局部变量的数值
  $(gdb) continue(c)继续执行
  $(gdb) print(p)打印值及地址
  $(gdb) quit(q)退出gdb
  $(gdb) break+num(b)在第num行设置的断点
  $(gdb) dispaly 追踪查看具体变量值
  $(gdb) undispaly 取消追踪观察变量
  $(gdb) watch 被设置观察点的变量发生修改时,打印显示
  $(gdb) i watch 显示观察点
  $(gdb) enable breakpints 启动断点
  $(gdb) disable breakpoints 禁用断点
  $(gdb) x 查看内存x/20xw显示20个单元,16进制,4字节每单元
  $(gdb)run argv[1]  argv[2]调试时命令传参
  $(gdb)set follow-fork-mode child Makefile项目管理:选择跟踪父子进程(foerk())

tips:

1.编译程序时需要加上-g,之后才能用gdb进行调试:gcc -g mian.cpp -o main

2.回车键:重复上命令

4.2【实战】命令行调试

给出一段简单代码,准备调试。

  
  #include <iostream>
  using namespace std;
  int main(int argc,char **argv)
  {
      int N = 100;
      int sum = 0;
      int i = 1;
  // calculate sum from 1 to 100
      while (i <= N)
      {
          sum = sum + i;
          i = i + 1;
      }
      cout << "sum = " << sum << endl;
      cout << "The program is over."   << endl;
      return 0;
  }

打断点调试过程中遇到:Missing separate debuginfos, use:debuginfo-install glibc-2.17-322.el7_9.x86_64 libgcc-4.8.5-44.el7.x86_64,因为一般发行版内核中是不带debuginfo,需要自行去安装,找到与内核匹配的:Index of /7/x86_64

第五讲 IDE-VSCode

在线安装:在linux系统(centOS7)中安装VSCode(Visual Studio Code)_沈醉不知的博客-CSDN博客

5.1界面介绍

5.2插件安装

5.3快捷键

5.4【实战】2个小项目

第六讲 CMake

前言:

CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)

CMake可以说已经成为大部分C++开源项目标配

6.1cross-platform development

​ 跨平台开发环境

6.2语法特性介绍

  • 基本语法格式 :指令(参数1 参数2...)

  • 参数使用括弧括起

  • 参数之间使用空格或分号分开

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

  • set(HELLO hello.cpp)

  • add_executable(hello main.cpp hello.cpp)

  • ADD_EXECUTABLE(hello.cpp main.cpp $

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

6.3重要指令和CMake常用变量

6.3.1重要指令

  • cmake_minimum_required 指定CMake的最小版本要求

#CMake最小版本要求为2.8.3

cmake_minimum_required(VERSION 2.8.3)

语法:cmake_minimum_required(VSERION versoinNumber[FATAL_ERROR])

  • project -定义工程名称,并可指定工程支持的语言

#指定工程名称为HELLOWORLD

project(HELLOWORLD)

语法:project(projectname CXX[Java])//[]内可省略

  • set-显示的定义变量

定义SRC变量,其值为main.cpp hello.cpp

set (SRC main.cpp hello.cpp)

  • include_directories-向工程中添加多个特定的头文件所搜路径-->相当于指定g++编译器的-I(i的小写)参数

#将/usr/include/myinclude和./include添加到头文件搜索路径

include_directories(/usr/include/myinclude ./include)

语法:include_directories(AFTER|BEFORE dir1 dir2 …)

  • link_directories--向工程中添加多个特定的库文件搜索路径--相当于指定g++编译器的-L参数

#将/usr/lib/mylib和./lib添加到库文件搜索路径

link_directories(/usr/lib/mylib ./lib)

语法:link_directories(dir1 dir2 …)

  • add_library--生成库文件

#通过变量SRC生成 libhello.so共享库

add_library(hello SHARED ${SRC}

语法:add_library(libname SHARED|STATIC|MODULE source1 source2 … sourceN)shared:动态库关键字;static:静态库关键字

  • add_compile_options-添加编译参数

#添加编译参数-Wall -std=c++11

add_compile_options(-Wall -std=c++11 --O2)

语法:**add_compile_options(<options>...)

  • add_executable--生成可执行文件

#编译main.cpp生成可执行文件main

add_executable(main main.cpp)相当于g++ main.cpp -o main

语法:add_executable(exename source1 source2 … sourceN)

  • target_link_libraries--为target添加需要连接的共享库-->相当于指定g++编译器-l(L的小写)参数

将hello动态库文件连接到库执行文件main

target_link_libraries(main hello)

语法:target_link_libraries(target library1library2…)

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

#添加src子目录,src中需要有一个CMakeLists.txt

add_subdirectory(src)

语法:add_subdirectory(source_dir binary_dir)

  • aux_source_directory --发现一个目标下所有的源代码文件并将列表存储在一个变量中,这个指令临时被用来自动构建源文件列表

#定义SRC变量,其值为当前目录下所有的源代码文件

aux_source_directory(. SRC)

#编译SRC变量所代表的源代码文件,生成main可执行文件

add_executable(main ${SRC})

语法:aux_source_directory(dir VARIABLE)

6.3.2 CMake 常用变量

CMAKE_C_FLAGS gcc编译选项

CMAKE_CXX_FALGS g++ 编译选项

在CMAKE_CXX_FALGS编译选项后追加 -std=c++11

set (CMAKE_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

1.这三个变量指代的内容是一致的。

2.如果in source build指的是工程顶层目录

3.如果out-of-source编译,指的是工程编译发生的目录

4.PROJECT_BINARY_DIR跟其他指令稍有区别,不过现在可以理解为他们是一致的

  • CMAKE_SOURCE_DIR

PROJECT_SOURCE_DIR

<projectname>__SOURCE_DIR

1.这三个变量指代的内容是一致的,不论采用何种编译方式都是工程顶层目录

2.也就是在in source build 时,它跟CMAKE_BINARY_DIR等变量一致

3.PROJECT_SOURCE_DIR跟其他指令稍有区别,可以理解为他们是一致的


CMAKE_C_COMPILER:指定C编译器

CMAKE_CXX_COMPILER:指定C++编译器

EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径

LIBRARY_OUTPUT_PATH:库文件输出的存档路径

6.4CMake编译工程

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

两种方式设置编译原则:

1.包含源文件的子文件包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加目录即可;

2.包含源文件的子文件加未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中;

6.4.1 编译流程

在Linux平台下使用CMake构建从C/C++工程的流程如下:

  • 手动编写CMakeLists.txt

  • 执行领命cmake PATH生成Makefile(PATH 是顶层CMakeLists.txt所在的目录)

  • 执行命令make进行编译

      
      #important tips
      .      # 表示当前目录
      ./     #表示当前目录
      ..     #表示上级目录
      ../    #表示上级目录

    6.4.2 两种构建方式

    内部构建(a in-source build):不推荐使用

    内部构建会在同级目录下产生一大堆中间文件,这些中间文件不是我们最终所需要的的,和工程源文件放在一起会显得杂乱无章

    ## 内部构建
    # 在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
    [root@localhost LinuxC++]#cmake .
    # 执行make命令,生成target
    [root@localhost LinuxC++]#make
    
    
    

    外部构建(out-source build)=推荐使用=

    将编译输出文件与源文件放到不同目录中
    
    #1.在当前目录下,创建build文件夹
    [root@localhost LinuxC++]#mkdir build
    
    #2.进入到build文件夹
    [root@localhost LinuxC++]#cd build
    
    #3.编译上级目录的CMakeLists.txt,生成Makefile和其他文件
    [root@localhost LinuxC++]#cmake  ..
    
    #4.执行make命令,生成target
    [root@localhost LinuxC++]#make
    
    
    

6.5【实战】CMake代码实战

6.5.1最小CMake工程

# #set  the minimum version of  CMake  that  can be used
cmake_minimum_required(VERSON 3.0)

#set the project name 
project (HELLO)

#Add an  executable 
add_executable(hello_cmake main.cpp)


6.5.2 多目录工程-直接编译

#set the minimum version of  CMake that  can be used 
cmake_minimum_required (VERSION 3.0 )

#project  name 
project (SWAP)

#head file pat 
include_directory (src DIR_SRCS)

#source directory files to var 
add_executable(swap_02 ${TEST_MATH})

#add link library 
target_link_libraries(${FS_BUILD_BINARY_PREFIX}sqrt ${LIBRARIES})


6.5.3 多目录工程-生成库编译

#set the minimum vresion  of CMake that can be used 
cmake_minimum_required(VERSION 3.0)

#project     name 
project(SWAP_LIBRARY)

#add complie options 
add_compile_options("-Wall  -std=c++11")

#set CMAKE_BUILD_TYPE
set( CMAKE_BUILD_TYPE  Debug)

#set  ouput binrary   path
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

####################################################
#Create a  library
####################################################
#generate the static library from the library sources
add_library( swap_library STATIC src/Swap.cpp)
target_include_directories (swap_lib PUBLIC ${PROJECT_SOURCE_DIR}/include)

#################################################
#create an  executable 
#################################################
#add an executable with the above sources 
add_executable (swap_01 main.cpp)

#link the new swap_01 target   with the swap_lib  target 
target_link_libraries( swap_01 swap_liby)


第七讲【实战】:使用VSCode进行完整项目开发

7.1 合理设置项目目录

7.2 编写项目源文件

7.3 编写CMakeLists.txt构建项目编译规则

7.4 使用外部构建,手动编译CMake项目

7.5 配置VSCode的json文件并调试项目

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值