bazel 和 github codespaces
├── BUILD.bazel# Bazel 构建文件,定义 main 可执行文件及依赖。├── .bazeliskrc# Bazelisk 配置文件,可指定 Bazel 版本。├── WORKSPACE.bazel# Bazel 工作区文件,定义第三方依赖和外部仓库。├── .gitignore# Git 忽略列表,指定哪些文件不纳入版本控制。,保证打开 Codespaces 就能直接。就能正常
打开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 和容器设置
注释说明
- Dockerfile
- 指定容器使用的基础镜像(如 Ubuntu 22.04)
- 安装常用开发工具、C++ 编译器、Bazel/Bazelisk
- 设置工作目录
/workspace
,挂载本地代码
- 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/Dockerfile
和 devcontainer.json
的配置安装依赖。
在 VS Code Codespaces GUI 中操作
- 打开你的 Codespaces 界面(VS Code 或浏览器版)。
- 点击左下角绿色的 >< 图标(Codespaces / Remote Container 图标)。
- 选择 Command Palette…(或者直接按
Ctrl+Shift+P
/Cmd+Shift+P
)。 - 输入并选择 Dev Containers: Rebuild Container。
- 等待几分钟,容器会根据 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
- 安装 VSCode 插件:
code --install-extension llvm-vs-code-extensions.vscode-clangd
code --uninstall-extension ms-vscode.cpptools # 防止干扰
- VSCode 设置:
"clangd.arguments": [
"--header-insertion=never",
"--compile-commands-dir=${workspaceFolder}/",
"--query-driver=**"
]
- 关闭自动插入头文件
- 指定
compile_commands.json
位置 - 让 clangd 使用 Bazel 的 compiler wrapper
- 刷新 clangd:
- 每次 BUILD 文件变化时运行
bazel run @hedron_compile_commands//:refresh_all
- clangd 会自动读取新的
compile_commands.json
4⃣ 注意事项
- 如果项目很大,生成
compile_commands.json
可能很慢- 可用
exclude_external_sources=True
或exclude_headers="external"
来加速
- 可用
- 如果使用远程构建/缓存,可能需要设置
--remote_download_regex
来拉取头文件 - 对团队协作,建议把
.vscode/settings.json
检入 Git,这样每个人都可以直接用同样配置
总结:
- 添加
hedron_compile_commands
到 WORKSPACE 或 MODULE.bazel - Bazel run
refresh_all
生成compile_commands.json
- 配置 VSCode clangd 使用这个文件
- 每次 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
更多推荐
所有评论(0)