Neunomizuの日記

俺だけが俺だけじゃない

Firefoxのブックマーク機能を変えた

tags: 情報

大規模ソフトウェアを手探るという授業の一環でやっています

Firefoxのビルドに関して

前回の記事を読んで下さい

propyon.hateblo.jp

現在のブックマーク機能

現在のFirefoxのブックマーク機能では常にデフォルトの保存先フォルダ(Other Bookmarks)に保存することが決まっています

これを,最後にブックマークを保存したフォルダに随時変更するようにしたいと思いました

変更されたブックマーク機能

ということで,ブラウザが開いている間にブックマークしたページの最新の保存先にデフォルトのフォルダが更新されるように変更を加えました

加えて,その機能をToggleできるようにしました

デフォルトの保存先を変更するためのソースコード

結局ソースコードを見るのが一番わかるはずです

デフォルトの保存先フォルダを変更するために修正を加える必要があるのはbrowser/base/content/browser-placesにあるparentGuidです

この変数が保存先フォルダを指しています

最初の実装では別にLAST_USED_PARENT_IDというグローバル変数を作り,これで最後に保存したフォルダを記憶し,これをparentGuidに代入するようにしました

diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index 809e6b642f..9e567ad831 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -5,6 +5,8 @@
 // This file is loaded into the browser window scope.
 /* eslint-env mozilla/browser-window */ 
+var LAST_USED_PARENT_ID = undefined;

 XPCOMUtils.defineLazyScriptGetter(
   this,
   ["PlacesToolbar", "PlacesMenu", "PlacesPanelview", "PlacesPanelMenuView"],
@@ -70,6 +72,7 @@ var StarUI = {
         clearTimeout(this._autoCloseTimer);
         if (aEvent.originalTarget == this.panel) {
           let selectedFolderGuid = gEditItemOverlay.selectedFolderGuid;
+          LAST_USED_PARENT_ID = selectedFolderGuid;
           gEditItemOverlay.uninitPanel(true);
 
           this._anchorElement.removeAttribute("open");
@@ -444,7 +447,12 @@ var PlacesCommandHook = {
     let isNewBookmark = !info;
     let showEditUI = !isNewBookmark || StarUI.showForNewBookmarks;
     if (isNewBookmark) {
-      let parentGuid = PlacesUtils.bookmarks.unfiledGuid;
+      let parentGuid;
+      if (LAST_USED_PARENT_ID !== undefined) {
+        parentGuid = LAST_USED_PARENT_ID;
+      } else {
+        parentGuid = PlacesUtils.bookmarks.unfiledGuid;
+      }
       info = { url, parentGuid };
       // Bug 1148838 - Make this code work for full page plugins.
       let charset = null;

しかし,これは安全なコードではないのでグローバル変数をなくすために以下のように書き直しました

diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index 809e6b642f..994d573568 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -28,6 +28,7 @@ var StarUI = {
   // in browser/components/pocket/content/panels/js/saved.js.
   _autoCloseTimeout: 3500,
   _removeBookmarksOnPopupHidden: false,
+  _lastUsedParentId : undefined,
 
   _element(aID) {
     return document.getElementById(aID);
@@ -70,6 +71,7 @@ var StarUI = {
         clearTimeout(this._autoCloseTimer);
         if (aEvent.originalTarget == this.panel) {
           let selectedFolderGuid = gEditItemOverlay.selectedFolderGuid;
+          this._lastUsedParentId = selectedFolderGuid;
           gEditItemOverlay.uninitPanel(true);
 
           this._anchorElement.removeAttribute("open");
@@ -443,8 +445,14 @@ var PlacesCommandHook = {
     let info = await PlacesUtils.bookmarks.fetch({ url });
     let isNewBookmark = !info;
     let showEditUI = !isNewBookmark || StarUI.showForNewBookmarks;
+    let lastUsedParentId = StarUI._lastUsedParentId;
     if (isNewBookmark) {
-      let parentGuid = PlacesUtils.bookmarks.unfiledGuid;
+      let parentGuid;
+      if (lastUsedParentId !== undefined) {
+        parentGuid = lastUsedParentId;
+      } else {
+        parentGuid = PlacesUtils.bookmarks.unfiledGuid;
+      }
       info = { url, parentGuid };
       // Bug 1148838 - Make this code work for full page plugins.
       let charset = null;

ついでにJSのお作法を知らなかったのでそこも直しました

Javascriptでのnullは何もない値とこちらから決めた値です.しかし上ではundefinedが使われています

つまりundefinedは意図的に定める値ではないのにここでは定められています.それをnullに変更

diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index 994d573568..ae8041e65e 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -28,7 +28,7 @@ var StarUI = {
   // in browser/components/pocket/content/panels/js/saved.js.
   _autoCloseTimeout: 3500,
   _removeBookmarksOnPopupHidden: false,
-  _lastUsedParentId : undefined,
+  _lastUsedParentId: null,
 
   _element(aID) {
     return document.getElementById(aID);
@@ -448,7 +448,7 @@ var PlacesCommandHook = {
     let lastUsedParentId = StarUI._lastUsedParentId;
     if (isNewBookmark) {
       let parentGuid;
-      if (lastUsedParentId !== undefined) {
+      if (lastUsedParentId !== null) {
         parentGuid = lastUsedParentId;
       } else {
         parentGuid = PlacesUtils.bookmarks.unfiledGuid;
diff --git a/done.txt b/done.txt
new file mode 100644
index 0000000000..cfa2b8818c
--- /dev/null
+++ b/done.txt
@@ -0,0 +1,38 @@

これで完成です.本当に少ししかいじっていないし,僕は大規模ソフトウェアの表面をなぞっているだけだ...と若干鬱です

Toggleするためのソースコード

上の機能を使用したくない人もいると思います.ということで切り替えができるようにしました

既存のFirefoxにはブックマークをした時に,ブックマーク先をどうするか選ぶためのエディタ(下の画像の通り)が開くかどうかをToggleできます.これをパクって利用してやろうということになりました

ブックマークエディタ

"Show editor when saving"がデフォルトの部分

"Use default folder"が今回追加した部分

実際にコードを変更したのは次の4箇所です

firefox.js

ここではtoggleするために必要な変数を設定しています.デフォルトだとtrueにしてあります(つまり,最後の保存先フォルダを記憶しない設定にしてあります)

diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index 2bbfc67da2..7606fad678 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1009,6 +1009,9 @@ pref("browser.privatebrowsing.autostart", false);
 // Whether the bookmark panel should be shown when bookmarking a page.
 pref("browser.bookmarks.editDialog.showForNewBookmarks", true);
 
+// Whether the default bookmark foulder should be shown when bookmarking a page
+pref("browser.bookmarks.editDialog.toggleDefaultFolder", true);
+
 // Don't try to alter this pref, it'll be reset the next time you use the
 // bookmarking dialog
 pref("browser.bookmarks.editDialog.firstEditField", "namePicker");

browser-places.js

ここでは実際にブラウザ上でブックマークをした際にtoggleに必要な変数が変更がされるようにしています

何が起こっているのかはおそらく多少プログラミングをしたことがある人にはわかるでしょ.ただ,わからないという人もいると思うので説明しておきます

下から説明します

  • if構文から説明します.ここではtoggleボタンで最後の保存先をフォルダを使うかどうか決めています
  • 次のonToggleDefaultFolderCheckboxではチェックボックスがチェックされているかに応じてブックマークの設定を決める値にブール値を設定しています
  • 次のthis._elementの部分ではjavascriptの文法がよくわからないのですが,thisの中にthis.toggleDefaultFolderの値を代入しています
  • getの部分はthis.toggleDefaultFolderで呼び出された際にbrowser.bookmarks.editDialog.toggleDefaultFolderのブール値を返します

この部分はブックマークエディタでチェックを入れたり,消した際に呼び出される関数郡が書かれています

diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index ae8041e65e..aa8bc2f7b0 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -40,6 +40,12 @@ var StarUI = {
     );
   },
 
+  get toggleDefaultFolder() {
+    return Services.prefs.getBoolPref(
+      "browser.bookmarks.editDialog.toggleDefaultFolder"
+    )
+  },
+
   // Edit-bookmark panel
   get panel() {
     delete this.panel;
@@ -221,6 +227,10 @@ var StarUI = {
       "editBookmarkPanel_showForNewBookmarks"
     ).checked = this.showForNewBookmarks;
 
+    this._element(
+      "editBookmarkPanel_toggleDefaultFolder"
+    ).checked = this.toggleDefaultFolder;
+
     this._itemGuids = [];
     await PlacesUtils.bookmarks.fetch({ url: aUrl }, bookmark =>
       this._itemGuids.push(bookmark.guid)
@@ -400,6 +410,13 @@ var StarUI = {
     );
   },
 
+  onToggleDefaultFolderCheckboxCommand() {
+    Services.prefs.setBoolPref(
+      "browser.bookmarks.editDialog.toggleDefaultFolder",
+      this._element("editBookmarkPanel_toggleDefaultFolder").checked
+    );
+  },
+
   showConfirmation() {
     let animationTriggered = LibraryUI.triggerLibraryAnimation("bookmark");
 
@@ -448,10 +465,10 @@ var PlacesCommandHook = {
     let lastUsedParentId = StarUI._lastUsedParentId;
     if (isNewBookmark) {
       let parentGuid;
-      if (lastUsedParentId !== null) {
-        parentGuid = lastUsedParentId;
-      } else {
+      if (StarUI.toggleDefaultFolder || lastUsedParentId === null) {
         parentGuid = PlacesUtils.bookmarks.unfiledGuid;
+      } else {
+        parentGuid = lastUsedParentId;
       }
       info = { url, parentGuid };
       // Bug 1148838 - Make this code work for full page plugins.   

browser.xhtml

ここではブックマークエディタの表示を決めています.checkboxという部分からチェックボックスを作っていることがわかると思います

特に重要なのはoncommandという部分で,ここでチェックされた際に呼び出される関数を決めています

diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml
index e53c9f7f4b..69daa32920 100644
--- a/browser/base/content/browser.xhtml
+++ b/browser/base/content/browser.xhtml
@@ -290,6 +290,13 @@
                   accesskey="&editBookmark.showForNewBookmarks.accesskey;"
                   oncommand="StarUI.onShowForNewBookmarksCheckboxCommand();"/>
       </vbox>
+      <vbox id="editBookmarkPanelBottomContent"
+            flex="1">
+        <checkbox id="editBookmarkPanel_toggleDefaultFolder"
+                  label="&editBookmark.toggleDefaultFolder.label;"
+                  accesskey="&editBookmark.toggleDefaultFolder.accesskey;"
+                  oncommand="StarUI.onToggleDefaultFolderCheckboxCommand();"/>
+      </vbox>
       <hbox id="editBookmarkPanelBottomButtons"
             class="panel-footer"
             style="min-width: &editBookmark.panel.width;;">

browser.dtd

ここはブックマークエディタで表示される文言を設定しています.上で定めたlabelaccesskeyと対応しているとわかると思います

チェックボックスにチェックを加えるとデフォルトのフォルダを使うようにしているので"Use default folder"という文言にしています

diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd
index 0407ec8a0b..1cac2da49b 100644
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -627,6 +627,8 @@ you can use these alternative items. Otherwise, their values should be empty.  -
 <!ENTITY editBookmark.done.label                     "Done">
 <!ENTITY editBookmark.showForNewBookmarks.label       "Show editor when saving">
 <!ENTITY editBookmark.showForNewBookmarks.accesskey   "S">
+<!ENTITY editBookmark.toggleDefaultFolder.label       "Use default folder">
+<!ENTITY editBookmark.toggleDefaultFolder.accesskey   "S">
 
 <!ENTITY identity.connectionSecure3 "Connection secure">
 <!ENTITY identity.connectionNotSecure2 "Connection not secure">

開発に関して

Searchfox, Bugzillaというツールが有効でした

SearchfoxはFirefox用のGoogle検索みたいなもので,変数名などを検索したら色々と出てきます

BugzillaはMozilla(Firefoxを開発しているところ)のIssueが転がっている場所です.関連したIssueを見て勉強に成りました(ソースコードが変わっていてあまり使えなかった)

より使えたのはDeveloper toolsです

このページがわかりやすいです

これらを見ながら機能を推測して,変えて,その結果を眺めるというのを繰り返して開発をしていました

スライド

授業の一環でやったのでスライドにしてあります.以下の通りです

気になったらご覧ください

感想

前回のインターン

大規模ソフトウェアをいじった経験はインターン以来でした(夏にWeb系の企業にインターンに行った)

この時はRuby on Railsをいじっていました

で,そのときに感じたのは,大規模ソフトウェアの開発って変えたい機能に関連する部分をちょこちょこ変えるだけでつまらなくないですか???ということです

そこではタスクが振られて,それをこなすという風に開発をしていたのですが,毎回異なる機能について実装をしていたので新しいことをやれるという反面,毎回同じことを覚える必要があり,「あまりおもしろくない...」と思っていました

今回の実験

しかし,今回はもう少し長い時間同じソフトウェアを触れていたのでまた違った感想を持ちました

開発に関する速度はそのソフトウェアに関する知識を真数とした対数グラフみたいになっていて,だんだん知識が深まると開発も早くなり楽しくなるよねということです

大規模ソフトウェアと言っても挙動を理解するだけならある程度読めばなんとか理解できます

ということで「大規模ソフトウェアも楽しいよ」というのが今回の感想

それと早く「慣れる」速度を高めたいなということです.慣れるのが早ければ早くなるほど多分もっとソフトウェアの開発も楽しめるはずです

最後に

相方と先生,TAの方に感謝

大規模ソフトウェアをいじるといっても大したことはないと思えるように成りました

眺めているだけでも楽しいのでコミットまでできるように頑張りたい

Ubuntu環境について表示する方法

tags: 情報

環境を確認する方法

以下のコマンドを打つと自分の環境をTerminal上で確認できます

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

また,結果をコピーしたいときもあると思います.そのときはxselコマンドを使います

そのため,まずはxselをインストールします

sudo apt install -y xsel 

-yオプションは問い合わせを全てyesで回答するということです

そして,次のようにコマンドを打つと自分の環境に関してコピーができます

cat /etc/os-release | xsel --clipboard --input

参照

OS自作入門に入門した

tags: 情報

OS自作のような問題は楽しくかっこよくセクシーであるべきだ

今学期,OSの授業が始まりました

ハードウェアとソフトウェアの接点であるOSのことを,なかなか面白そうだな,と前々から思っていたので今回は勉強がてら自作を始めてみようと思います

そこで読もうと決めたのがOS自作入門なのですが,この本はWindowsで開発することがデフォになっています

環境構築をする必要があると思います.だからこそ環境構築をする必要があると思っています

環境構築

まずは自分の環境に関して

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

はい.次に色々インストールをします

sudo apt update
sudo apt install -y ghex # バイナリエディタ
sudo apt install -y qemu # エミュレータ
sudo apt install -y nasm  # x86を対象としたアセンブラ

後は書いていくだけみたいなのでやっていきます

Githubにレポジトリを作ったので,何日目にこんなところで詰まったんだなとか思いながら温かく見守って下さい

https://github.com/diohabara/dOS

参考

GitbookとGithub Pagesを使ってMarkdownで書けるブログを作りました

tags: 情報

背景

GitbookとGithub Pagesを使ってローカルで編集したMarkdownファイルからオンライン上で自分の勉強に関するメモを共有できるものが作りたいと思いました

最初はGitbookに全てを書こうと思っていたのですが,インライン数式を"$$"で囲う必要があったのが思った以上に面倒でした

またそのため,Markdownファイルを他で使うこともできずもったいないのでより汎用的な形式で書きたいと思いました

それならばGithub Pagesで数式を書いてしまおうと思ったのですがそれもレイアウトが美しくなく(自分にフロントの経験があれば良いのですが,その勉強をするのも大変なので)上手く両者の良い所取りができるものはないかと探した結果両者を合わせて使うことになりました

どういうものがほしかったのか

ほしいものの条件は以下の通り

  • 数式とコードが普通のMarkdown形式で書ける(再利用可能)
  • ローカルで書けてオンラインで共有できる
  • 他人が編集することが可能

GitbookとGithub Pagesを選んだ理由

なぜ両者を使うことになったかというと他のサービスで上の3条件のどれかが満たせるものが見つからず,両サービスを使うと両立ができるからです

  • Gitbookはmarkdown形式でファイルを書いてそれを使って電子書籍が書けます
    • gitを使って管理するので他の人と共同で編集できます
  • Github Pagesもgitを使ったサービス
    • 自分で設定ができる範囲が広い
    • しかも独自のドメインが使えるので後々便利

また,どちらも仕様が分かっているサービスで新たに学ぶ点が少ないのも選んだ理由

どのような手順でこれをするか

環境構築

npmというNode.jsのパッケージ管理ツールを使います

自分の環境は以下の通りです

NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

次にnodejsnpmについてインストールします

sudo apt install -y nodejs npm

上手くインストールができない場合があるらしいので,エラーが出たら頑張ってください...

それが終わったら,次にgitbookをインストールします

sudo npm install -g gitbook-cli

-gを付けるかどうかはインストール先をグローバルな場所にするかどうかによります.僕はどこでも使うので付けましたが必要ないという人は付けない方が後々面倒に成るかもしれないらしいので気を付けて下さい

Gitbookの使い方

試しに架空のsampleというフォルダを作ってその中でGitbookを作る方法を試してみましょう

$ mkdir sample && cd sample # sampleフォルダを作り,そこへ移動する
$ gitbook init # gitbookを始める
warn: no summary file in this book 
info: create README.md 
info: create SUMMARY.md 
info: initialization is finished 
$ ls # 中身を確認
README.md  SUMMARY.md
$ cat README.md # README.mdの中身を確認
# Introduction

$ cat SUMMARY.md # SUMMARY.mdの中身を確認
# Summary

* [Introduction](README.md)

という風になっています

SUMMARY.mdがフォルダの構造を示すようになっています

SUMMARY.mdを編集して,gitbook initをするとそれに合わせたフォルダ,ファイルを生成してくます

試しにSUMMARY.mdを編集してみます

$ cat SUMMARY.md # SUMMARY.mdを次のように編集
# Summary

* [Introduction](README.md)
* [hoge](hoge/hoge.md)
    * [hogehoge](hoge/hogehoge.md)

$ ls # hogeフォルダが生成されている
hoge  README.md  SUMMARY.md
$ ls hoge/ # hogeフォルダにはhoge.mdとhogehoge.mdが生成されている
hogehoge.md  hoge.md

SUMMARY.mdを書いてから,それに合わせて適宜ファイルを編集するといい感じになるはずです

book.jsonを追加してプラグインを書くことも可能です.最後に自分のbook.jsonを書いておきます

書いた内容を反映するには以下のコマンドを打って下さい

gitbook install

ローカルで出来上がったGitbookを見るにはgitbook serveを実行します.ブラウザ上のURL欄にhttp://localhost:4000/と打つと見ることができます.ちなみにここで作ったファイルは_bookディレクトリ内のものです

最後にビルドをします

gitbook build

これでビルドはできますが,ビルド先のデフォルトは_bookというディレクトリです.これを例えばdocというディレクトリにするには

gitbook build . doc # gitbook build <ビルド対象ディレクトリ> <ビルド先>

というコマンドを打ちます

Github Pages

<ユーザー名>.github.ioというレポジトリをGithub上で作るとそれがそのままGithub Pageになりホームページとして公開されます.しかし,この場合多少の不都合が有ります

下の写真はdiohabara.github.io(僕のGithubのユーザー名はdiohabaraなので)におけるGithub Pagesのソース部分を選択する項目ですが,この場合このレポジトリ内の全てのコードが使われてしまいます

一方,cs-recapというレポジトリ内のSettings→Github PagesではちゃんとSourceという項目を選択できます

cs-recapというレポジトリ内にあるdocsというフォルダを選択すると,diohabara.github.io/docsというURLでdocs以下のファイルのみがホームページ上で公開されます

これによりGitbookで生成する_bookの部分だけを公開でき,無駄にREADME.mdSUMMARY.mdを公開しなくて済むようになります

また,公開する際にGithub Pages側からJekyllだと思われると不都合があるようなので以下のコマンドで.nojekyllファイルを加える必要が有ります

touch .nojekyll

book.jsonの設定

後回しにすると言ったbook.jsonの設定について書きます

自分は以下のように書きました

{
  "title": "CS-Recap",
  "plugins": [
    "katex@git+https://github.com/gaoxiaosong/plugin-katex.git",
    "copy-code-button",
    "search-pro-kui",
    "custom-favicon",
    "image-captions",
    "japanese-support",
    "advanced-emoji",
    "-lunr",
    "-search",
    "-sharing"
  ],
  "pluginsConfig": {
    "favicon": "img/favicon.ico"
  }
}

それぞれ説明するのは面倒なので端折りますが,大事なのはmathjaxの場合,レンダリングに時間がかかりすぎるのでkatexにしたという点です

加えて,デフォルトのものだとインラインで書く際に"$$"で囲う必要があるので有志の方が改造したバージョンを使っているという点です

"katex@git+https://github.com/gaoxiaosong/plugin-katex.git"と書いてある部分がそれです

実際の画面

以下のコードが書かれたMarkdownファイルはビルドされると次のようになります

コード

実際の画面

これを見るとかなりいい感じなのでは?

まとめ

GitbookGithub Pagesを使えばドキュメントをキレイに公開できるのでおすすめです

他にももう少し改造できるらしいですが,これで結構満足しているので十分かも知れません

かなり気に入っているのでそのうちカスタムドメインを取るかもしれません

参照

Firefoxのビルド方法

tags: 情報

動機

EEICの後期実験で「大規模ソフトウェアを手探る」というものを取りました

この実験はチームに分かれて(最低限の目安として)10万行以上のソースコードのソフトウェアの改変,拡張をするというものです

僕はここで以下の点からブラウザのソースコード手探ってみたいと思いました

  • 個人的に改善したい点がある
  • Rustを使っていたりセキュリティに注力していたり技術的に面白そう
  • 非営利団体であるMozillaによって運営されている(他己的な点)
  • ブラウザで使われている技術が幅の広いことから自分でも貢献できる部分はあると思った

というわけで実際にビルドするまでの解説です

ビルド前のSetup

基本的には公式のFirefoxのビルドに関する記事に従います

ただ,自分の環境ではところどころエラーが出たのでそれに関しても適宜話したいと思います

まずはビルド用のディレクトリを作ります

cd && mkdir src # srcでなくてfirefoxでも良い
cd src

bootstrap.pyというファイルをダウンロードし実行します(vscオプションはgitで管理がしたい人のみでそうでない人は付ける必要はありません)

wget https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py -O bootstrap.py
python bootstrap.py --vcs=git

実行をすると

Please choose the version of Firefox you want to build:
  1. Firefox for Desktop Artifact Mode
  2. Firefox for Desktop
  3. GeckoView/Firefox for Android Artifact Mode
  4. GeckoView/Firefox for Android

と聞かれます

Artifact ModeC/C++ソースコードをいじらない人用らしいので僕は2を選択しました

このときに以下のようなエラーが出てきた時は

Executing as root: sudo pip install --upgrade Mercurial
Traceback (most recent call last):
  File "/usr/bin/pip", line 9, in <module>
    from pip import main
ImportError: cannot import name main
Traceback (most recent call last):
  File "bootstrap.py", line 194, in <module>
    sys.exit(main(sys.argv))
  File "bootstrap.py", line 185, in main
    dasboot.bootstrap()
  File "/tmp/tmp0g3sqwqd/mozboot/bootstrap.py", line 451, in bootstrap
  File "/tmp/tmp0g3sqwqd/mozboot/base.py", line 553, in ensure_mercurial_modern
  File "/tmp/tmp0g3sqwqd/mozboot/debian.py", line 184, in upgrade_mercurial
  File "/tmp/tmp0g3sqwqd/mozboot/base.py", line 354, in run_as_root
  File "/home/denjo/.pyenv/versions/3.6.8/lib/python3.6/subprocess.py", line 311, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', 'pip', 'install', '--upgrade', 'Mercurial']' returned non-zero exit status 1.

/etc/apt/sources.list.d/というディレクトリ内のファイルが悪さをしている可能性が有ります

ここはaptapt-getで入れたパッケージの管理ファイルが入っている場所なのでいらなそうなものは消しましょう

僕は全部いらなそうだったので全て削除しました

cd /etc/apt/sources.list.d
rm -rf *

これでエラーが消えました

その後,

How would you like to continue?
  1. Install a modern Mercurial via pip (recommended)
  2. Install a legacy Mercurial via apt
  3. Do not install Mercurial

という選択肢が出てきます

1で試した所エラーが出たので3でやったところ上手く行きました(こわい)

その後,RETURNキーを押すように言われるので言われるがままに押します

そして色々質問が出てきます.

質問形式はYES/NOです.僕は全てyと答えました

下のような文言が出てきたら準備は完了です.次はソースコードcloneしてビルドをします

Installing Stylo and NodeJS packages requires a checkout of mozilla-central.
Once you have such a checkout, please re-run `./mach bootstrap` from the
checkout directory.

ソースコードのダウンロードとビルド

ソースコードのダウンロード

以下のコードでソースコードをダウンロードすることができます

hg clone https://hg.mozilla.org/mozilla-central
cd mozilla-central

オプションに関して

C/C++のファイルを扱わない場合は以下のオプションを./mozconfigに書き込みます

# Automatically download and use compiled C++ components:
# This option will disable C/C++ compilation
ac_add_options --enable-artifact-builds

# Write build artifacts to (not mandatory):
mk_add_options MOZ_OBJDIR=./objdir-frontend

もし,デバッガを使う場合は以下のコードも

ac_add_options --disable-optimize
ac_add_options --enable-debug

いざビルド

最後に以下のコマンドでビルドをします

./mach build

すると以下のようなエラーが..

 0:09.93 ERROR: Cannot find cbindgen. Please run `mach bootstrap`,
 0:09.94 `cargo install cbindgen`, ensure that `cbindgen` is on your PATH,
 0:09.94 or point at an executable with `CBINDGEN`.
 0:09.99 *** Fix above errors and then restart with\
 0:09.99                "./mach build"
 0:09.99 client.mk:111: recipe for target 'configure' failed

ということなので

./mach bootstrap

cargo install cbindge

をします(ちなみに僕は下から読んで焦ってcargoの方からしました)

./mach bootstrapを済ませると

Your system should be ready to build Firefox for Desktop!

というメッセージが...(わくわく)

そして再度

./mach build

をしてみます

夜中に実行して朝見てみると...

If filing a bug, please include the full output of mach, including this error
message.

The details of the failure are as follows:

IOError: [Errno 28] No space left on device

というエラー文が...

どうやら容量が足りなかった模様...

容量の確認

なのでビルドする前には容量の確認をした方が良いでしょう

ncduコマンドを使うと下のようにグラフィカルに容量が確認でき,またvimキーバインド,十字キーディレクトリの移動も可能です

だからncduを以下のコマンドでインストールして先に確認を済ませてから./mach buildをしましょう

sudo apt install ncdu

iキーを押すと詳細も表示してくれます

再びビルド

./mach build

をします

エラーなしで完了した場合

./mach run

をすると以下のような表示が出て成功です

初回のビルドの時間は大体20分でした

メモリは16GBで,CPUはCore i5 vPro 第8世代のPCで行いました