在 VSCode 中配置使用 CMake 的 Linux C/C++ 开发环境
本文默认你已经有在 VSCode 中配置 Linux C/C++ 开发环境的经验。前置微软官方文档 Gcc on Linux。我们知道,在配置 C/C++ 的常规方法中,VSCode 会在项目目录中生成一个名为 .vscode 的隐藏文件夹,里面放着一些相关的配置 json 文件。其中与 C/C++ 环境开发有关的主要有三个:
task.json:编译器的编译相关配置。例如编译命令、编译参数设置等等。
launch.json:调试相关的配置。例如调试器路径、调试目录配置等。
c_cpp_properties.json:编译器路径和智能提示(Intellisense)设置。例如 C++ 版本、用于智能提示的头文件路径设置等。
而如果使用 CMake 的话,我们就只需要配置 CMakeLists.txt 文件(可能是多个)就可以了。
本文用于在 VSCode 中配置使用 CMake 的 Linux C/C++ 开发环境的快速入门,关于更深入的内容,建议看:
CMake Tools for Visual Studio Code documentation:微软官方出的在 VSCode ...
如何创建一个 Linux RPM 包
这篇文章包含以下内容:
什么是 RPM 包。
如何创建一个 RPM 包。
如何安装(install)、查询(query)、移除(remove)一个 RPM 包。
RPM 相关功能非常强大,并非一篇文章所能涵盖,本文相关内容仅用于入门。如果你有本文没有提到的、更复杂的需求,建议参考官方指导:RPM Packaging Guide。
1. 什么是 RPM 包?RPM 全称 Red Hat Package Manager,即红帽包管理器,这是一个由 Red Hat 开发,主要用在基于红帽的操作系统上的(如 Fedora、CentOS、RHEL 等)。
RPM 包使用 .rpm 扩展名,是一个不同文件的捆绑包(一个集合),其可以包含以下内容:
二进制文件,也就是我们常说的可执行文件(如 nmap、stat、xattr、ssh、sshd 等)。
配置文件(如 sshd.conf、updatedb.conf,logrotate.conf 等)。
文档文件(如 README、TODO、AUTHOR 等)。
RPM 包的文件名格式如下:1<name>-<version&g ...
我的 Vim 常用配置与命令笔记
首先说明呢,我并不是 vim 的深度用户,我只是经常 ssh 到远程机器上编辑一些文件什么的,这时候 vim 就顺手用了。
所以呢,这篇文章记录的也都是些简单的东西,vim 高级功能我也用不上。
1. vim 常用配置记录我的常用配置呢,主要就是每当我登录一个新机器并且需要使用 vim 的时候,可以把这里的配置直接 copy 一份省时省力 ~
当然我还是会说明每个配置项是干啥的。
vim 的配置文件有两个,一个是全局的 /etc/vimrc,一个是用户级的 ~/.vimrc,用户级的优先级高。注意这里全局的 /etc/vimrc 文件名没有前缀 .。
编辑哪个都可以,这里就编辑用户级的 ~/.vimrc 了(不过如果你有在非 root 用户下 sudo vim 编辑的需求的话,建议把 /etc/vimrc 也改了):
1vim ~/.vimrc
(注意不管是全局的还是用户级的配置文件,如果默认不存在的话,直接通过 vim 自动创建并编辑保存就好了,我们追加写就可以,可以不改原本有的配置 ~)
前面的单引号表示注释 "。
12345678910set fileencodings ...
我的 Git 常用命令笔记
1. 基础命令这篇文章并不是一次性写完的,而是我想到什么就加进来什么的,所以下面的顺序并不重要。
1.1. 修改本地分支名字1git branch -m <old_branch_name> <new_branch_name>
修改后会与关联的远程分支失去联系,首次 push 需要指定远程分支,一般在你首次 push 的时候会给你个提示,告诉你怎样做,好解决。
比如我将本地的 master 分支改名为 main,然后首次 push 应当这样:
1git push origin HEAD:master
这样会将本地的 main 分支与远程的 master 分支关联,就可以正常使用了。
修改本地分支关联的远程分支:
1git branch --set-upstream-to=<remote_rep_name>/<remote_branch_name> <local_branch_name>
例如:
1git branch --set-upstream-to=origin/main main
将本地分支 main 的与远程仓库 ori ...
解决 CentOS 中 LD_LIBRARY_PATH 配置正确却找不到动态链接库的问题
今天遇到一个很离谱的问题,场景如下:
运行某可执行程序时,提示某动态库找不到,错误如下:
1libxxx.so: cannot open shared object file: No such file or directory
通过 ldd 命令查看可执行程序的链接库,可以得到其确实没有找到此库:
123...libxxx.so => not found...
但在这里,我可以 100% 确定,我的 LD_LIBRARY_PATH 配置没有问题,此动态库也确实存在!
最终找出问题所在,但应当是 bug。
我们知道,动态库往往都是,有一个名字上带有详细版本号的真正的动态库文件,如 libxxx.so.7.6.0,有多个精简了版本的软连接指向前面那个真正的动态库,如 libxxx.so,libxxx.so.7,libxxx.so.7.6 等。就像下面这样:
1234libxxx.so -> libxxx.so.7.6.0libxxx.so.7 -> libxxx.so.7.6.0libxxx.so.7.6 -> libxxx.so.7.6.0libxxx.so. ...
解决 mysqld: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.30' not found
1. 遇到的错误报告在安装/运行 mysql 时可能会遇到类似如下错误(节选):
12345...mysqld: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by xxx)...mysqld: /usr/lib64/libstdc++.so.6: version `CXXABI_1.3.13' not found (required by xxx)...
其他场景也可能遇到类似错误,这其实很高频,解决方法都是一样的。
2. 错误分析猜测主要原因是 GCC 的版本过低,而编译过程依赖更新版本 GCC 中的库。
以 GLIBCXX 举例,我们按如下命令我们当前 /usr/lib64/libstdc++.so.6 关联的 GLIBCXX :
1strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX*
12345678910111213141516171819202122232425262728[gukaifeng@3afe42f ...
C++ 实现线程安全的懒汉单例模式
这篇文章不讲什么是单例模式,什么是饿汉和懒汉,假定读者已经知道这些。
我们知道,最朴素的懒汉单例模式是线程不安全的,这篇文章逐步将其升级,直到实现一个完全线程安全的。
另外,线程安全的懒汉式单例的实现依赖于特定语言,不同的语言有不同的实现,比如 Java 中依赖其虚拟机的实现,而本文要说的 C++ 实现则依赖标准库。
1. 朴素的单线程懒汉式单例实现我们先看一个最朴素的实现:
1234567891011121314151617181920212223242526272829#include <iostream>class LazySingleton { static LazySingleton* instance; LazySingleton() {} LazySingleton(LazySingleton const &) = delete; LazySingleton& operator=(LazySingleton const &) = delete;public: static La ...
C++ 读写锁的用法
读锁和写锁其实就是通常意义上的共享锁和排他锁。
在 C++14 以前,标准库中是没有共享锁提供的,我们需要使用其他库(如 boost),或自行实现(如利用两个 std::mutex 实现)。C++14 以后标准库中才有了对共享锁 std::shared_timed_mutex 的支持。不过我们更常用的应当是 C++17 中提供的共享锁 std::shared_mutex。至于两者区别,不是本文重点,读者可以自行了解。本文的建议是除非特别需要,请使用 C++17 中的 std::shared_mutex。
本文默认读者有一点 C++ 并发编程基础。
我们首先使用 C++17 提供的互斥 std::shared_mutex,从名字上也能看出来了,这是个共享互斥。在使用上,读锁(共享锁)使用 std::shared_lock() 操作互斥;建议写锁(排他锁)使用 std::lock_guard() 或 std::unique_lock() 等操作互斥。因为这些包装类提供了 RAII 机制。
我们下面看代码理解:
12345678910111213141516class TestSharedM ...
C++ 实现一个简单的层级互斥
锁的层级划分就是按特定方式规定加锁次序,在运行期据此查验加锁操作是否遵从预设规则。按照构思,我们应该把应用程序分层,并且明确每个互斥位于哪个层级。若某线程已经对低层级互斥加锁,则不准它再对高层级互斥加锁。具体做法是将层级的编号赋予对应层级应用程序的互斥,并记录各线程分别锁定了哪些互斥。
层级互斥其实是比较常见的一种模式,但 C++ 标准库并未提供。我们这里实现一个简单的层级互斥,并且支持与 std::lock_guard、std::scoped_lock 等配套使用。要想我们自己实现的互斥支持 std::lock_guard、std::scoped_lock,有三个方法是必要的,即 lock()、unlock() 和 try_lock()。
我们下面看具体实现:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071#include <mutex>#include ...
C++ 并发编程问题笔记
这篇文章是我阅读《C++ 并发编程实战(第 2 版)》的疑问笔记。
从开始到复杂,有些问题现在回看其实十分基础,甚至有些好笑,但我还是决定留下它们。
一些问题初次整理时可能理解上还是有问题的,在后期学习如有发现会更正。
第 1 章:你好,C++ 并发世界第 2 章:线程管控Q1. join() 函数会阻塞当前线程直至关联的线程结束吗?
A1:是的,只有 join 的线程结束后,当前线程才会继续执行。
我们这里引用 cppreference.com 的关于 join() 描述:
Blocks the current thread until the thread identified by *this finishes its execution.
阻塞当前线程直至 *this 所标识的线程结束其执行。
我们看一段代码:
123456789101112131415161718192021222324#include <iostream>#include <thread>#include <unistd.h>class SleepLoop ...