
Sebagian besar orang terbiasa dengan fakta bahwa Chromium adalah peramban dan dasar bagi peramban lain. Sampai baru-baru ini, saya juga berpikir begitu, tetapi, mempelajari topik ini selama beberapa bulan, saya mulai menemukan dunia lain yang indah. Chromium adalah ekosistem besar di mana ada segalanya: sistem ketergantungan, sistem pembangunan lintas platform, dan komponen untuk hampir semua kesempatan. Jadi mengapa tidak mencoba membuat aplikasi sendiri menggunakan semua kekuatan ini?
Di bawah kat, panduan kecil tentang cara mulai melakukan ini.
Persiapan lingkungan
Dalam artikel saya akan menggunakan Ubuntu 18.04, prosedur untuk OS lain dapat ditemukan dalam dokumentasi:
Langkah-langkah berikut membutuhkan Git dan Python. Jika mereka tidak diinstal, maka mereka harus diinstal menggunakan perintah:
sudo apt install git python
Pengaturan depot_tools
depot_tools
adalah toolkit pengembangan Chromium. Untuk menginstalnya, Anda harus melakukan:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
Dan tambahkan path ke variabel lingkungan PATH:
export PATH="$PATH:/path/to/depot_tools"
Penting: jika
depot_tools
diunduh ke folder rumah Anda, jangan gunakan
~
dalam variabel
PATH
, jika tidak, masalah dapat terjadi. Anda harus menggunakan variabel
$HOME
:
export PATH="$PATH:${HOME}/depot_tools"
Pengambilan kode
Pertama, Anda perlu membuat folder untuk sumbernya. Misalnya, di direktori home (dibutuhkan ruang kosong sekitar 30 GB):
mkdir ~/chromium && cd ~/chromium
Setelah itu, Anda dapat mengunduh sumber menggunakan utilitas
fetch
dari
depot_tools
:
fetch --nohooks --no-history chromium
Sekarang Anda bisa minum teh / kopi, karena prosedurnya tidak cepat. Untuk percobaan, tidak diperlukan riwayat, sehingga bendera
--no-history
digunakan. Ceritanya akan lebih panjang.
Instalasi Ketergantungan
Semua sumber ada di folder
src
, buka:
cd src
Sekarang Anda harus meletakkan semua dependensi menggunakan skrip:
./build/install-build-deps.sh
Dan jalankan hooks:
gclient runhooks
Ini melengkapi persiapan lingkungan.
Membangun sistem
Ninja digunakan sebagai sistem perakitan utama untuk Chromium, dan utilitas
GN digunakan untuk menghasilkan file
.ninja
.
Untuk memahami cara menggunakan alat ini, saya mengusulkan untuk membuat contoh utilitas pengujian. Untuk melakukan ini, buat
example
subfolder di folder
src
:
mkdir example
Kemudian, di folder
src/example
, buat file
BUILD.gn
, yang berisi:
executable("example") { sources = [ "example.cc", ] }
BUILD.gn
terdiri dari target (
example
executable) dan daftar file yang diperlukan untuk membangun target.
Langkah selanjutnya adalah membuat file
example.cc
itu sendiri. Untuk memulai, saya mengusulkan untuk membuat aplikasi klasik "Hello world":
#include <iostream> int main(int argc, char **argv) { std::cout << "Hello world" << std::endl; return 0; }
Kode sumber dapat ditemukan di
GitHub .
Agar GN dapat mempelajari tentang proyek baru, dalam file
BUILD.gn
terletak di
src
, tambahkan baris
"//example"
di bagian
deps
:
... group("gn_all") { testonly = true deps = [ ":gn_visibility", "//base:base_perftests", "//base:base_unittests", "//base/util:base_util_unittests", "//chrome/installer", "//chrome/updater", "//net:net_unittests", "//services:services_unittests", "//services/service_manager/public/cpp", "//skia:skia_unittests", "//sql:sql_unittests", "//third_party/flatbuffers:flatbuffers_unittests", "//tools/binary_size:binary_size_trybot_py", "//tools/ipc_fuzzer:ipc_fuzzer_all", "//tools/metrics:metrics_metadata", "//ui/base:ui_base_unittests", "//ui/gfx:gfx_unittests", "//url:url_unittests", # ↓↓↓↓↓↓↓↓ "//example", ] ...
Sekarang Anda perlu kembali ke folder
src
dan menghasilkan proyek menggunakan perintah:
gn gen out/Default
GN juga memungkinkan Anda menyiapkan proyek untuk salah satu IDE yang didukung:
- gerhana
- vs.
- vs2013
- vs2015
- vs2017
- vs2019
- xcode
- qtcreator
- json
Informasi lebih lanjut dapat diperoleh dengan menggunakan perintah:
gn help gen
Misalnya, untuk bekerja dengan proyek
example
di
QtCreator, Anda perlu menjalankan perintah:
gn gen --ide=qtcreator --root-target=example out/Default
Setelah itu, Anda dapat membuka proyek di QtCreator:
qtcreator out/Default/qtcreator_project/all.creator
Langkah terakhir adalah membangun proyek menggunakan Ninja:
autoninja -C out/Default example
Pengantar singkat tentang sistem perakitan ini dapat diselesaikan.
Aplikasi dapat diluncurkan menggunakan perintah:
./out/Default/example
Dan lihat Hello world. Bahkan, Anda dapat menulis artikel terpisah tentang sistem perakitan di Chromium. Mungkin bukan satu.
Bekerja dengan baris perintah
Sebagai contoh pertama menggunakan basis kode Chromium sebagai kerangka kerja, saya sarankan bermain-main dengan baris perintah.
Tugas:
menampilkan semua argumen yang diteruskan ke aplikasi dalam gaya Chromium.Untuk bekerja dengan baris perintah, Anda harus menyertakan file header di example.cc:
Dan juga kita tidak boleh lupa untuk menambahkan ketergantungan pada proyek
base
di
BUILD.gn
.
BUILD.gn
akan terlihat seperti ini:
executable("example") { sources = [ "example.cc", ] deps = [ "//base", ] }
Sekarang semua yang Anda butuhkan akan terhubung ke
example
.
Untuk bekerja dengan baris perintah, Chromium menyediakan
base::CommandLine
tunggal
base::CommandLine
. Untuk mendapatkan tautan ke sana, Anda perlu menggunakan
base::CommandLine::ForCurrentProcess
metode statis
base::CommandLine::ForCurrentProcess
, tetapi pertama-tama Anda perlu menginisialisasi menggunakan
base::CommandLine::Init
Metode
base::CommandLine::Init
:
base::CommandLine::Init(argc, argv); auto *cmd_line = base::CommandLine::ForCurrentProcess();
Semua argumen yang diteruskan ke aplikasi pada baris perintah dan dimulai dengan a
-
dikembalikan sebagai
base::SwitchMap
(pada dasarnya
map<string, string>
) menggunakan metode
GetSwitches
. Semua argumen lain dikembalikan sebagai
base::StringVector
(pada dasarnya
vectr<strig>
). Pengetahuan ini cukup untuk mengimplementasikan kode untuk tugas:
for (const auto &sw : cmd_line->GetSwitches()) { std::cout << "Switch " << sw.first << ": " << sw.second << std::endl; } for (const auto &arg: cmd_line->GetArgs()) { std::cout << "Arg " << arg << std::endl; }
Versi lengkap dapat ditemukan di
GitHub .
Untuk membangun dan menjalankan aplikasi, Anda perlu menjalankan:
autoninja -C out/Default example ./out/Default/example arg1 --sw1=val1 --sw2 arg2
Layar akan menampilkan:
Switch sw1: val1 Switch sw2: Arg arg1 Arg arg2
Jaringan
Sebagai contoh kedua dan terakhir untuk hari ini, saya mengusulkan untuk bekerja dengan bagian jaringan Chromium.
Tugas:
menampilkan konten URL yang diteruskan sebagai argumen .
Subsistem Jaringan Chromium
Subsistem jaringan cukup besar dan kompleks. Titik masuk untuk permintaan HTTP, HTTPS, FTP dan sumber daya data lainnya adalah
URLRequest
, yang sudah menentukan klien mana yang akan digunakan. Diagram yang disederhanakan terlihat seperti ini:
Versi lengkap dapat ditemukan di dokumentasi .Untuk membuat
URLRequest
Anda harus menggunakan
URLRequestContext
. Membuat konteks adalah operasi yang agak rumit, oleh karena itu disarankan untuk menggunakan
URLRequestContextBuilder
. Ini akan menginisialisasi semua variabel yang diperlukan dengan nilai default, tetapi, jika diinginkan, mereka dapat diubah sendiri, misalnya:
net::URLRequestContextBuilder context_builder; context_builder.DisableHttpCache(); context_builder.SetSpdyAndQuicEnabled(true , false ); context_builder.SetCookieStore(nullptr);
Multithreading
Tumpukan jaringan Chromium dirancang untuk bekerja di lingkungan multi-utas, sehingga Anda tidak dapat melewati topik ini. Objek dasar untuk bekerja dengan multithreading di Chromium adalah:
- Tugas - tugas untuk dieksekusi, di Chromium itu adalah fungsi dari tipe
base::Callback
, yang dapat dibuat menggunakan base::Bind
.
- Antrian tugas - antrian tugas untuk dieksekusi.
- Fisik thread - pembungkus lintas platform di atas sistem operasi thread (
pthread
pada POSIX atau CreateThread()
pada Windows). Diterapkan dalam base::PlatformThread
kelas base::PlatformThread
, jangan gunakan secara langsung.
- base :: Utas - utas nyata yang memproses pesan dari antrian tugas khusus tanpa henti; Tidak disarankan untuk membuatnya secara langsung.
- Thread pool - pool thread dengan antrian tugas umum. Diimplementasikan dalam
base::ThreadPool
kelas base::ThreadPool
. Sebagai aturan, buat satu instance. Tugas dikirim ke sana menggunakan fungsi dari base/task/post_task.h
.
- Urutan atau Urutan virtual - utas virtual yang menggunakan utas nyata dan dapat beralih di antara mereka.
- Pelari tugas - antarmuka untuk mengatur tugas, diimplementasikan di
base::TaskRunner
.
- Pelari tugas berurutan - antarmuka untuk mengatur tugas, yang memastikan bahwa tugas akan dieksekusi dalam urutan yang sama dengan saat mereka tiba. Diimplementasikan dalam
base::SequencedTaskRunner
kelas base::SequencedTaskRunner
.
- Pelari tugas utas tunggal - mirip dengan yang sebelumnya, tetapi menjamin bahwa semua tugas akan dilakukan dalam satu utas OS. Diterapkan dalam
base::SingleThreadTaskRunner
.
Implementasi
Beberapa komponen Chromium memerlukan kehadiran
base::AtExitManager
- ini adalah kelas yang memungkinkan Anda untuk mendaftarkan operasi yang harus dilakukan ketika aplikasi berakhir. Menggunakannya sangat sederhana, Anda perlu membuat objek di stack:
base::AtExitManager exit_manager;
Ketika
exit_manager
keluar dari ruang lingkup, semua panggilan balik yang terdaftar akan dieksekusi.
Sekarang Anda perlu menjaga ketersediaan semua komponen multithreading yang diperlukan untuk subsistem jaringan. Untuk melakukan ini, buat kumpulan
Thread pool
,
Message loop
dengan tipe
TYPE_IO
untuk memproses pesan jaringan, dan
Run loop
- loop program utama:
base::ThreadPool::CreateAndStartWithDefaultParams("downloader"); base::MessageLoop msg_loop(base::MessageLoop::TYPE_IO); base::RunLoop run_loop;
Selanjutnya, gunakan
Context builder
untuk membuat
Context
:
auto ctx = net::URLRequestContextBuilder().Build();
Untuk mengirim permintaan, Anda harus membuat objek
URLRequest
menggunakan metode
CreateRequest
dari objek
ctx
. Parameter berikut dilewatkan:
- URL, string dengan tipe GURL;
- prioritas;
- delegasikan yang menangani acara.
Delegasi adalah kelas yang mengimplementasikan antarmuka
net::URLRequest::Delegate
. Untuk tugas ini, mungkin terlihat seperti ini:
class MyDelegate : public net::URLRequest::Delegate { public: explicit MyDelegate(base::Closure quit_closure) : quit_closure_(std::move(quit_closure)), buf_(base::MakeRefCounted<net::IOBuffer>(BUF_SZ)) {} void OnReceivedRedirect(net::URLRequest *request, const net::RedirectInfo &redirect_info, bool *defer_redirect) override { std::cerr << "redirect to " << redirect_info.new_url << std::endl; } void OnAuthRequired(net::URLRequest* request, const net::AuthChallengeInfo& auth_info) override { std::cerr << "auth req" << std::endl; } void OnCertificateRequested(net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) override { std::cerr << "cert req" << std::endl; } void OnSSLCertificateError(net::URLRequest* request, int net_error, const net::SSLInfo& ssl_info, bool fatal) override { std::cerr << "cert err" << std::endl; } void OnResponseStarted(net::URLRequest *request, int net_error) override { std::cerr << "resp started" << std::endl; while (true) { auto n = request->Read(buf_.get(), BUF_SZ); std::cerr << "resp read " << n << std::endl; if (n == net::ERR_IO_PENDING) return; if (n <= 0) { OnReadCompleted(request, n); return; } std::cout << std::string(buf_->data(), n) << std::endl; } } void OnReadCompleted(net::URLRequest *request, int bytes_read) override { std::cerr << "completed" << std::endl; quit_closure_.Run(); } private: base::Closure quit_closure_; scoped_refptr<net::IOBuffer> buf_; };
Semua logika utama ada di event
OnResponseStarted
: isi respons dikurangi sampai kesalahan terjadi atau tidak ada yang dibaca. Karena setelah membaca respons yang Anda butuhkan untuk menyelesaikan aplikasi, delegasi harus memiliki akses ke fungsi yang akan mengganggu
Run loop
utama, dalam hal ini panggilan balik dari tipe
base::Closure
digunakan.
Sekarang semuanya siap untuk mengirim permintaan:
MyDelegate delegate(run_loop.QuitClosure()); auto req = ctx->CreateRequest(GURL(args[0]), net::RequestPriority::DEFAULT_PRIORITY, &delegate); req->Start();
Untuk permintaan untuk mulai memproses, Anda perlu menjalankan
Run loop
:
run_loop.Run();
Versi lengkap dapat ditemukan di
GitHub .
Untuk membangun dan menjalankan aplikasi, Anda perlu menjalankan:
autoninja -C out/Default example out/Default/example "https://example.com/"
Terakhir
Bahkan, di Chromium Anda dapat menemukan banyak kubus dan batu bata yang berguna untuk membangun aplikasi. Ini terus berkembang, yang, di satu sisi, merupakan nilai tambah, dan di sisi lain, perubahan reguler pada API tidak membuat Anda rileks. Misalnya, dalam rilis terbaru,
base::TaskScheduler
berubah menjadi
base::ThreadPool
, untungnya, tanpa mengubah API.
PS Kami mencari programmer C ++ terkemuka di tim kami! Jika Anda merasakan kekuatan dalam diri Anda, maka keinginan kami dijelaskan di sini:
team.mail.ru/vacancy/4641/ . Ada juga tombol "Tanggapi".