Flutter Engine 編譯構建-05

AidenCang發表於2019-11-29

介紹

在前面編譯環境安裝GNTools工具原理,Ninja編譯工具原理的理解,已經瞭解了Flutter Engine相關的一下概念,接下來,繼續分析執行編譯命令呼叫的命令,檔案,和相關的邏輯,有與篇幅問題,只介紹相關的這些邏輯和構建的檔案說明(紙上得來終覺淺,....),整個思維架構打通了之後,剩下的就是時間問題,這個可以克服。。。。。。。

準備工作

在開始分析GN是怎麼產生Ninja配置檔案的流程,需要對一下的內容有一個加單的瞭解 !!! info "優點"

* 1.可讀性好
* 2.速度更快
* 3.修改gn 之後 構建ninja檔案時候會自動更新
* 4.依賴分明
複製程式碼

!!! info "兩種檔案型別"

* BUILID.gn : 採用層級結構 檔案根目錄下通常有一個BUILD.gn檔案,該檔案是所有的程式碼模組組裝的集合
* .gni :一般用來新增一些引數的配置,在gn檔案中import這些檔案或者裡面定義的變數引數值
複製程式碼

GNTools 是一款構建系統,用於編譯大規模程式碼生成ninja檔案

Ninja原始碼分析、優化、編譯系統

Flutter Engine Complie Engine編譯官方教程

預處理編譯檔案

使用不同的引數指定我們準備要構建的flutter引擎支援的平臺(Windows,Linux,Mac,Android,IOS,Web,Embedder),在同一個平臺上支援不同的模式(debug,release,profile),接下來我們怎麼玩這個系統在不同平臺上的支援庫,和同一平臺上的不同模式

!!! info "預處理編譯檔案不同平臺的編譯指令碼"

* ./flutter/tools/gn --android --unoptimized for device-side executables.
* ./flutter/tools/gn --android --android-cpu x86 --unoptimized for x86 emulators.
* ./flutter/tools/gn --android --android-cpu x64 --unoptimized for x64 emulators.
* ./flutter/tools/gn --unoptimized for host-side executables, needed to compile the code.
* ./flutter/tools/gn --ios --unoptimized
* ./flutter/tools/gn --ios --simulator --unoptimized
* ./flutter/tools/gn --unoptimized
* python .\flutter\tools\gn --unoptimized
* web編譯[felt工具](https://github.com/flutter/engine/blob/master/lib/web_ui/dev/README.md)
複製程式碼

通過這些上述的命令,跟蹤命令的執行過程:./flutter/tools/gn --android --unoptimized,參加Flutter Engine 編譯模式

  • flutter/tools/gn python指令碼下列程式碼
  • --android 指定平臺
  • --android-cpu x86 cpu架構
  • --unoptimized 是否需要優化

執行下列指令碼主要是在構建GN構建指令碼引數:


SRC_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
/* 根據傳入的引數判斷平臺的輸出路徑 */
def get_out_dir(args):
    if args.target_os is not None:
        target_dir = [args.target_os]
    else:
        target_dir = ['host']
    ........
    return os.path.join(args.out_dir, 'out', '_'.join(target_dir))

def to_command_line(gn_args):
    def merge(key, value):
        if type(value) is bool:
            return '%s=%s' % (key, 'true' if value else 'false')
        return '%s="%s"' % (key, value)
    return [merge(x, y) for x, y in gn_args.iteritems()]

def cpu_for_target_arch(arch):
  if arch in ['ia32', 'arm', 'armv6', 'armv5te', 'mips',
              'simarm', 'simarmv6', 'simarmv5te', 'simmips', 'simdbc',
              'armsimdbc']:
    return 'x86'
  if arch in ['x64', 'arm64', 'simarm64', 'simdbc64', 'armsimdbc64']:
    return 'x64'

def to_gn_args(args):
    gn_args = {}

    # Skia GN args.
    gn_args['skia_enable_flutter_defines'] = True # Enable Flutter API guards in Skia.
    gn_args['skia_use_dng_sdk'] = False    # RAW image handling.
    gn_args['skia_use_sfntly'] = False     # PDF handling depedency.
  ...............

    return gn_args

def parse_args(args):
  args = args[1:]
  parser = argparse.ArgumentParser(description='A script run` gn gen`.')

  parser.add_argument('--unoptimized', default=False, action='store_true')

  parser.add_argument('--runtime-mode', type=str, choices=['debug', 'profile', 'release'], default='debug')
..........
  return parser.parse_args(args)

def main(argv):
  args = parse_args(argv)

  if sys.platform.startswith(('cygwin', 'win')):
    subdir = 'win'
  elif sys.platform == 'darwin':
    subdir = 'mac-x64'
  elif sys.platform.startswith('linux'):
     subdir = 'linux-x64'
  else:
    raise Error('Unknown platform: ' + sys.platform)

  command = [
    '%s/buildtools/%s/gn' % (SRC_ROOT, subdir),
    'gen',
    '--check',
  ]

  if sys.platform == 'darwin':
    # On the Mac, also generate Xcode projects for ease of editing.
    command.append('--ide=xcode')

  if sys.platform.startswith('win'):
    # On Windows, also generate Visual Studio project for ease of editing.
    command.append('--ide=vs')

  gn_args = to_command_line(to_gn_args(args))
  out_dir = get_out_dir(args)
  print "gn gen --check in %s" % out_dir
  command.append(out_dir)
  command.append('--args=%s' % ' '.join(gn_args))
  gn_call_result = subprocess.call(command, cwd=SRC_ROOT)
  print command [1]

  if gn_call_result == 0:
    # Generate/Replace the compile commands database in out.
    compile_cmd_gen_cmd = [
      'ninja',
      '-C',
      out_dir,
      '-t',
      'compdb',
      'cc',
      'cxx',
      'objc',
      'objcxx',
      'asm',
    ]
    print  compile_cmd_gen_cmd [2]
    呼叫`GN`生成構建檔案

    contents = subprocess.check_output(compile_cmd_gen_cmd, cwd=SRC_ROOT)
    compile_commands = open('%s/out/compile_commands.json' % SRC_ROOT, 'w+')
    compile_commands.write(contents)
    compile_commands.close()

  return gn_call_result

if __name__ == '__main__':
    sys.exit(main(sys.argv))
複製程式碼

生成的GN命令引數

./flutter/tools/gn --android --unoptimized

通過呼叫下面的命令查詢當前目錄下的.ng檔案開始分析整個原始碼專案的依賴樹

command = [
    '%s/buildtools/%s/gn' % (SRC_ROOT, subdir),
    'gen',
    '--check',
  ]
複製程式碼

.gn檔案的查詢過程

在引擎的目錄下engine/src查詢入口的.gn檔案,使用src/tools/gn工具查詢根目錄樹下的原始檔樹和開始配置資料

# The location of the build configuration file.
buildconfig = "//build/config/BUILDCONFIG.gn"

# The secondary source root is a parallel directory tree where
# GN build files are placed when they can not be placed directly
# in the source tree, e.g. for third party source trees.
secondary_source = "//build/secondary/"

# The set of targets known to pass 'gn check'. When all targets pass, remove
# this.
check_targets = [
  "//dart/*",
  "//flow/*",
  "//flutter/*",
  "//glue/*",
  "//mojo/*",
  "//skia/*",
  "//sky/*",
]
複製程式碼

[1] 處使用列印命令輸出這些構建命令生成的引數型別,通過檢視生成的命令列引數,就能夠理解在Flutter Engine 編譯模式提到的不同模式,是怎麼組織程式碼和相關的編譯檔案相關的內容,基本的思路和框架理解了之後,接下來就是GN工具呼叫BUILD.gn相關的檔案,提供給Ninja去編譯的檔案 [2] 處構建的命令


['ninja', '-C', 'out/android_debug_unopt', '-t', 'compdb', 'cc', 'cxx', 'objc', 'objcxx', 'asm']
複製程式碼

在[1]構建的命令中指定使用的GN路徑'buildtools/mac-x64/gn'接著會呼叫執行/engine/src# ./flutter/tools/gn的Build.gn檔案engine/src/BUILD.gn,會根據當前目錄中的BUILD.gn檔案配置一層一層的目錄去查詢指定的目錄中的BUILD.gn,檔案每一個目錄中都會定義當前目錄編譯的規則和依賴引數,所以可以理解為一顆倒掛的樹:從葉子結點開始配置,配置父節點,如果需要新增新的功能模組,就在上一級模組中把下一級的BUILD.gn檔案引用就能夠向下包含需要的檔案依賴。最終生成ninja的配置檔案。

/* This target will be built if no target is specified when invoking ninja. */
group("default") {
  testonly = true
  deps = [
    "//flutter",
  ]
}
group("dist") {
  testonly = true
  deps = [
    "//flutter:dist",
  ]
}
複製程式碼

如何配置OS,CPU,編譯工具鏈

engine/src/build/config/BUILDCONFIG.gn檔案中主要配置內容:

    1. 指定Flutter原始碼目錄
    1. 指定平臺架構
    1. 指定一些構建標識
    1. 指定系統(Window,Mac,Linux,Android,ios)
    1. 指定工具鏈的使用
    1. 第三方開源庫的使用

指定flutter的根目錄

# Set the root of the engine project.
flutter_root = "//flutter"
複製程式碼

指定平臺

使用的變數

- host_os, host_cpu, host_toolchain
- target_os, target_cpu, default_toolchain
- current_os, current_cpu, current_toolchain.
複製程式碼

build Flag

declare_args() {
  # How many symbols to include in the build. This affects the performance of
  # the build since the symbols are large and dealing with them is slow.
  #   2 means regular build with symbols.
  #   1 means minimal symbols, usually enough for backtraces only.
  #   0 means no symbols.
  #   -1 means auto-set (off in release, regular in debug).
  symbol_level = -1

  # Component build.
  is_component_build = false

  # Official build.
  is_official_build = false

  # Debug build.
  is_debug = true

  # Whether we're a traditional desktop unix.
  is_desktop_linux = current_os == "linux" && current_os != "chromeos"

  # Set to true when compiling with the Clang compiler. Typically this is used
  # to configure warnings.
  is_clang = current_os == "mac" || current_os == "ios" ||
             current_os == "linux" || current_os == "chromeos"

  # Compile for Address Sanitizer to find memory bugs.
  is_asan = false

  # Compile for Leak Sanitizer to find leaks.
  is_lsan = false

  # Compile for Memory Sanitizer to find uninitialized reads.
  is_msan = false

  # Compile for Thread Sanitizer to find threading bugs.
  is_tsan = false

  # Compile for Undefined Behavior Sanitizer.
  is_ubsan = false

  if (current_os == "chromeos") {
    # Allows the target toolchain to be injected as arguments. This is needed
    # to support the CrOS build system which supports per-build-configuration
    # toolchains.
    cros_use_custom_toolchain = false
  }

  # DON'T ADD MORE FLAGS HERE. Read the comment above.
}
複製程式碼

指定平臺

Windows,Linux,Mac,Android,IOS,Web,embedder

f (current_os == "mac") {
  is_android = false
  is_chromeos = false
  is_fuchsia = false
  is_fuchsia_host = false
  is_ios = false
  is_linux = false
  is_mac = true
  is_posix = true
  is_win = false
} else if (current_os == "android") {
  is_android = true
  is_chromeos = false
  is_fuchsia = false
  is_fuchsia_host = false
  is_ios = false
  is_linux = false
  is_mac = false
  is_posix = true
  is_win = false
}
............

複製程式碼

工具鏈設定

import("//build/toolchain/custom/custom.gni")

# Define this to allow Fuchsia's fork of harfbuzz to build.
# shlib_toolchain is a Fuchsia-specific symbol and not used by Flutter.
shlib_toolchain = false

if (custom_toolchain != "") {
  assert(custom_sysroot != "")
  assert(custom_target_triple != "")
  host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
  set_default_toolchain("//build/toolchain/custom")
} else if (is_win) {
  # On windows we use the same toolchain for host and target by default.
  host_toolchain = "//build/toolchain/win:$current_cpu"
  set_default_toolchain("$host_toolchain")
} else if (is_android) {
  if (host_os == "linux") {
    # Use clang for the x86/64 Linux host builds.
    if (host_cpu == "x86" || host_cpu == "x64") {
      host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
    } else {
      host_toolchain = "//build/toolchain/linux:$host_cpu"
    }
  } else if (host_os == "mac") {
    host_toolchain = "//build/toolchain/mac:clang_$host_cpu"
  } else if (host_os == "win") {
    host_toolchain = "//build/toolchain/win:$current_cpu"
  } else {
    assert(false, "Unknown host for android cross compile")
  }
  if (is_clang) {
    set_default_toolchain("//build/toolchain/android:clang_$current_cpu")
  } else {
    set_default_toolchain("//build/toolchain/android:$current_cpu")
  }
} else if (is_linux) {
  if (is_clang) {
    host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
    set_default_toolchain("//build/toolchain/linux:clang_$current_cpu")
  } else {
    host_toolchain = "//build/toolchain/linux:$host_cpu"
    set_default_toolchain("//build/toolchain/linux:$current_cpu")
  }
  if (is_chromeos && cros_use_custom_toolchain) {
    set_default_toolchain("//build/toolchain/cros:target")
  }
} else if (is_mac) {
  host_toolchain = "//build/toolchain/mac:clang_x64"
  set_default_toolchain(host_toolchain)
} else if (is_ios) {
  import("//build/config/ios/ios_sdk.gni")  # For use_ios_simulator
  host_toolchain = "//build/toolchain/mac:clang_$host_cpu"
  if (use_ios_simulator) {
    set_default_toolchain("//build/toolchain/mac:ios_clang_x64")
  } else {
    set_default_toolchain("//build/toolchain/mac:ios_clang_arm")
  }
} else if (is_fuchsia) {
  if (host_os == "mac") {
    host_toolchain = "//build/toolchain/mac:clang_$host_cpu"
  } else {
    host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
  }
  set_default_toolchain("//build/toolchain/fuchsia")
} else {
  assert(false, "Toolchain not set because of unknown platform.")
}

# Sets default dependencies for executable and shared_library targets.
#
# Variables
#   no_default_deps: If true, no standard dependencies will be added.
if (is_android || (is_linux && current_cpu != "x86")) {
  foreach(_target_type,
          [
            "executable",
            "loadable_module",
            "shared_library",
          ]) {
    template(_target_type) {
      target(_target_type, target_name) {
        forward_variables_from(invoker, "*", [ "no_default_deps" ])
        if (!defined(deps)) {
          deps = []
        }
        if (!defined(invoker.no_default_deps) || !invoker.no_default_deps) {
          deps += [ "//third_party/libcxx" ]
        }
      }
    }
  }
}

複製程式碼

COMPONENT 配置

指定需要依賴的共享庫和原始檔目錄,所有的依賴配置檔案頂層檔案目錄 //build/config/sanitizers:deps

//build/config/sanitizers:deps


if (is_component_build) {
  component_mode = "shared_library"
} else {
  component_mode = "source_set"
}


if (defined(invoker.deps)) {
  deps = invoker.deps + [ "//build/config/sanitizers:deps" ]
} else {
  deps = [
    "//build/config/sanitizers:deps",
  ]
}

....engine/src/build/config/sanitizers/BUILD.gn 指定第三方庫的依賴....

# Contains the dependencies needed for sanitizers to link into executables and
# shared_libraries. Unconditionally depend upon this target as it is empty if
# |is_asan|, |is_lsan|, |is_tsan|, |is_msan| and |use_custom_libcxx| are false.
group("deps") {
  deps = [
    "//third_party/instrumented_libraries:deps",
  ]
  if (is_asan || is_lsan || is_tsan || is_msan) {
    public_configs = [ ":sanitizer_options_link_helper" ]
    deps += [ ":options_sources" ]
  }
  if (use_custom_libcxx) {
    deps += [ "//buildtools/third_party/libc++:libcxx_proxy" ]
  }
}
複製程式碼

使用gn命令和引數之後生成編譯清單檔案


['buildtools/mac-x64/gn', 'gen', '--check', '--ide=xcode',
'out/android_debug_unopt', '--args=skia_enable_pdf=false enable_lto=false
use_clang_static_analyzer=false
full_dart_sdk=false
dart_runtime_mode="develop"
skia_use_fontconfig=false
skia_use_dng_sdk=false
skia_enable_flutter_defines=true
use_goma=false
dart_custom_version_for_pub="flutter"
embedder_for_target=false
is_official_build=true
host_cpu="x86" # 編譯主機架構
is_clang=true
skia_use_sfntly=false
 dart_target_arch="arm"
flutter_runtime_mode="debug"
goma_dir="None"
android_full_debug=true
target_os="android"  # 生成的目標平臺
mac_sdk_path=""
skia_use_x11=false
enable_coverage=false
target_cpu="arm"  # 目標cpu架構
skia_use_expat=true
dart_lib_export_symbols=false
is_debug=true  # debug模式
flutter_aot=false' # 不需要優化
]

複製程式碼

接著進入 //Flutter目錄查詢`# Copyright 2013 The Flutter Authors. All rights reserved.


import("$flutter_root/common/config.gni")
import("//third_party/dart/build/dart/dart_action.gni")

<!-- # Temporary snapshot copy rules until we can use the full SDK. -->
_flutter_sdk_snapshots = [
  [
    "dart2js",
    "//third_party/dart/utils/compiler:dart2js",
  ],
  [
    "kernel_worker",
    "//third_party/dart/utils/bazel:kernel_worker",
  ],
]

group("flutter") {
  testonly = true

  public_deps = [
    "$flutter_root/lib/snapshot:generate_snapshot_bin",
    "$flutter_root/lib/snapshot:kernel_platform_files",
    "$flutter_root/shell/platform/embedder:flutter_engine",
    "$flutter_root/sky",
  ]

  if (current_toolchain == host_toolchain) {
    public_deps += [ "$flutter_root/shell/testing" ]
  }

  if (!is_fuchsia && !is_fuchsia_host) {
    if (current_toolchain == host_toolchain) {
      public_deps += [
        "$flutter_root/frontend_server",
        "//third_party/dart:create_sdk",
        "$flutter_root/lib/stub_ui:stub_ui",
        ":dart2js_platform_files",
        ":flutter_dartdevc_kernel_sdk",
      ]
      foreach(snapshot, _flutter_sdk_snapshots) {
        public_deps += [ ":copy_flutter_${snapshot[0]}_snapshot" ]
      }
    }
  }

  <!-- # If on the host, compile all unittests targets. -->
  if (current_toolchain == host_toolchain) {
    if (is_mac) {
      public_deps +=
          [ "$flutter_root/shell/platform/darwin:flutter_channels_unittests" ]
    }

    public_deps += [
      "$flutter_root/flow:flow_unittests",
      "$flutter_root/fml:fml_unittests",
      "$flutter_root/runtime:runtime_unittests",
      "$flutter_root/shell/common:shell_unittests",
      "$flutter_root/shell/platform/embedder:embedder_unittests",
      "$flutter_root/shell/platform/embedder:embedder_a11y_unittests", # TODO(cbracken) build these into a different kernel blob in the embedder tests and load that in a test in embedder_unittests
      "$flutter_root/synchronization:synchronization_unittests",
      "$flutter_root/third_party/txt:txt_unittests",
    ]

    if (!is_win) {
      public_deps += [ "$flutter_root/shell/common:shell_benchmarks" ]
    }
  }
}

config("config") {
  include_dirs = [ ".." ]
}

group("dist") {
  testonly = true

  deps = [
    "$flutter_root/sky/dist",
  ]
}

foreach(snapshot, _flutter_sdk_snapshots) {
  copy("copy_flutter_${snapshot[0]}_snapshot") {
    deps = [
      snapshot[1],
    ]
    sources = [
      "$root_gen_dir/${snapshot[0]}.dart.snapshot",
    ]
    outputs = [
      "$root_out_dir/dart-sdk/bin/snapshots/flutter_{{source_file_part}}",
    ]
  }
}

copy("dart2js_platform_files") {
  deps = [
    "//third_party/dart/utils/compiler:compile_dart2js_platform"
  ]

  sources = [
    "$root_out_dir/dart2js_outline.dill",
    "$root_out_dir/dart2js_platform.dill",
  ]

  outputs = [
    "$root_out_dir/flutter_patched_sdk/{{source_file_part}}",
  ]
}


prebuilt_dart_action("flutter_dartdevc_kernel_sdk") {
  deps = [
     "//third_party/dart:create_sdk",
  ]

  packages = "//third_party/dart/.packages"

  script = "//third_party/dart/pkg/dev_compiler/tool/kernel_sdk.dart"

  inputs = [
    "//third_party/dart/pkg/dev_compiler/tool/kernel_sdk.dart",
  ]

  outputs = [
    "$target_gen_dir/kernel/amd/dart_sdk.js",
    "$target_gen_dir/kernel/amd/dart_sdk.js.map",
    "$target_gen_dir/kernel/common/dart_sdk.js",
    "$target_gen_dir/kernel/common/dart_sdk.js.map",
    "$target_gen_dir/kernel/es6/dart_sdk.js",
    "$target_gen_dir/kernel/es6/dart_sdk.js.map",
    "$target_gen_dir/kernel/legacy/dart_sdk.js",
    "$target_gen_dir/kernel/legacy/dart_sdk.js.map",
  ]

  libraries_path = rebase_path("$flutter_root/lib/snapshot/libraries.json")
  output_path = rebase_path("$target_gen_dir/kernel/flutter_ddc_sdk.dill")

  args = [
    "--output=$output_path",
    "--libraries=$libraries_path",
  ]
}
複製程式碼

ninja配置檔案

通過GN工具生成配置檔案之後會在out目錄中生成相關的Ninja配置檔案

!!! info "GN產生的檔案說明"

* args.gn  # 使用`GN`工具構建是生成的配置引數,可以驗證配置引數是否正確
* build.ninja # Ninja 配置檔案,也是預設的編譯指令碼
* build.ninja.d # GN 產生構建檔案查詢的檔案路徑
複製程式碼

編譯完成之後,我們來了解一下目錄的內容,詳細的編譯檔案的內容,我們在下一篇中在進行詳細說明

➜  android_debug_unopt_x86 git:(master) ✗ tree -L 3
.
├── all.xcworkspace
│   └── contents.xcworkspacedata
├── args.gn  # 使用`GN`工具構建是生成的配置引數,可以驗證配置引數是否正確
├── build.ninja # Ninja 配置檔案,也是預設的編譯指令碼
├── build.ninja.d # GN 產生構建檔案查詢的檔案路徑
├── clang_x64
│   ├── obj
│   │   └── third_party
│   └── toolchain.ninja
├── clang_x86
│   ├── obj
│   │   └── third_party
│   └── toolchain.ninja
├── dart-sdk
│   └── bin
│       └── snapshots
├── gyp-mac-tool
├── obj
│   ├── flutter
│   │   ├── assets
│   │   ├── benchmarking
│   │   ├── common
│   │   ├── flow
│   │   ├── fml
│   │   ├── lib
│   │   ├── runtime
│   │   ├── shell
│   │   ├── synchronization
│   │   ├── testing
│   │   ├── third_party
│   │   └── vulkan
│   └── third_party
│       ├── android_tools
│       ├── benchmark
│       ├── boringssl
│       ├── cpu-features
│       ├── dart
│       ├── expat
│       ├── freetype2
│       ├── googletest
│       ├── harfbuzz
│       ├── icu
│       ├── libcxx
│       ├── libcxxabi
│       ├── libjpeg-turbo
│       ├── libpng
│       ├── libwebp
│       ├── rapidjson
│       ├── skia
│       ├── tonic
│       └── zlib
├── products.xcodeproj
│   └── project.pbxproj
└── toolchain.ninja

45 directories, 9 files
複製程式碼

args.gn

skia_enable_pdf = false
enable_lto = false
use_clang_static_analyzer = false
full_dart_sdk = false
dart_runtime_mode = "develop"
skia_use_fontconfig = false
skia_use_dng_sdk = false
skia_enable_flutter_defines = true
use_goma = false
dart_custom_version_for_pub = "flutter"
embedder_for_target = false
is_official_build = true
host_cpu = "x86"
is_clang = true
skia_use_sfntly = false
dart_target_arch = "x86"
flutter_runtime_mode = "debug"
goma_dir = "None"
android_full_debug = true
target_os = "android"
mac_sdk_path = ""
skia_use_x11 = false
enable_coverage = false
target_cpu = "x86"
skia_use_expat = true
dart_lib_export_symbols = false
is_debug = true
flutter_aot = false

複製程式碼

build.ninja

記錄編譯的相關連檔案的時間戳來跟蹤原始碼的變化資訊

ninja_required_version = 1.7.2

rule gn
  command = ../../buildtools/mac-x64/gn --root=../.. -q --check --ide=xcode gen .
  description = Regenerating ninja files

build build.ninja: gn
  generator = 1
  depfile = build.ninja.d

subninja toolchain.ninja
subninja clang_x64/toolchain.ninja
subninja clang_x86/toolchain.ninja

build default: phony obj/default.stamp
build dist: phony obj/dist.stamp
build flutter: phony obj/flutter/flutter.stamp
build _http: phony obj/flutter/sky/packages/sky_engine/_http.stamp
build android: phony obj/flutter/shell/platform/android/android.stamp
build android_arch_lifecycle_common: phony obj/flutter/shell/platform/android/android_arch_lifecycle_common.stamp

build all: phony $
    obj/default.stamp $
    obj/dist.stamp $
    ...........
    obj/third_party/zlib/libzlib_x86_simd.a

default default

複製程式碼

build.ninja.d

該檔案中記錄了GN檔案儲存的構建檔案的路徑,在GN完成之後生成的檔案依賴路徑中的檔案可以在檔案中找到,這個檔案記錄了編譯是的所有檔案會從這些檔案的路徑中注意查詢

build.ninja: ../../BUILD.gn
../../build/compiled_action.gni
../../build/config/BUILD.gn
.........
../../third_party/tonic/scopes/BUILD.gn
../../third_party/tonic/typed_data/BUILD.gn
../../third_party/zlib/BUILD.gn
複製程式碼

總結

我們分析了使用GN工具對相關的原始檔和配置引數進行設定,不同平臺版本,統一平臺的不同模式的編譯依賴檔案有所不同,最終最在out目錄中生成給ninja編譯器需要的配置檔案,通過原始檔的學習,我們更能夠理解FlutterEngine目錄下的原始碼的目錄結構和使用到的內容依賴,配置引數和生成的清單檔案,接下了就需要學習如何使用編譯命令和引數,以及生成的檔案包含哪些內容,我們將通過下一篇的學習來讀Flutter編譯產物和作用有一個更加深入的瞭解。

執行編譯命令

NinjaComplie ninja -C out/android_debug_unopt_x86開始編譯android_debug_unopt_x86目錄下GN生成的構建檔案關聯的原始檔,讀取android_debug_unopt_x86目錄下的engine/src/out/android_debug_unopt_x86/build.ninja從該檔案開始查詢

相關文章