Wire local TDLib into iOS FFI build
This commit is contained in:
55
scripts/build-ios-ffi-with-local-tdlib.sh
Executable file
55
scripts/build-ios-ffi-with-local-tdlib.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
target="${IOS_RUST_TARGET:-aarch64-apple-ios-sim}"
|
||||
|
||||
case "${target}" in
|
||||
aarch64-apple-ios)
|
||||
tdlib_platform_dir="${TDLIB_IOS_PLATFORM_DIR:-iphoneos}"
|
||||
;;
|
||||
aarch64-apple-ios-sim | x86_64-apple-ios)
|
||||
tdlib_platform_dir="${TDLIB_IOS_PLATFORM_DIR:-iphonesimulator}"
|
||||
;;
|
||||
*)
|
||||
printf 'Unsupported iOS Rust target: %s\n' "${target}" >&2
|
||||
printf 'Supported targets: aarch64-apple-ios, aarch64-apple-ios-sim, x86_64-apple-ios\n' >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
tdlib_root="${LOCAL_TDLIB_PATH:-${repo_root}/.build/tdlib-ios/${tdlib_platform_dir}}"
|
||||
tdlib_version="${TDLIB_VERSION:-1.8.29}"
|
||||
|
||||
if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then
|
||||
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||
fi
|
||||
|
||||
if [[ ! -d "${tdlib_root}/include" ]]; then
|
||||
printf 'TDLib include directory not found: %s\n' "${tdlib_root}/include" >&2
|
||||
printf 'Run scripts/build-tdlib-ios.sh first or set LOCAL_TDLIB_PATH to a TDLib install root.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${tdlib_root}/lib/libtdjson.${tdlib_version}.dylib" ]]; then
|
||||
printf 'TDLib dylib not found: %s\n' "${tdlib_root}/lib/libtdjson.${tdlib_version}.dylib" >&2
|
||||
printf 'tdlib-rs local-tdlib expects the versioned dylib name on macOS-hosted builds.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "${repo_root}"
|
||||
|
||||
if ! rustup target list --installed | grep -qx "${target}"; then
|
||||
rustup target add "${target}"
|
||||
fi
|
||||
|
||||
export LOCAL_TDLIB_PATH="${tdlib_root}"
|
||||
|
||||
cargo build \
|
||||
-p tele-ios-ffi \
|
||||
--no-default-features \
|
||||
--features core-session-local-tdlib \
|
||||
--target "${target}" \
|
||||
--release
|
||||
|
||||
printf 'Built tele-ios-ffi for %s with LOCAL_TDLIB_PATH=%s\n' "${target}" "${LOCAL_TDLIB_PATH}"
|
||||
131
scripts/build-ios-real-ffi-xcframework.sh
Executable file
131
scripts/build-ios-real-ffi-xcframework.sh
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
package_dir="${repo_root}/apps/ios/TeleTuiIOS"
|
||||
out_dir="${1:-${repo_root}/build/ios-real-ffi-xcframework}"
|
||||
artifacts_dir="${package_dir}/BinaryArtifacts"
|
||||
swift_sources_dir="${package_dir}/Generated/tele_ios_ffi/Sources/tele_ios_ffi"
|
||||
framework_name="${IOS_FFI_FRAMEWORK_NAME:-tele_ios_ffi}"
|
||||
tdjson_framework_name="${IOS_TDJSON_FRAMEWORK_NAME:-tdjson}"
|
||||
targets="${IOS_RUST_TARGETS:-}"
|
||||
|
||||
if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then
|
||||
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||
fi
|
||||
|
||||
if [[ -z "${targets}" ]]; then
|
||||
targets="x86_64-apple-ios aarch64-apple-ios-sim"
|
||||
fi
|
||||
|
||||
cd "${repo_root}"
|
||||
|
||||
case "${out_dir}" in
|
||||
"" | "/" | "/tmp" | "/private" | "/private/tmp")
|
||||
printf 'Refusing unsafe output directory: %s\n' "${out_dir}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
rm -rf "${out_dir}"
|
||||
mkdir -p "${out_dir}/Swift" "${out_dir}/Headers" "${out_dir}/TdjsonHeaders"
|
||||
|
||||
tdjson_args=()
|
||||
first_lib_path=""
|
||||
simulator_libs=()
|
||||
device_lib=""
|
||||
seen_simulator=0
|
||||
seen_device=0
|
||||
|
||||
for target in ${targets}; do
|
||||
IOS_RUST_TARGET="${target}" "${repo_root}/scripts/build-ios-ffi-with-local-tdlib.sh"
|
||||
lib_path="${repo_root}/target/${target}/release/libtele_ios_ffi.a"
|
||||
if [[ -z "${first_lib_path}" ]]; then
|
||||
first_lib_path="${lib_path}"
|
||||
fi
|
||||
|
||||
case "${target}" in
|
||||
aarch64-apple-ios)
|
||||
seen_device=1
|
||||
device_lib="${lib_path}"
|
||||
;;
|
||||
aarch64-apple-ios-sim | x86_64-apple-ios)
|
||||
seen_simulator=1
|
||||
simulator_libs+=("${lib_path}")
|
||||
;;
|
||||
*)
|
||||
printf 'Unsupported iOS Rust target for XCFramework packaging: %s\n' "${target}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${first_lib_path}" ]]; then
|
||||
printf 'No Rust targets selected for iOS FFI packaging\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Swift" --swift-sources
|
||||
cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Headers" --headers
|
||||
cargo run -p uniffi-bindgen-swift -- "${first_lib_path}" "${out_dir}/Headers" \
|
||||
--modulemap \
|
||||
--module-name tele_ios_ffiFFI \
|
||||
--modulemap-filename module.modulemap
|
||||
|
||||
cat > "${out_dir}/TdjsonHeaders/tdjson.h" <<'HEADER'
|
||||
void td_json_client_send(void *client, const char *request);
|
||||
const char *td_json_client_receive(void *client, double timeout);
|
||||
const char *td_json_client_execute(void *client, const char *request);
|
||||
void *td_json_client_create(void);
|
||||
void td_json_client_destroy(void *client);
|
||||
HEADER
|
||||
|
||||
if [[ "${seen_simulator}" == "1" ]]; then
|
||||
tdjson_args+=(
|
||||
"-library" "${repo_root}/.build/tdlib-ios/iphonesimulator/lib/libtdjson.1.8.29.dylib"
|
||||
"-headers" "${out_dir}/TdjsonHeaders"
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ "${seen_device}" == "1" ]]; then
|
||||
tdjson_args+=(
|
||||
"-library" "${repo_root}/.build/tdlib-ios/iphoneos/lib/libtdjson.1.8.29.dylib"
|
||||
"-headers" "${out_dir}/TdjsonHeaders"
|
||||
)
|
||||
fi
|
||||
|
||||
rm -rf "${artifacts_dir}/${framework_name}.xcframework" \
|
||||
"${artifacts_dir}/${tdjson_framework_name}.xcframework" \
|
||||
"${swift_sources_dir}"
|
||||
mkdir -p "${artifacts_dir}" "${swift_sources_dir}"
|
||||
|
||||
ffi_args=()
|
||||
if [[ "${#simulator_libs[@]}" -gt 0 ]]; then
|
||||
simulator_lib="${out_dir}/libtele_ios_ffi-iphonesimulator.a"
|
||||
if [[ "${#simulator_libs[@]}" -eq 1 ]]; then
|
||||
cp "${simulator_libs[0]}" "${simulator_lib}"
|
||||
else
|
||||
xcrun lipo -create "${simulator_libs[@]}" -output "${simulator_lib}"
|
||||
fi
|
||||
ffi_args+=("-library" "${simulator_lib}" "-headers" "${out_dir}/Headers")
|
||||
fi
|
||||
|
||||
if [[ -n "${device_lib}" ]]; then
|
||||
ffi_args+=("-library" "${device_lib}" "-headers" "${out_dir}/Headers")
|
||||
fi
|
||||
|
||||
xcodebuild -create-xcframework \
|
||||
"${ffi_args[@]}" \
|
||||
-output "${artifacts_dir}/${framework_name}.xcframework"
|
||||
|
||||
xcodebuild -create-xcframework \
|
||||
"${tdjson_args[@]}" \
|
||||
-output "${artifacts_dir}/${tdjson_framework_name}.xcframework"
|
||||
|
||||
cp "${out_dir}/Swift/tele_ios_ffi.swift" "${swift_sources_dir}/tele_ios_ffi.swift"
|
||||
|
||||
printf 'Generated real iOS FFI artifacts:\n'
|
||||
printf ' %s\n' "${artifacts_dir}/${framework_name}.xcframework"
|
||||
printf ' %s\n' "${artifacts_dir}/${tdjson_framework_name}.xcframework"
|
||||
printf ' %s\n' "${swift_sources_dir}/tele_ios_ffi.swift"
|
||||
printf 'Build Swift package with: TELE_IOS_USE_LOCAL_FFI=1 DEVELOPER_DIR=%s xcodebuild ...\n' "${DEVELOPER_DIR:-}"
|
||||
@@ -81,6 +81,17 @@ cat > "${app_path}/Info.plist" <<PLIST
|
||||
</plist>
|
||||
PLIST
|
||||
|
||||
tdjson_path="${product_dir}/libtdjson.1.8.29.dylib"
|
||||
if [[ -f "${tdjson_path}" ]]; then
|
||||
mkdir -p "${app_path}/Frameworks"
|
||||
cp "${tdjson_path}" "${app_path}/Frameworks/libtdjson.dylib"
|
||||
codesign --remove-signature "${app_path}/TeleTuiIOSApp" >/dev/null 2>&1 || true
|
||||
if ! otool -l "${app_path}/TeleTuiIOSApp" | grep -q '@executable_path/Frameworks'; then
|
||||
install_name_tool -add_rpath '@executable_path/Frameworks' "${app_path}/TeleTuiIOSApp"
|
||||
fi
|
||||
codesign --force --sign - --timestamp=none "${app_path}/Frameworks/libtdjson.dylib" >/dev/null
|
||||
fi
|
||||
|
||||
codesign --force --sign - --timestamp=none "${app_path}/TeleTuiIOSApp" >/dev/null
|
||||
codesign --force --sign - --timestamp=none "${app_path}" >/dev/null
|
||||
|
||||
|
||||
187
scripts/build-tdlib-ios.sh
Executable file
187
scripts/build-tdlib-ios.sh
Executable file
@@ -0,0 +1,187 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
tdlib_version="${TDLIB_VERSION:-1.8.29}"
|
||||
tdlib_commit="${TDLIB_COMMIT:-af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6}"
|
||||
tdlib_repo="${TDLIB_REPO:-https://github.com/tdlib/td.git}"
|
||||
source_dir="${TDLIB_SOURCE_DIR:-${repo_root}/.build/tdlib-src}"
|
||||
build_root="${TDLIB_BUILD_ROOT:-${repo_root}/.build/tdlib-ios-build}"
|
||||
output_root="${TDLIB_OUTPUT_ROOT:-${repo_root}/.build/tdlib-ios}"
|
||||
platforms="${TDLIB_IOS_PLATFORMS:-iOS iOS-simulator}"
|
||||
openssl_platforms="${TDLIB_OPENSSL_PLATFORMS:-iOS iOS-simulator}"
|
||||
ios_deployment_target="${TDLIB_IOS_DEPLOYMENT_TARGET:-17.0}"
|
||||
jobs="${TDLIB_BUILD_JOBS:-3}"
|
||||
|
||||
if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]]; then
|
||||
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||
fi
|
||||
|
||||
require_tool() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
printf 'Required tool not found: %s\n' "$1" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
missing=0
|
||||
for tool in git cmake c++ gperf make perl rsync xcodebuild xcrun install_name_tool; do
|
||||
require_tool "${tool}" || missing=1
|
||||
done
|
||||
|
||||
if [[ "${missing}" -ne 0 ]]; then
|
||||
printf '\nInstall missing TDLib build dependencies on macOS with:\n' >&2
|
||||
printf ' brew install cmake gperf coreutils\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! xcrun --sdk iphoneos --show-sdk-path >/dev/null; then
|
||||
printf 'The iphoneos SDK is unavailable through xcrun.\n' >&2
|
||||
printf 'Set DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer and install the iOS platform in Xcode.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${source_dir}")" "${build_root}" "${output_root}"
|
||||
|
||||
if [[ ! -d "${source_dir}/.git" ]]; then
|
||||
git clone "${tdlib_repo}" "${source_dir}"
|
||||
fi
|
||||
|
||||
git -C "${source_dir}" fetch --depth 1 origin "${tdlib_commit}"
|
||||
git -C "${source_dir}" checkout --detach "${tdlib_commit}"
|
||||
|
||||
openssl_root="${source_dir}/example/ios/third_party/openssl"
|
||||
python_apple_support_dir="${source_dir}/example/ios/Python-Apple-support"
|
||||
|
||||
prepare_python_apple_support() {
|
||||
if [[ ! -d "${python_apple_support_dir}/.git" ]]; then
|
||||
git clone https://github.com/beeware/Python-Apple-support "${python_apple_support_dir}"
|
||||
fi
|
||||
|
||||
git -C "${python_apple_support_dir}" checkout 6f43aba0ddd5a9f52f39775d0141bd4363614020
|
||||
git -C "${python_apple_support_dir}" reset --hard
|
||||
(
|
||||
cd "${python_apple_support_dir}"
|
||||
git apply ../Python-Apple-support.patch
|
||||
# Python-Apple-support at this revision emits apple-ios-simulator-simulator
|
||||
# under newer Xcode SDK naming. Use the base OS name before appending
|
||||
# "-simulator" to the target triple.
|
||||
perl -pi -e 's/apple-\$\$\(OS_LOWER-\$\(target\)\)-simulator/apple-\$\$\(patsubst %-simulator,%,\$\$\(OS_LOWER-\$\(target\)\)\)-simulator/' Makefile
|
||||
)
|
||||
}
|
||||
|
||||
prepare_td_auto_sources() {
|
||||
local host_build_dir="${build_root}/build-host-generate"
|
||||
local td_auto_dir="${source_dir}/td/generate/auto/td/telegram"
|
||||
local mime_auto_dir="${source_dir}/tdutils/generate/auto"
|
||||
|
||||
if [[ -f "${td_auto_dir}/td_api.cpp" \
|
||||
&& -f "${td_auto_dir}/td_api_json.cpp" \
|
||||
&& -f "${mime_auto_dir}/mime_type_to_extension.cpp" \
|
||||
&& -f "${mime_auto_dir}/extension_to_mime_type.cpp" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
ZERO_AR_DATE=1 cmake -S "${source_dir}" -B "${host_build_dir}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
-DCMAKE_MAKE_PROGRAM=make
|
||||
|
||||
cmake --build "${host_build_dir}" --target prepare_cross_compiling -- -j"${jobs}"
|
||||
}
|
||||
|
||||
prepare_openssl_platform() {
|
||||
local platform="$1"
|
||||
local output_dir="${openssl_root}/${platform}"
|
||||
|
||||
if [[ -f "${output_dir}/lib/libcrypto.a" && -f "${output_dir}/lib/libssl.a" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
prepare_python_apple_support
|
||||
|
||||
(
|
||||
cd "${python_apple_support_dir}"
|
||||
rm -rf "build/${platform}" "install/${platform}" "merge/${platform}"
|
||||
make "OpenSSL-${platform}"
|
||||
)
|
||||
|
||||
rm -rf "${output_dir}"
|
||||
mkdir -p "${output_dir}/lib"
|
||||
cp "${python_apple_support_dir}/merge/${platform}/openssl/lib/libcrypto.a" "${output_dir}/lib/"
|
||||
cp "${python_apple_support_dir}/merge/${platform}/openssl/lib/libssl.a" "${output_dir}/lib/"
|
||||
cp -R "${python_apple_support_dir}/merge/${platform}/openssl/include" "${output_dir}/include"
|
||||
}
|
||||
|
||||
if [[ ! -f "${openssl_root}/iOS/lib/libcrypto.a" || ! -f "${openssl_root}/iOS-simulator/lib/libcrypto.a" ]]; then
|
||||
printf 'OpenSSL for iOS was not found under %s.\n' "${openssl_root}" >&2
|
||||
printf 'Building only required OpenSSL platforms: %s\n' "${openssl_platforms}"
|
||||
for platform in ${openssl_platforms}; do
|
||||
prepare_openssl_platform "${platform}"
|
||||
done
|
||||
fi
|
||||
|
||||
prepare_td_auto_sources
|
||||
|
||||
build_platform() {
|
||||
local td_platform="$1"
|
||||
local ios_platform
|
||||
local out_platform
|
||||
|
||||
case "${td_platform}" in
|
||||
iOS)
|
||||
ios_platform="OS"
|
||||
out_platform="iphoneos"
|
||||
;;
|
||||
iOS-simulator)
|
||||
ios_platform="SIMULATOR"
|
||||
out_platform="iphonesimulator"
|
||||
;;
|
||||
*)
|
||||
printf 'Unsupported TDLib iOS platform: %s\n' "${td_platform}" >&2
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local openssl_path="${openssl_root}/${td_platform}"
|
||||
local openssl_crypto_library="${openssl_path}/lib/libcrypto.a"
|
||||
local openssl_ssl_library="${openssl_path}/lib/libssl.a"
|
||||
local build_dir="${build_root}/build-${td_platform}"
|
||||
local install_dir="${build_root}/install-${td_platform}"
|
||||
local output_dir="${output_root}/${out_platform}"
|
||||
|
||||
if [[ ! -f "${openssl_crypto_library}" || ! -f "${openssl_ssl_library}" ]]; then
|
||||
printf 'OpenSSL libraries are missing for %s under %s\n' "${td_platform}" "${openssl_path}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -rf "${build_dir}" "${install_dir}" "${output_dir}"
|
||||
mkdir -p "${build_dir}" "${install_dir}" "${output_dir}/include" "${output_dir}/lib"
|
||||
|
||||
ZERO_AR_DATE=1 cmake -S "${source_dir}" -B "${build_dir}" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
-DCMAKE_INSTALL_PREFIX="${install_dir}" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${source_dir}/CMake/iOS.cmake" \
|
||||
-DIOS_PLATFORM="${ios_platform}" \
|
||||
-DIOS_DEPLOYMENT_TARGET="${ios_deployment_target}" \
|
||||
-DCMAKE_MAKE_PROGRAM=make \
|
||||
-DOPENSSL_FOUND=1 \
|
||||
-DOPENSSL_CRYPTO_LIBRARY="${openssl_crypto_library}" \
|
||||
-DOPENSSL_SSL_LIBRARY="${openssl_ssl_library}" \
|
||||
-DOPENSSL_INCLUDE_DIR="${openssl_path}/include" \
|
||||
-DOPENSSL_LIBRARIES="${openssl_crypto_library};${openssl_ssl_library}"
|
||||
|
||||
cmake --build "${build_dir}" --target install -- -j"${jobs}"
|
||||
|
||||
install_name_tool -id @rpath/libtdjson.dylib "${install_dir}/lib/libtdjson.dylib"
|
||||
rsync -a "${install_dir}/include/" "${output_dir}/include/"
|
||||
cp "${install_dir}/lib/libtdjson.dylib" "${output_dir}/lib/libtdjson.dylib"
|
||||
cp "${install_dir}/lib/libtdjson.dylib" "${output_dir}/lib/libtdjson.${tdlib_version}.dylib"
|
||||
|
||||
printf 'Installed TDLib %s for %s at %s\n' "${tdlib_version}" "${td_platform}" "${output_dir}"
|
||||
}
|
||||
|
||||
for platform in ${platforms}; do
|
||||
build_platform "${platform}"
|
||||
done
|
||||
@@ -5,10 +5,4 @@ if [[ -z "${DEVELOPER_DIR:-}" && -d /Applications/Xcode.app/Contents/Developer ]
|
||||
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
|
||||
fi
|
||||
|
||||
target="${IOS_RUST_TARGET:-aarch64-apple-ios-sim}"
|
||||
|
||||
if ! rustup target list --installed | grep -qx "${target}"; then
|
||||
rustup target add "${target}"
|
||||
fi
|
||||
|
||||
cargo build -p tele-ios-ffi --target "${target}" --release
|
||||
exec "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/build-ios-ffi-with-local-tdlib.sh"
|
||||
|
||||
Reference in New Issue
Block a user