首页 > 编程语言 >c++编译

c++编译

时间:2023-09-02 16:55:04浏览次数:42  
标签:文件 src ++ c++ 编译 cpp include

1.1 c++编译

c++脚本程序写完之后,并不能直接运行,需要进行编译,转成.o文件,再链接才能运行,一般包括:预处理,汇编,编译。链接四步,如下:

  • 预编译

    把 .c源文件编译成 .ii 预处理文件

    gcc -E [源文件.c] -o [自定义名.ii]
    
  • 编译成汇编语言

    把 .i 文件编译成 .s 汇编语言文件

    gcc -S [源文件.c] 
    
    • 注意:隐藏了预编译、删除预处理i文件的过程
  • 编译成二进制
    把 .s 编译成二进制.o 文件

    gcc -c [源文件.c] -o [自定义文件名.o] [编译选项]
    
    • 注意:隐藏了。。。
  • 链接成可执行文件
    把 .o 文件,链接成可执行的二进制文件

    gcc [.o] -o [自定义文件名] [链接选项]
    

注意:实际使用中一般就是编译成二进制.o 文件,然后将所有 .o 文件,链接成可执行的二进制文件

1.1.1 单文件或少文件编译

  • 编译:源文件[.c/cpp] -> Object文件[.o]

    g++ -c [.c/cpp][.c/cpp]... -o [.o][.o]... -I[.h/hpp]
    # g++是编译命令 -c,-o,-I是选项 -c接源脚本文件 -o接目标文件 -I接头文件(-c c++ /-o object/ -I include)
    
  • 链接:Object文件[.o]->可执行文件

    gcc [.o] -o out.exe -l[库名称] -L[库路径]
    

1.1.2多文件编译(使用Makefile 和 CMake)

cmake比Makefile高级,但是两者的功能都是快速地进行批量的编译(因为当你有很多的c++源文件的时候,一个一个地去用g++去编译是很麻烦的)

1.1.3 Makefile教程

参考: https://zhuanlan.zhihu.com/p/396448133

GNU Make官方网站:https://www.gnu.org/software/make/

GNU Make官方文档下载地址:https://www.gnu.org/software/make/manual/

1. 基本格式

targets : prerequisties

  command
  • target:目标文件,可以是OjectFile,也可以是执行文件,还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

  • prerequisite:要生成那个target所需要的文件或是目标。

  • command:是make需要执行的命令,

2. Makefile规则

(1)make会在当前目录下找到一个名字叫“Makefile”或“makefile”的文件。

(2)如果找到,它会找文件中第一个目标文件(target),并把这个文件作为最终的目标文件。

(3)如果target文件不存在,或是target文件依赖的.o文件(prerequities)的文件修改时间要比target这个文件新,就会执行后面所定义的命令command来生成target这个文件

(4)如果target依赖的.o文件(prerequisties)也存在,make会在当前文件中找到target为.o文件的依赖性,如果找到,再根据那个规则生成.o文件。

3 Makefile的变量

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,并用小括号“()”把变量给包括起来。

3.1 变量的定义和使用

  • 定义
# 头文件路径
include_paths := /usr/local/cuda-10.1/include \
         /datav/lean/opencv4.5.1/include/opencv4 \
         /datav/lean/tensorRT6.0.1.5_cuda10.1_cudnn7.6.0.3/include/ \
         src \
         src/tensorRT \
         src/tensorRT/common \
  • 使用
include_paths := $(foreach item,$(include_path),-I(item))

3.2 Makefile常用的预定义变量

  • $@  目标(target)的完整名称。

  • $<  第一个依赖文件(prerequisties)的名称。

  • $^  所有的依赖文件(prerequisties),以空格分开,不包含重复的依赖文件。

4 Makefile的常用运算符

4.1赋值:=

  用于变量的定义、赋值

# 链接库名称
link_library := cudart opencv_core opencv_imgcodecs opencv_imgproc \
         gomp nvinfer protobuf cudnn pthread \
         cublas nvcaffe_parser nvinfer_plugin python3.8

4.2 累加+=

# 编译选项设置
cpp_compile_flags := -m64 -fPIC -g -O0 -std=c++11 -w -fopenmp
cpp_compile_flags += $(include_paths)

5 Makefile的常用函数

函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:

$(<function> <arguments>)
  • <function>就是函数名,make 支持的函数不多。

  • <arguments>是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。

5.1 shell

$(shell <command> <arguments>)
  • 名称:shell命令函数——subst。

  • 功能:调用shell命令command

  • 返回:函数返回shell命令command的执行结果

  • 示例:

cpp_srcs := $(shell find src -name "*.cpp") 

5.2 patsubst

$(patsubst <pattern>,<replacement>,<text>)
  • 名称:模式字符串替换函数——patsubst。

  • 功能:查看中的单词是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。

  • 返回:函数返回被替换过后的字符串。

  • 示例:

cpp_srcs := $(shell find src -name "*.cpp") #shell指令,src文件夹下找到.cpp文件
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) #cpp_srcs变量下cpp文件替换成 .o文件

5.3 subst

$(subst <from>,<to>,<text>)
  • 名称:字符串替换函数——subst。

  • 功能:把字串中的字符串替换成

  • 返回:函数返回被替换过后的字符串。

  • 示例:

cpp_srcs := $(shell find src -name "*.cpp") #shell指令,src文件夹下找到.cpp文件
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) #cpp_srcs变量下cpp文件替换成 .o文件
cpp_objs := $(subst src/,objs/,$(cpp_objs)) #cpp_objs 变量下替换后的 .o文件 从src文件夹移植到objs文件夹

5.4 foreach

$(foreach <var>,<list>,<text>)
  • 名称:循环函数——subst。

  • 功能:把字串<list>中的元素逐一取出来,执行<text>包含的表达式

  • 返回:<text>所返回的每个字符串所组成的整个字符串(以空格分隔)

  • 示例:

library_paths := /datav/shared/100_du/03.08/lean/protobuf-3.11.4/lib \
        /usr/local/cuda-10.1/lib64 \
library_paths := $(foreach item,$(library_paths),-L$(item))

5.5 dir

$(dir <names...>)
  • 名称:取目录函数——dir。

  • 功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。

  • 返回:返回文件名序列的目录部分。

  • 示例:

$(dir src/foo.c hacks)   # 返回值是“src/ ./”。

6 伪目标

“伪目标”不是一个文件,只是一个标签,。我们要显示地指明这个“目标”才能让其生效。“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。

为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目标”。

.PHONY : clean
  • 只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”。

7 编译过程

7.1 总览

源文件[.c/cpp] -> 预处理成[.i/.ii] -> 编译成[.s] -> 汇编成[.o] -> 链接成可执行文件

7.2 包含静态库的编译过程

### 步骤:

(1)源文件[.c/cpp] -> Object文件[.o]

g++ -c [.c/cpp][.c/cpp]... -o [.o][.o]... -I[.h/hpp] -g

(2)Object文件[.o] -> 静态库文件[lib库名.a]

ar -r [lib库名.a] [.o][.o]...      # 编译静态库用ar

(3)main文件[.c/cpp] -> Object文件[.o]

g++ -c [main.c/cpp] -o [.o] -I[.h/hpp] -g

(4)链接 main的Object文件 与 静态库文件[lib库名.a]

g++ [main.o] -o [可执行文件] -l[库名] -L[库路径]

7.3 包含动态库(共享库)的编译过程

### 步骤:

源文件[.c/cpp] -> Object文件[.o]

g++ -c [.c/cpp][.c/cpp]... -o [.o][.o]... -I[.h/hpp] -g -fpic

Object文件[.o] -> 动态库文件[lib库名.so]

g++ -shared [.o][.o]... -o [lib库名.so]    # 编译动态库用g++ -shared

main文件[.c/cpp] -> Object文件[.o]

g++ -c [main.c/cpp] -o [.o] -I[.h/hpp] -g

链接 main的Object文件 与 动态库文件[lib库名.so]

g++ [main.o] -o [可执行文件] -l[库名] -L[库路径] -Wl,-rpath=[库路径]

注意: 编译静态库用ar; 编译动态库用g++ -shared

1.2 include

#include<> 和 #include ""的区别

  • 对于#include <filename.h>,编译器先从标准库路径开始搜索filename.h,使得系统文件调用比较快

  • 对于#include "filename.h",编译器先从用户的工作路径开始搜索filename.h,后去寻找系统路径,使得自定义文件较快。
    所以在写代码的过程中要根据实际情况选择是<>还是"",

    一般标准库文件用include <> , 自定义文件 include ""

1.3 指针定义 与 使用

  • 定义的时候* 和 & 指的是指针变量和引用

    • 如下:
      int* a = nullptr;  // 指的是指向 int的指针类型
      void func(int* a); // 形参时,你传入的得是 地址/指针
      void func(int& a); // 形参时,你传入的得是 引用
      
  • 使用的时候* 和 & 指的是取地址上的值 和 取变量的地址

    • 如下:
      int value = *a;   // 此时a是个指针变量,取该地址的变量值
      int* ptr = &b;    // 此时b是个非指针变量,取该变量的地址
      func(*a);         
      func(&b); 
      

标签:文件,src,++,c++,编译,cpp,include
From: https://www.cnblogs.com/silence-cho/p/17673892.html

相关文章

  • aarch64/arm_v8 环境下编译Arcade-Learning-Environment —— ale-py
       condainstallg++=12   cmake../-DCMAKE_BUILD_TYPE=Release-DPYTHON_INCLUDE_DIR=/home/share/xxx/home/software/anaconda3/include-DPYTHON_LIBRARY=/home/share/xxx/home/software/anaconda3/lib/libpython3.11.so-DPython3_EXECUTABLE=/home/share/x......
  • C++程序的内存模型--模型四区
      C++中在程序运行前分为全局区和代码区 代码区特点是共享和只读 全局区中存放全局变量、静态变量、常量 常量区中存放const修饰的全局变量和字符串常量 //栈区//由编译器自动分配释放、存放函数的参数值、局部变量等//注意:不要返回局部变量的地址,栈区开辟的数据由编译器......
  • GCC实现多文件编译,静态库,动态库
    GCC实现多文件编译,静态库,动态库一代码 //add.hintadd(inta,intb);  //add.cintadd(inta,intb){  returna+b;}  //main.c #include<stdio.h>#include"add.h" voidmain(){   printf("3+2=%d\n",add(3+2));} 二......
  • linux开发C/C++
    最近在部署项目的时候总是会遇到关于C++的编译问题,由于之前学习C++只是为了参加算法竞赛,缺少这一部分的知识,所以学习一下这一相关内容,并做一下记录参考:VSCode开发C++七讲【基于VSCode和CMake实现C/C++开发|Linux篇】https://www.bilibili.com/video/BV1fy4y1b7TC?p=17&vd_sourc......
  • 如何在CMAKE中指定python路径——使用cmake为python编译扩展模块时指定python路径
     答案:cmake-DPython3_EXECUTABLE=/path/to/bin/python3   =================================================    参考:https://stackoverflow.com/questions/49908989/cmake-cant-find-python3   =================================== ......
  • windows10,编译rust程序到so文件,供android调用,笔记
    1、用D:\myProgram\android_sdk\ndk\ndk-22.0.7026061\ndk-build.cmd编译,全路径,只写ndk-build,似乎不行2、在androidas里编译,提示soisnotaABI,其实是so放错地方了。应该放在src\main\jniLibs\arm64-v8a目录下(其他cpu类似),我就是缺少arm64-v8a目录,导致这个错误,新建arm64-v8......
  • CLion进行远程/本地编译、GDB调试postgres(含阅读源码)
    Clion-RemoteGDB调试postgres(本地为windows,远程为centos)通过Make+Makefile编译,并构建索引下面一步一步跟着做即可下载源码压缩包、编译postgres的源码:使用Clion调试postgresql源码-知乎(zhihu.com)(系统用户的配置文件是~/.zshrc)下载源码压缩包、编译postgres的源码:Lin......
  • 从源码编译OpenCV
    从源码编译的原因官方已经有编译好的包可下载:https://opencv.org/releases/但是在iOS项目中集成官方编译的pack(目前为4.8.0),出现以下错误:ld:in/.../opencv2.framework/opencv2(opencl_kernels_calib3d.o),buildingforiOSSimulator,butlinkinginobjectfilebuiltf......
  • C/C++毕业设计管理系统[2023-09-02]
    C/C++毕业设计管理系统[2023-09-02]二、毕业设计管理系统学校有若干学院,每个学院有若干专业,需要通过一个毕业设计管理系统对现有的毕业设计情况进行管理。系统适用对象:教务处管理员、院系负责人、教师、学生。1、教务处管理员:全校教学事务管理、全校课题过程管理、学生及课题......
  • 《C++并发编程实战》读书笔记(1):线程管控
    1、线程的基本管控包含头文件<thread>后,通过构建std::thread对象启动线程,任何可调用类型都适用于std::thread。voiddo_some_work();structBackgroundTask{voidoperator()()const;};//空的thread对象,不接管任何线程函数std::threadt1;//传入普通函数std::thr......