Chromium

提供:senooken JP Wiki

About

ChromiumはOSSのWebブラウザー。Google Chromeのベースコードになっている。

Base

baseディレクトリーに共通のユーティリティーなどがいろいろある。

strings

string_util.h

StartsWith/EndsWith。大文字小文字の区別もできるので便利。

base::StartsWith(label, "WOPI", base::CompareCase::INSENSITIVE_ASCII));

ToLowerASCII

UI

以下が基本。

  • コマンド全般: chrome.browser.ui.browser_command_controller.cc
  • ツールバー: chrome.browser.ui.views.toolbar/toolbar_view.cc
  • ツールメニュー: chrome.browser.ui.toolbar.app_menu_model.cc AppMenuModel::Build
  • コンテキストメニュー (通常): BrowserCommandController::ExecuteCommandWithDisposition
  • コンテキストメニュー (フレーム類): chrome.browser.renderer_context_menu.render_view_context_menu.cc
  • アドレスバー: chrome/browser/ui/views/page_action/page_action_icon_controller.cc
  • 設定画面: chrome/browser/source/settings

bool型でメニューの無効などが決まる。

Bind

出典:

Bindがよく登場するので整理しておく。

PostTask(FROM_HERE, base::BindOnce(cb, 42));

cbがコールバック関数。42がコールバックの引数。

int Floor(float f) {​​​ return std::floor(f); }​​​​​​​​​​
std::string IntToString(int i) {​​​​​​​​​​ return base::NumberToString(i); }​​​​​​​​​​
base::OnceCallback<int(float)> first = Base::BindOnce(&Floor);
base::OnceCallback<std::string(int)> second = Base::BindOnce(&IntToString); 

base::BindOnce/base::BindCallbackでbase::OnceCallback/base::RepeatingCallbackを生成する。

Callbackに引数がある場合、使用するときの引数となる。Bind時の関数に、その引数受取の存在が必要になる。

バインド時に引数を設定することができる。その場合、引数の型は空にする。

void MyFunc(int i, const std::string& str) {​​​​​​​​​​​​​}​​​​​​​​​​​​​​​​​​​​
base::RepeatingCallback<void()> cb = Base::BindRepeating(&MyFunc, 23, "hello world");
// base::RepeatingClosure cb = Base::BindRepeating(&MyFunc, 23, "hello world");
cb.Run();
int Return5() {​​​​​​​​​​​​​​​​​​​ return 5; }​​​​​​​​​​​​​​​​​​​​​​​​​​
base::RepeatingCallback<int()> func_cb = Base::BindRepeating(&Return5);
LOG(INFO) << func_cb.Run();  // Prints 5.

バインド時にインスタンスメソッドを指定する場合は第2引数にthisなどのインスタンスを指定する。staticなどインスタンスメソッドでなければ、インスタンス指定はいらない。

引数が空の場合は、base::OnceClosureと同じ意味になる。つまり、以下は同一。

base::RepeatingCallback<void()>
base::RepeatingClosure<void>

部分的に引数を指定することもできる。例えば、コールバック呼出し時には引数を使いたいが、割り当て時に引数を指定したい時など。

void ReadIntFromFile(const std::string& filename,
                     base::OnceCallback<void(int)> on_read);
void DisplayIntWithPrefix(const std::string& prefix, int result) {​​​​​​​​​​​​​​
  LOG(INFO) << prefix << result;
}​​​​​​​​​​​​​​
void AnotherFunc(const std::string& file) {​​​​​​​​​​​​​​
  ReadIntFromFile(file, base::BindOnce(&DisplayIntWithPrefix, "MyPrefix: "));
}​​​​​​​​​​​​​​;

上記の例だと、コールバックon_readの呼び出し時に引数にintを使用するが、このコールバックの元関数DisplayIntWithPrefixバインド時に第1引数に文字列を設定している。RepeatingCallback/BIndRepeatingは何回も実行できるから、std::moveで渡すのではなく、コピー渡しにする必要がある。 例が分かりにくい。

base/callback.hがわかりやすい。

//   // The lambda takes two arguments, but the first argument |x| is bound at
//   // callback creation.
//   base::OnceCallback<int(int)> cb = base::BindOnce([] (int x, int y) {
//     return x + y;
//   }, 1);
//   // Run() only needs the remaining unbound argument |y|.
//   printf("1 + 2 = %d\n", std::move(cb).Run(2));  // Prints 3
//   printf("cb is null? %s\n",
//          cb.is_null() ? "true" : "false");  // Prints true
//   std::move(cb).Run(2);  // Crashes since |cb| has already run.

OnceCallback/RepeatingCallbackの引数は、[返却型(引数の型)] の書式になる。

Repeating→Onceにはそのまま暗黙に変換できる。逆はできない。

BindRepeatingの関数内で、std::moveしたいなら、引数に渡す際にはstd::refにする。違う。こうしないとクラッシュする。

std::move(cb).Run()
}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​, base::OwnedRef(std::move(cb))

この引数が曲者。

単に変更可能な参照を渡す場合はstd::ref。コピーや既存値の移譲など、値の所有権が必要な場合、base::OwnedRefを使う。

base::BindRepeating/base::BindOnceは右辺値として渡されると、内部ストレージへパラメーターを移譲する。base::BindOnceは問答無用で移譲するが、base::BindRepeatingはbase::Passedを使用したときだけ。

base::BindOnceではstd::move/base::BindRepeatingではbase::Passedで1回だけの処理のパラメーターを移譲する。

  • std::move
  • base::Passed: base::BIndRepeatingでの1回だけのパラメーターの移譲。
  • base::Owned: コールバック削除時にパラメーターも削除。
  • std::ref: 単に変更可能な参照を渡す場合。
  • base::OwnedRef: コピーや既存値の移譲など、値の所有権が必要な場合。
  • base::Unretained
  • base::RetainedRef: 参照を保持し、コールバック実行時に生ポインターを渡す。

Bindする際にラムダ式で関数を生成する場合、キャプチャーは使えない。使おうとするとコンパイルエラーになる。変数を参照したい場合、Bind時に引数を渡してClosureなどにする。

Debug

Logging

ChromiumはLOG/DLOGとVLOG/DVLOGの2系統のログ出力マクロが用意されている。それぞれ対応するオプションが異なる。VLOG/DVLOGが新しくて推奨されている。

情報源

DLOG/DVLOGはis_debug=trueのときのみ有効になる。

  • --log-level=0: LOG/DLOGの出力ログの制御。
  • --v=0: VLOG/DVLOGの出力ログの制御。
  • --enable-logging: is_debug=falseでもログ出力する?

VLOG系は-v=のオプションを指定しない限り出力されないので注意する。

LOG系はオプションなしでも出力される。LOG(INFO)はVLOG(1)相当。

LOG系よりもVLOG系が推奨される。理由は以下。

  • LOG(INFO)をデバッグ目的に使う人がいてINFOのノイズが大きい。
  • VLOGは実行時にモジュール単位で調整可能。
./chrome --v=0 --vmodule=foo=2,bar=3

--v=1で全体のログレベル。vmodule=でfoo.ccのファイル単位でログレベルを変更。

Stacktrace

以下のようなコードでスタックトレースを出力できる (ChromiumOS Docs - How to get a stack trace at runtime for debugging purposes)。

#include "base/logging.h"
#include "base/debug/stack_trace.h"
VLOG(0) << base::debug::StackTrace();
base::debug::StackTrace().Print(); // stderr

CHECK/DCHECK

assert用のマクロがある (Chromium C++ style guide)。

DCHECKはDCHECK_IS_ONがtrueの場合にコンパイルされる。基本はこれを使う。

Option

起動オプションは [content/public/common/content_switches.cc - chromium/src - Git at Google] のソースコードにある。

GN

情報源:

GNはChromiumで採用されているBUILD.gnのビルド設定記述言語。

GN build configuration

情報源: Chromium - GN build configuration

Chromiumのargs.gnのビルド設定で使用できる設定がいくつかある。

  • is_debug=false
  • dcheck_always_on=true
  • is_component_build
  • symol_level
  • enable_nacl
  • remove_webcore_debug_symbols
  • target_cpu
  • use_goma
  • is_official_build
  • is_chrome_branded

Targets

[target] というのがあって、これがビルドグラフのノードになる。一般的には、生成物のバイナリー、ライブラリーを指す。targetは別のtargetに依存する。組み込みのtargetは以下となる。gn help <targettype> で細かい情報を確認できる。

  • action
  • action_foreach
  • bundle_data
  • create_bundle
  • executable
  • group: targetのグループ。
  • shared_library
  • loadable_module
  • source_set: 軽量仮想静的ライブラリー。
  • static_library: .lib/.aファイル (source_setを使ったほうがいい)。

templateを使うことでカスタムtargetタイプを作れる。Chromeでは以下のtemplateを使っている。

  • component: ビルドタイプに応じたsource_setかshred_library。

Variable

Configs

[configs] は名前付きオブジェクト。ディレクトリーやdefineを含むフラグの集合を指定する。[target] に適用され、依存targetに押し込まれる。

以下のように定義する。

config("myconfig") {
  includes = [ "src/include" ]
  defines = [ "ENABLE_DOOM_MELON" ]
}

targetへのconfigの適用には以下のようにする。

executable("doom_melon") {
  configs = [ ":myconfig" ]
}

一般的に、configs += “:myconfig” でデフォルトのリストに追記する。

deps

targetにリンクされる依存関係。

Public configs

targetは依存している他のtargetに設定を適用できる。もっとも一般的な例はサードパーティーtargetだ。適切なコンパイルのためのヘッダーのためのdefineやディレクトリーincludeを必要とする。サードパーティーライブラリーと同様に、そのサードパーティーライブラリーを使用するtargetもコンパイルのために、設定を適用したいでしょう。

このために、適用したい設定のconfigを以下のように書く。

config("my_external_library_config") {
  includes = "."
  defines = [ "DISABLE_JANK" ]
}

それから、以下の記述でこのconfigはpublic configとしてtargetに追加される。これは依存しているtargetと同様にtargetにも両方に適用する。

shared_library("my_external_library") {
  ...
  # Targets that depend on this get this config applied.
  public_configs = [ ":my_external_library_config" ]
}

依存targetは、public_depsとしてあなたのtargetに追加することで、他の依存ツリーレベルを前倒しできる。

static_library("intermediate_library") {
  ...
  # Targets that depend on this one also get the configs from "my external library".
  public_deps = [ ":my_external_library" ]
}

targetは全依存物にconfigを進められる。all_dependent_configとしての設定のリンク境界に達するまで。これは推奨しない。代わりに、フラグの適用場所の制御にはpublic_depsを使う。

Chromeには、build/buildflag_header.gniのビルドフラグヘッダーシステムがある。コンパイラーdefineのdefineのために。

わかりにくいので整理する。

  • public_configs: targetと依存targetの両方に指定したconfigが適用される。
  • public_deps: targetと依存targetの両方に指定したtargetのconfigが適用される。

public_configsがconfig同士なのに対し、public_depsはtarget同士になる。基本はpublic_configsだろうか。

sources

target用のソースファイルのリスト。