xinali/articles

002-chromium新老版本编译

xinali opened this issue · 0 comments

chromium build

[toc]

latest update: 2024.03.08

因为工作需要,需要经常构建多个平台各种版本的chromium,所以可能会遇到各种各样的问题,

在这里做一下记录,会不断更新遇到的最新问题

所有的源码和相关工具,尽力别使用挂载的方式挂在wslvirtualbox/vmware中,挂载的方式,无论是编译,还是git操作,速度都会特别慢

初次构建(latest on linux)

  1. 准备depot_tools:

    git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
    export PATH=/xxx/path/to/depot_tools:$PATH
  2. 获取chromium源码

    mkdir ~/chromium && cd ~/chromium
    fetch --nohooks chromium
  3. 构建及获取依赖

    cd src
    ./build/install-build-deps.sh
    gclient runhooks
  4. 构建chrome

    gn gen out/Default
    autoninja -C out/Default chrome

只要按照流程走,一般构建最新版,不会出问题

初次构建(latest on windows)

直接利用构建脚本

@echo off
rem 设置源码路径
set chromium_dir="G:\chromium"
set chromium_source=%chromium_dir%\src

rem 设置不更新depot_tools
set DEPOT_TOOLS_WIN_TOOLCHAIN=0

rem 设置depot_tools路径
rem 如果有多版本的depot_tools,根据需要设定特定版本
set DEPOT_TOOLS_PATH=G:\codes\depot_tools
set PATH=%DEPOT_TOOLS_PATH%;%PATH%

rem 针对环境存在多个版本python时
rem 可能还需要设置python路径
rem set PYTHON_PATH=G:\tools\Python27
rem set PATH=%PYTHON_PATH%;%PATH%

rem 设置vs版本
set vs2022_install=D:\tools\vs_community

rem 编译
cd %chromium_source%
gn gen out\Release
ninja -C out\Release chrome

build older version

# 切换分支或commit
git checkout old_version

# 设置depot_tools不自动升级 
export DEPOT_TOOLS_UPDATE=0

# 设置依赖
COMMIT_DATE=$(git log -n 1 --pretty=format:%ci)
cd ~/depot_tools
git checkout $(git rev-list -n 1 --before="$COMMIT_DATE" main)

# 清理原始第三方库
git clean -ffd

# 同步第三方库
gclient sync -D --force --reset

# 构建依赖
./build/install-build-deps.sh

# 上古版本构建依赖
./build/gyp_chromium

gclient runhooks

# 构建chrome
gn gen out/Default
ninja -C out/Default chrome

如果想要构建一个调试版本,在gn后,更改out/Default目录args.gn中的参数

is_debug = true
is_component_build = true
symbol_level = 2

编译问题

chromium代码非常复杂,所以在不同的系统不同的版本的编译过程中会遇到非常多的问题,以下主要是记录我自己遇到的各种问题

  1. 代理问题

    如果直接在shell的配置文件里设置代理,在运行gclient sync/fetch --nohooks chromium时都不一定有问题,但是在运行gclient runhooks 可能会出错,解决办法是设置.boto文件/home/[user]/.boto,类似于

    [Boto]
    debug = 0
    num_retries = 10
    
    proxy = [proxy ip]
    proxy_port = [proxy port]

    在启动shell时,载入.boto配置文件export NO_AUTH_BOTO_CONFIG="/home/[user]/.boto"

  2. webrtc版本问题(其他库操作相同)

    cd src/third_party/webrtc
    git checkout $(git rev-list -n 1 --before="$COMMIT_DATE" main)

    然后在src/DEPS中更改对应的webrtccommit id ,这种方法在很多情况下都适用,但是在某些情况下不适用,在这种方法失效时,还有另一种更加直接的方法,在对应的源码网站上下载该commit的源码,然后放在对应目录下,这种方法的前提是,不停执行gclient sync -D --force --reset 直至最后一个需要处理的库为你需要处理的库为止,然后就可以直接build

    在处理该问题时,还遇到一个奇怪的问题,在google源码站上有某个commit ,代码也是根据该commit拉取的代码,但是却无法checkout到该commit,这时候就必须使用第二种方法

    20230815 update:

    针对这种无法checkout到固定commit,最近发现了一个新的方法,比如webrtc库,这里可以直接这么干

    fetch --nohooks webrtc
    git checkout branch-heads/m79

    然后把checkout完成的代码放到chromium/src/third_party/webrtc目录下

  3. python问题

    a. 目前部分老版本所使用的脚本,均为python2,如果使用python3,则出错,更改默认的python版本即可
    b. 其自带的python编译脚本存在编码错误,这个一般存在老版本中,会提示如下错误

    UnicodeDecodeError: 'gbk' codec can't decode byte 0xxx in position yyyy: illegal multibyte sequence
    

    vscode打开提示是utf-8编码,但是使用如下的代码会发现其编码

    def guess_encoding(filename, encodings=None):
       if encodings is None:
           encodings = ['utf-8', 'iso-8859-1', 'gbk', 'big5', 'windows-1252', 'utf-16', 'utf-32']
    
       for enc in encodings:
           try:
               with open(filename, 'r', encoding=enc) as f:
                   f.read()
               return enc
           except UnicodeDecodeError:
               pass
       return None

    在找到具体编码后,打开文件时,比如open(file_name, 'r', encoding='windows-1252')即可

    c. depot_tools自带python版本在处理os.path.relpath问题

    在部分chromium版本对应的depot_tools中使用的python版本为3.11.2貌似存在问题,大概是这种情况

    Traceback (most recent call last):
      File "G:\chromium\src\mojo\public\tools\bindings\mojom_bindings_generator.py", line 418, in <module>
        ret = main()
              ^^^^^^
      File "G:\chromium\src\mojo\public\tools\bindings\mojom_bindings_generator.py", line 413, in main
        return args.func(args, remaining_args)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "G:\chromium\src\mojo\public\tools\bindings\mojom_bindings_generator.py", line 275, in _Generate
        processor._GenerateModule(
      File "G:\chromium\src\mojo\public\tools\bindings\mojom_bindings_generator.py", line 243, in _GenerateModule
        generator.GenerateFiles(filtered_args)
      File "G:\chromium\src\mojo\public\tools\bindings\generators\mojom_ts_generator.py", line 280, in GenerateFiles
        self.WriteWithComment(self._GenerateWebUiModule(),
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "G:\chromium\src\mojo\public\tools\mojom\mojom\generate\template_expander.py", line 34, in GeneratorInternal
        parameters = generator(*args, **kwargs2)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "G:\chromium\src\mojo\public\tools\bindings\generators\mojom_ts_generator.py", line 266, in _GenerateWebUiModule
        return self._GetParameters()
               ^^^^^^^^^^^^^^^^^^^^^
      File "G:\chromium\src\mojo\public\tools\bindings\generators\mojom_ts_generator.py", line 228, in _GetParameters
        self._GetJsModuleImports(),
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "G:\chromium\src\mojo\public\tools\bindings\generators\mojom_ts_generator.py", line 633, in _GetJsModuleImports
        os.path.relpath(
      File "<frozen ntpath>", line 766, in relpath
    

    具体的修复方法

  4. 编译参数问题

    如果想要获取chromium默认的编译参数,可以使用

    gn args out\Release --list
    

    windows系统上,使用默认参数编译,可以正常打印出调用堆栈信息,并精确到具体的函数及行号。

    类似于

     base::internal::TaskTracker::RunTaskImpl [0x00007FFC2C6E1322+146] (...\task_tracker.cc:679)
     base::internal::TaskTracker::RunContinueOnShutdown [0x00007FFC2C6E1271+113] (...\task_tracker.cc:656)
     base::internal::TaskTracker::RunTaskWithShutdownBehavior [0x00007FFC2C6E08EF+143] (...\task_tracker.cc:692)
     base::internal::TaskTracker::RunTask [0x00007FFC2C6E0259+1993] (...\task_tracker.cc:525)
     base::internal::TaskTracker::RunAndPopNextTask [0x00007FFC2C6DF3CA+778] (...\task_tracker.cc:418)
     base::internal::WorkerThread::RunWorker [0x00007FFC2C707E63+1171] (...\worker_thread.cc:438)
     base::internal::WorkerThread::RunPooledWorker [0x00007FFC2C707862+34] (...\worker_thread.cc:323)
     base::internal::WorkerThread::ThreadMain [0x00007FFC2C707668+248] (...\worker_thread.cc:303)
     base::`anonymous namespace'::ThreadFunc [0x00007FFC2C834A92+450] (...\platform_thread_win.cc:142)
    

    linux操作系统上,默认无法打印出调用堆栈涉及的具体行号

    类似于

    #1 0x7fb8361725fa base::debug::StackTrace::StackTrace()
    #2 0x7fb8361725b5 base::debug::StackTrace::StackTrace()
    #3 0x7fb8236b7899 net::CertVerifyProc::Verify()
    #4 0x7fb823704d76 net::(anonymous namespace)::DoVerifyOnWorkerThread()
    #5 0x7fb823706441 base::internal::FunctorTraits<>::Invoke<>()
    #6 0x7fb8237063cf base::internal::InvokeHelper<>::MakeItSo<>()
    #7 0x7fb8237062cd base::internal::Invoker<>::RunImpl<>()
    #8 0x7fb823706197 base::internal::Invoker<>::RunOnce()
    #9 0x7fb82370788b base::OnceCallback<>::Run()
    #10 0x7fb823706b4f base::internal::ReturnAsParamAdapter<>()
    #11 0x7fb823706f1d base::internal::FunctorTraits<>::Invoke<>()
    #12 0x7fb823706ed3 base::internal::InvokeHelper<>::MakeItSo<>()
    #13 0x7fb823706e6d base::internal::Invoker<>::RunImpl<>()
    #14 0x7fb823706de7 base::internal::Invoker<>::RunOnce()
    

    如果想在linux下打印出的堆栈显示具体的行号,可以在out/Release/args.gn增加配置项

    enable_stack_trace_line_numbers = true
    

    该配置项只在近两年的版本中支持,古早的版本可能不支持。

    该配置项需要注意一点,在启用is_asan时,调用StackTrace是无法打印出带有行号信息的,但是AddressSanitizer触发时会打印出行号

    类似于

    [801212:801212:0306/100934.195483:INFO:debug_logger.h(28)] chromium(STACK): ~DebugLogger#0 0x5561d07c968e (/home/xina1i/chromium/src/out/Release/chrome+0xca4b68d)
    #1 0x7f7dfc58397c (/home/xina1i/chromium/src/out/Release/libbase.so+0x158397b)
    #2 0x7f7dfc4a6cb4 (/home/xina1i/chromium/src/out/Release/libbase.so+0x14a6cb3)
    #3 0x7f7dfc4a6b25 (/home/xina1i/chromium/src/out/Release/libbase.so+0x14a6b24)
    ...
    #111 0x7f7ceba29e40 (/usr/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
    #112 0x5561d0782a1a (/home/xina1i/chromium/src/out/Release/chrome+0xca04a19)
    
    =================================================================
    ==801212==ERROR: AddressSanitizer: heap-use-after-free on address 0x5110004111c0 at pc 0x7f7dfbc24f3f bp 0x7ffeb089feb0 sp 0x7ffeb089fea8
    READ of size 1 at 0x5110004111c0 thread T0 (chrome)
        #0 0x7f7dfbc24f3e in base::internal::(anonymous namespace)::CrashImmediatelyOnUseAfterFree(unsigned long) base/memory/raw_ptr_asan_hooks.cc:53:17
        #1 0x7f7dfbc249bf in base::internal::(anonymous namespace)::SafelyUnwrapForDereference(unsigned long) base/memory/raw_ptr_asan_hooks.cc:76:5
        #2 0x5561ef31666f in BubbleContentsWrapper* base::internal::RawPtrHookableImpl<true>::SafelyUnwrapPtrForDereference<BubbleContentsWrapper>(BubbleContentsWrapper*) base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_hookable_impl.h:85:9
        #3 0x5561ef43f109 in base::raw_ptr<BubbleContentsWrapper, (partition_alloc::internal::RawPtrTraits)0>::GetForDereference() const base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr.h:833:12
    
    
  5. git问题

    git配置文件.git/config(linux), .gitconfig(windows)

    a. fatal: Out of memory, malloc failed
    git缓存不够,通过更改git的配置项postbuffer=1048576000

    b. Conflicting directory
    目录冲突,这个很有可能是因为git配置项中的depot_tools目录不对,改到对应的目录即可

  6. vs环境问题

    a. No supported Visual Studio can be found. Supported versions are: 17.0 (2022), 16.0 (2019), 15.0 (2017)
    找不到安装的vs信息,解决: set vs2022_install=D:\tools\vs_community

    b. Exception: Path "D:\Windows Kits\10\\include\10.0.22621.0\\um" from environment variable "include" does not exist. Make sure the necessary SDK is installed.
    这个是表明目前构建的chromium版本需要的windows SDK版本错误或者是找不到对应的版本,

    ​ 首先设置SDK目录set WINDOWSSDKDIR=D:\Windows Kits\10

    ​ 然后查看D:\Windows Kits\10\Include目录下是否存在10.0.22621.0版本的SDK,如果不存在,则安装即可

    c. midl.exe output different from files
    该问题,根据经验应该是msvc的版本混乱了,比如最新版的需要vs2022,老版本的需要vs2017

    ​ 安装完vs2017之后,没有重启,可能会存在该问题,重启之后,打开特定的vs2017命令行,重新编译即可

    d. 提示构建代码需要更高版本的clang,比如third_party/llvm-build中的clang版本是11.0,但是提示需要使用11.0 or newer
    这个问题一般在编译老版本时出现,主要的原因在于使用了高版本的msvc,比如安装了vs2019

    ​ 但随着vs的更新其对应的msvc也会更新,这就导致部分msvc的头文件不再支持clang10.0

    ​ 但是我没找到在编译过程中设定只使用固定msvc的方法,最后没办法我装了旧版本的vs2017解决了这个问题

  7. 编译工具问题

    a. LLVM ERROR: out of memory
    这个问题在chromium最近(2024.03.04)的版本中经常性遇到,也不知道后期能不能解决
    我们在正常默认编译的情况下,会使用ninja -C out\Release chrome进行编译,

    ninja会将所有可使用的cpu全部占用,所以就会有一个问题跑满的情况下,

    会出现大量的clang进程直接把所有的内存也占满,导致oom,解决办法: ninja -C out\Release -j 12

    限制并发数,从而限制内存的使用,具体使用几个并发,可以自己测试

还有部分上古版本,会涉及到编译器和其对应的c++标准等,这类的,最好的解决办法是找到当时最新的对应系统进行编译,不然会恶心到想吐。

调试技巧

该部分内容主要写一些在调试chromium或者其组件过程中可能使用到的部分技巧

使用带console调试

我们在调试chromium时,如果可以使用日志的话,一般会使用日志,但是在很多third_party库中无法直接使用base库中的日志功能,可能需要fprintf这类的输出来显示我们需要的日志,所以有时候带consolechromium就很有用。

  1. Build.gn中添加链接选项

    if (is_win) {
        ldflags = ["/SUBSYSTEM:CONSOLE"]
    }
    
  2. 启动时启用日志并设置日志等级: .\out\Release\chrome.exe --enable-logging --v=0

    在比较新的系统中,直接使用这种方法应该会报错

    ERROR at //BUILD.gn:43:13: Assignment had no effect.
      ldflags = ["/SUBSYSTEM:CONSOLE"]
                ^--------------------
    You set the variable "ldflags" here and it was unused before it went
    out of scope.
    

    比较通用的方法是引入chromium自身提供的win_console支持

    import("//build/config/win/console_app.gni")
    

    在最新版的chromium中已经默认支持console编译(2024.03.05)