如何编译llvm 20 并且用上import std
35

如何编译 llvm 20 用上 import std 并配置 clangd 跳转

前言

最近想写个新项目造点轮子练练手,打算用上C++20的modules能力,不过既然都用模块了,没有import std也是差点意思。由于我用的是 openSUSE Tumbleweed,直接可以sudo zypper in gcc15用上gcc-15.1,但是有个痛点是无论cmake还是xmake生成的compile_commands.json,clangd 都无法跳转。

后来用zypper 装了个clang20,但是由于我的clangd是自己手动安装的,会提示一个分支不匹配的错误:

Module file '/usr/share/libc++/v1/std.pcm' built from a different branch () than the compiler ((https://github.com/llvm/llvm-project47addd4540b4c393e478ba92bea2589e330c57fb))clang(ast_file_different_branch)

所以决定从头编译llvm工具链,这篇文章做个记录。

以下内容大部分由 claude + cursor 完成

第一步:清理现有环境

1. 停止相关进程

sudo pkill clangd 2>/dev/null || true

1.2 删除手动安装的 LLVM(如果有)

sudo rm -rf /usr/local/bin/clang*
sudo rm -rf /usr/local/bin/llvm-*
sudo rm -rf /usr/local/bin/ld.lld
sudo rm -rf /usr/local/include/c++
sudo rm -rf /usr/local/lib/clang
sudo rm -rf /usr/local/lib/libc++*
sudo rm -rf /usr/local/lib/libclang*
sudo rm -rf /usr/local/lib/libLLVM*
sudo rm -rf /usr/local/lib/libLTO*
sudo rm -rf /usr/local/lib/libRemarks*
sudo rm -rf /usr/local/lib/x86_64-unknown-linux-gnu
sudo rm -rf /usr/local/share/clang
sudo rm -rf /usr/local/share/libc++

1.3 清理配置文件

sudo rm -f /etc/ld.so.conf.d/llvm-local.conf
sudo ldconfig

1.4 清理环境变量

# 从 shell 配置文件中移除相关配置
sed -i '/\/usr\/local.*clang\|\/usr\/local.*llvm\|LD_LIBRARY_PATH.*usr\/local/d' ~/.bashrc ~/.zshrc 2>/dev/null

1.5 卸载通过包管理器安装的 clang

sudo zypper remove clang clang-devel libc++ libc++-devel 2>/dev/null || true

1.6 删除旧的源码目录

rm -rf ~/llvm-project

第二步:安装编译依赖

sudo zypper install -t pattern devel_basis
sudo zypper install cmake ninja python3 git

第三步:下载 LLVM 源码

# 克隆 LLVM 项目
git clone https://github.com/llvm/llvm-project.git

# 切换到 release 分支
cd llvm-project
git checkout release/20.x 

第四步:配置编译选项

mkdir build && cd build

# 配置 CMake
cmake -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=/usr/local \
  -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
  -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
  -DCLANG_ENABLE_STATIC_ANALYZER=ON \
  -DCLANG_ENABLE_ARCMT=ON \
  -DCLANG_BUILD_EXAMPLES=OFF \
  -DLIBCXX_ENABLE_MODULES=ON \
  -DLIBCXX_ENABLE_STD_MODULES=ON \
  -DLIBCXX_ENABLE_INCOMPLETE_FEATURES=ON \
  -DLIBCXXABI_USE_LLVM_UNWINDER=ON \
  -DCLANG_ENABLE_MODULES=ON \
  -DCLANG_DEFAULT_CXX_STDLIB=libc++ \
  -DLLVM_INSTALL_UTILS=ON \
  ../llvm

配置说明:

  • DLIBCXX_ENABLE_MODULES=ON: 启用 libc++ 模块支持

  • DLIBCXX_ENABLE_STD_MODULES=ON: 启用 std 标准库模块

  • DLIBCXXABI_USE_LLVM_UNWINDER=ON: 使用 LLVM 的 unwinder

  • DCLANG_DEFAULT_CXX_STDLIB=libc++: 设置 libc++ 为默认标准库

第五步:编译

ninja -j$(nproc)

注意: 编译过程可能需要几个小时,确保有足够的磁盘空间(至少20GB)。

第六步:安装

sudo ninja install

第七步:配置环境

7.1 配置动态库路径

sudo tee /etc/ld.so.conf.d/llvm-local.conf << 'EOF'
/usr/local/lib
/usr/local/lib/x86_64-unknown-linux-gnu
EOF

sudo ldconfig

7.2 配置 PATH

echo 'export PATH=/usr/local/bin:$PATH' >> ~/.zshrc
source ~/.zshrc

第八步:验证基本安装

# 验证工具版本
clang++ --version
clangd --version

# 测试基本编译
cat > test_basic.cpp << 'EOF'
#include <iostream>
int main() {
    std::cout << "Hello, clean LLVM!" << std::endl;
    return 0;
}
EOF

clang++ -std=c++23 -stdlib=libc++ test_basic.cpp -o test_basic
./test_basic

第九步:预编译标准库模块

9.1 检查模块文件

# 检查模块配置
cat /usr/local/lib/x86_64-unknown-linux-gnu/libc++.modules.json

# 检查模块源文件
ls -la /usr/local/share/libc++/v1/

9.2 预编译 std 模块

cd ~

# 在用户目录预编译(避免权限问题导致的崩溃)
clang++ -std=c++23 -stdlib=libc++ \
    -resource-dir=/usr/local/lib/clang/20 \
    --precompile /usr/local/share/libc++/v1/std.cppm \
    -o ./std.pcm

# 移动到系统目录
sudo mv ./std.pcm /usr/local/share/libc++/v1/

9.3 预编译 std.compat 模块

# 预编译 std.compat(需要已编译的 std 模块)
clang++ -std=c++23 -stdlib=libc++ \
    -resource-dir=/usr/local/lib/clang/20 \
    -fprebuilt-module-path=/usr/local/share/libc++/v1 \
    --precompile /usr/local/share/libc++/v1/std.compat.cppm \
    -o ./std.compat.pcm

# 移动到系统目录
sudo mv ./std.compat.pcm /usr/local/share/libc++/v1/

9.4 验证模块文件

ls -la /usr/local/share/libc++/v1/*.pcm
file /usr/local/share/libc++/v1/*.pcm

第十步:测试 C++23 模块功能

10.1 创建测试文件

cat > test_cpp23_modules.cpp << 'EOF'
import std;
import std.compat;

int main() {
    std::println("=== C++23 Modules Test ===");
    
    // 测试 std 模块
    std::vector<int> numbers{1, 2, 3, 4, 5};
    auto even_doubled = numbers 
        | std::views::filter([](int n) { return n % 2 == 0; })
        | std::views::transform([](int n) { return n * 2; });
    
    std::print("Even numbers doubled: ");
    for (auto n : even_doubled) {
        std::print("{} ", n);
    }
    std::println("");
    
    // 测试 std.compat 模块
    double x = 3.14159 / 4;
    std::println("sin(π/4) = {:.6f}", std::sin(x));
    
    // 测试 C 兼容性功能
    char buffer[50];
    std::strcpy(buffer, "C++ modules work!");
    std::println("C-style string: {}", buffer);
    
    std::println("=== All tests passed! ===");
    return 0;
}
EOF

10.2 编译和运行测试

# 编译测试程序
clang++ -std=c++23 -stdlib=libc++ \
    -fprebuilt-module-path=/usr/local/share/libc++/v1 \
    test_cpp23_modules.cpp -o test_cpp23_modules

# 运行测试
./test_cpp23_modules

第十一步 使用vscode+xmake开始写代码

10.1 安装xmake

curl-fsSL https://xmake.io/shget.text|bash

10.2 创建vscode项目

mkdir hello_world

# 使用vscode打开
code hello_world 

10.3 项目结构

hello_world
├── src
│  └── main.cc
└── xmake.lua

10.4 编写代码和构建脚本

// main.cc
import std;

int main() {
    std::println("Hello, World!");
    return 0;
}
// xmake.lua
target("hello")
    set_languages("c++23")
    set_kind("binary")
    set_toolchains("clang")
    add_files("src/main.cc")
    -- add_cxxflags("-stdlib=libc++")
    -- add_ldflags("-stdlib=libc++")
    add_cxxflags("-fprebuilt-module-path=/usr/local/share/libc++/v1")

10.5 配置clangd

先安装vscode的clangd插件,然后编写vscode配置文件

// .vscode/settings.json
{
    "clangd.arguments": [
        "--compile-commands-dir=${workspaceFolder}",
        "--experimental-modules-support"
    ]
}

然后使用xmake生成compile_commands.json

xmake project -k compile_commands

10.6 编译和运行

xmake build
xmake run

更新工具链

要更新到新版本:

  1. 进入源码目录:cd ~/llvm-build-clean/llvm-project

  2. 拉取最新代码:git pull

  3. 重新编译:cd build && ninja && sudo ninja install

  4. 重新预编译模块(步骤九)

附录

让cursor生成了一个morden c++的demo,编译和跳转都没问题

import std;

// C++23 概念:定义可处理的数据类型约束
template<typename T>
concept Processable = requires(T t) {
    { t + t } -> std::convertible_to<T>;
    { t * 2 } -> std::convertible_to<T>;
    std::totally_ordered<T>;
};

// C++23 概念:异步生成器约束
template<typename T>
concept AsyncGeneratorType = requires(T t) {
    typename T::promise_type;
    { t.begin() };
    { t.end() };
};

// 现代化的数据结构,使用结构化绑定
struct ProcessingResult {
    std::size_t processed_count;
    double average_value;
    std::chrono::milliseconds processing_time;
    
    // C++23 比较运算符自动生成
    auto operator<=>(const ProcessingResult&) const = default;
};

// 协程:异步数据生成器
template<Processable T>
class AsyncDataGenerator {
public:
    struct promise_type {
        T current_value{};
        
        auto get_return_object() {
            return AsyncDataGenerator{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        
        auto initial_suspend() { return std::suspend_always{}; }
        auto final_suspend() noexcept { return std::suspend_always{}; }
        
        auto yield_value(T value) {
            current_value = value;
            return std::suspend_always{};
        }
        
        void return_void() {}
        void unhandled_exception() { std::terminate(); }
    };
    
    using handle_type = std::coroutine_handle<promise_type>;
    
    explicit AsyncDataGenerator(handle_type h) : coro_handle(h) {}
    
    ~AsyncDataGenerator() {
        if (coro_handle) {
            coro_handle.destroy();
        }
    }
    
    // 移动语义支持
    AsyncDataGenerator(AsyncDataGenerator&& other) noexcept 
        : coro_handle(std::exchange(other.coro_handle, {})) {}
    
    AsyncDataGenerator& operator=(AsyncDataGenerator&& other) noexcept {
        if (this != &other) {
            if (coro_handle) {
                coro_handle.destroy();
            }
            coro_handle = std::exchange(other.coro_handle, {});
        }
        return *this;
    }
    
    // 删除拷贝构造和赋值
    AsyncDataGenerator(const AsyncDataGenerator&) = delete;
    AsyncDataGenerator& operator=(const AsyncDataGenerator&) = delete;
    
    // 迭代器支持
    class iterator {
        handle_type coro_;
        
    public:
        using iterator_category = std::input_iterator_tag;
        using value_type = T;
        using difference_type = std::ptrdiff_t;
        using pointer = T*;
        using reference = T&;
        
        explicit iterator(handle_type h) : coro_(h) {}
        
        iterator& operator++() {
            coro_.resume();
            if (coro_.done()) {
                coro_ = {};
            }
            return *this;
        }
        
        T operator*() const {
            return coro_.promise().current_value;
        }
        
        bool operator==(const iterator& other) const {
            return coro_ == other.coro_;
        }
    };
    
            iterator begin() {
            if (coro_handle) {
                coro_handle.resume();
                if (coro_handle.done()) {
                    return iterator{handle_type{}};
                }
            }
            return iterator{coro_handle};
        }
        
        iterator end() {
            return iterator{handle_type{}};
        }

private:
    handle_type coro_handle;
};

// 协程生成器函数
template<Processable T>
AsyncDataGenerator<T> generate_fibonacci_sequence(std::size_t count) {
    T a = 0, b = 1;
    
    for (std::size_t i = 0; i < count; ++i) {
        co_yield a;
        auto next = a + b;
        a = b;
        b = next;
        
        // 模拟异步延迟
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
}

// 现代化的异步处理器类
template<Processable T>
class AsyncDataProcessor {
private:
    std::unique_ptr<std::vector<T>> buffer_;
    mutable std::shared_mutex mutex_;
    
public:
    AsyncDataProcessor() : buffer_(std::make_unique<std::vector<T>>()) {}
    
    // 异步处理函数,使用协程
    std::future<ProcessingResult> process_async(AsyncDataGenerator<T> generator) {
        return std::async(std::launch::async, [this, gen = std::move(generator)]() mutable -> ProcessingResult {
            auto start_time = std::chrono::high_resolution_clock::now();
            
            // 使用范围库进行函数式处理
            std::vector<T> data;
            
            // 收集数据
            for (auto value : gen) {
                data.push_back(value);
            }
            
            // 使用C++23范围库进行数据转换和过滤
            auto processed_data = data 
                | std::views::filter([](const T& x) { return x > 0; })
                | std::views::transform([](const T& x) { return x * 2; })
                | std::views::take(10);
            
            // 计算统计信息
            std::vector<T> result_vec;
            for (auto value : processed_data) {
                result_vec.push_back(value);
            }
            
            {
                std::unique_lock lock(mutex_);
                *buffer_ = result_vec;
            }
            
            auto end_time = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
            
            double average = result_vec.empty() ? 0.0 : 
                std::accumulate(result_vec.begin(), result_vec.end(), 0.0) / result_vec.size();
            
            return ProcessingResult{
                .processed_count = result_vec.size(),
                .average_value = average,
                .processing_time = duration
            };
        });
    }
    
    // 获取处理后的数据(只读访问)
    std::vector<T> get_processed_data() const {
        std::shared_lock lock(mutex_);
        return *buffer_;
    }
};

// 现代化的格式化输出函数
template<Processable T>
void print_results(const ProcessingResult& result, const std::vector<T>& data) {
    std::println("=== 处理结果 ===");
    std::println("处理数量: {}", result.processed_count);
    std::println("平均值: {:.2f}", result.average_value);
    std::println("处理时间: {}ms", result.processing_time.count());
    
    std::println("\n处理后的数据:");
    for (std::size_t index = 0; index < data.size(); ++index) {
        std::print("{:2}: {:6} ", index, data[index]);
        if ((index + 1) % 5 == 0) std::println("");
    }
    if (!data.empty() && data.size() % 5 != 0) std::println("");
}

// 主异步演示函数
std::future<void> run_modern_cpp_demo() {
    return std::async(std::launch::async, []() {
        std::println("🚀 C++23 现代化特性演示");
        std::println("展示特性: 模块、协程、概念、范围、格式化、智能指针、结构化绑定\n");
        
        try {
            // 创建异步数据处理器
            auto processor = std::make_unique<AsyncDataProcessor<long long>>();
            
            // 生成斐波那契数列
            std::println("📊 生成斐波那契数列...");
            auto generator = generate_fibonacci_sequence<long long>(15);
            
            // 异步处理数据
            std::println("⚡ 异步处理数据...");
            auto future_result = processor->process_async(std::move(generator));
            
            // 等待处理完成
            auto result = future_result.get();
            
            // 获取处理后的数据
            auto processed_data = processor->get_processed_data();
            
            // 使用结构化绑定解包结果
            auto [count, average, time] = result;
            
            // 格式化输出结果
            print_results(result, processed_data);
            
            // 展示更多现代C++特性
            std::println("\n🔍 额外的现代特性演示:");
            
            // 使用std::expected (C++23)进行错误处理
            auto safe_divide = [](double a, double b) -> std::expected<double, std::string> {
                if (b == 0.0) {
                    return std::unexpected("除零错误");
                }
                return a / b;
            };
            
            if (auto division_result = safe_divide(average, 2.0)) {
                std::println("安全除法结果: {:.2f}", *division_result);
            } else {
                std::println("错误: {}", division_result.error());
            }
            
            // 使用std::format进行复杂格式化
            auto summary = std::format(
                "总结: 在{}ms内处理了{}个数据点,平均值为{:.2f}",
                time.count(), count, average
            );
            std::println("\n📋 {}", summary);
            
        } catch (const std::exception& e) {
            std::println("❌ 异常: {}", e.what());
        }
        
        std::println("\n✅ 演示完成!");
    });
}

// 主函数
auto main() -> int {
    try {
        // 运行现代C++演示
        auto demo_future = run_modern_cpp_demo();
        demo_future.wait();
        
        return 0;
    } catch (const std::exception& e) {
        std::println("💥 程序异常: {}", e.what());
        return 1;
    } catch (...) {
        std::println("💥 未知异常");
        return 1;
    }
}

如何编译llvm 20 并且用上import std
http://localhost:8090/archives/ru-he-bian-yi-llvm-20-bing-qie-yong-shang-import-std
作者
wqli
发布于
更新于
许可