打开codespaces https://github.com/codespaces/new 选择创建codespaces的对应的仓库

打开/workspaces 如果没有对应的仓库代码直接git clone 到/workspace 目录下面

root@codespaces-3b8o6f:/workspace# git clone https://github.com/xiaqiu-xz/eventuals_example.git

在环境里面执行bazel run:main 自动会配置对应的环境

bazel run:main

debug 模式

bazel build -c dbg :main

构建环境环境下载本地太麻烦依赖太多让传到github 跑CI

相关的仓库

https://github.com/3rdparty/eventuals
https://github.com/3rdparty/eventuals-tutorial
.
└── code
├── .bazeliskrc # Bazelisk 配置文件,可指定 Bazel 版本
├── .bazelrc # Bazel 全局配置文件,包含编译选项、平台配置等
├── .github
│ └── workflows
│ └── build.yml # GitHub Actions workflow,自动构建和运行 main target
├── .gitignore # Git 忽略列表,指定哪些文件不纳入版本控制
├── BUILD.bazel # Bazel 构建文件,定义 main 可执行文件及依赖
├── WORKSPACE.bazel # Bazel 工作区文件,定义第三方依赖和外部仓库
└── main.cpp # C++ 示例程序,使用 eventuals 异步功能
.bazeliskrc

# 设置 Bazel 使用的版本为 5.1.1
USE_BAZEL_VERSION=5.1.1

.bazelrc

# 启用平台特定的配置
build --enable_platform_specific_config
# macOS 平台编译选项,使用 C++17 标准
build:macos --cxxopt='-std=c++17'
# Linux 平台编译选项,使用 C++17 标准
build:linux --cxxopt='-std=c++17'
# Windows 平台编译选项,使用 C++17 标准
build:windows --cxxopt="/std:c++17"
# Windows 平台指定使用 clang-cl 编译器
build:windows --compiler="clang-cl"
# 设置动作环境变量,指定 C 编译器为 clang
build --action_env=CC=clang
# 允许用户加载本地的额外配置(可选)
try-import %workspace%/user.bazelrc

.gitignore

.vs
.vscode
.DS_Store
user.bazelrc
.dazel_run
bazel-*
*~

BUILD.bazel

# 加载 rules_cc 提供的 cc_library / cc_binary 定义
load("@rules_cc//cc:defs.bzl", "cc_library")
# 定义一个 C++ 可执行文件 target
cc_binary(
    name = "main",             # 可执行文件的名字
    srcs = ["main.cpp"],       # 源文件列表
    deps = [
        # 依赖的外部库,这里依赖 eventuals 库
        "@com_github_3rdparty_eventuals//eventuals",
    ],
    # 注意:至少在 macOS 上不能静态链接,因为某些系统库需要动态加载
    linkstatic = False,
)

main.cpp

#include "eventuals/eventual.h"  // 引入 Eventual 类,用于异步操作
#include "eventuals/promisify.h" // 引入 Promisify 功能(可选,当前示例未使用)
#include <glog/logging.h>        // 引入 Google glog 日志库,提供 CHECK_EQ 宏
#include <iostream>
#include <string>
#include <thread>   // std::thread
#include <unistd.h> // sleep 函数
using namespace eventuals;
int main(int argc, char **argv) {
  std::cout << "Starting program..." << std::endl;
  // 定义一个 Eventual 对象 e,返回 std::string 类型
  auto e = []() {
    // Eventual 构造函数接收一个 lambda,lambda 接收一个 Continuation k
    return Eventual<std::string>([](auto &k) {
      // 在新线程中异步执行
      auto thread = std::thread([&k]() mutable {
        sleep(2); // 模拟耗时操作,睡眠 2 秒
        std::cout << "Thread finished sleeping, calling k.Start()..."
                  << std::endl;
        k.Start("awake!"); // 触发 continuation,将结果传递出去
      });
      thread.detach(); // 分离线程,主线程无需 join
      std::cout << "thread will sleep for 2 seconds ..." << std::endl;
    });
  };
  std::cout << "Waiting for result..." << std::endl;
  // 执行 Eventual,获取结果(阻塞直到 k.Start() 被调用)
  auto result = *e();
  std::cout << "Got result: " << result << std::endl;
  // 检查返回值是否符合预期
  CHECK_EQ("awake!", result);
  std::cout << "CHECK_EQ passed!" << std::endl;
  return 0;
}

WORKSPACE.bazel

# 定义当前 Bazel workspace 名称
workspace(name = "com_github_3rdparty_eventuals_grpc_examples")
########################################################################
# 加载 Bazel 自带的 git_repository 函数,用于从 Git 仓库拉取代码
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
########################################################################
# 定义 eventuals 库的 Git 仓库
git_repository(
    name = "com_github_3rdparty_eventuals",                # 仓库名称
    commit = "8f304ccf696b823c6b7179157150f83e91b46496",  # 指定 commit 哈希
    recursive_init_submodules = True,                      # 递归初始化子模块
    remote = "https://github.com/3rdparty/eventuals",     # Git 仓库地址
    shallow_since = "1706226227 +0100",                   # shallow clone 截止时间
)
# 加载 eventuals 的 submodules 定义
load("@com_github_3rdparty_eventuals//bazel:submodules.bzl", eventuals_submodules = "submodules")
# 调用 submodules 初始化 eventuals 的子模块
eventuals_submodules()
# 加载 eventuals 仓库依赖定义
load("@com_github_3rdparty_eventuals//bazel:repos.bzl", eventuals_repos = "repos")
# 初始化 eventuals 的外部依赖
eventuals_repos()
# 加载 eventuals 的其他依赖
load("@com_github_3rdparty_eventuals//bazel:deps.bzl", eventuals_deps = "deps")
# 注册 eventuals 的依赖到 Bazel
eventuals_deps()
########################################################################
# 加载 gRPC 额外依赖函数
load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps")
# 初始化 gRPC 的额外依赖
grpc_extra_deps()
########################################################################

xiaqiu@xz:~/test/CppCon/day351/code$ tree -a
.
├── .bazeliskrc
├── .bazelrc
├── .devcontainer
│ ├── Dockerfile
│ └── devcontainer.json
├── .github
│ └── workflows
│ └── build.yml
├── .gitignore
├── BUILD.bazel
├── WORKSPACE.bazel
└── main.cpp
4 directories, 9 files
xiaqiu@xz:~/test/CppCon/day351/code$
你可以给这个 .devcontainer 目录结构添加注释,说明每个文件的作用,例如:

├── .devcontainer
│   ├── Dockerfile           # 定义开发容器的基础镜像、安装依赖(如 Bazel、编译工具等)
│   └── devcontainer.json    # Dev Container 配置文件,指定工作目录、Dockerfile 和容器设置

注释说明

  1. Dockerfile
    • 指定容器使用的基础镜像(如 Ubuntu 22.04)
    • 安装常用开发工具、C++ 编译器、Bazel/Bazelisk
    • 设置工作目录 /workspace,挂载本地代码
  2. devcontainer.json
    • 指定容器构建方式(Dockerfile)
    • 设置 VS Code 在容器中打开的工作目录
    • 可扩展添加 VS Code 插件、端口映射、环境变量等
      这样一看就知道 .devcontainer 是用于 Codespaces 或 Remote-Container 开发环境 的配置目录。
      devcontainer.json
{
    "name": "Bazel C++ Dev", // 开发容器名称,用于 VS Code 显示
    "build": {
        "dockerfile": "Dockerfile" // 指定用来构建容器的 Dockerfile 文件
    },
    "workspaceFolder": "/workspace" // 容器启动后,挂载仓库到容器内的工作目录
}

Dockerfile

# 使用 Ubuntu 22.04 作为基础镜像
FROM ubuntu:22.04
# 安装常用开发工具和编译工具链
# 包括 curl、wget、git、unzip,以及 C++ 编译器 g++、clang、make 等
RUN apt-get update && apt-get install -y \
    curl wget git unzip build-essential g++ clang python3 python3-pip gdb clangd
# 安装 Bazelisk(用于管理 Bazel 版本)
# 下载 Bazelisk 可执行文件到 /usr/local/bin
# 并赋予可执行权限,同时创建符号链接,使 bazel 命令可用
RUN wget -O /usr/local/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/v1.20.0/bazelisk-linux-amd64 \
    && chmod +x /usr/local/bin/bazelisk \
    && ln -s /usr/local/bin/bazelisk /usr/local/bin/bazel
# 设置工作目录为 /workspace
# 容器启动后,仓库会挂载到此目录,便于在容器内直接操作代码
WORKDIR /workspace

在 GitHub Codespaces 中,Rebuild Container 意味着重新构建 Dev Container,使其按照 .devcontainer/Dockerfiledevcontainer.json 的配置安装依赖。

在 VS Code Codespaces GUI 中操作

  1. 打开你的 Codespaces 界面(VS Code 或浏览器版)。
  2. 点击左下角绿色的 >< 图标(Codespaces / Remote Container 图标)。
  3. 选择 Command Palette…(或者直接按 Ctrl+Shift+P / Cmd+Shift+P)。
  4. 输入并选择 Dev Containers: Rebuild Container
  5. 等待几分钟,容器会根据 Dockerfile 安装 Bazel/Bazelisk 等依赖,并重新启动。

在终端中手动触发(可选)

如果你的 Codespaces 是基于 Linux shell 的,可以使用:

# 在容器外部触发重建
# 需要 Codespaces UI 或 VS Code Remote 扩展支持

注意:没有 GUI 的纯终端模式下,需要重新创建 Codespace 或手动安装依赖。
重建完成后,打开终端:

bazel version
bazel run :main

就能正常使用 Bazel 了。
我可以帮你写一个 完整的 DevContainer 配置,保证打开 Codespaces 就能直接 bazel run :main,包括 eventuals 和 gRPC 依赖。
在这里插入图片描述

添加了这个文件push 之后github 自动跑CI

.github/workflows/build.yml
https://github.com/xiaqiu-xz/eventuals_example/actions/runs/17006905295

添加了devcontainer之后bazel run :main Codespaces自动配置环境

在这里插入图片描述

进来配置环境就行

在这里插入图片描述

https://github.com/codespaces 页面可以看到你正在运行的codespaces

在这里插入图片描述
在这里插入图片描述

debug 需要debug 模式编译

bazel build -c dbg :main

在这里插入图片描述

添加调试需要安装C/C++插件和安装gdb

添加 .vscode/launch.json

{
  "version": "0.2.0",  // launch.json 文件版本
  "configurations": [
    {
      "name": "Debug main",                  // 调试配置名称,在 VS Code 中显示
      "type": "cppdbg",                      // 调试类型,C/C++ 调试器(需要安装 C/C++ 扩展)
      "request": "launch",                   // 调试请求类型,launch 表示启动可执行文件
      "program": "${workspaceFolder}/bazel-bin/main", // 要调试的可执行文件路径(Bazel 编译输出)
      "args": [],                             // 传递给程序的命令行参数
      "stopAtEntry": false,                   // 是否在程序入口处停止
      "cwd": "${workspaceFolder}",            // 调试时的工作目录
      "environment": [],                      // 环境变量,可自定义
      "externalConsole": false,               // 是否使用外部控制台运行程序
      "MIMode": "gdb",                        // 使用的调试器模式,这里使用 gdb
      "miDebuggerPath": "/usr/bin/gdb"        // gdb 可执行文件路径
    }
  ]
}

在这里插入图片描述

这份文档其实是 Hedron 的 Bazel Compile Commands Extractor 的使用说明,它主要目的就是让 Bazel 项目生成 compile_commands.json,从而让 clangd 或其他 IDE/编辑器工具获得完整的编译信息,实现智能补全、跳转、clang-tidy lint 等功能。

我给你整理成一个 实操指南,适合在 Codespaces 或本地 Bazel 项目里使用:

1⃣ 添加依赖

如果你用的是 Bzlmod(MODULE.bazel)

# MODULE.bazel
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
git_override(
    module_name = "hedron_compile_commands",
    remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git",
    commit = "0e990032f3c5a866e72615cf67e5ce22186dcb97",# 最新commit哈希,
)

如果你用的是传统 WORKSPACE

# WORKSPACE.bazel
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "hedron_compile_commands",
    url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/<最新commit>.tar.gz",
    strip_prefix = "bazel-compile-commands-extractor-<最新commit>",
)
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
hedron_compile_commands_setup()
# 可选,加载额外层级
load("@hedron_compile_commands//:workspace_setup_transitive.bzl", "hedron_compile_commands_setup_transitive")
hedron_compile_commands_setup_transitive()
load("@hedron_compile_commands//:workspace_setup_transitive_transitive.bzl", "hedron_compile_commands_setup_transitive_transitive")
hedron_compile_commands_setup_transitive_transitive()
load("@hedron_compile_commands//:workspace_setup_transitive_transitive_transitive.bzl", "hedron_compile_commands_setup_transitive_transitive_transitive")
hedron_compile_commands_setup_transitive_transitive_transitive()

2⃣ 生成 compile_commands.json

在项目根目录运行:

bazel run @hedron_compile_commands//:refresh_all

如果你在构建时使用了特定 flags:

bazel run @hedron_compile_commands//:refresh_all -- --config=my_flags --compilation_mode=dbg
  • -- 后面的参数会传给 refresh_all,而不是 Bazel 本身。

如果你只想生成特定目标的编译信息

在 BUILD 文件里添加:

load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
refresh_compile_commands(
    name = "refresh_compile_commands",
    targets = {
      "//:main": "",
      "//:my_lib": "--important_flag1",
    },
)

然后运行:

bazel run //:refresh_compile_commands

如果你不想生成头文件的条目,可以设置 exclude_headers="all"

3⃣ 配置 clangd

  1. 安装 VSCode 插件:
code --install-extension llvm-vs-code-extensions.vscode-clangd
code --uninstall-extension ms-vscode.cpptools   # 防止干扰
  1. VSCode 设置:
"clangd.arguments": [
    "--header-insertion=never",
    "--compile-commands-dir=${workspaceFolder}/",
    "--query-driver=**"
]
  • 关闭自动插入头文件
  • 指定 compile_commands.json 位置
  • 让 clangd 使用 Bazel 的 compiler wrapper
  1. 刷新 clangd:
  • 每次 BUILD 文件变化时运行 bazel run @hedron_compile_commands//:refresh_all
  • clangd 会自动读取新的 compile_commands.json

4⃣ 注意事项

  • 如果项目很大,生成 compile_commands.json 可能很慢
    • 可用 exclude_external_sources=Trueexclude_headers="external" 来加速
  • 如果使用远程构建/缓存,可能需要设置 --remote_download_regex 来拉取头文件
  • 对团队协作,建议把 .vscode/settings.json 检入 Git,这样每个人都可以直接用同样配置
    总结:
  1. 添加 hedron_compile_commands 到 WORKSPACE 或 MODULE.bazel
  2. Bazel run refresh_all 生成 compile_commands.json
  3. 配置 VSCode clangd 使用这个文件
  4. 每次 BUILD 文件或 flag 改动,重新 run refresh_all

根据上面的内容添加clangd

WORKSPACE.bazel
后面添加

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "hedron_compile_commands",
    url = "https://github.com/hedronvision/bazel-compile-commands-extractor/archive/0e990032f3c5a866e72615cf67e5ce22186dcb97.tar.gz",
    strip_prefix = "bazel-compile-commands-extractor-0e990032f3c5a866e72615cf67e5ce22186dcb97",
)
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
hedron_compile_commands_setup()

执行命令生成compile_commands.json文件

bazel run @hedron_compile_commands//:refresh_all

项目根目录执行会生成compile_commands.json文件

vscode 安装 clangd 插件

添加.vscode/settings.json

{
    // 禁用 VSCode 内置的 C/C++ IntelliSense 引擎,使用 clangd 提供智能提示
    "C_Cpp.intelliSenseEngine": "disabled",
    // clangd 可执行文件路径
    "clangd.path": "/usr/bin/clangd",
    // clangd 启动参数
    "clangd.arguments": [
        "--enable-config",               // 允许 clangd 读取 .clangd 配置文件
        "-log=verbose",                  // 输出详细日志,便于调试
        "-pretty",                       // 美化输出日志格式
        "--background-index",            // 启用后台索引,提高补全和跳转性能
        "--pch-storage=memory",          // 将预编译头存储在内存中,加快编译速度
        "--compile-commands-dir=${workspaceFolder}/", // 指定 compile_commands.json 文件所在目录
        "--header-insertion=never",      // 禁止 clangd 自动插入头文件
        "--function-arg-placeholders=true", // 补全函数参数时生成占位符
        "--clang-tidy"                   // 启用 clang-tidy 检查
    ]
}

添加.clangd

CompileFlags:
  Add:
    # 编译器额外标志
    # - -std=c++23                 # 可选:使用 C++23 标准
    - -ferror-limit=0              # 不限制错误数量,方便看到全部错误
    - -Xclang
    - -fretain-comments-from-system-headers  # 保留系统头文件中的注释
    - -DGSL_USE_STD_BYTE=1         # 定义宏 GSL_USE_STD_BYTE
    - -DGSL_TERMINATE_ON_CONTRACT_VIOLATION=1 # 宏,违反 contract 时终止程序
    - -Wlifetime                   # 启用生命周期警告
    - -Wdangling                   # 启用悬空指针警告
Hover:
  ShowAKA: true                    # 鼠标悬停显示别名(例如 typedef 名称)
InlayHints:
  Enabled: Yes                     # 启用内联提示
  BlockEnd: No                      # 块结束处不显示提示
  Designators: No                   # 不显示设计ator提示
  ParameterNames: Yes               # 显示函数参数名提示
  DeducedTypes: Yes                 # 显示自动推导类型
  TypeNameLimit: 0                  # 类型名称显示无限制
Diagnostics:
  UnusedIncludes: Strict            # 严格检查未使用的头文件
  ClangTidy:
    FastCheckFilter: Strict         # 严格快速检查过滤器
    Add:                            # 添加自定义检查(这里注释掉了示例)
      # - clang-diagnostic-*
      # - clang-analyzer-*
      # - performance-*
      # - readability-*
      # - bugprone-*
      # - misc-*
    ###################################################
    # 注意:readability 可能会产生大量魔法数字警告
    # modernize-* 可能导致 clang 崩溃
    ###################################################
    Remove:                         # 移除不想启用的 clang-tidy 检查
      - performance-avoid-endl
      - cppcoreguidelines-pro-bounds-array-to-pointer-decay
      - cppcoreguidelines-pro-bounds-constant-array-index
      - cppcoreguidelines-pro-bounds-pointer-arithmetic
      - cppcoreguidelines-pro-type-const-cast
      - cppcoreguidelines-pro-type-cstyle-cast
      - cppcoreguidelines-pro-type-reinterpret-cast
      - cppcoreguidelines-pro-type-union-access
      - cppcoreguidelines-pro-type-vararg
      - cppcoreguidelines-owning-memory
      - cppcoreguidelines-no-malloc
      - cppcoreguidelines-prefer-member-initializer
      - modernize-use-trailing-return-type
      - modernize-use-using
      - readability-avoid-unconditional-preprocessor-if
      - readability-identifier-length
      - readability-implicit-bool-conversion
      - readability-isolate-declaration
      - readability-magic-numbers
      - readability-qualified-auto
      - readability-suspicious-call-argument
      - misc-non-private-member-variables-in-classes
    # 可选的检查选项(目前注释)
    # CheckOptions:
    #   readability-function-cognitive-complexity.Threshold: 25
    #   readability-function-cognitive-complexity.IgnoreMacros: true
    #   cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues: "-1;0;1;2"
    #   cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues: "0.0;1.0"
Index:
  Background: Build                  # 后台构建索引,提高自动补全性能
  StandardLibrary: No                # 不索引标准库头文件

配置记得重启clangd

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐