首页 > 系统相关 >在Linux系统下用命令行编译调试C++

在Linux系统下用命令行编译调试C++

时间:2024-04-29 22:23:12浏览次数:30  
标签:-- 下用 C++ 编译 c++ br Linux include 断点

在Linux系统下用命令行编译调试C++

目录

总结 Ubuntu 下使用 clang 和 lldb 对 C++ 进行编译调试的常用命令。

贴一下系统及工具版本:

mayrain@PC-HOME-Y:~$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
mayrain@PC-HOME-Y:~$ cat /proc/version
Linux version 5.15.146.1-microsoft-standard-WSL2 (root@65c757a075e2) (gcc (GCC) 11.2.0, GNU ld (GNU Binutils) 2.37) #1 SMP Thu Jan 11 04:09:03 UTC 2024
mayrain@PC-HOME-Y:~$ clang++ --version
Ubuntu clang version 14.0.0-1ubuntu1.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
mayrain@PC-HOME-Y:~$ lldb --version
lldb version 14.0.0

一、编译

这里仅介绍常用的单文件及多文件编译,包括第三方库的链接。复杂项目还是直接上IDE哈哈哈。

注意,ubuntu默认是不安装libc++的,我在网上没搜到有什么方便的安装方式,干脆自己编译一下,过程记录如下(参考llvm官网编译指引):

git clone https://github.com/llvm/llvm-project.git ./llvm

cd llvm

mkdir build

cmake -G Ninja -S runtimes -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind"

ninja -C build cxx cxxabi unwind

ninja -C build check-cxx check-cxxabi check-unwind 

ninja -C build install-cxx install-cxxabi install-unwind

1. 单文件编译

将源文件 main.cpp 编译为可执行文件 foo:

clang++ -Wall -g -std=c++11 -stdlib=libc++ main.cpp -o foo

2. 多文件编译

首先准备三个文件:

add.h

int add(int a, int b);

add.cpp

#include <iostream>

using namespace std;

int add(int a, int b)
{
	int ret = a + b;
	cout << "sum of " << a << " and " << b << " is " << ret << endl;
	return ret;
}

main.cpp

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include "add.h"

using namespace std;

template <typename T>
void print(const T& v)
{
    for (auto iter = v.begin(); iter != v.end(); iter++)
    {
        cout << *iter << " ";
    }
    cout << endl;
}

int main(int argc, char** argv) 
{
    cout << "hello lldb!" << endl;
    
    int i = 42;
    int *pi = &i;
    
    int i2 = 15;
    int i3 = add(i, i2);
    
    string s("A lazy dog jumps over the fox");
    string *ps = &s;

    vector<int> iv = {0,1,2,3,4,5,6,7,8,9};
    
    set<int> is;
    is.insert(0);
    is.insert(42);

    print(iv);
    print(is);

    return 0;
}

将以上代码编译为可执行文件 foo:

clang++ -Wall -g -std=c++11 -stdlib=libc++ main.cpp add.cpp -o foo

编译器默认会在当前目录中寻找头文件,所以这里无需单独指定包含目录。

3. 链接第三方动态库

以 opencv 为例:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <string>

using namespace std;
using namespace cv;

int main()
{
    string path = "./cv_test.png";
    Mat img = imread(path);
    namedWindow("cv_test", 0);
    resizeWindow("cv_test", 1024, 768);
    imshow("cv_test", img);
    waitKey(0);
    return 0;
}

编译以上示例程序的命令为:

clang++ -Wall -g -std=c++11 -stdlib=libstdc++ -I /usr/local/include/opencv4 -L /usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_imgcodecs main.cpp -o foo

为什么改成 -stdlib==libstdc++ ?

因为 opencv 库是使用 libstdc++ 进行编译的,如果两者不一致,会报cv::imread函数找不到定义。细节可以看这篇文章


二、调试

本文仅列举常用调试命令,遇到不清楚的用法可以使用以下命令看说明:

lldb --help

也可以在lldb交互命令行中使用help [命令]获取某个具体命令的帮助信息:

image-20240429104935502

以下内容用本文三.2节的三个源文件作为调试demo。

1. 启动和退出

两种启动方式:

image-20240429104121541

image-20240429104148178

退出也有两种方式:

exitquit

2. 查看源代码:list/l

查看从给定行号开始的10行代码:

list [行号]l [行号]

按回车可以显示下边10行

image-20240429104214795

查看函数代码:

l [函数名]

image-20240429105055162

3. 断点:breakpoint/br、watchpoint

在函数起始处设置断点:

br set --name [函数名]

设置完断点,run运行foo即可

image-20240429113017798

在指定行设置断点:

br set --line [行号]

因为此时程序还断在main函数的开头,所以输入continuec让程序继续

image-20240429113044684

在指定文件的指定行设置断点:

br set --file [文件名] --line [行号]

image-20240429113119146

查看断点列表:

br list

image-20240429113800403

删除某个/多个断点:

br delete [断点序号1] [断点序号2] [断点序号3]

br delete [n-m]

image-20240429113735035

删除所有断点:

br delete

启用/禁用断点:

br enable [序号]

br disable [序号]

image-20240429113700209

内存断点:watchpoint/watch(当内存发生读/写操作时触发)

常用的条件断点:

watch set var [变量名]

watch modify -c '([变量名]==[值])'

image-20240429134648045

image-20240429134758843

删除、启用/禁用操作和breakpoint类似。

4. 单步、步入、跳出

单步 Step-over:

nextn

步入 Step-in:

steps

跳出 Step-out:

finish

操作截图:

add函数调用行设置并触发断点

image-20240429114330482

步入add

image-20240429114400611

单步

image-20240429114423759

跳出add,可以看到lldb会把返回值列出来

image-20240429114519795

修改函数返回值:

thread return [表达式]

image-20240429130419709

5. 计算表达式命令:expression/expr、p、po

pexpr --的简写,poexpr -o --的简写,它们会把参数编译并打印输出,两者仅是格式不同。

查看变量的值:

p [变量名]po [变量名]

image-20240429121525388

指定输出格式/做进制转换:

p/[格式] [变量名]

image-20240429123936865

修改变量值:

expr [变量名]=[值]

frame variable查看变量前后变化

image-20240429121821052

6. 操作内存:memory read/x、memory write

读内存:

x/[读取个数][字节数][格式] [内存地址]

[读取个数]:整数

[字节数]:b-1Byte、h-2Byte、w-4Byte、g-8Byte

[格式]:x-16进制、f-浮点数、d-10进制

image-20240429125742696

写内存:

memory write [内存地址] [值]

image-20240429125927396

7. 获取当前线程调用栈:thread backtrace/bt

image-20240429130239747

8. 一些进阶操作

显示汇编代码:disassemble/d

d -b

d --frame

d --name [函数名]

d -a [内存地址]

d -s [内存地址]

寄存器操作:register read、register write

image-20240429131328156

标签:--,下用,C++,编译,c++,br,Linux,include,断点
From: https://www.cnblogs.com/jy5380/p/18166743

相关文章

  • C++ 学习笔记
    ​1、基础概念C++是一种高性能的编程语言,由BjarneStroustrup在1980年代初设计,旨在为C语言添加面向对象的功能。自那时起,C++已发展成为一种支持过程性、面向对象和泛型编程的多范式语言,广泛应用于系统软件、游戏开发、驱动程序、嵌入式固件等领域。要开始使用C++,首先需要......
  • 深入理解 C++ 中的多态与文件操作
    C++多态多态(Polymorphism)是面向对象编程(OOP)的核心概念之一,它允许对象在相同操作下表现出不同的行为。在C++中,多态通常通过继承和虚函数来实现。理解多态想象一个场景,你有一个动物园,里面有各种动物,如猫、狗、鸟等。每个动物都有自己的叫声。使用面向对象编程,我们可以创建一个......
  • Linux基础之权限管理
    目录通用权限的管理扩展权限的管理特殊权限的管理权限掩码在Linux中,权限管理是通过文件系统中的权限位来实现的。通用权限的管理每个文件或目录都有一个所有者、一个用户组和其他用户的权限设置。主要的权限包括读取、写入和执行。文件权限包括读、写和执行权限:读权限(r):允许......
  • windows使用samba共享linux文件服务
    一、服务结构服务端:linux服务器192.168.2.251客户端:windows服务器192.168.2.252二、linux部署samba服务端1.安装samba~]#yum-yinstallsamba2.创建共享文件夹~]#mkdir/mnt/svr33.创建samba用户~]#smbpasswdwyg或者~]#pdbedit-a-utest密码:wyg.1234.编......
  • 在 ArchLinux 上完美使用高漫 M6 数位板
    没想到这个问题还能产生第三篇博客。前言2022年和2023年我针对这个问题写了两篇博客(见此处和此处),非常高兴能够看到博客帮到了一些网友。那个时候我的系统是Kubuntu22.04。今年换到Arch之后,发现原先使用的digimenddkmsdriver的fork(https://github.com/inochisa......
  • 稳扎稳打 部署丝滑 开源即时通讯(IM)项目OpenIM源码部署流程(linux windows mac)
    背景OpenIM包含多个关键组件,每个都是系统功能必不可少的一部分。具体来说,MongoDB用于持久化存储;Redis用作缓存;Kafka用于消息队列;Zookeeper用于服务发现;Minio用于对象存储。这些组件的众多可能会增加部署的复杂性。此外,系统包含多个微服务模块,这要求有效管理进程的启动、停止......
  • linux网络DNS域名解析服务
    DNS概述1.DNS系统DNS(DomainNameSystem),使用应用层协议,是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。简单来说就是:把域名转换成网络可以识别的IP地址,在通过IP地址访问主机。这种由文字组成的名称,显而易见要更容易记忆。每......
  • Linux中ssh
    ssh原理SSH(SecureShell)是一种用于安全访问远程计算机的网络协议。SSH使用加密技术来确保通信的安全性,其中包括使用公钥加密和私钥解密的方法。下面是SSH公钥传输的基本原理:生成密钥对:在使用SSH进行通信之前,首先需要在客户端生成一对密钥,包括公钥和私钥。通常使用RSA或DSA算法......
  • Linux手动安装JD详细教程
    1、下载JDK下载网址:https://www.oracle.com/technetwork/java/javase/downloads/index.html下拉,找到jdk8 2、手动安装2.1先新建一个文件夹,目录是/usr/local/java 进入安装目录。输入命令:cd/usr/local/java 2.2安装JDK1.新建一个存放安装包的文件夹命令:mkdir......
  • Linux扩展根目录磁盘容量
    https://www.cnblogs.com/kk8085/articles/17227008.html1、先查看磁盘分区是否是lvm格式执行lsblk命令,可以看到root为lvm类型,表示磁盘可以扩容 2、查看磁盘容量执行fdisk-l可以看到有一个500多G的盘没有使用3、新建分区根据第2步获取未使用的磁盘路径:/dev/vdb执......