使用clangd在UE项目中阅读Unreal Engine源代码

· 2760字 · 6分钟

使用clangd在UE项目中阅读Unreal Engine源代码 🔗

本文介绍了如何为clangd生成Unreal引擎源代码的compilation database。

工欲善其事必先利其器,让我们使用clangd打造高效的UE代码环境吧。

Why 🔗

安装引擎时同时也会安装源代码。

  • 此时使用Visual Studio打开一个C++ UE 项目,在Engine部分能够查看源代码,大部分代码可以跳转与阅读,但是比较缓慢。少部分代码标红,一些宏定义完全是错误的。
  • 此时使用clangd配置的VSCode打开一个C++ UE 项目,UE5会以Workspace的一个文件夹的形式打开,此时引擎中的头文件以及源代码充斥着大量的错误,跳转完全无法工作。

clangd虽然功能强大,但特别依赖配置,clangd对于项目所需要知道的信息,和能成功编译项目的编译器所需要知道的信息是一样多的。这也是解释了为什么compile_commands.json可以被叫做compilation database。UE引擎这样的大型项目,又没有使用cmake这类构建工具,很难有开箱即用的通用自动化工具生成compilation database。所以还是需要求助于U++自己的自动化工具。

U++代码的特殊性在于:

  1. UE的引擎代码包含Cpp文件与一部分header的Private部分,也包含全部由header组成的Public部分。两部分依赖的头文件路径不同。
  2. 不同的引擎组件,不同的内置plugin,依赖的头文件也不同,不能让所有的文件都是用同一套include路径。
  3. UE中的源代码只是U++的源代码,需要经过Unreal Header Tool处理,自动生成类型信息后才是完整的C++代码。这些生成的代码是.generate.h.gen.cpp等。
  4. Unreal Build Tool还为不同的组件在不同配置下生成了不同的定义文件,定义宏开关,控制条件编译下的代码。

由于笔者对Visual Studio的配置不够熟悉,所以本文不会探究为什么Visual Studio打开的C++ UE 项目能够基本可用的阅读UE引擎代码。 但是综上所属,想要让clangd知晓的信息像(能完整编译引擎的)编译器一样多,开箱的情况下差的很远。

How 🔗

下面介绍的如何配置,基于Linux环境下的Unreal Engine。( 所以为什么我一定要用VScode做C++ UE 项目的编辑器呢?:)

  1. clone同版本tag的引擎源码,注意添加–depth=1,否则会拉下来大量的历史commit。
  2. Run Setup.sh and GenerateProjectFiles.sh, 让项目变得完整。(这里需要下载20G的文件,缓存在.git/ue-gitdeps中,可以复制出去,当传家宝共享给其他版本的引擎代码)
  3. (Windows) .\Engine\Build\BatchFiles\RunUBT.bat -mode=GenerateClangDatabase -Target=UnrealEditor Development Win64
  4. (Linux) ./Engine/Build/BatchFiles/RunUBT.sh -mode=GenerateClangDatabase -Target=UnrealEditor Development Linux

上一步生成了很多文件,跟踪新建的文件并分析:

  • 其中所有新产生的UnrealEditorGCD文件夹都是Epic预编译版没有的,对于代码补全,我们只关心其中新生成的.h .cpp .rsp文件
  • 在目录^./Engine/(Plugins|Intermediate)生成了很多^.*(generated\.h|gen\.cpp|Classes\.h|gen\.h|Definitions\.h)$文件,这些都是让U++变为完整C++所需要的。
  • 对比上一条新生成的文件列表,在Linux版预编译release的引擎中,有几十个中间生成文件在预编译release版也存在。而在Windows下的通过Epic Launcher安装预编译release版引擎,有上万个被保留下来的中间生成文件。(可能这也是Visual Studio用来阅读引擎代码能够刚刚好能用的原因?)
  • 最重要的一点是,观察生成的rsp文件、以及引用rsp文件的compile_commands.json里的编译命令,全部使用了相对目录表示。这个相对目录是相对于compile_commands.json给编译指令指定的directory属性的。
  • 最终,compile_commands.json本身是使用绝对目录表示的。但仅限于directory属性以及源代码路径。

经过上面的分析,补全U++到C++的所需要的生成文件模式很统一。我们是可以把这些补全信息搬运到release版的引擎中的!

上bash代码

# make sure in UE source dir
cd /media/store/UnrealEngineOfficial/UnrealEngine

# set up TARGET_ROOT, generated files will be put here
TARGET_ROOT=/media/store/UnrealEngineOfficial/UE5_CompilationDatabase
#UE_ROOT=/media/store/UnrealEngineOfficial/Linux_Unreal_Engine_5.4.2

# generate Required Intermediate Files 
./Engine/Build/BatchFiles/RunUBT.sh -mode=GenerateClangDatabase -Target=UnrealEditor Development Linux

# copy compile_commands.json
mkdir -p "${TARGET_ROOT}/.vscode"
cp compile_commands.json "${TARGET_ROOT}/.vscode"
# patch absolute path
sed "s#$(pwd)#${TARGET_ROOT}#g" -i "${TARGET_ROOT}/.vscode"/compile_commands.json
# generate clangd config
cat > "${TARGET_ROOT}/.clangd" <<EOF
CompileFlags:
  #Compiler: /usr/bin/g++
  CompilationDatabase: .vscode
  Add: 
    - -std=gnu++20
    - -stdlib=libstdc++
EOF
 
# only copy files we interested
while read; do cp --parent -vn "$REPLY" "${TARGET_ROOT}"/; done < <(
    find ./Engine/Plugins/ ./Engine/Intermediate/ -type f -name '*generated.h' -or -name '*gen.cpp' -or -name '*Classes.h' -or -name '*gen.h' -or -name '*Definitions.h' | grep -v UnrealEditorGCD;
    while read; do find "$REPLY" -name '*.h' -or -name '*.cpp' -or -name '*.rsp'; done< <(find -name UnrealEditorGCD -type d)
)

然后就可以将UE5_CompilationDatabase打包了,使用的时候只需要再次替换compile_commands.json里的绝对路径,然后覆盖到预编译版本引擎中即可。 如此不需要自己编译引擎也能够获得完整的clangd体验。由于windows下引擎安装位置固定,这一步还可以更“自动”一点。

还需注意的一点是,Windows下不要随意的覆盖Compiler配置,clangd会根据使用的是clang++.exe还是clang-cl.exe解析rsp文件中编译器指令采取哪个平台的格式。

产物 🔗

下面的连接包含按照上述步骤打包好的clangd compilation database以及需要的中间文件,包含Linux与Windows两个平台可用的版本。

https://1drv.ms/f/s!AgkXMslnDVNlumVlSLbVONthimwd?e=w6c7ID

也可以从下面的本站链接下载:

5.4.2

5.4.3

5.4.4

最后推荐一个VSCode下增强UE开发体验的插件unreal clangd

Update 🔗

update 2024/11/08 🔗

更新了5.4.4的编译产物

update 2024/11/09 🔗

关于UE4的clangdb生成

  1. 4.24版本开始的UBT才添加了GenerateClangDatabase
  2. 早期的UBT不会调用UHT生成header,要完整编译后才有生成的相关header
  3. 早期的UBT在windows下会固定使用默认安装路径下的外部clang作为工具链,
    而非使用Visual Studio安装的clang。
    推荐使用VS2022安装“Clang C++编译器”与“LLVM (clang-cl)工具集”,
    然后管理员cmd运行mklink /J "C:\Program Files\LLVM" "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm",创建联接。
  4. Windows下UBT编译需要安装指定版本的.net SDK。
  5. Linux下需要手动给GenerateClangDatabase.cs打这个补丁pr8663
    然后运行GenerateProjectFiles.sh重新编译UBT。
    PS: GenerateClangDatabase模式在UE5.0才将Linux与Mac支持加入。
  6. Windows直接调用UBT,使用如下命令生成clangdb
    cmd: Engine\Binaries\DotNET\UnrealBuildTool.exe -mode=GenerateClangDatabase UE4Editor Linux Development
    Linux下需要使用build.sh自动配置mono环境
    ./Engine/Build/BatchFiles/Linux/Build.sh -mode=GenerateClangDatabase UE4Editor Linux Development