「Chromium」の版間の差分

提供:senooken JP Wiki
(Option)
 
(同じ利用者による、間の11版が非表示)
1行目: 1行目:
== About ==
== About ==
ChromiumはOSSのWebブラウザー。Google Chromeのベースコードになっている。
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 ==
出典:
* [https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/threading_and_tasks.md Chromium Docs - Threading and Tasks in Chrome]
* [https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/callback.md Chromium Docs - OnceCallback<> and BindOnce(), RepeatingCallback<> and BindRepeating()]
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 ==
== Debug ==
12行目: 114行目:
* [https://www.chromium.org/for-testers/enable-logging/ How to enable logging]
* [https://www.chromium.org/for-testers/enable-logging/ How to enable logging]
* [https://chromium.googlesource.com/chromium/src/+/refs/heads/main/base/logging.h base/logging.h - chromium/src - Git at Google]
* [https://chromium.googlesource.com/chromium/src/+/refs/heads/main/base/logging.h base/logging.h - chromium/src - Git at Google]
* [https://groups.google.com/a/chromium.org/g/chromium-dev/c/3NDNd1KzXeY ATTENTION: Use VLOG() instead of LOG(INFO)]


DLOG/DVLOGはis_debug=trueのときのみ有効になる。
DLOG/DVLOGはis_debug=trueのときのみ有効になる。
18行目: 121行目:
* --v=0: VLOG/DVLOGの出力ログの制御。
* --v=0: VLOG/DVLOGの出力ログの制御。
* --enable-logging: is_debug=falseでもログ出力する?
* --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 ===
=== Stacktrace ===
23行目: 136行目:
  #include "base/logging.h"
  #include "base/logging.h"
  #include "base/debug/stack_trace.h"
  #include "base/debug/stack_trace.h"
   
  VLOG(0) << base::debug::StackTrace();
LOG(ERROR) << base::debug::StackTrace();
  base::debug::StackTrace().Print(); // stderr
  base::debug::StackTrace().Print(); // stderr


34行目: 146行目:
=== Option ===
=== Option ===
起動オプションは [[https://chromium.googlesource.com/chromium/src/+/refs/heads/main/content/public/common/content_switches.cc content/public/common/content_switches.cc - chromium/src - Git at Google]] のソースコードにある。
起動オプションは [[https://chromium.googlesource.com/chromium/src/+/refs/heads/main/content/public/common/content_switches.cc content/public/common/content_switches.cc - chromium/src - Git at Google]] のソースコードにある。
== GN ==
情報源:
* [https://gn.googlesource.com/gn/+/main main - gn - Git at Google]
* [https://gn.googlesource.com/gn/+/main/docs/language.md GN Language and Operation]
GNはChromiumで採用されているBUILD.gnのビルド設定記述言語。
=== GN build configuration ===
情報源: [https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/gn-build-configuration.md 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用のソースファイルのリスト。

2024年1月31日 (水) 11:24時点における最新版

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用のソースファイルのリスト。