# C++ in Chromium 101 - Codelab This tutorial will guide you through the creation of various example C++ applications, highlighting important Chromium C++ concepts. This tutorial assumes robust knowledge of C++ (the language) but does not assume you know how to write an application specific to Chromium's style and architecture. This tutorial does assume that you know how to check files out of Chromium's repository. As always, consider the following resources as of primary importance: - [Coding Style](https://chromium.googlesource.com/chromium/src/+/main/styleguide/styleguide.md) - [Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md) - [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md) - [Intro to Mojo & Services](https://chromium.googlesource.com/chromium/src.git/+/main/docs/mojo_and_services.md) - [Important Abstractions and Data Structures](https://sites.google.com/a/chromium.org/dev/developers/coding-style/important-abstractions-and-data-structures) (badly needs updating) This tutorial does not assume you have read any of the above, though you should feel free to peruse them when necessary. This tutorial will cover information across all of those guides. Exercise solutions are available in the [codelabs/cpp101/]( https://source.chromium.org/chromium/chromium/src/+/main:codelabs/cpp101/) directory of the Chromium source code. Build all of the example solutions with `autoninja -C out/Default codelabs`. You are encouraged to create a new `base/cpp101/` directory locally if you want to try implementing these exercises yourself. ### Exercise 0: "Hello World!" This exercise demonstrates the use of the [ninja](https://ninja-build.org/) build system to build a simple C++ binary and demonstrates how typical C++ builds are organized within Chromium. Create a new target in `base/BUILD.gn` for a new executable named `codelab_hello_world`. Then write the classic "Hello, world!" program in C++. You should be able to build it with `autoninja -C out/Default codelab_hello_world` and execute it directly by finding the binary within `out/Default`. Sample execution: ```shell $ cd /path/to/chromium/src $ gclient runhooks $ autoninja -C out/Default codelab_hello_world $ out/Default/codelab_hello_world Hello, world! [0923/185218.645640:INFO:hello_world.cc(27)] Hello, world! ``` ### More information [Targets](https://gn.googlesource.com/gn/+/refs/heads/main/docs/language.md#Targets) [Git Tips](https://chromium.googlesource.com/chromium/src.git/+/main/docs/git_tips.md) and [Git Cookbook](https://chromium.googlesource.com/chromium/src.git/+/main/docs/git_cookbook.md) [Life of a Chromium Developer](https://docs.google.com/a/google.com/presentation/d/1abnqM9j6zFodPHA38JG1061rG2iGj_GABxEDgZsdbJg/) ## Part 1: Using command-line arguments We will augment our `codelab_hello_world` binary to parse command-line flags and use those values to print messages to the user. Command-line arguments within Chromium are processed by the `CommandLine::Init()` function, which takes command line flags from the [argc and argv](https://crasseux.com/books/ctutorial/argc-and-argv.html) (argument count & vector) variables of the main() method. A typical invocation of `CommandLine::Init()` looks like the following: ```cpp int main(int argc, char** argv) {   CommandLine::Init(argc, argv);   // Main program execution ...   return 0; } ``` Flags are not explicitly defined in Chromium. Instead, we use `GetSwitchValueASCII()` and friends to retrieve values passed in. ### Important include files ```cpp #include "base/command_line.h" #include "base/logging.h" ``` ### Exercise 1: Using command-line arguments Change `codelab_hello_world` to take a `--greeting` and a `--name` switch. The greeting, if not specified, should default to "Hello", and the name, if not specified, should default to "World". ## Part 2: Callbacks and Bind C++, unlike other languages such as Python, Javascript, or Lisp, has only rudimentary support for [callbacks](https://en.wikipedia.org/wiki/Callbacks) and no support for [partial application](https://en.wikipedia.org/wiki/Partial_application). However, Chromium has the `base::OnceCallback` and  `base::RepeatingCallback`class, whose instances can be freely passed around, returned, and generally be treated as first-class values. base::OnceCallback is the move-only, single-call variant, and base::RepeatingCallback is the copyable, multiple-call variant. The `Sig` template parameter is a function signature type: ```cpp // The type of a callback that: //  - Can run only once. //  - Is move-only and non-copyable. //  - Takes no arguments and does not return anything. // base::OnceClosure is an alias of this type. base::OnceCallback // The type of a callback that: //  - Can run more than once. //  - Is copyable. //  - Takes no arguments and does not return anything. // base::RepeatingClosure is an alias of this type. base::RepeatingCallback // The types of a callback that takes two arguments (a string and a double) // and returns an int. base::OnceCallback base::RepeatingCallback ``` Callbacks are executed by invoking the `Run()` member function. base::OnceCallback needs to be rvalue to run. ```cpp void MyFunction1(base::OnceCallback my_callback) {   // OnceCallback   int result1 = std::move(my_callback).Run("my string 1", 1.0);   // After running a OnceCallback, it's consumed and nulled out.   DCHECK(!my_callback);   ... } void MyFunction2(base::RepeatingCallback my_callback) {   int result1 = my_callback.Run("my string 1", 1.0);   // Run() can be called as many times as you wish for RepeatingCallback.   int result2 = my_callback.Run("my string 2", 2);   ... ``` Callbacks are constructed using the `base::BindOnce()` or `base::BindRepeating()` function, which handles partial application: ```cpp // Declare a function. void MyFunction(int32 a, double b); base::OnceCallback my_callback1 = base::BindOnce(&MyFunction, 10); base::RepeatingCallback my_callback2 = base::BindRepeating(&MyFunction, 10); // Equivalent to: // // MyFunction(10, 3.5); // std::move(my_callback1).Run(3.5); my_callback2.Run(3.5); ``` `base::BindOnce()` and `base::BindRepeating()` can do a lot more, including binding class member functions and binding additional arguments to an existing `base::OnceCallback` or `base::RepeatingCallback`. See [docs/callback.md](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md) for details. ### Important Include Files ```cpp #include "base/bind.h" #include "base/callback.h" ``` ### More Information [Callback<> and Bind()](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md) ### Exercise 2: Fibonacci closures Implement a function that returns a callback that takes no arguments and returns successive Fibonacci numbers. That is, a function that can be used like this: ```cpp base::RepeatingCallback fibonacci_closure = MakeFibonacciClosure(); LOG(INFO) << fibonacci_closure.Run(); // Prints "1" LOG(INFO) << fibonacci_closure.Run(); // Prints "1" LOG(INFO) << fibonacci_closure.Run(); // Prints "2" ... ``` Each returned Fibonacci callback should be independent; running one callback shouldn't affect the result of running another callback. Write a `fibonacci` executable that takes an integer argument `n` and uses your function to print out the first `n` Fibonacci numbers. (This exercise was inspired by [this Go exercise: Function closures](https://tour.golang.org/moretypes/25).) ## Part 3: Threads and task runners Chromium has a number of abstractions for sequencing and threading. [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md) is a must-read and go-to reference for anything related to tasks, thread pools, task runners, and more. Sequenced execution (on virtual threads) is strongly preferred to single-threaded execution (on physical threads). Chromium's abstraction for asynchronously running posted tasks is `base::TaskRunner`. Task runners allow you to write code that posts tasks without depending on what exactly will run those tasks. `base::SequencedTaskRunner` (which extends `base::TaskRunner`) is a commonly used abstraction which handles running tasks (which are instances of `base::OnceClosure`) in sequential order. These tasks are not guaranteed to run on the same thread. The preferred way of posting to the current (virtual) thread is `base::SequencedTaskRunnerHandle::Get()`. A task that can run on any thread and doesn’t have ordering or mutual exclusion requirements with other tasks should be posted using one of the `base::ThreadPool::PostTask()` functions. There are a number of ways to post tasks to a thread pool or task runner. - `PostTask()` - `PostDelayedTask()` if you want to add a delay. - `PostTaskAndReply()` lets you post a task which will post a task back to your current thread when its done. - `PostTaskAndReplyWithResult()` to automatically pass the return value of the first call as argument to the second call. Normally you wouldn't have to worry about setting up a threading environment and keeping it running, since that is automatically done by Chromium's thread classes. However, since the main thread doesn't automatically start off with `TaskEnvironment`, there's a bit of extra setup involved. The following setup code should be enough to create the necessary TaskEnvironment. Include `testonly=true` flag in the BUILD.gn file, along with `"//base/test:test_support"` set as a dependency. ### Important header files ```cpp #include "base/test/task_environment.h" #include "base/test/test_timeouts.h" #include "base/at_exit.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" #include "base/command_line.h" ``` ### Setup code: ```cpp int main(int argc, char* argv[]) { base::AtExitManager exit_manager; base::CommandLine::Init(argc, argv); TestTimeouts::Initialize(); base::test::TaskEnvironment task_environment{ base::test::TaskEnvironment::TimeSource::SYSTEM_TIME}; // The rest of your code will go here. ``` ### Exercise 3a: Sleep Implement the Unix command-line utility `sleep` using only a `base::SequencedTaskRunnerHandle` (i.e., without using the `sleep` function or `base::PlatformThread::Sleep`). Hint: You will need to use `base::RunLoop` to prevent the main function from exiting prematurely. ### Exercise 3b: Integer factorization Take the given (slow) function to find a non-trivial factor of a given integer: ```cpp absl::optional FindNonTrivialFactor(int n) { // Really naive algorithm. for (int i = 2; i < n; ++i) { if (n % i == 0) { return i; } } return absl::nullopt; } ``` Write a command-line utility `factor` that takes a number, posts a task to the background using `FindNonTrivialFactor`, and prints a status update every second as long as the factoring task is executing. ### More information [Threading and Tasks in Chrome](https://chromium.googlesource.com/chromium/src/+/main/docs/threading_and_tasks.md) ## Part 4: Mojo Mojo is Chromium's abstraction of IPC. Mojo allows for developers to easily connect interface clients and implementations across arbitrary intra- and inter-process boundaries. See the [Intro to Mojo and Services](https://chromium.googlesource.com/chromium/src.git/+/main/docs/mojo_and_services.md) guide to get started. ### Exercise 4: Building a simple out-of-process service See the [building a simple out-of-process service](https://chromium.googlesource.com/chromium/src.git/+/main/docs/mojo_and_services.md#example_building-a-simple-out_of_process-service) tutorial on using Mojo to define, hook up, and launch an out-of-process service. ### More Information [Mojo C++ Bindings API Docs](https://chromium.googlesource.com/chromium/src.git/+/main/mojo/public/cpp/bindings/README.md) [Mojo Docs](https://chromium.googlesource.com/chromium/src.git/+/main/mojo/README.md)