0

Building WebRTC directly is somewhat painful (& rather time consuming so not ideal in paid for CI environments) so I've opted to use some excellent precompiled static libraries released on GitHub to speed things up. This has worked perfectly for all platforms I'm targetting (Windows, MacOS, iOS, Apple TVOS, linux...) except for Android.

When linking the binary on Android I encounter several duplicate symbol errors related to the std libary:

ld: error: duplicate symbol: std::logic_error::logic_error(char const*)
>>> defined at stdexcept_default.ipp:24 (../../../../../_source/android/webrtc/src/buildtools/third_party/libc++/trunk/src/support/runtime/stdexcept_default.ipp:24)
>>>            stdexcept.o:(std::logic_error::logic_error(char const*)) in archive /root/webrtc/lib/armeabi-v7a/libwebrtc.a
>>> defined at stdexcept_default.ipp:24 (/buildbot/src/android/ndk-release-r23/toolchain/llvm-project/libcxx/src/support/runtime/stdexcept_default.ipp:24)
>>>            stdexcept.o:(.text._ZNSt11logic_errorC2EPKc+0x1) in archive /app/android-sdk-linux/ndk/23.1.7779620/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_static.a

...


ld: error: duplicate symbol: std::runtime_error::runtime_error(char const*)
>>> defined at stdexcept_default.ipp:35 (../../../../../_source/android/webrtc/src/buildtools/third_party/libc++/trunk/src/support/runtime/stdexcept_default.ipp:35)
>>>            stdexcept.o:(std::runtime_error::runtime_error(char const*)) in archive /root/webrtc/lib/armeabi-v7a/libwebrtc.a
>>> defined at stdexcept_default.ipp:35 (/buildbot/src/android/ndk-release-r23/toolchain/llvm-project/libcxx/src/support/runtime/stdexcept_default.ipp:35)
>>>            stdexcept.o:(.text._ZNSt13runtime_errorC2EPKc+0x1) in archive /app/android-sdk-linux/ndk/23.1.7779620/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_static.a

It appears that libwebrtc.a for Android includes some libc++ object files and I'm not entirely sure how to successfully link with this library here.

This might be coming down to the libwebrtc.a being compiled with Google's own patched libc++ (Based on what I've read online I believe Google contributes patches to upstream libc++ but they don't wait for the patches to go in - rather they use their fully patched version of libc++ for building WebRTC, Chrome, etc).

When compiling for Linux I actually use the exact versions of clang & libc++ that were downloaded & used in building the static library & I suspect I might need to be doing something similar here - I'm just not entirely sure how given the need to use the Android CMake toolchain.

I've put together a minimal example project on GitHub with Dockerfile that can be used to easily reproduce the above issue.

Does anyone have an idea how I can successfully link the library on Android?

For completeness the source files of interest are:

CMakeLists.txt

cmake_minimum_required(VERSION 3.23)
project(AndroidWebRTC)

set(CMAKE_CXX_STANDARD 17)

add_executable(AndroidWebRTC src/main.cpp)
target_link_libraries(AndroidWebRTC PRIVATE ${WEBRTC_LIBRARY})
add_compile_definitions(WEBRTC_POSIX WEBRTC_ANDROID WEBRTC_LINUX)
include_directories(
        ${WEBRTC_INCLUDE_DIR}
        ${WEBRTC_INCLUDE_DIR}/third_party/abseil-cpp
        ${WEBRTC_INCLUDE_DIR}/third_party/boringssl/src/include
        ${WEBRTC_INCLUDE_DIR}/third_party/libyuv/include
        ${WEBRTC_INCLUDE_DIR}/third_party/zlib
)

Dockerfile

# I explicitly specify an amd64 platform as I often build on Apple Silicon
# machines where the default of arm64 breaks things. I believe the alternative
# (and possibly better option) is to use NDK 24 and above, see:
# https://stackoverflow.com/a/69541958
FROM  --platform=linux/amd64 ubuntu:20.04 AS build

ENV ANDROID_SDK_ROOT /app/android-sdk-linux

WORKDIR /app

# Install dependencies to build the project
# include apt-get --no-install-recommends
RUN apt-get update && \
    apt-get -y upgrade && \
    apt-get --no-install-recommends -y install tzdata && \
    echo 'Europe/London' > /etc/timezone && \
    dpkg-reconfigure -f noninteractive tzdata

RUN apt-get --no-install-recommends -y install git lsb-release python rsync \
    emacs wget build-essential sudo pkg-config clang unzip openjdk-8-jdk ant  \
    android-sdk-platform-tools-common libncurses5 curl

RUN mkdir ${ANDROID_SDK_ROOT}

# ------------------------------------------------------
# --- Android SDK
RUN wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip && \
    unzip commandlinetools-linux-7583922_latest.zip && \
    mkdir ${ANDROID_SDK_ROOT}/cmdline-tools/ &&\
    mv cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest && \
    rm commandlinetools-linux-7583922_latest.zip

ENV PATH ${PATH}:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin

RUN yes | sdkmanager --licenses

RUN touch /root/.android/repositories.cfg

# Platform tools
RUN yes | sdkmanager "platform-tools"

RUN yes | sdkmanager --update --channel=0

# Keep all sections in descending order!
RUN yes | sdkmanager \
    "platforms;android-30" \
    "build-tools;31.0.0" \
    "ndk;23.1.7779620" \
    "extras;android;m2repository" \
    "extras;google;m2repository" \
    "extras;google;google_play_services" \
    "add-ons;addon-google_apis-google-24"

ENV ANDROID_HOME ${ANDROID_SDK_ROOT}
ENV ANDROID_NDK_HOME=${ANDROID_SDK_ROOT}/ndk/23.1.7779620
ENV PATH ${PATH}:${ANDROID_NDK_HOME}:${ANDROID_HOME}/build-tools/31.0.0/

# Get CMake
COPY scripts/get_cmake.sh scripts/get_cmake.sh
RUN ./scripts/get_cmake.sh "3.25.1" linux /root
ENV PATH "/root/cmake/bin:$PATH"

# Get WebRTC
COPY scripts/get_webrtc.sh scripts/get_webrtc.sh
RUN ./scripts/get_webrtc.sh 108.5359.5.0 android /root /root

## Copy resources
COPY src src
COPY CMakeLists.txt ./

RUN cmake -B build  \
    -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake" \
    -DANDROID_ABI=armeabi-v7a \
    -DANDROID_NATIVE_API_LEVEL=16 \
    -DBUILD_SHARED_LIBS=OFF \
    -DWEBRTC_INCLUDE_DIR=/root/webrtc/include \
    -DWEBRTC_LIBRARY=/root/webrtc/lib/armeabi-v7a/libwebrtc.a \
    -DCMAKE_BUILD_TYPE=Release

RUN cmake --build build --config Release --parallel $(nproc) --target AndroidWebRTC

src/main.cpp

#include <iostream>

#include <api/create_peerconnection_factory.h>

int main() {
    auto googleSessionDescription = webrtc::CreateSessionDescription(
            webrtc::SdpType::kOffer, "sdp");
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

scripts/get_webrtc.sh

#!/bin/bash

if [ $# -lt 4 ]; then
  echo "$0 <webrtc_build_version> <package_name> <output_dir> <source_dir>"
  exit 1
fi

WEBRTC_BUILD_VERSION=$1
PACKAGE_NAME=$2
OUTPUT_DIR=$3
SOURCE_DIR=$4

set -ex

if [ ! -e $SOURCE_DIR/webrtc.${PACKAGE_NAME}.${WEBRTC_BUILD_VERSION}.tar.gz ]; then
  curl -Lo $SOURCE_DIR/webrtc.${PACKAGE_NAME}.${WEBRTC_BUILD_VERSION}.tar.gz https://github.com/shiguredo-webrtc-build/webrtc-build/releases/download/m${WEBRTC_BUILD_VERSION}/webrtc.${PACKAGE_NAME}.tar.gz
fi

pushd $OUTPUT_DIR
  tar xf $SOURCE_DIR/webrtc.${PACKAGE_NAME}.${WEBRTC_BUILD_VERSION}.tar.gz
popd

scripts/get_cmake.sh

#!/bin/bash

# <platform> には Linux か Darwin を指定する
# <output_dir>/cmake に CMake が配置される
if [ $# -lt 3 ]; then
  echo "$0 <cmake_version> <platform> <output_dir>"
  exit 1
fi

CMAKE_VERSION=$1
PLATFORM=$2
OUTPUT_DIR=$3

set -ex

pushd $OUTPUT_DIR
  curl -LO https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64.tar.gz
  tar xf cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64.tar.gz
  rm cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64.tar.gz
  rm -rf cmake
  mv cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64 cmake
popd
dbotha
  • 1,501
  • 4
  • 20
  • 38

0 Answers0