
Большинство людей привыкли, что Chromium — это и браузер, и основа для других браузеров. До недавнего времени я тоже так думал, но, изучая эту тему уже пару месяцев, я начал открывать другой дивный мир. Chromium — это огромная экосистема, в которой есть всё: и система зависимостей, и система кроссплатформенной сборки, и компоненты почти на все случаи жизни. Так почему же не попробовать создавать свои приложения, используя всю эту мощь?
Под катом небольшое руководство, как начать это делать.
Подготовка окружения
В статье я буду использовать Ubuntu 18.04, порядок действий для других ОС можно посмотреть в документации:
- Linux
- Windows
- Mac
sudo apt install git python
Установка depot_tools
depot_tools — это набор инструментов для разработки Chromium. Для его установки необходимо выполнить:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
И добавить путь в переменную окружения PATH:
Пару слов про Microsoft Edge на базе Chromium
export PATH=»$PATH:/path/to/depot_tools»
Важно: если depot_tools были скачаны в домашнюю папку, то не используйте ~ в переменной PATH , иначе могут возникнуть проблемы. Необходимо использовать переменную $HOME :
export PATH=»$PATH:$/depot_tools»
Получение кода
Для начала надо создать папку для исходников. Например, в домашней директории (необходимо около 30 Гб свободного места):
mkdir ~/chromium cd ~/chromium
После этого можно скачать исходники с помощью утилиты fetch из depot_tools :
fetch —nohooks —no-history chromium
Теперь можно пойти попить чай/кофе, так как процедура небыстрая. Для экспериментов история не нужна, поэтому используется флаг —no-history . С историей будет ещё дольше.
Установка зависимостей
Все исходники лежат в папке src , идём в неё:
cd src
Теперь нужно поставить все зависимости с помощью скрипта:
./build/install-build-deps.sh
И запустить хуки:
gclient runhooks
На этом подготовка окружения завершена.
Система сборки
В качестве основной системы сборки Chromium используется Ninja, а утилита GN применяется для генерирования .ninja -файлов.
Чтобы понять, как пользоваться этими инструментами, предлагаю создать тестовую утилиту example. Для этого в папке src надо создать подпапку example :
mkdir example
Затем в папке src/example надо создать файл BUILD.gn , который содержит:
executable(«example»)
BUILD.gn состоит из цели (исполняемого файла example ) и списка файлов, которые необходимы для сборки цели.
Следующим шагом надо создать сам файл example.cc . Для начала предлагаю сделать классическое приложение «Hello world»:
#include int main(int argc, char **argv)
Исходный код можно найти на GitHub.
Чтобы GN узнала о новом проекте, нужно в файле BUILD.gn , который находится в src , в разделе deps добавить строку «//example» :
Chromium для Windows: как скачать с официального сайта, как обновить браузер
. 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», ] .
Теперь необходимо вернуться в папку src и сгенерировать проект с помощью команды:
gn gen out/Default
GN также позволяет подготовить проект для одной из поддерживаемых IDE:
- eclipse
- vs
- vs2013
- vs2015
- vs2017
- vs2019
- xcode
- qtcreator
- json
gn help gen
Например, для работы с проектом example в QtCreator надо выполнить команду:
gn gen —ide=qtcreator —root-target=example out/Default
После этого можно открыть проект в QtCreator:
qtcreator out/Default/qtcreator_project/all.creator
Финальный шаг — сборка проекта с помощью Ninja:
autoninja -C out/Default example
На этом краткое ознакомление с системой сборки можно завершить.
Приложение можно запустить с помощью команды:
./out/Default/example
И увидеть Hello world. На самом деле, про систему сборки в Chromium можно написать отдельную статью. Возможно, и не одну.
Работа с командной строкой
В качестве первого примера использования кодовой базы Chromium как фреймворка предлагаю поиграться с командной строкой.
Задача: вывести на экран все аргументы, переданные приложению в стиле Chromium.
Для работы с командной строкой необходимо в example.cc подключить заголовочный файл:
#include «base/command_line.h»
А также надо не забыть в BUILD.gn добавить зависимость от проекта base . BUILD.gn должен выглядеть так:
executable(«example») < sources = [ «example.cc», ] deps = [ «//base», ] >
Теперь всё необходимое будет подключено к example .
Для работы с командной строкой Chromium предоставляет синглтон base::CommandLine . Чтобы получить ссылку на него, надо использовать статический метод base::CommandLine::ForCurrentProcess , но сначала надо его инициализировать с помощью метода base::CommandLine::Init :
base::CommandLine::Init(argc, argv); auto *cmd_line = base::CommandLine::ForCurrentProcess();
Все аргументы, переданные приложению в командной строке и начинающиеся с символа — возвращаются в виде base::SwitchMap (по сути, map ) с помощью метода GetSwitches . Все остальные аргументы возвращаются в виде base::StringVector (по сути, vectоr ). Этих знаний достаточно, чтобы реализовать код для задачи:
for (const auto GetSwitches()) < std::cout for (const auto GetArgs())
Полную версию можно найти на GitHub.
Чтобы собрать и запустить приложение надо выполнить:
autoninja -C out/Default example ./out/Default/example arg1 —sw1=val1 —sw2 arg2
На экран будет выведено:
Switch sw1: val1 Switch sw2: Arg arg1 Arg arg2
Работа с сетью
В качестве второго и последнего на сегодня примера предлагаю поработать с сетевой частью Chromium.
Задача: вывести на экран содержимое URL’а, переданного в качестве аргумента.
Сетевая подсистема Chromium
Сетевая подсистема довольно большая и сложная. Входной точкой для запросов к HTTP, HTTPS, FTP и другим data-ресурсам является URLRequest , который уже определяет, какой из клиентов задействовать. Упрощённая схема выглядит так:

Полную версию можно посмотреть в документации.
Для создания URLRequest ‘а необходимо использовать URLRequestContext . Создание контекста — довольно сложная операция, поэтому рекомендуется использовать URLRequestContextBuilder . Он проинициализирует все необходимые переменные значениями по умолчанию, но, при желании, их можно поменять на свои, например:
net::URLRequestContextBuilder context_builder; context_builder.DisableHttpCache(); context_builder.SetSpdyAndQuicEnabled(true /* http2 */, false /* quic */); context_builder.SetCookieStore(nullptr);
Многопоточность
Сетевой стек Chromium расчитан на работу в многопоточной среде, поэтому пропустить эту тему нельзя. Базовыми объектами для работы с многопоточностью в Chromium являются:
- Task — задача для выполнения, в Chromium это функция с типом base::Callback , которую можно создать с помощью base::Bind .
- Task queue — очередь задач для выполнения.
- Physical thread — кроссплатформенная обёртка над потоком операционной системы ( pthread в POSIX или CreateThread() в Windows). Реализовано в классе base::PlatformThread , не используйте напрямую.
- base::Thread — реальный поток, который бесконечно обрабатывает сообщения из выделенной очереди задач; не рекомендуется создавать их напрямую.
- Thread pool — пул потоков с общей очередью задач. Реализован в классе base::ThreadPool . Как правило, создают один экземпляр. Задачи в него отправляются с помощью функций из base/task/post_task.h .
- Sequence or Virtual thread — виртуальный поток, который использует реальные потоки и может переключаться между ними.
- Task runner — интерфейс для постановки задач, реализован в классе base::TaskRunner .
- Sequenced task runner — интерфейс для постановки задач, который гарантирует, что задачи будут исполнены в том же порядке, в каком пришли. Реализовано в классе base::SequencedTaskRunner .
- Single-thread task runner — аналогичен предыдущему, но гарантирует, что все задачи будут выполнены в одном потоке ОС. Реализовано в классе base::SingleThreadTaskRunner .
Реализация
Некоторые компоненты Chromium требуют наличия base::AtExitManager — это класс, позволяющий зарегистрировать операции, которые надо выполнить при завершении приложения. Использовать его очень просто, необходимо в стеке создать объект:
base::AtExitManager exit_manager;
Когда exit_manager выйдет из области видимости, все зарегистрированные callback’и будут выполнены.
Теперь нужно позаботиться о наличии всех необходимых компонентов многопоточности для сетевой подсистемы. Для этого нужно создать Thread pool , Message loop с типом TYPE_IO для обработки сетевых сообщений, и Run loop — основной цикл программы:
base::ThreadPool::CreateAndStartWithDefaultParams(«downloader»); base::MessageLoop msg_loop(base::MessageLoop::TYPE_IO); base::RunLoop run_loop;
Дальше нужно с помощью Context builder ‘а создать Context :
auto ctx = net::URLRequestContextBuilder().Build();
Чтобы послать запрос, необходимо с помощью метода CreateRequest объекта ctx создать объект URLRequest . В качестве параметров передаются:
- URL, строка с типом GURL;
- приоритет;
- делегат, который обрабатывает события.
class MyDelegate : public net::URLRequest::Delegate < public: explicit MyDelegate(base::Closure quit_closure) : quit_closure_(std::move(quit_closure)), buf_(base::MakeRefCounted(BUF_SZ)) <> void OnReceivedRedirect(net::URLRequest *request, const net::RedirectInfo std::cerr void OnAuthRequired(net::URLRequest* request, const net::AuthChallengeInfo std::cerr void OnCertificateRequested(net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) override < std::cerr void OnSSLCertificateError(net::URLRequest* request, int net_error, const net::SSLInfo std::cerr void OnResponseStarted(net::URLRequest *request, int net_error) override < std::cerr Read(buf_.get(), BUF_SZ); std::cerr std::cout data(), n) > void OnReadCompleted(net::URLRequest *request, int bytes_read) override < std::cerr private: base::Closure quit_closure_; scoped_refptr buf_; >;
Вся основная логика находится в обработчике события OnResponseStarted : содержимое ответа вычитывается, пока не произойдёт ошибка или будет нечего читать. Так как после чтения ответа нужно завершить приложение, то делегат должен иметь доступ к функции, которая прервёт основной Run loop , в данном случае используется callback типа base::Closure .
Теперь всё готово для отправки запроса:
MyDelegate delegate(run_loop.QuitClosure()); auto req = ctx->CreateRequest(GURL(args[0]), net::RequestPriority::DEFAULT_PRIORITY, req->Start();
Чтобы запрос начал обрабатываться, надо запустить Run loop :
run_loop.Run();
Полную версию можно найти на GitHub.
Чтобы собрать и запустить приложение нужно выполнить:
autoninja -C out/Default example out/Default/example «https://example.com/»
Финал
На самом деле, в Chromium можно найти много полезных кубиков и кирпичиков, из которых можно строить приложения. Он постоянно развивается, что, с одной стороны, является плюсом, а с другой стороны, регулярные изменения API не дают расслабиться. Например, в последнем релизе base::TaskScheduler превратился в base::ThreadPool , к счастью, без изменения API.
P.S. Мы ищем ведущего программиста на C++ в свою команду! Если чувствуете в себе силы, то наши пожелания описаны тут: team.mail.ru/vacancy/4641/. Там же есть кнопка «Откликнуться».
Источник: habr.com
Браузеры и их движки. (Часть 1 — Chromium)

Немного теории. Chromium, вы не поверите, это тоже браузер, построенный на движке Blink, который в свою очередь построен на WebKit. Не нужно хромиум обзывать движком 😉 PS Как самый настоящий тестировщик веб-приложений вам говорю 🙂
Все равно Google Chrome лучший Пробовал юзать яндекс и амиго-не понравились
Little NuBito aka Tapki а какая разница должна быть если один и тот же движок? Только дизайн.
BAHAHDP а я на Оперу подсел давно и теперь только она
Лис наиболее многофункциональный, у него мощная поддержка плагинами + ужасно стабильный. У меня 700+ вкладок открыто, так ему ходьбы хны(и, конечно, спасибо плагину менеджер сессий), остальные браузеры краэшутся только так.
Wrecking Ball поддерживаю, хромированный не двигло а оболочка
Dreickoders Годных плагинов реально дофига, но они нагружают систему недурно. Я, например, в автоматизации по возможности использую хром, ибо опыт показывает, что тесты на нём летят шустрее всего
Блог очень информативен. Просто написал названия браузеров, основанных на хромиуме. PS: http://freeadvice.ru/browsers.php — я думал, ты сделал что то похожее.
DarkBloodyZector Посыл был в том, что не нужно путать движок с браузером
ExModern не нравится сделай сам. Хочу увидеть как ты оформишь так как на том сайте у нас на playgrounde
furious_duck Так можно почти все игровые движки называть «id Tech [любая цифра]», но так не делают.
Гугл Хром и Мозилла лучшие!А всякие яндексы, орбитиумы засуньте в задницу
Источник: www.playground.ru