1# Open Screen Library 2 3The openscreen library implements the Open Screen Protocol and the Chromecast 4protocols (both control and streaming). 5 6Information about the protocol and its specification can be found [on 7GitHub](https://github.com/webscreens/openscreenprotocol). 8 9# Getting the code 10 11## Installing depot_tools 12 13openscreen library dependencies are managed using `gclient`, from the 14[depot_tools](https://www.chromium.org/developers/how-tos/depottools) repo. 15 16To get gclient, run the following command in your terminal: 17```bash 18 git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 19``` 20 21Then add the `depot_tools` folder to your `PATH` environment variable. 22 23Note that openscreen does not use other features of `depot_tools` like `repo` or 24`drover`. However, some `git-cl` functions *do* work, like `git cl try`, `git cl 25lint` and `git cl upload.` 26 27## Checking out code 28 29From the parent directory of where you want the openscreen checkout (e.g., 30`~/my_project_dir`), configure `gclient` and check out openscreen with the 31following commands: 32 33```bash 34 cd ~/my_project_dir 35 gclient config https://chromium.googlesource.com/openscreen 36 gclient sync 37``` 38 39The first `gclient` command will create a default .gclient file in 40`~/my_project_dir` that describes how to pull down the `openscreen` repository. 41The second command creates an `openscreen/` subdirectory, downloads the source 42code, all third-party dependencies, and the toolchain needed to build things; 43and at their appropriate revisions. 44 45## Syncing your local checkout 46 47To update your local checkout from the openscreen master repository, just run 48 49```bash 50 cd ~/my_project_dir/openscreen 51 git pull 52 gclient sync 53``` 54 55This will rebase any local commits on the remote top-of-tree, and update any 56dependencies that have changed. 57 58# Build setup 59 60The following are the main tools are required for development/builds: 61 62 - Build file generator: `gn` 63 - Code formatter: `clang-format` 64 - Builder: `ninja` ([GitHub releases](https://github.com/ninja-build/ninja/releases)) 65 - Compiler/Linker: `clang` (installed by default) or `gcc` (installed by you) 66 67All of these--except `gcc` as noted above--are automatically downloaded/updated 68for the Linux and Mac environments via `gclient sync` as described above. The 69first two are installed into `buildtools/<platform>/`. 70 71Mac only: XCode must be installed on the system, to link against its frameworks. 72 73`clang-format` is used for maintaining consistent coding style, but it is not a 74complete replacement for adhering to Chromium/Google C++ style (that's on you!). 75The presubmit script will sanity-check that it has been run on all new/changed 76code. 77 78## Linux clang 79 80On Linux, the build will automatically download the Clang compiler from the 81Google storage cache, the same way that Chromium does it. 82 83Ensure that libstdc++ 8 is installed, as clang depends on the system 84instance of it. On Debian flavors, you can run: 85 86```bash 87 sudo apt-get install libstdc++-8-dev 88``` 89 90## Linux gcc 91 92Setting the `gn` argument "is_gcc=true" on Linux enables building using gcc 93instead. 94 95```bash 96 gn gen out/Default --args="is_gcc=true" 97``` 98 99Note that g++ version 7 or newer must be installed. On Debian flavors you can 100run: 101 102```bash 103 sudo apt-get install gcc-7 104``` 105 106## Mac clang 107 108On Mac OS X, the build will use the clang provided by 109[XCode](https://apps.apple.com/us/app/xcode/id497799835?mt=12), which must be 110installed. 111 112## Debug build 113 114Setting the `gn` argument "is_debug=true" enables debug build. 115 116```bash 117 gn gen out/Default --args="is_debug=true" 118``` 119 120To install debug information for libstdc++ 8 on Debian flavors, you can run: 121 122```bash 123 sudo apt-get install libstdc++6-8-dbg 124``` 125 126## gn configuration 127 128Running `gn args` opens an editor that allows to create a list of arguments 129passed to every invocation of `gn gen`. 130 131```bash 132 gn args out/Default 133``` 134 135# Building targets 136 137## Building the OSP demo 138 139The following commands will build a sample executable and run it. 140 141``` bash 142 mkdir out/Default 143 gn gen out/Default # Creates the build directory and necessary ninja files 144 ninja -C out/Default demo # Builds the executable with ninja 145 ./out/Default/demo # Runs the executable 146``` 147 148The `-C` argument to `ninja` works just like it does for GNU Make: it specifies 149the working directory for the build. So the same could be done as follows: 150 151``` bash 152 ./gn gen out/Default 153 cd out/Default 154 ninja 155 ./demo 156``` 157 158After editing a file, only `ninja` needs to be rerun, not `gn`. If you have 159edited a `BUILD.gn` file, `ninja` will re-run `gn` for you. 160 161Unless you like to wait longer than necessary for builds to complete, run 162`autoninja` instead of `ninja`, which takes the same command-line arguments. 163This will automatically parallelize the build for your system, depending on 164number of processor cores, RAM, etc. 165 166For details on running `demo`, see its [README.md](demo/README.md). 167 168## Building other targets 169 170Running `ninja -C out/Default gn_all` will build all non-test targets in the 171repository. 172 173`gn ls --type=executable out/Default/` will list all of the executable targets 174that can be built. 175 176If you want to customize the build further, you can run `gn args out/Default` to 177pull up an editor for build flags. `gn args --list out/Default` prints all of 178the build flags available. 179 180## Building and running unit tests 181 182```bash 183 ninja -C out/Default unittests 184 ./out/Default/unittests 185``` 186 187## Building and running fuzzers 188 189In order to build fuzzers, you need the GN arg `use_libfuzzer=true`. It's also 190recommended to build with `is_asan=true` to catch additional problems. Building 191and running then might look like: 192```bash 193 gn gen out/libfuzzer --args="use_libfuzzer=true is_asan=true is_debug=false" 194 ninja -C out/libfuzzer some_fuzz_target 195 out/libfuzzer/some_fuzz_target <args> <corpus_dir> [additional corpus dirs] 196``` 197 198The arguments to the fuzzer binary should be whatever is listed in the GN target 199description (e.g. `-max_len=1500`). These arguments may be automatically 200scraped by Chromium's ClusterFuzz tool when it runs fuzzers, but they are not 201built into the target. You can also look at the file 202`out/libfuzzer/some_fuzz_target.options` for what arguments should be used. The 203`corpus_dir` is listed as `seed_corpus` in the GN definition of the fuzzer 204target. 205 206# Continuous build and try jobs 207 208openscreen uses [LUCI builders](https://ci.chromium.org/p/openscreen/builders) 209to monitor the build and test health of the library. Current builders include: 210 211| Name | Arch | OS | Toolchain | Build | Notes | 212|------------------------|--------|--------------------|-----------|---------|------------------------| 213| linux64_debug | x86-64 | Ubuntu Linux 16.04 | clang | debug | ASAN enabled | 214| linux64_gcc_debug | x86-64 | Ubuntu Linux 18.04 | gcc-7 | debug | | 215| linux64_tsan | x86-64 | Ubuntu Linux 16.04 | clang | release | TSAN enabled | 216| mac_debug | x86-64 | Mac OS X/Xcode | clang | debug | | 217| chromium_linux64_debug | x86-64 | Ubuntu Linux 16.04 | clang | debug | built within chromium | 218| chromium_mac_debug | x86-64 | Mac OS X/Xcode | clang | debug | built within chromium | 219| linux64_coverage_debug | x86-64 | Ubuntu Linux 16.04 | clang | debug | used for code coverage | 220 221You can run a patch through the try job queue (which tests it on all 222non-chromium builders) using `git cl try`, or through Gerrit (details below). 223 224The chromium builders compile openscreen HEAD vs. chromium HEAD. They run as 225experimental trybots and continuous-integration FYI bots. 226 227# Submitting changes 228 229openscreen library code should follow the [Open Screen Library Style 230Guide](docs/style_guide.md). 231 232openscreen uses [Chromium Gerrit](https://chromium-review.googlesource.com/) for 233patch management and code review (for better or worse). 234 235The following sections contain some tips about dealing with Gerrit for code 236reviews, specifically when pushing patches for review, getting patches reviewed, 237and committing patches. 238 239## Uploading a patch for review 240 241The `git cl` tool handles details of interacting with Gerrit (the Chromium code 242review tool) and is recommended for pushing patches for review. Once you have 243committed changes locally, simply run: 244 245```bash 246 git cl format 247 git cl upload 248``` 249 250The first command will will auto-format the code changes. Then, the second 251command runs the `PRESUBMIT.sh` script to check style and, if it passes, a 252newcode review will be posted on `chromium-review.googlesource.com`. 253 254If you make additional commits to your local branch, then running `git cl 255upload` again in the same branch will merge those commits into the ongoing 256review as a new patchset. 257 258It's simplest to create a local git branch for each patch you want reviewed 259separately. `git cl` keeps track of review status separately for each local 260branch. 261 262## Addressing merge conflicts 263 264If conflicting commits have been landed in the repository for a patch in review, 265Gerrit will flag the patch as having a merge conflict. In that case, use the 266instructions above to rebase your commits on top-of-tree and upload a new 267patchset with the merge conflicts resolved. 268 269## Tryjobs 270 271Clicking the `CQ DRY RUN` button (also, confusingly, labeled `COMMIT QUEUE +1`) 272will run the current patchset through all LUCI builders and report the results. 273It is always a good idea get a green tryjob on a patch before sending it for 274review to avoid extra back-and-forth. 275 276You can also run `git cl try` from the commandline to submit a tryjob. 277 278## Code reviews 279 280Send your patch to one or more committers in the 281[COMMITTERS](https://chromium.googlesource.com/openscreen/+/refs/heads/master/COMMITTERS) 282file for code review. All patches must receive at least one LGTM by a committer 283before it can be submitted. 284 285## Submission 286 287After your patch has received one or more LGTM commit it by clicking the 288`SUBMIT` button (or, confusingly, `COMMIT QUEUE +2`) in Gerrit. This will run 289your patch through the builders again before committing to the main openscreen 290repository. 291 292<!-- TODO(mfoltz): split up README.md into more manageable files. --> 293## Working with ARM/ARM64/the Raspberry PI 294 295openscreen supports cross compilation for both arm32 and arm64 platforms, by 296using the `gn args` parameter `target_cpu="arm"` or `target_cpu="arm64"` 297respectively. Note that quotes are required around the target arch value. 298 299Setting an arm(64) target_cpu causes GN to pull down a sysroot from openscreen's 300public cloud storage bucket. Google employees may update the sysroots stored 301by requesting access to the Open Screen pantheon project and uploading a new 302tar.xz to the openscreen-sysroots bucket. 303 304NOTE: The "arm" image is taken from Chromium's debian arm image, however it has 305been manually patched to include support for libavcodec and libsdl2. To update 306this image, the new image must be manually patched to include the necessary 307header and library dependencies. Note that if the versions of libavcodec and 308libsdl2 are too out of sync from the copies in the sysroot, compilation will 309succeed, but you may experience issues decoding content. 310 311To install the last known good version of the libavcodec and libsdl packages 312on a Raspberry Pi, you can run the following command: 313 314```bash 315sudo ./cast/standalone_receiver/install_demo_deps_raspian.sh 316``` 317 318NOTE: until [Issue 106](http://crbug.com/openscreen/106) is resolved, you may 319experience issues streaming to a Raspberry Pi if multiple network interfaces 320(e.g. WiFi + Ethernet) are enabled. The workaround is to disable either the WiFi 321or ethernet connection. 322 323## Code Coverage 324 325Code coverage can be checked using clang's source-based coverage tools. You 326must use the GN argument `use_coverage=true`. It's recommended to do this in a 327separate output directory since the added instrumentation will affect 328performance and generate an output file every time a binary is run. You can 329read more about this in [clang's 330documentation](http://clang.llvm.org/docs/SourceBasedCodeCoverage.html) but the 331bare minimum steps are also outlined below. You will also need to download the 332pre-built clang coverage tools, which are not downloaded by default. The 333easiest way to do this is to set a custom variable in your `.gclient` file. 334Under the "openscreen" solution, add: 335```python 336 "custom_vars": { 337 "checkout_clang_coverage_tools": True, 338 }, 339``` 340then run `gclient runhooks`. You can also run the python command from the 341`clang_coverage_tools` hook in `//DEPS` yourself or even download the tools 342manually 343([link](https://storage.googleapis.com/chromium-browser-clang-staging/)). 344 345Once you have your GN directory (we'll call it `out/coverage`) and have 346downloaded the tools, do the following to generate an HTML coverage report: 347```bash 348out/coverage/openscreen_unittests 349third_party/llvm-build/Release+Asserts/bin/llvm-profdata merge -sparse default.profraw -o foo.profdata 350third_party/llvm-build/Release+Asserts/bin/llvm-cov show out/coverage/openscreen_unittests -instr-profile=foo.profdata -format=html -output-dir=<out dir> [filter paths] 351``` 352There are a few things to note here: 353 - `default.profraw` is generated by running the instrumented code, but 354 `foo.profdata` can be any path you want. 355 - `<out dir>` should be an empty directory for placing the generated HTML 356 files. You can view the report at `<out dir>/index.html`. 357 - `[filter paths]` is a list of paths to which you want to limit the coverage 358 report. For example, you may want to limit it to cast/ or even 359 cast/streaming/. If this list is empty, all data will be in the report. 360 361The same process can be used to check the coverage of a fuzzer's corpus. Just 362add `-runs=0` to the fuzzer arguments to make sure it only runs the existing 363corpus then exits. 364