From 688315d42982fa4661969ad0fdbbeecde3c3c0bb Mon Sep 17 00:00:00 2001 From: xingguangcuican6666 Date: Sun, 8 Mar 2026 13:12:13 +0800 Subject: [PATCH] addpkg(main/turbopack): 16.2.0~canary.84 Co-authored-by: Kuldeep-Dilliwar --- packages/turbopack/add_android_build.patch | 579 +++++++++++++++++++++ packages/turbopack/build.sh | 81 +++ 2 files changed, 660 insertions(+) create mode 100644 packages/turbopack/add_android_build.patch create mode 100644 packages/turbopack/build.sh diff --git a/packages/turbopack/add_android_build.patch b/packages/turbopack/add_android_build.patch new file mode 100644 index 00000000000..2d2f461bba9 --- /dev/null +++ b/packages/turbopack/add_android_build.patch @@ -0,0 +1,579 @@ +diff --git a/Cargo.lock b/Cargo.lock +index a06447a339..26a3e5247a 100644 +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -2404,6 +2404,16 @@ dependencies = [ + "syn 2.0.104", + ] + ++[[package]] ++name = "fs2" ++version = "0.4.3" ++source = "registry+https://github.com/rust-lang/crates.io-index" ++checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" ++dependencies = [ ++ "libc", ++ "winapi", ++] ++ + [[package]] + name = "fs_extra" + version = "1.3.0" +@@ -4633,6 +4643,7 @@ dependencies = [ + "dhat", + "either", + "flate2", ++ "fs2", + "futures-util", + "getrandom 0.2.15", + "iana-time-zone", +diff --git a/crates/next-napi-bindings/Cargo.toml b/crates/next-napi-bindings/Cargo.toml +index 1858344947..6e936d86f4 100644 +--- a/crates/next-napi-bindings/Cargo.toml ++++ b/crates/next-napi-bindings/Cargo.toml +@@ -102,6 +102,9 @@ swc_core = { workspace = true, features = [ + "ecma_visit", + ] } + ++[target.'cfg(target_os = "android")'.dependencies] ++fs2 = "0.4" ++ + # Dependencies for the native, non-wasm32 build. + [target.'cfg(not(target_arch = "wasm32"))'.dependencies] + lightningcss-napi = { workspace = true } +diff --git a/crates/next-napi-bindings/src/lockfile.rs b/crates/next-napi-bindings/src/lockfile.rs +index 35293d8a7b..2ea9913d0e 100644 +--- a/crates/next-napi-bindings/src/lockfile.rs ++++ b/crates/next-napi-bindings/src/lockfile.rs +@@ -71,7 +71,7 @@ pub fn lockfile_try_acquire_sync( + } + }; + +- #[cfg(not(windows))] ++ #[cfg(all(not(windows), not(target_os = "android")))] + return { + use std::{fs::TryLockError, io::Seek}; + +@@ -102,6 +102,42 @@ pub fn lockfile_try_acquire_sync( + Err(TryLockError::Error(err)) => Err(err.into()), + } + }; ++ ++ #[cfg(target_os = "android")] ++ return { ++ use std::io::{Seek, SeekFrom}; ++ use fs2::FileExt; ++ ++ let mut open_options = OpenOptions::new(); ++ open_options.write(true).create(true).read(true); ++ ++ let file = open_options.open(&path)?; ++ ++ match file.try_lock_exclusive() { ++ Ok(_) => { ++ file.set_len(0)?; ++ (&file).seek(SeekFrom::Start(0))?; ++ ++ if let Some(ref data) = content { ++ (&file).write_all(data.as_bytes())?; ++ (&file).flush()?; ++ } ++ ++ Ok(Some(External::new(Mutex::new(ManuallyDrop::new(Some( ++ LockfileInner { ++ file, ++ path: path.into(), ++ }, ++ )))))) ++ } ++ Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => { ++ Ok(None) ++ } ++ Err(e) => { ++ Err(e.into()) ++ } ++ } ++ }; + } + + #[napi(ts_return_type = "Promise<{ __napiType: \"Lockfile\" } | null>")] +diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json +index 486a91f893..1bf2e9aff8 100644 +--- a/packages/next-swc/package.json ++++ b/packages/next-swc/package.json +@@ -32,7 +32,8 @@ + "x86_64-unknown-linux-musl", + "aarch64-unknown-linux-musl", + "aarch64-pc-windows-msvc", +- "wasm32-wasip1-threads" ++ "wasm32-wasip1-threads", ++ "aarch64-linux-android" + ] + } + }, +diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts +index ba7900daf8..51b0783812 100644 +--- a/packages/next/src/build/swc/index.ts ++++ b/packages/next/src/build/swc/index.ts +@@ -149,7 +149,7 @@ function checkVersionMismatch(pkgData: any) { + // we'll not include native bindings for these platform at all. + const knownDefaultWasmFallbackTriples = [ + 'x86_64-unknown-freebsd', +- 'aarch64-linux-android', ++ //'aarch64-linux-android', + 'arm-linux-androideabi', + 'armv7-unknown-linux-gnueabihf', + 'i686-pc-windows-msvc', +diff --git a/turbopack/crates/turbo-tasks-fetch/Cargo.toml b/turbopack/crates/turbo-tasks-fetch/Cargo.toml +index 177972f672..1c779bc330 100644 +--- a/turbopack/crates/turbo-tasks-fetch/Cargo.toml ++++ b/turbopack/crates/turbo-tasks-fetch/Cargo.toml +@@ -42,7 +42,7 @@ reqwest = { workspace = true, features = ["rustls"] } + # - Windows: aws-lc-sys requires NASM and CMake which we don't have installed in + # CI, and would complicate the development environment setup. We could + # possibly switch to always using `native-tls` on Windows in the future. +-[target.'cfg(any(target_os = "linux", all(windows, not(target_arch = "aarch64"))))'.dependencies] ++[target.'cfg(any(target_os = "linux", target_os = "android", all(windows, not(target_arch = "aarch64"))))'.dependencies] + reqwest = { workspace = true, features = ["rustls-no-provider"] } + rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } + +diff --git a/turbopack/crates/turbo-tasks-fetch/src/client.rs b/turbopack/crates/turbo-tasks-fetch/src/client.rs +index 6dafa4099f..3b81eb5f8e 100644 +--- a/turbopack/crates/turbo-tasks-fetch/src/client.rs ++++ b/turbopack/crates/turbo-tasks-fetch/src/client.rs +@@ -47,7 +47,7 @@ impl FetchClientConfig { + fn try_build_uncached_reqwest_client(&self) -> reqwest::Result { + #[allow(unused_mut)] + let mut builder = reqwest::Client::builder(); +- #[cfg(any(target_os = "linux", all(windows, not(target_arch = "aarch64"))))] ++ #[cfg(any(target_os = "linux", target_os = "android", all(windows, not(target_arch = "aarch64"))))] + { + use std::sync::Once; + static ONCE: Once = Once::new(); +@@ -74,6 +74,84 @@ impl FetchClientConfig { + }, + )) + } ++ #[cfg(target_os = "android")] ++ { ++ let termux_path = std::path::Path::new("/data/data/com.termux/files/usr/etc/tls/cert.pem"); ++ let env_var = std::env::var("TURBO_SSL_CERT_FILE"); ++ ++ // --- BRANCH A: TERMUX MODE (Fix the Crash) --- ++ if termux_path.exists() { ++ //println!("[Turbopack] Termux environment detected."); ++ ++ let mut root_store = rustls::RootCertStore::empty(); ++ let mut paths_to_load = vec![termux_path.to_path_buf()]; ++ ++ // If user also provided a custom cert, add it to our manual list ++ if let Ok(p) = env_var { ++ paths_to_load.push(std::path::PathBuf::from(p)); ++ } ++ ++ for cert_path in paths_to_load { ++ if let Ok(pem_bytes) = std::fs::read(&cert_path) { ++ let content = String::from_utf8_lossy(&pem_bytes); ++ // ... (Reuse the parsing logic from before) ... ++ let header = "-----BEGIN CERTIFICATE-----"; ++ let footer = "-----END CERTIFICATE-----"; ++ let mut current_idx = 0; ++ while let Some(start_offset) = content[current_idx..].find(header) { ++ let start = current_idx + start_offset + header.len(); ++ if let Some(end_offset) = content[start..].find(footer) { ++ let end = start + end_offset; ++ let base64_str = content[start..end].lines().map(|l| l.trim()).collect::(); ++ if let Ok(der_bytes) = simple_base64_decode(&base64_str) { ++ let cert = rustls::pki_types::CertificateDer::from(der_bytes); ++ let _ = root_store.add(cert); ++ } ++ current_idx = end + footer.len(); ++ } else { break; } ++ } ++ } ++ } ++ ++ // REPLACEMENT: We bypass the system entirely because the system crashes in Termux. ++ let tls_config = rustls::ClientConfig::builder() ++ .with_root_certificates(root_store) ++ .with_no_client_auth(); ++ builder = builder.use_preconfigured_tls(tls_config); ++ } ++ // --- BRANCH B: REAL APP MODE (Add, don't Replace) --- ++ else if let Ok(p) = env_var { ++ // We are NOT in Termux, but we have a custom cert. ++ // We want to KEEP the Android System certs and ADD this one. ++ //println!("[Turbopack] Custom cert env var detected (Android App mode)."); ++ ++ if let Ok(pem_bytes) = std::fs::read(&p) { ++ let content = String::from_utf8_lossy(&pem_bytes); ++ // ... (Reuse the same parsing logic) ... ++ let header = "-----BEGIN CERTIFICATE-----"; ++ let footer = "-----END CERTIFICATE-----"; ++ let mut current_idx = 0; ++ while let Some(start_offset) = content[current_idx..].find(header) { ++ let start = current_idx + start_offset + header.len(); ++ if let Some(end_offset) = content[start..].find(footer) { ++ let end = start + end_offset; ++ let base64_str = content[start..end].lines().map(|l| l.trim()).collect::(); ++ ++ if let Ok(der_bytes) = simple_base64_decode(&base64_str) { ++ // ADDITION: We use reqwest's API to add to the existing system list. ++ if let Ok(cert) = reqwest::Certificate::from_der(&der_bytes) { ++ builder = builder.add_root_certificate(cert); ++ } ++ } ++ current_idx = end + footer.len(); ++ } else { break; } ++ } ++ } ++ } ++ // --- BRANCH C: STANDARD MODE --- ++ // No Termux, No Env Var. Do nothing. ++ // reqwest will automatically use Android System Certs via JNI. ++ } + builder.build() + } + } +@@ -120,6 +198,19 @@ impl FetchClientConfig { + match response_result { + Ok(resp) => Ok(Vc::cell(Ok(resp.resolved_cell()))), + Err(err) => { ++ ++ //#[cfg(target_os = "android")] ++ //{ ++ // --- DEBUGGING START --- ++ //eprintln!("\n[Turbopack] NETWORK ERROR DEBUG:"); ++ //eprintln!("URL: {}", url_ref); ++ //eprintln!("Error: {:?}", err); // Prints the high level error ++ //if let Some(source) = std::error::Error::source(&err) { ++ // eprintln!("Caused by: {:?}", source); // Prints the deep TLS error ++ //} ++ // --- DEBUGGING END --- ++ //} ++ + // the client failed to construct or the HTTP request failed + mark_session_dependent(); + Ok(Vc::cell(Err( +@@ -130,6 +221,33 @@ impl FetchClientConfig { + } + } + ++ ++#[cfg(target_os = "android")] ++fn simple_base64_decode(input: &str) -> Result, ()> { ++ let mut buffer = Vec::new(); ++ let mut bits: u32 = 0; ++ let mut bit_count = 0; ++ for byte in input.bytes() { ++ let val = match byte { ++ b'A'..=b'Z' => byte - b'A', ++ b'a'..=b'z' => byte - b'a' + 26, ++ b'0'..=b'9' => byte - b'0' + 52, ++ b'+' => 62, ++ b'/' => 63, ++ b'=' => continue, ++ _ => continue, ++ }; ++ bits = (bits << 6) | (val as u32); ++ bit_count += 6; ++ if bit_count >= 8 { ++ bit_count -= 8; ++ buffer.push((bits >> bit_count) as u8); ++ bits &= (1 << bit_count) - 1; ++ } ++ } ++ Ok(buffer) ++} ++ + #[doc(hidden)] + pub fn __test_only_reqwest_client_cache_clear() { + CLIENT_CACHE.clear() +diff --git a/turbopack/crates/turbo-tasks-malloc/src/counter.rs b/turbopack/crates/turbo-tasks-malloc/src/counter.rs +index d5faff91ba..061426541b 100644 +--- a/turbopack/crates/turbo-tasks-malloc/src/counter.rs ++++ b/turbopack/crates/turbo-tasks-malloc/src/counter.rs +@@ -6,6 +6,9 @@ use std::{ + + use crate::AllocationCounters; + ++#[cfg(target_os = "android")] ++use crate::IS_THREAD_EXITING_FLAG; ++ + /// Tracks the current total amount of memory allocated through all the [ThreadLocalCounter] + /// instances. This is an overestimate as individual threads 'preallocate' a [TARGET_BUFFER] bytes + /// to reduce the number of global synchronizations. This means at any given time this might +@@ -29,6 +32,21 @@ struct ThreadLocalCounter { + allocation_counters: AllocationCounters, + } + ++#[cfg(target_os = "android")] ++fn atomic_sub(atomic: &AtomicUsize, val: usize) { ++ let mut current = atomic.load(Ordering::Relaxed); ++ loop { ++ let new = current.saturating_sub(val); ++ match atomic.compare_exchange_weak( ++ current, new, ++ Ordering::Relaxed, Ordering::Relaxed, ++ ) { ++ Ok(_) => break, ++ Err(x) => current = x, ++ } ++ } ++} ++ + impl ThreadLocalCounter { + const fn new() -> Self { + Self { +@@ -55,7 +73,12 @@ impl ThreadLocalCounter { + if self.buffer > MAX_BUFFER { + let offset = self.buffer - TARGET_BUFFER; + self.buffer = TARGET_BUFFER; ++ ++ #[cfg(not(target_os = "android"))] + ALLOCATED.fetch_sub(offset, Ordering::Relaxed); ++ ++ #[cfg(target_os = "android")] ++ atomic_sub(&ALLOCATED, offset); + } + } + +@@ -82,7 +105,12 @@ impl ThreadLocalCounter { + if self.buffer > MAX_BUFFER { + let offset = self.buffer - TARGET_BUFFER; + self.buffer = TARGET_BUFFER; ++ ++ #[cfg(not(target_os = "android"))] + ALLOCATED.fetch_sub(offset, Ordering::Relaxed); ++ ++ #[cfg(target_os = "android")] ++ atomic_sub(&ALLOCATED, offset); + } + } + } +@@ -90,15 +118,49 @@ impl ThreadLocalCounter { + + fn unload(&mut self) { + if self.buffer > 0 { ++ ++ #[cfg(not(target_os = "android"))] + ALLOCATED.fetch_sub(self.buffer, Ordering::Relaxed); ++ ++ #[cfg(target_os = "android")] ++ atomic_sub(&ALLOCATED, self.buffer); ++ + self.buffer = 0; + } + self.allocation_counters = AllocationCounters::default(); + } + } + ++#[cfg(target_os = "android")] ++struct CounterGuard(ThreadLocalCounter); ++ ++#[cfg(target_os = "android")] ++impl Drop for CounterGuard { ++ fn drop(&mut self) { ++ self.0.unload(); ++ unsafe { ++ *IS_THREAD_EXITING_FLAG.get() = true; ++ } ++ } ++} ++ ++#[cfg(target_os = "android")] ++impl CounterGuard { ++ const fn new() -> Self { ++ Self(ThreadLocalCounter::new()) ++ } ++} ++ ++#[cfg(target_os = "android")] ++type InnerCounter = CounterGuard; ++ ++#[cfg(not(target_os = "android"))] ++type InnerCounter = ThreadLocalCounter; ++ + thread_local! { +- static LOCAL_COUNTER: UnsafeCell = const {UnsafeCell::new(ThreadLocalCounter::new())}; ++ static LOCAL_COUNTER: UnsafeCell = const { ++ UnsafeCell::new(InnerCounter::new()) ++ }; + } + + pub fn get() -> usize { +@@ -118,7 +180,14 @@ fn with_local_counter(f: impl FnOnce(&mut ThreadLocalCounter) -> T) -> T { + let ptr = local.get(); + // SAFETY: This is a thread local. + let mut local = unsafe { NonNull::new_unchecked(ptr) }; +- f(unsafe { local.as_mut() }) ++ ++ #[cfg(target_os = "android")] ++ let inner = unsafe { &mut local.as_mut().0 }; ++ ++ #[cfg(not(target_os = "android"))] ++ let inner = unsafe { local.as_mut() }; ++ ++ f(inner) + }) + } + +diff --git a/turbopack/crates/turbo-tasks-malloc/src/lib.rs b/turbopack/crates/turbo-tasks-malloc/src/lib.rs +index 47410b0e11..c8e05a1ff9 100644 +--- a/turbopack/crates/turbo-tasks-malloc/src/lib.rs ++++ b/turbopack/crates/turbo-tasks-malloc/src/lib.rs +@@ -1,3 +1,5 @@ ++#![feature(thread_local)] ++ + mod counter; + + use std::{ +@@ -6,8 +8,31 @@ use std::{ + ops::{Add, AddAssign}, + }; + ++#[cfg(target_os = "android")] ++use std::cell::UnsafeCell; ++ + use self::counter::{add, flush, get, remove, update}; + ++#[cfg(target_os = "android")] ++#[thread_local] ++static mut IN_ALLOCATOR: bool = false; ++ ++#[cfg(target_os = "android")] ++#[thread_local] ++pub(crate) static IS_THREAD_EXITING_FLAG: UnsafeCell = UnsafeCell::new(false); ++ ++#[cfg(target_os = "android")] ++#[inline(always)] ++fn should_bypass() -> bool { ++ unsafe { IN_ALLOCATOR || *IS_THREAD_EXITING_FLAG.get() } ++} ++ ++#[cfg(not(target_os = "android"))] ++#[inline(always)] ++fn should_bypass() -> bool { ++ false ++} ++ + #[derive(Default, Clone, Debug)] + pub struct AllocationInfo { + pub allocations: usize, +@@ -91,6 +116,11 @@ impl TurboMalloc { + + pub fn thread_stop() { + flush(); ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ *IS_THREAD_EXITING_FLAG.get() = true; ++ } + } + + pub fn allocation_counters() -> AllocationCounters { +@@ -121,30 +151,91 @@ unsafe fn base_alloc_size(ptr: *const u8, layout: Layout) -> usize { + + unsafe impl GlobalAlloc for TurboMalloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { ++ ++ #[cfg(target_os = "android")] ++ if should_bypass() { ++ return unsafe { base_alloc().alloc(layout) }; ++ } ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = true; ++ } ++ + let ret = unsafe { base_alloc().alloc(layout) }; + if !ret.is_null() { + let size = unsafe { base_alloc_size(ret, layout) }; + add(size); + } ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = false; ++ } ++ + ret + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { ++ ++ #[cfg(target_os = "android")] ++ if should_bypass() { ++ return unsafe { base_alloc().dealloc(ptr, layout) }; ++ } ++ ++ #[cfg(target_os = "android")] ++ unsafe{ ++ IN_ALLOCATOR = true; ++ } ++ + let size = unsafe { base_alloc_size(ptr, layout) }; + unsafe { base_alloc().dealloc(ptr, layout) }; + remove(size); ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = false; ++ } + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { ++ ++ #[cfg(target_os = "android")] ++ if should_bypass() { ++ return unsafe { base_alloc().alloc_zeroed(layout) }; ++ } ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = true; ++ } ++ + let ret = unsafe { base_alloc().alloc_zeroed(layout) }; + if !ret.is_null() { + let size = unsafe { base_alloc_size(ret, layout) }; + add(size); + } ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = false; ++ } ++ + ret + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { ++ ++ #[cfg(target_os = "android")] ++ if should_bypass() { ++ return unsafe { base_alloc().realloc(ptr, layout, new_size) }; ++ } ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = true; ++ } ++ + let old_size = unsafe { base_alloc_size(ptr, layout) }; + let ret = unsafe { base_alloc().realloc(ptr, layout, new_size) }; + if !ret.is_null() { +@@ -154,6 +245,12 @@ unsafe impl GlobalAlloc for TurboMalloc { + let new_size = unsafe { base_alloc_size(ret, new_layout) }; + update(old_size, new_size); + } ++ ++ #[cfg(target_os = "android")] ++ unsafe { ++ IN_ALLOCATOR = false; ++ } ++ + ret + } + } diff --git a/packages/turbopack/build.sh b/packages/turbopack/build.sh new file mode 100644 index 00000000000..3e7d70e5298 --- /dev/null +++ b/packages/turbopack/build.sh @@ -0,0 +1,81 @@ +TERMUX_PKG_HOMEPAGE=https://nextjs.org/ +TERMUX_PKG_DESCRIPTION="Rust-based incremental compilation engine and bundler for Next.js" +TERMUX_PKG_MAINTAINER="@termux" +TERMUX_PKG_LICENSE="MIT" +TERMUX_PKG_VERSION=16.2.0~canary.84 +TERMUX_PKG_SRCURL=https://github.com/vercel/next.js/archive/refs/tags/v${TERMUX_PKG_VERSION//\~/-}.tar.gz +TERMUX_PKG_SHA256=0836a14ac5efd245a0fca272c96f5b4a6d4fd0e5996f6d06f649fd5e9424fae8 +TERMUX_PKG_BUILD_IN_SRC=true +TERMUX_PKG_EXCLUDED_ARCHES="arm, i686" +TERMUX_PKG_DEPENDS="ca-certificates" +TERMUX_PKG_AUTO_UPDATE=true +TERMUX_PKG_UPDATE_TAG_TYPE=latest-release-tag + +termux_step_pre_configure() { + export ANDROID_NDK_LATEST_HOME="${TERMUX_STANDALONE_TOOLCHAIN}" +} + +termux_step_make() { + export RUSTC_BOOTSTRAP=1 + local RUST_TARGET + case "$TERMUX_ARCH" in + aarch64) RUST_TARGET="aarch64-linux-android" ;; + x86_64)RUST_TARGET="x86_64-linux-android" ;; + esac + termux_setup_rust + termux_setup_nodejs + export RUSTFLAGS="--cfg tokio_unstable" + local ENV_PREFIX=$(echo "$RUST_TARGET" | tr '[:lower:]-' '[:upper:]_') + if [ "$TERMUX_ARCH" == "aarch64" ]; then + export RUSTFLAGS="$RUSTFLAGS -Zshare-generics=y -Csymbol-mangling-version=v0" + npm i -g "@napi-rs/cli@2.18.4" # Hardcoded NAPI_CLI_VERSION from workflow + else + export "CARGO_TARGET_${ENV_PREFIX}_LINKER"="$CC" + export "CC_${RUST_TARGET//-/_}"="$CC" + fi + npx pnpm install + cd packages/next-swc + npx pnpm run build-native-release --target "$RUST_TARGET" +} + +termux_step_make_install() { + cd packages/next-swc + ls -l native + local NAPI_ARCH + case "$TERMUX_ARCH" in + aarch64) NAPI_ARCH="arm64" ;; + x86_64)NAPI_ARCH="x64" ;; + esac + local PACKAGE_NAME="@next/swc-android-${NAPI_ARCH}" + local INSTALL_DIR="$TERMUX_PREFIX/lib/node_modules/${PACKAGE_NAME}" + local BINARY_NAME="next-swc.android-${NAPI_ARCH}.node" + mkdir -p "$INSTALL_DIR" + mkdir -p "$TERMUX_PREFIX/lib/node_modules/next/next-swc-fallback/@next/swc-android-${NAPI_ARCH}/" + install -Dm755 "native/${BINARY_NAME}" "$INSTALL_DIR/${BINARY_NAME}" + install -Dm755 "native/${BINARY_NAME}" "$TERMUX_PREFIX/lib/node_modules/next/next-swc-fallback/@next/swc-android-${NAPI_ARCH}/${BINARY_NAME}" + ${STRIP} --strip-unneeded "$INSTALL_DIR/${BINARY_NAME}" + ${STRIP} --strip-unneeded "$TERMUX_PREFIX/lib/node_modules/next/next-swc-fallback/@next/swc-android-${NAPI_ARCH}/${BINARY_NAME}" + cat > "$INSTALL_DIR/package.json" <<-EOF + { + "name": "${PACKAGE_NAME}", + "version": "$TERMUX_PKG_VERSION", + "os": ["android"], + "cpu": ["${NAPI_ARCH}"], + "main": "${BINARY_NAME}" + } + EOF + # this fixes 'Error: turbo.createProject is not supported by the wasm bindings' and 'Failed to load SWC binary for android/arm64' in the 'npm run dev -- --turbo' command + mkdir -p "$TERMUX_PREFIX/etc/profile.d/" + cat > "$TERMUX_PREFIX/etc/profile.d/turbopack.sh" <<-EOF + export NEXT_TEST_WASM_DIR=/dev/null + export NEXT_TEST_NATIVE_DIR=$TERMUX_PREFIX/lib/node_modules/@next/swc-android-arm64 + EOF + chmod 0755 "$TERMUX_PREFIX/etc/profile.d/turbopack.sh" +} + +termux_step_create_debscripts() { + cat > ./postinst <<-EOF + #!$TERMUX_PREFIX/bin/sh + echo "You must explicitly use 'npx create-next-app@v${TERMUX_PKG_VERSION//\~/-}' to avoid the error of Missing field 'isPersistentCachingEnabled'" + EOF +}