Skip to content

Commit 1b4dda6

Browse files
committed
webrtc-sys: build libwebrtc from source on Linux
1 parent 9b0b467 commit 1b4dda6

File tree

4 files changed

+229
-53
lines changed

4 files changed

+229
-53
lines changed

webrtc-sys/build.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,59 @@ fn main() {
8181
"src/desktop_capturer.cpp",
8282
]);
8383

84-
let webrtc_dir = webrtc_sys_build::webrtc_dir();
84+
let mut webrtc_dir = webrtc_sys_build::webrtc_dir();
85+
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
86+
87+
#[cfg(target_os = "linux")]
88+
println!("cargo:rerun-if-env-changed=LK_LIBWEBRTC_SOURCE");
89+
#[cfg(target_os = "linux")]
90+
if let Ok(source_archive) = env::var("LK_LIBWEBRTC_SOURCE") {
91+
let out_dir = env::var("OUT_DIR").unwrap();
92+
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
93+
94+
fn check_command_output(output: std::process::Output) {
95+
let status = output.status;
96+
if !status.success() {
97+
let stderr = String::from_utf8_lossy(&output.stderr);
98+
let stdout = String::from_utf8_lossy(&output.stdout);
99+
panic!("Command exited unsuccessfully: {status:?},\nstdout:\n{stdout}\nstderr:\n{stderr}");
100+
}
101+
}
102+
103+
if !std::fs::exists(format!("{out_dir}/src")).unwrap() {
104+
check_command_output(
105+
Command::new("tar")
106+
.args(["-Jxf", &source_archive, "-C", &out_dir])
107+
.output()
108+
.unwrap(),
109+
);
110+
}
111+
112+
let script_arch = match target_arch.as_str() {
113+
"x86_64" => "x64",
114+
"aarch64" => "arm64",
115+
a => a,
116+
};
117+
check_command_output(
118+
Command::new("bash")
119+
.args([
120+
&format!("{manifest_dir}/libwebrtc/build_linux.sh"),
121+
"--sources",
122+
&format!("{out_dir}/src"),
123+
"--toolchain",
124+
"gnu",
125+
"--arch",
126+
script_arch,
127+
"--profile",
128+
"release",
129+
])
130+
.output()
131+
.unwrap(),
132+
);
133+
134+
webrtc_dir = PathBuf::from(format!("{out_dir}/linux-{script_arch}-release"));
135+
}
136+
85137
let webrtc_include = webrtc_dir.join("include");
86138
let webrtc_lib = webrtc_dir.join("lib");
87139

@@ -112,7 +164,6 @@ fn main() {
112164
println!("cargo:rustc-link-lib=static=webrtc");
113165

114166
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
115-
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
116167
match target_os.as_str() {
117168
"windows" => {
118169
println!("cargo:rustc-link-lib=dylib=msdmo");

webrtc-sys/build/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::{
1818
env,
1919
fs::{self, File},
2020
io::{self, BufRead, Write},
21-
path,
21+
path::{self, Path},
2222
process::Command,
2323
};
2424

@@ -115,14 +115,15 @@ pub fn webrtc_dir() -> path::PathBuf {
115115
prebuilt_dir()
116116
}
117117

118-
pub fn webrtc_defines() -> Vec<(String, Option<String>)> {
118+
pub fn webrtc_defines(path: impl AsRef<Path>) -> Vec<(String, Option<String>)> {
119+
let path = path.as_ref();
119120
// read preprocessor definitions from webrtc.ninja
120121
let defines_re = Regex::new(r"-D(\w+)(?:=([^\s]+))?").unwrap();
121-
let mut files = vec![webrtc_dir().join("webrtc.ninja")];
122+
let mut files = vec![path.join("webrtc.ninja")];
122123
// include desktop_capture.ninja to avoid ABI mismatch for DesktopCaptureOptions due to WEBRTC_USE_X11 missing
123124
// libwebrtc does not implement desktop capture on Android
124125
if env::var("CARGO_CFG_TARGET_OS").unwrap() != "android" {
125-
files.push(webrtc_dir().join("desktop_capture.ninja"));
126+
files.push(path.join("desktop_capture.ninja"));
126127
}
127128

128129
let mut seen = HashSet::new();

webrtc-sys/libwebrtc/build_linux.sh

Lines changed: 27 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ toolchain="gnu"
2020

2121
while [ "$#" -gt 0 ]; do
2222
case "$1" in
23+
--sources)
24+
sources="$(realpath $2)"
25+
shift 2
26+
;;
2327
--arch)
2428
arch="$2"
25-
if [ "$arch" != "x64" ] && [ "$arch" != "arm64" ]; then
26-
echo "Error: Invalid value for --arch. Must be 'x64' or 'arm64'."
27-
exit 1
28-
fi
2929
shift 2
3030
;;
3131
--profile)
@@ -56,14 +56,20 @@ if [ -z "$arch" ]; then
5656
exit 1
5757
fi
5858

59+
if [ -z "$sources" ]; then
60+
echo "Error: --sources must be set."
61+
exit 1
62+
fi
63+
5964
echo "Building LiveKit WebRTC - Linux"
6065
echo "Arch: $arch"
6166
echo "Profile: $profile"
6267
echo "Toolchain: $toolchain"
6368

64-
export COMMAND_DIR=$(cd $(dirname $0); pwd)
65-
export OUTPUT_DIR="$(pwd)/build-$arch-$profile"
66-
export ARTIFACTS_DIR="$(pwd)/linux-$arch-$profile"
69+
COMMAND_DIR=$(cd $(dirname $0); pwd)
70+
OUTPUT_DIR="$(dirname "$sources")"
71+
BUILD_DIR="$OUTPUT_DIR/build-$arch-$profile"
72+
ARTIFACTS_DIR="$OUTPUT_DIR/linux-$arch-$profile"
6773

6874
if [ "$toolchain" == "gnu" ]; then
6975
[ -n "$CC" ] || export CC="$(which gcc)"
@@ -91,39 +97,12 @@ elif [ "$toolchain" == "llvm" ]; then
9197
custom_toolchain=\"//build/toolchain/linux/unbundle:default\" \
9298
host_toolchain=\"//build/toolchain/linux/unbundle:default\""
9399
elif [ "$toolchain" == "chromium-llvm" ]; then
94-
AR="$COMMAND_DIR/src/third_party/llvm-build/Release+Asserts/bin/llvm-ar"
95-
OBJCOPY="$COMMAND_DIR/src/third_party/llvm-build/Release+Asserts/bin/llvm-objcopy"
100+
AR="$sources/third_party/llvm-build/Release+Asserts/bin/llvm-ar"
101+
OBJCOPY="$sources/third_party/llvm-build/Release+Asserts/bin/llvm-objcopy"
96102
chromium_libcxx=true
97103
toolchain_gn_args="is_clang=true use_custom_libcxx=true"
98104
fi
99105

100-
set -x
101-
102-
if [ ! -e "$(pwd)/depot_tools" ]
103-
then
104-
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
105-
fi
106-
107-
# must be done after runing `which` to find toolchain's executables above
108-
export PATH="$(pwd)/depot_tools:$PATH"
109-
110-
if [ ! -e "$(pwd)/src" ]; then
111-
# use --nohooks to avoid the download_from_google_storage hook that takes > 6 minutes
112-
# then manually run the other hooks
113-
gclient sync -D --no-history --nohooks
114-
python3 src/tools/rust/update_rust.py
115-
if [ "$toolchain" == "chromium-llvm" ] || [ "$toolchain" == "llvm" ]; then
116-
python3 src/tools/clang/scripts/update.py
117-
fi
118-
fi
119-
120-
cd src
121-
git apply "$COMMAND_DIR/patches/add_licenses.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
122-
git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
123-
git apply "$COMMAND_DIR/patches/add_deps.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
124-
git apply "$COMMAND_DIR/patches/david_disable_gun_source_macro.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
125-
cd ..
126-
127106
debug="false"
128107
if [ "$profile" = "debug" ]; then
129108
debug="true"
@@ -156,30 +135,31 @@ args="is_debug=$debug \
156135
rtc_use_x11=true \
157136
$toolchain_gn_args"
158137

159-
set -e
138+
set -xe
160139

161140
# generate ninja files
162-
gn gen "$OUTPUT_DIR" --root="src" --args="${args}"
141+
export PATH="$sources/depot_tools:$PATH"
142+
gn gen "$BUILD_DIR" --root="$sources" --args="${args}"
163143

164144
# build static library
165-
ninja -C "$OUTPUT_DIR" :default
145+
ninja -C "$BUILD_DIR" :default
166146

167147
mkdir -p "$ARTIFACTS_DIR/lib"
168148

169149
# make libwebrtc.a
170150
# don't include nasm
171-
"$AR" -rc "$ARTIFACTS_DIR/lib/libwebrtc.a" `find "$OUTPUT_DIR/obj" -name '*.o' -not -path "*/third_party/nasm/*"`
151+
"$AR" -rc "$ARTIFACTS_DIR/lib/libwebrtc.a" `find "$BUILD_DIR/obj" -name '*.o' -not -path "*/third_party/nasm/*"`
172152
"$OBJCOPY" --redefine-syms="$COMMAND_DIR/boringssl_prefix_symbols.txt" "$ARTIFACTS_DIR/lib/libwebrtc.a"
173153

174-
python3 "./src/tools_webrtc/libs/generate_licenses.py" \
175-
--target :default "$OUTPUT_DIR" "$OUTPUT_DIR"
154+
python3 "$sources/tools_webrtc/libs/generate_licenses.py" \
155+
--target :default "$BUILD_DIR" "$BUILD_DIR"
176156

177-
cp "$OUTPUT_DIR/obj/webrtc.ninja" "$ARTIFACTS_DIR"
178-
cp "$OUTPUT_DIR/obj/modules/desktop_capture/desktop_capture.ninja" "$ARTIFACTS_DIR"
179-
cp "$OUTPUT_DIR/args.gn" "$ARTIFACTS_DIR"
180-
cp "$OUTPUT_DIR/LICENSE.md" "$ARTIFACTS_DIR"
157+
cp "$BUILD_DIR/obj/webrtc.ninja" "$ARTIFACTS_DIR"
158+
cp "$BUILD_DIR/obj/modules/desktop_capture/desktop_capture.ninja" "$ARTIFACTS_DIR"
159+
cp "$BUILD_DIR/args.gn" "$ARTIFACTS_DIR"
160+
cp "$BUILD_DIR/LICENSE.md" "$ARTIFACTS_DIR"
181161

182-
cd src
162+
cd $sources
183163
if [ $chromium_libcxx == "true" ]; then
184164
mkdir -p "$ARTIFACTS_DIR/include/buildtools/third_party"
185165
cp -R buildtools/third_party/libc++ "$ARTIFACTS_DIR/include/buildtools/third_party"
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/bin/bash
2+
3+
COMMAND_DIR="$(cd $(dirname $0); pwd)"
4+
SOURCE_DIR="$COMMAND_DIR/src"
5+
ARCHIVE_PATH="$COMMAND_DIR/libwebrtc-source.tar.xz"
6+
7+
set -x
8+
9+
# for debugging this script
10+
reset() {
11+
rm -rf "$SOURCE_DIR" "$COMMAND_DIR/depot_tools" "$ARCHIVE_PATH"
12+
}
13+
14+
download() {
15+
cd "$COMMAND_DIR"
16+
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
17+
# use --nohooks to avoid the download_from_google_storage hook that takes > 6 minutes
18+
# then manually run the other hooks
19+
export PATH="$COMMAND_DIR/depot_tools:$PATH"
20+
gclient sync -D --no-history --nohooks
21+
python3 "$SOURCE_DIR/tools/rust/update_rust.py"
22+
python3 "$SOURCE_DIR/tools/clang/scripts/update.py"
23+
mv depot_tools src
24+
}
25+
26+
patch() {
27+
cd $SOURCE_DIR
28+
git apply "$COMMAND_DIR/patches/add_licenses.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
29+
git apply "$COMMAND_DIR/patches/ssl_verify_callback_with_native_handle.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
30+
git apply "$COMMAND_DIR/patches/add_deps.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
31+
cd third_party
32+
git apply "$COMMAND_DIR/patches/david_disable_gun_source_macro.patch" -v --ignore-space-change --ignore-whitespace --whitespace=nowarn
33+
}
34+
35+
clean() {
36+
required_files_and_dirs=(
37+
abseil-cpp
38+
boringssl
39+
catapult
40+
closure_compiler
41+
dav1d
42+
ffmpeg
43+
freetype
44+
googletest
45+
harfbuzz-ng
46+
icu
47+
jsoncpp
48+
libaom
49+
libjpeg_turbo
50+
libjpeg.gni
51+
BUILD.gn
52+
libpng
53+
libsrtp
54+
libvpx
55+
libyuv
56+
nasm
57+
openh264
58+
opus
59+
perfetto
60+
protobuf
61+
protobuf-javascript
62+
rust
63+
rust-toolchain
64+
zlib
65+
fuzztest
66+
crc32c
67+
pffft
68+
re2
69+
google_benchmark
70+
rnnoise
71+
)
72+
for filename in $(ls -1 "$SOURCE_DIR/third_party"); do
73+
if ! [[ ${required_files_and_dirs[@]} =~ $filename ]]; then
74+
rm -rf "$SOURCE_DIR/third_party/$filename"
75+
fi
76+
done
77+
78+
third_party_dirs=(
79+
rust-toolchain/bin
80+
rust-toolchain/lib
81+
catapult/tracing/test_data
82+
catapult/third_party/vinn/third_party/v8
83+
catapult/third_party/gsutil
84+
rust/chromium_crates_io
85+
boringssl/src/third_party/wycheproof_testvectors
86+
openh264/src/res
87+
ffmpeg/tests
88+
harfbuzz-ng/src/test
89+
harfbuzz-ng/src/perf
90+
perfetto/src/traced/probes/ftrace/test
91+
perfetto/src/trace_processor
92+
perfetto/docs
93+
perfetto/test
94+
perfetto/ui
95+
icu/source/data
96+
icu/source/test
97+
icu/source
98+
boringssl/src/crypto/cipher/test
99+
boringssl/src/fuzz
100+
opus/src/dnn/torch/osce/resources
101+
nasm/travis
102+
nasm/test
103+
closure_compiler/compiler
104+
)
105+
for dir in "${third_party_dirs[@]}"; do
106+
rm -rf "$SOURCE_DIR/third_party/$dir"
107+
done
108+
109+
src_dirs=(
110+
depot_tools/.cipd_bin
111+
depot_tools/.cipd_client
112+
buildtools/reclient
113+
tools/perf/testdata
114+
tools/luci-go
115+
tools/metrics
116+
tools/resultdb
117+
tools/perf/page_sets
118+
tools/perf/core/shard_maps/timing_data
119+
tools/disable_tests/tests
120+
data
121+
base/test
122+
)
123+
for dir in "${src_dirs[@]}"; do
124+
rm -rf "$SOURCE_DIR/$dir"
125+
done
126+
127+
dir_names=(testdata test_data doc docs \.git)
128+
for dir_name in "${dir_names[@]}"; do
129+
for dir in $(find "$SOURCE_DIR" -name $dir_name); do
130+
rm -rf "$dir"
131+
done
132+
done
133+
}
134+
135+
package() {
136+
tar -Jcf "$ARCHIVE_PATH" -C "$COMMAND_DIR" src
137+
}
138+
139+
reset
140+
set -e
141+
download
142+
patch
143+
clean
144+
package

0 commit comments

Comments
 (0)