GCC编译器

GCC编译器

前言:

  1. GCC编译器支持编译Go、Objective-C、Objective-C ++、Fortran、Ada、D和BRIG(HSALL)等程序;
  2. Linux开发C/C++一定要熟悉GCC
  3. VSCode是通过调用GCC编译器来实现C/C++的编译工作的;

实际使用中:

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

1、编译过程

一个.cpp文件经过了怎样的过程形成目标文件的?

  1. 预处理-Pre-Processing
# -E选项指示编译器仅对输入文件进行预处理
g++	   -E    test.cpp    -o    test.i    //.i文件
  1. 编译-Compiling
#  -S    编译选项告诉  g++  在为C++  代码产生了汇编语言文件后停止编译
#    g++    产生的汇编语言文件的缺省拓展名是  ..S
g++    -S    test.i    -o    test.s
  1. 汇编-Assembling
#    -c    选项告诉    g++    仅把源代码编译成为机器语言的目标代码
#    缺省时    g++    建立的目标代码文件有一个    .o的拓展名
g++    -c    test.s    -o    test.o
  1. 链接
#    -o    编译选项来未将产生的可执行文件用指定的文件名
g++    test.o    -o    test

2、重要编译参数

  1. -g 编译带调试信息的可执行文件
#    -g    选项告诉  GCC  产生能被GNU调试器GDB使用的调试信息,以调试程序。(这个非常重要,如果后续需要调试就必须要有-g选项)

#    产生带调试信息的可执行文件test
g++    -g    test.cpp    -o    test
  1. -O[n] 优化源代码
##    所谓优化,例如省略掉代码中从未使用过的变量,直接将常量表达式用结果值代替等等,这些操作会缩减目标文件中所包含的代码量,提高最终生成的可执行文件的效率。

#    -O   选项告诉  g++  对源代码进行基本优化。这些优化在大多数情况下都会使程序执行的更快。    -O2    选项告诉  g++ 产生尽可能小和尽可能快的代码。如-O2,-O3,-On(n常为0-3)
#    -O  同时减小代码的长度和执行时间,其效果等价与-O1
#    -O0  表示不做优化
#    -O1  为默认优化
#    -O2  除了完成  -O1 的优化之外,还进行一些额外的调整工作,如指令调整等。
#    -O3  则包括循环展开和其他一些与处理特性相关的优化工作。
#    选项将使编译的速度比使用    -O  时慢, 但通常产生的代码执行速度会更快。

#    使用   -O2优化源代码,并输出可执行文件
g++  -O2  test.cpp  -o   test
  1. -l-L 指定库文件 | 指定库文件路径
#    -l参数(小写)就是用来指定程序要链接的库,-l参数紧接着就是库名
#    在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接

#    链接glog库
g++    -lglog    test.cpp

#    如果库文件没放在上面三个目录里,需要使用-L参数(大写)指定库文件所在目录
#    -L参数跟着的时库文件所在的目录名

#    链接mytest库,libmytest.so在/home/bing/mytestlibfolder目录下
g++    -L/home/bing/mytestlibfolder    -lmytest    test.cpp
  1. -I(大写的i)
#    -I
#    /usr/include目录一般是不用指定的,gcc知道去哪里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译指令就要加上-I/myinclude 参数了,如果不加你会得到一个“xxxx.h:No such file or directory”的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定。上面我们提到的-cflags参数就是用来生成-I参数的。

g++    -I/myinclude    test.cpp
  1. -Wall 打印警告信息
#    打印出gcc提供的警告信息
g++    -Wall    test.cpp
  1. -w 关闭警告信息
#    关闭所有警告信息
g++    -w    test.cpp
  1. -std=c++11 设置编译标准
#    使用  c++11   标准编译    test.cpp
g++    -std=c++11    test.cpp
  1. -o 指定输出文件名
#    指定即将产生的文件名

#    指定输出可执行文件名为test
g++   test.cpp    -o    test
  1. -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");
        return 0;
}

// 1.在编译的时候,使用g++  -DDEBUG main.cpp
// 2.第七行代码可以被执行

​ 执行结果:

DEBUG log
in

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

3、编译实战

1、直接编译

最简单的编译,并运行

#    将main.cpp   src/Swap.cpp   编译为可执行文件
g++ mian.cpp src/swap.cpp  -Iinclude
#    运行a.out
./a.out

增加参数编译,并运行

#    将main.cpp  src/Swap.cpp 编译成可执行文件   附带一些参数
g++ main.cpp  src/swap.cpp -Iinclude -O2 -Wall -std=c++11 -o b.out
#    运行b.out
./b.out

2、生成库文件进行编译

示例树目录结构:

  • 三个箭头指向的红色框框是初始的结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iW5oCK67-1666614550319)(GCC编译器.assets/image-20221011233947287.png)]

链接静态库生成可执行文件:

##    进入src目录下
cd src

#    汇编,生成swap.o文件
g++ -c swap.cpp -I../include -o swap.o
#    生成静态库libswap.a
ar rcs libswap.a swap.o

##     回到上级目录
cd ..


#    链接,生成可执行文件:static_main
g++ main.cpp -lswap -Lsrc -Iinclude -o static_main

链接动态库生成可执行文件:

##    进入src目录下
cd src

#    生成动态链接库libswap.so
 g++ swap.cpp -I../include -fPIC -shared -o libswap.so
##   上方的命令相当于以下两种指令
#    gcc swap.cpp -I../include -fPIC -c
#    gcc swap.o -shared -o libswap.so

#    回到上级目录
cd ..

#    链接,生成可执行文件:share_main
 g++ main.cpp -Iinclude -Lsrc -lSwap -o share_main
 #    然后运行可执行文件share_main,会发现出现以下错误
 ./share_main: error while loading shared libraries: libSwap.so: cannot open shared object file: No such file or directory

image-20221012000645504

  • 具体解决方法如下节所示。

3、运行可执行文件

运行静态库可执行文件:

#    运行静态库可执行文件
./static_main

运行动态库可执行文件:

#   运行动态库可执行文件
LD_LIBRARY_PATH=src ./share_main    # 强制编译器扫描指定的路径

4、案例目录结构

image-20221012001828264

GDB调试器

前言:

  • GDB(GUN Debugger)是一个用来调试C/C++程序的功能强大的调试器,是Linux系统开发C/C++最常用的调试器。
  • 程序员可以使用GDB来跟踪程序中的错误,从而减少程序员的工作量。
  • Linux开发C/C++一定要熟悉GDB
  • VSCode是通过调用GDB调试器来实现C/C++的调试工作的;

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

GDB主要功能:

  • 设置断点(断点可以是条件表达式)
  • 使程序在指定代码上暂停运行,便于观察
  • 单步执行程序,便与调试
  • 查看程序中变量值的变化
  • 动态改变程序的执行环境
  • 分析崩溃程序产生的core文件

1、常用调试命令参数

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

##以下命令后括号内为命令的简化使用,比如run(r),直接输入命令r就代表命令run

$(gdb)help(h)    #查看命令帮助,具体命令查询在gdb中输入help+命令
$(gdb)run (r)      #重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件)
$(gdb)start        #单步执行,运行程序,停在第一行执行语句
$(gdb)list(1)        #查看原代码(1ist-n,从第n行开始查看代码。11st+函数名:查看具体函数)
$(gdb)set        #设置变量的值
$(gdb)next(n)        #单步调试(逐过程,函数直接执行)
$(gdb)step(s)        #单步调试(遂语句:跳入自定义函数内部执行)
$(gdb)backtrace(bt)        #查看函数的调用的栈帧和层级关系
$(gdb)frame(f)        #切换函数的帧
$(gdb)info(i)        #查看函数内部局部变量的数值
$(gdb)finish        #结束当前函数,返回到函数调用点
$(gdb)continue(c)        #陆续执行
$(gdb)print(p)        #打印值及地址
$(gdb)quit(q)        #退出gdb
$(gdb)break+num(b)        #在第num行设置断点
$(gdb)info breakpoints        #查看当前设置的所有断点
$(gdb)delete breakpoints num(d)        #删除第num个断点
$(gdb)display        #追踪查看具体变量值
$(gdb)undisplay        #取消追踪观察变显
$(gdb)watch        #被设置观察点的变量发生修改时,打印显示
$(gdb)i watch        #显示观察点
$(gdb)enable breakpoints        #启用断点
$(gdb)disable breakpoints        #禁用断点
$(gdb)x        #查看内存×/20xW显示20个单元,16进制,4字节每单元
$(gdb)run argv[1]argv[2]        #调试时命令行传参
$(gdb)set fo11ow-fork-mode chi1d        #Makefi1e项目管理:选择跟踪父了进程(fork))

Tips:

  1. 编译程序时需要加上-g,之后才能用gdb进行调试:gcc -g main.cpp -o main
  2. 回车键:重复上一指令

VSCode整合

1、插件安装

以下三个是Linux下开发C/C++必要的三个插件:

  • C/C++
  • CMake
  • CMake Tools

2、快捷键

  • 一定要熟练学习

CMake编译工程

前言:

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

1、Cross-platform development

Let’s assume you have some cross-platform project with C++code shared along different platforms/IDEs.Say you use visual studio on Windows,Xcode on OSX and Makefile for Linux:

image-20221012234621792

What you will do if you want to add new bar.cpp source file?You have to add it to every tool you use:

image-20221012234715787

To keep the environment consistent you have to do the similar update several times.And the most important thing is that you have to do it manually (arrow marked with a red color on the diagram in thiscase).Of course such approach is error prone and not flexible.
CMake solve this design flaw by adding extra step to development process.You can describe your project in cMakeLists.txt file and use CMake to generate tools you currently interested in using cross-platformCMake code:

image-20221012234844539

Same action-adding new bar.cpp file,will be done in one step now:

image-20221012235040236

Note that the bottom part of the diagram was not changed.l.e.you still can keep using your favorite tools like visual studio/msbuild,Xcode/xcodebuild and Makefile/make!

2、语法特性介绍

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

    • 参数使用括孤括起
    • 参数之间使用空格分号分开
  • 指令是大小写无关的,参数和变量是大小写相关的

    set(HELLO hello.cpp)
    add_executable(hello main.cpp hello.cpp)
    ADD_EXECUTABLE(hello main.cpp ${HELLO})
    
  • 变量使用$0方式取值,但是在IF控制语句中是直接使用变量名

3、重要指令和CMake常用变量

3.1、重要指令

注意:下列代码示例中,只示范了最常用的格式。

  • 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(HELLOWORLD)
    
  • set - 显式的定义变量

    • 语法:Set(VAR[VALUE][CACHE TYPE DOCSTRING[FORCE])
    # 定义SRC变量,其值为main.cpp hello.cpp
    set(SRC sayhello.cpp hello.cpp)
    
  • include_directories - 向工程添加多个特定的头文件搜索路径–>相当于指定g++编译器的-参数

    • 语法:include_directories([AFTERBEFORE][SYSTEM]dir1dir2.)
    #        将/usr/include/myincludefolder和./include添加到头文件搜索路径
    include_directories(/usr/include/myincludefolder    ./include)
    
  • link_directories - 向工程添加多个特定的库文件搜索路径->相当于指定g++编译器的-L参数

    • 语法:link directories(dir1dir2.…)
    #        将/usr/1ib/my1bfo1der和./1b添加到库文件搜索路径
    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})
    
  • add_compile_options - 添加编译参数

    • 语法:add_compile_options( …)
    #    添加编译参数  -wall -O2 -std=c++11
    add_compile_options(-Wall -std=c++11 -O2)
    
  • add_executable - 生成可执行文件

    • 语法:add_library(exename source1 source2 … sourceN)
    #    编译main.cpp生成可执行文件
    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})
    

3.2、常用变量

  • CMAKE_C_FLAGS gcc编译选项
  • CMAKE_CXX_FLAGS g++编译选项
# 在CMAKE_CXX_FLAGS编译选项后追加-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
    _BINARY_DIR

    1. 这三个变量指代的内容是一致的。
    2. 如果是 in source build,指的就是工程顶层目录。
    3. 如果是 out-of-source 编译,指的是工程编译发生的目录。
    4. PROJECT_BINARY_DIR跟其他指令稍有不同,不过现在,你可以理解它们是一致的。
  • CMAKE_SOURCE_DIR
    PROJECT_SOURCE_DIR
    _SOURCE_DIR

  • CMAKE_C_COMPILER:指定C编译器

  • CMAKE_CXX_COMPILER:指定C++编译器

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

  • LIBRARY_OUTPUT_PATH:库文件输出的存放路径

3.3、CMake编译工程

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

两种方式设置编译规则:

  1. 包含源文件的子文件夹包含CMakeLists.txt文件,主目录的CMakeLists.txt通过add_subdirectory添加子目录即可;
  2. 包含源文件的子文件夹未包含CMakeLists.txt文件,子目录编译规则体现在主目录的CMakeLists.txt中;
3.3.1、编译流程
  1. 手动编写CMakeLists.txt
  2. 执行命令cmake PATH生成Makefile(PATH是顶层CMakeLists.txt所在的目录)
  3. 执行命令make进行编译
3.3.2、两种构建方式
  • **内部构建(in-source build):**不推荐使用

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

    ##  内部构建
    
    #    在当前目录下,编译本目录的CMakeLists.txt,生成Makefile和其他文件
    cmake  .
    #    执行make命令,生成target
    make
    
  • 外部构建(out-of-source build)推荐使用

    将编译输出文件与源文件放到不同目录中

    ##   外部构建
    
    #   在当前目录下,创建build文件夹
    mkdir build
    # 2. 进入到build文件夹
    cd build
    # 3. 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
    cmake ..
    # 4. 执行make命令,生成target
    make
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RISC-V GCC编译器手册是一本详细介绍如何使用RISC-V架构下GCC编译器的参考手册。GCC是一种自由软件,被广泛用于编译各种编程语言,包括C、C++和Fortran等。RISC-V是一种基于精简指令集计算机(RISC)原理的开源处理器架构。 手册中首先介绍了RISC-V工具链的安装和配置,包括如何获取GCC编译器和相关的工具。它详细说明了如何在不同的操作系统上进行编译器和工具链的安装过程,并提供了一些常见问题的解答。 接下来,手册详细介绍了GCC编译器的各种选项和参数的用法。这些选项和参数可以用于控制编译器的行为,如优化级别、调试选项、错误处理、输出文件格式等。手册还提供了一些示例和说明,以帮助用户理解和使用这些选项。 此外,手册还涵盖了GCC编译器针对RISC-V架构的特定优化策略。这些优化策略可以提高代码的性能和效率,包括指令调度、寄存器分配、循环优化等。手册中还解释了如何使用这些优化选项,并给出了一些示例来说明其作用。 最后,手册还包括对GCC编译器的一些扩展功能的介绍,如内联汇编、向量指令集扩展、浮点运算支持等。这些扩展功能使得GCC编译器能够更好地支持RISC-V架构下特定的编程需求。 总之,RISC-V GCC编译器手册是一本详细、全面的参考手册,为用户提供了使用GCC编译器进行RISC-V架构开发的必备指南。无论是初学者还是有经验的开发者,都可以通过这本手册深入了解和掌握GCC编译器的用法,从而更加高效地进行RISC-V架构下的软件开发。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值