Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,50 @@ jobs:
name: app-debug
path: app/build/outputs/apk/debug/app-debug.apk

# ── Job 2b: Build debug APK on Linux (NDK cross-compile sanity on every PR) ──
# The macOS job above covers the primary dev path; this one guards the Linux
# toolchain (apt Boost in /usr/include + #include_next) so it can't silently rot.
build-linux:
name: Build Debug APK (Linux)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: recursive

- uses: actions/setup-java@v5
with:
java-version: '17'
distribution: temurin
cache: gradle

- uses: gradle/actions/setup-gradle@v6

- name: Install Boost via apt
run: sudo apt-get install -y libboost-dev

- name: Resolve Boost dirs
run: |
BOOST_DIR=$(find /usr/lib -maxdepth 4 -name "Boost-*" -type d 2>/dev/null \
| sort -V | tail -1)
echo "BOOST_CMAKE_DIR=$BOOST_DIR" >> "$GITHUB_ENV"
# Isolated dir with ONLY a boost/ symlink: -I<dir> finds boost/* but does
# not expose glibc system headers (features-time64.h → bits/wordsize.h)
# which are absent in the NDK cross-compilation sysroot.
mkdir -p /tmp/boost-headers
ln -sfn /usr/include/boost /tmp/boost-headers/boost
echo "BOOST_INCLUDE_DIR=/tmp/boost-headers" >> "$GITHUB_ENV"
echo "Found Boost CMake dir: $BOOST_DIR"

- name: Build debug APK
run: ./gradlew assembleDebug --no-daemon

- name: Upload APK
uses: actions/upload-artifact@v7
with:
name: app-debug-linux
path: app/build/outputs/apk/debug/app-debug.apk

# ── Job 3: Lint ─────────────────────────────────────────────────────────────
lint:
name: Lint
Expand Down
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,35 @@ export BOOST_CMAKE_DIR=/path/to/cmake/Boost-X.Y.Z
```bash
sudo apt-get install -y libboost-dev

BOOST_CMAKE_DIR=$(find /usr -name "BoostConfig.cmake" 2>/dev/null \
| head -1 | xargs dirname)
# 1. Boost's CMake config dir (for find_package)
BOOST_CMAKE_DIR=$(dirname "$(find /usr -name BoostConfig.cmake 2>/dev/null | head -1)")
export BOOST_CMAKE_DIR

# 2. An *isolated* Boost include dir — a directory containing ONLY a boost/ entry.
# Do NOT use /usr/include directly: the Android NDK headers use #include_next,
# which would pull the host glibc headers from /usr/include into the cross
# build and break it (missing bits/wordsize.h, bits/libc-header-start.h).
mkdir -p "$HOME/.boost-include"
ln -sfn /usr/include/boost "$HOME/.boost-include/boost"
export BOOST_INCLUDE_DIR="$HOME/.boost-include"

./gradlew assembleDebug
```

> On macOS this isolation is automatic — Homebrew's prefix holds Boost but no
> competing libc — which is why only `BOOST_CMAKE_DIR` is needed there.

#### Building from Android Studio on Linux

The IDE doesn't see your shell `export`s. Instead of env vars, put the same two
paths in `local.properties` (gitignored, alongside `sdk.dir`); the build falls
back to them automatically:

```properties
BOOST_CMAKE_DIR=/usr/lib/x86_64-linux-gnu/cmake/Boost-1.83.0
BOOST_INCLUDE_DIR=/home/<you>/.boost-include
```

## Running Tests

```bash
Expand Down
23 changes: 18 additions & 5 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import java.util.Properties

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.screenshot)
}

// Boost paths resolve in this order: environment variable, then local.properties
// (gitignored, same place as sdk.dir — handy when building from the IDE where shell
// exports aren't visible), then the macOS Homebrew default. See README "Linux".
val localProperties = Properties().apply {
val file = rootProject.file("local.properties")
if (file.exists()) file.inputStream().use { load(it) }
}
fun boostProperty(name: String, default: String): String =
System.getenv(name) ?: localProperties.getProperty(name) ?: default

android {
namespace = "com.jpcottin.simpletorrent"
compileSdk = 36
Expand All @@ -19,14 +31,15 @@ android {
externalNativeBuild {
cmake {
cppFlags += "-std=c++17"
// BOOST_CMAKE_DIR env var lets CI override the Homebrew default path
val boostDir = System.getenv("BOOST_CMAKE_DIR")
?: "/opt/homebrew/lib/cmake/Boost-1.90.0"
// BOOST_CMAKE_DIR (env or local.properties) overrides the Homebrew default path
val boostDir = boostProperty("BOOST_CMAKE_DIR",
"/opt/homebrew/lib/cmake/Boost-1.90.0")
// BOOST_INCLUDE_DIR: passed to CMake as a cache var; used via
// target_compile_options() in CMakeLists.txt so it bypasses both
// CMake's implicit-include filtering AND configure-time feature checks.
val boostInclude = System.getenv("BOOST_INCLUDE_DIR")
?: "/opt/homebrew/include"
// On Linux this must be a Boost-only dir, never /usr/include (see CMakeLists.txt).
val boostInclude = boostProperty("BOOST_INCLUDE_DIR",
"/opt/homebrew/include")
arguments(
// libtorrent is in libs/libtorrent submodule — no path override needed
"-DBoost_DIR=$boostDir",
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ add_library(simpletorrent SHARED torrent_jni.cpp)
# emits raw -I flags that bypass this filtering. Using cppFlags/CMAKE_CXX_FLAGS is
# also wrong because those affect configure-time feature probes (e.g. std::atomic
# check in libtorrent) and break cross-compilation with host headers in the way.
#
# IMPORTANT: BOOST_INCLUDE_DIR must point at a directory that contains ONLY Boost
# (i.e. just a `boost/` subdir), never the host's /usr/include. The NDK headers use
# #include_next, which walks past the sysroot into any dir on the search path; if
# host libc headers (limits.h, features.h, ...) are reachable there, the cross
# build breaks. On macOS, Homebrew's prefix already satisfies this. On Debian/Ubuntu
# the system Boost lives in /usr/include alongside glibc, so point BOOST_INCLUDE_DIR
# at an isolated Boost prefix instead (see README "Linux").
if(DEFINED BOOST_INCLUDE_DIR)
target_compile_options(torrent-rasterbar PRIVATE "-I${BOOST_INCLUDE_DIR}")
target_compile_options(simpletorrent PRIVATE "-I${BOOST_INCLUDE_DIR}")
Expand Down