You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
14 KiB

# Open Screen Library
The openscreen library implements the Open Screen Protocol and the Chromecast
protocols (both control and streaming).
Information about the protocol and its specification can be found [on
GitHub](https://github.com/webscreens/openscreenprotocol).
# Getting the code
## Installing depot_tools
openscreen library dependencies are managed using `gclient`, from the
[depot_tools](https://www.chromium.org/developers/how-tos/depottools) repo.
To get gclient, run the following command in your terminal:
```bash
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
```
Then add the `depot_tools` folder to your `PATH` environment variable.
Note that openscreen does not use other features of `depot_tools` like `repo` or
`drover`. However, some `git-cl` functions *do* work, like `git cl try`, `git cl
lint` and `git cl upload.`
## Checking out code
From the parent directory of where you want the openscreen checkout (e.g.,
`~/my_project_dir`), configure `gclient` and check out openscreen with the
following commands:
```bash
cd ~/my_project_dir
gclient config https://chromium.googlesource.com/openscreen
gclient sync
```
The first `gclient` command will create a default .gclient file in
`~/my_project_dir` that describes how to pull down the `openscreen` repository.
The second command creates an `openscreen/` subdirectory, downloads the source
code, all third-party dependencies, and the toolchain needed to build things;
and at their appropriate revisions.
## Syncing your local checkout
To update your local checkout from the openscreen master repository, just run
```bash
cd ~/my_project_dir/openscreen
git pull
gclient sync
```
This will rebase any local commits on the remote top-of-tree, and update any
dependencies that have changed.
# Build setup
The following are the main tools are required for development/builds:
- Build file generator: `gn`
- Code formatter: `clang-format`
- Builder: `ninja` ([GitHub releases](https://github.com/ninja-build/ninja/releases))
- Compiler/Linker: `clang` (installed by default) or `gcc` (installed by you)
All of these--except `gcc` as noted above--are automatically downloaded/updated
for the Linux and Mac environments via `gclient sync` as described above. The
first two are installed into `buildtools/<platform>/`.
Mac only: XCode must be installed on the system, to link against its frameworks.
`clang-format` is used for maintaining consistent coding style, but it is not a
complete replacement for adhering to Chromium/Google C++ style (that's on you!).
The presubmit script will sanity-check that it has been run on all new/changed
code.
## Linux clang
On Linux, the build will automatically download the Clang compiler from the
Google storage cache, the same way that Chromium does it.
Ensure that libstdc++ 8 is installed, as clang depends on the system
instance of it. On Debian flavors, you can run:
```bash
sudo apt-get install libstdc++-8-dev
```
## Linux gcc
Setting the `gn` argument "is_gcc=true" on Linux enables building using gcc
instead.
```bash
gn gen out/Default --args="is_gcc=true"
```
Note that g++ version 7 or newer must be installed. On Debian flavors you can
run:
```bash
sudo apt-get install gcc-7
```
## Mac clang
On Mac OS X, the build will use the clang provided by
[XCode](https://apps.apple.com/us/app/xcode/id497799835?mt=12), which must be
installed.
## Debug build
Setting the `gn` argument "is_debug=true" enables debug build.
```bash
gn gen out/Default --args="is_debug=true"
```
To install debug information for libstdc++ 8 on Debian flavors, you can run:
```bash
sudo apt-get install libstdc++6-8-dbg
```
## gn configuration
Running `gn args` opens an editor that allows to create a list of arguments
passed to every invocation of `gn gen`.
```bash
gn args out/Default
```
# Building targets
## Building the OSP demo
The following commands will build a sample executable and run it.
``` bash
mkdir out/Default
gn gen out/Default # Creates the build directory and necessary ninja files
ninja -C out/Default demo # Builds the executable with ninja
./out/Default/demo # Runs the executable
```
The `-C` argument to `ninja` works just like it does for GNU Make: it specifies
the working directory for the build. So the same could be done as follows:
``` bash
./gn gen out/Default
cd out/Default
ninja
./demo
```
After editing a file, only `ninja` needs to be rerun, not `gn`. If you have
edited a `BUILD.gn` file, `ninja` will re-run `gn` for you.
Unless you like to wait longer than necessary for builds to complete, run
`autoninja` instead of `ninja`, which takes the same command-line arguments.
This will automatically parallelize the build for your system, depending on
number of processor cores, RAM, etc.
For details on running `demo`, see its [README.md](demo/README.md).
## Building other targets
Running `ninja -C out/Default gn_all` will build all non-test targets in the
repository.
`gn ls --type=executable out/Default/` will list all of the executable targets
that can be built.
If you want to customize the build further, you can run `gn args out/Default` to
pull up an editor for build flags. `gn args --list out/Default` prints all of
the build flags available.
## Building and running unit tests
```bash
ninja -C out/Default unittests
./out/Default/unittests
```
## Building and running fuzzers
In order to build fuzzers, you need the GN arg `use_libfuzzer=true`. It's also
recommended to build with `is_asan=true` to catch additional problems. Building
and running then might look like:
```bash
gn gen out/libfuzzer --args="use_libfuzzer=true is_asan=true is_debug=false"
ninja -C out/libfuzzer some_fuzz_target
out/libfuzzer/some_fuzz_target <args> <corpus_dir> [additional corpus dirs]
```
The arguments to the fuzzer binary should be whatever is listed in the GN target
description (e.g. `-max_len=1500`). These arguments may be automatically
scraped by Chromium's ClusterFuzz tool when it runs fuzzers, but they are not
built into the target. You can also look at the file
`out/libfuzzer/some_fuzz_target.options` for what arguments should be used. The
`corpus_dir` is listed as `seed_corpus` in the GN definition of the fuzzer
target.
# Continuous build and try jobs
openscreen uses [LUCI builders](https://ci.chromium.org/p/openscreen/builders)
to monitor the build and test health of the library. Current builders include:
| Name | Arch | OS | Toolchain | Build | Notes |
|------------------------|--------|--------------------|-----------|---------|------------------------|
| linux64_debug | x86-64 | Ubuntu Linux 16.04 | clang | debug | ASAN enabled |
| linux64_gcc_debug | x86-64 | Ubuntu Linux 18.04 | gcc-7 | debug | |
| linux64_tsan | x86-64 | Ubuntu Linux 16.04 | clang | release | TSAN enabled |
| mac_debug | x86-64 | Mac OS X/Xcode | clang | debug | |
| chromium_linux64_debug | x86-64 | Ubuntu Linux 16.04 | clang | debug | built within chromium |
| chromium_mac_debug | x86-64 | Mac OS X/Xcode | clang | debug | built within chromium |
| linux64_coverage_debug | x86-64 | Ubuntu Linux 16.04 | clang | debug | used for code coverage |
You can run a patch through the try job queue (which tests it on all
non-chromium builders) using `git cl try`, or through Gerrit (details below).
The chromium builders compile openscreen HEAD vs. chromium HEAD. They run as
experimental trybots and continuous-integration FYI bots.
# Submitting changes
openscreen library code should follow the [Open Screen Library Style
Guide](docs/style_guide.md).
openscreen uses [Chromium Gerrit](https://chromium-review.googlesource.com/) for
patch management and code review (for better or worse).
The following sections contain some tips about dealing with Gerrit for code
reviews, specifically when pushing patches for review, getting patches reviewed,
and committing patches.
## Uploading a patch for review
The `git cl` tool handles details of interacting with Gerrit (the Chromium code
review tool) and is recommended for pushing patches for review. Once you have
committed changes locally, simply run:
```bash
git cl format
git cl upload
```
The first command will will auto-format the code changes. Then, the second
command runs the `PRESUBMIT.sh` script to check style and, if it passes, a
newcode review will be posted on `chromium-review.googlesource.com`.
If you make additional commits to your local branch, then running `git cl
upload` again in the same branch will merge those commits into the ongoing
review as a new patchset.
It's simplest to create a local git branch for each patch you want reviewed
separately. `git cl` keeps track of review status separately for each local
branch.
## Addressing merge conflicts
If conflicting commits have been landed in the repository for a patch in review,
Gerrit will flag the patch as having a merge conflict. In that case, use the
instructions above to rebase your commits on top-of-tree and upload a new
patchset with the merge conflicts resolved.
## Tryjobs
Clicking the `CQ DRY RUN` button (also, confusingly, labeled `COMMIT QUEUE +1`)
will run the current patchset through all LUCI builders and report the results.
It is always a good idea get a green tryjob on a patch before sending it for
review to avoid extra back-and-forth.
You can also run `git cl try` from the commandline to submit a tryjob.
## Code reviews
Send your patch to one or more committers in the
[COMMITTERS](https://chromium.googlesource.com/openscreen/+/refs/heads/master/COMMITTERS)
file for code review. All patches must receive at least one LGTM by a committer
before it can be submitted.
## Submission
After your patch has received one or more LGTM commit it by clicking the
`SUBMIT` button (or, confusingly, `COMMIT QUEUE +2`) in Gerrit. This will run
your patch through the builders again before committing to the main openscreen
repository.
<!-- TODO(mfoltz): split up README.md into more manageable files. -->
## Working with ARM/ARM64/the Raspberry PI
openscreen supports cross compilation for both arm32 and arm64 platforms, by
using the `gn args` parameter `target_cpu="arm"` or `target_cpu="arm64"`
respectively. Note that quotes are required around the target arch value.
Setting an arm(64) target_cpu causes GN to pull down a sysroot from openscreen's
public cloud storage bucket. Google employees may update the sysroots stored
by requesting access to the Open Screen pantheon project and uploading a new
tar.xz to the openscreen-sysroots bucket.
NOTE: The "arm" image is taken from Chromium's debian arm image, however it has
been manually patched to include support for libavcodec and libsdl2. To update
this image, the new image must be manually patched to include the necessary
header and library dependencies. Note that if the versions of libavcodec and
libsdl2 are too out of sync from the copies in the sysroot, compilation will
succeed, but you may experience issues decoding content.
To install the last known good version of the libavcodec and libsdl packages
on a Raspberry Pi, you can run the following command:
```bash
sudo ./cast/standalone_receiver/install_demo_deps_raspian.sh
```
NOTE: until [Issue 106](http://crbug.com/openscreen/106) is resolved, you may
experience issues streaming to a Raspberry Pi if multiple network interfaces
(e.g. WiFi + Ethernet) are enabled. The workaround is to disable either the WiFi
or ethernet connection.
## Code Coverage
Code coverage can be checked using clang's source-based coverage tools. You
must use the GN argument `use_coverage=true`. It's recommended to do this in a
separate output directory since the added instrumentation will affect
performance and generate an output file every time a binary is run. You can
read more about this in [clang's
documentation](http://clang.llvm.org/docs/SourceBasedCodeCoverage.html) but the
bare minimum steps are also outlined below. You will also need to download the
pre-built clang coverage tools, which are not downloaded by default. The
easiest way to do this is to set a custom variable in your `.gclient` file.
Under the "openscreen" solution, add:
```python
"custom_vars": {
"checkout_clang_coverage_tools": True,
},
```
then run `gclient runhooks`. You can also run the python command from the
`clang_coverage_tools` hook in `//DEPS` yourself or even download the tools
manually
([link](https://storage.googleapis.com/chromium-browser-clang-staging/)).
Once you have your GN directory (we'll call it `out/coverage`) and have
downloaded the tools, do the following to generate an HTML coverage report:
```bash
out/coverage/openscreen_unittests
third_party/llvm-build/Release+Asserts/bin/llvm-profdata merge -sparse default.profraw -o foo.profdata
third_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]
```
There are a few things to note here:
- `default.profraw` is generated by running the instrumented code, but
`foo.profdata` can be any path you want.
- `<out dir>` should be an empty directory for placing the generated HTML
files. You can view the report at `<out dir>/index.html`.
- `[filter paths]` is a list of paths to which you want to limit the coverage
report. For example, you may want to limit it to cast/ or even
cast/streaming/. If this list is empty, all data will be in the report.
The same process can be used to check the coverage of a fuzzer's corpus. Just
add `-runs=0` to the fuzzer arguments to make sure it only runs the existing
corpus then exits.