From e62bfca19c144727635f86a97c542343be60b688 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 10:51:06 +0200 Subject: [PATCH 01/17] Fix musl target handling in tonlib build --- build.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/build.rs b/build.rs index 15d4456..23f597e 100644 --- a/build.rs +++ b/build.rs @@ -12,6 +12,7 @@ use std::{env, fs}; const TON_MONOREPO_URL: &str = "https://github.com/ton-blockchain/ton"; const TON_MONOREPO_REVISION: &str = "v2026.04-1"; const TON_MONOREPO_DIR_ENV: &str = "TON_MONOREPO_DIR"; +const MUSL_TARGET: &str = "x86_64-unknown-linux-musl"; #[cfg(feature = "with_debug_info")] const CMAKE_BUILD_TYPE: &str = "RelWithDebInfo"; @@ -27,6 +28,8 @@ fn main() { } fn build_monorepo() { + let is_linux_target = target_os() == "linux"; + let is_musl_target = target_env() == "musl"; let monorepo_dir = resolve_monorepo_dir(); println!("Using {} folder for TON monorepo", monorepo_dir.display()); if let Some(parent_dir) = monorepo_dir.parent() { @@ -47,13 +50,17 @@ fn build_monorepo() { #[cfg(target_os = "macos")] install_macos_deps(); - if cfg!(target_os = "macos") { + if target_os() == "macos" { println!("cargo:rustc-link-lib=dylib=c++"); println!("cargo:rustc-link-arg=-lc++"); } - if cfg!(target_os = "linux") { - println!("cargo:rustc-link-lib=dylib=stdc++"); - println!("cargo:rustc-link-arg=-lstdc++"); + if is_linux_target { + if is_musl_target { + println!("cargo:rustc-link-lib=static=stdc++"); + } else { + println!("cargo:rustc-link-lib=dylib=stdc++"); + println!("cargo:rustc-link-arg=-lstdc++"); + } println!("cargo:rustc-env=CC=clang"); println!("cargo:rustc-env=CXX=clang++"); println!("cargo:rustc-env=CMAKE_CXX_STANDARD=20"); @@ -110,7 +117,7 @@ fn build_monorepo() { println!("cargo:rustc-link-search=native={build_dir}/build/third-party/blst"); println!("cargo:rustc-link-lib=static=blst"); // openssl - if cfg!(target_os = "linux") { + if is_linux_target { // TON builds its own OpenSSL. Use that on Linux to avoid symbol/version mismatches // with runner-provided system libcrypto. println!("cargo:rustc-link-search=native={build_dir}/build/third-party/openssl/lib"); @@ -119,9 +126,10 @@ fn build_monorepo() { println!("cargo:rustc-link-lib=crypto"); } // dynamic libs - println!("cargo:rustc-link-lib=dylib=z"); // zlib - println!("cargo:rustc-link-lib=dylib=sodium"); - println!("cargo:rustc-link-lib=dylib=secp256k1"); + let native_link_kind = if is_musl_target { "static" } else { "dylib" }; + println!("cargo:rustc-link-lib={native_link_kind}=z"); // zlib + println!("cargo:rustc-link-lib={native_link_kind}=sodium"); + println!("cargo:rustc-link-lib={native_link_kind}=secp256k1"); println!("cargo:rustc-link-search=native={build_dir}/build/third-party/crc32c"); println!("cargo:rustc-link-lib=static=crc32c"); } @@ -130,7 +138,9 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { println!("\nBuilding target: {target}..."); let mut cxx_flags = "-w"; - if cfg!(target_os = "linux") { + let is_linux_target = target_os() == "linux"; + let is_musl_target = target_env() == "musl"; + if is_linux_target { cxx_flags = "-w -std=c++20 --include=algorithm"; } let use_emscripten = env::var("CARGO_CFG_TARGET_ARCH") @@ -138,12 +148,19 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { .unwrap_or(false); let mut cfg = Config::new(monorepo_dir); - if cfg!(target_os = "linux") { + if is_linux_target { env::set_var("CC", "clang-21"); env::set_var("CXX", "clang++-21"); cfg.define("CMAKE_C_COMPILER", "clang-21") .define("CMAKE_CXX_COMPILER", "clang++-21"); } + if is_musl_target { + cfg.define("CMAKE_SYSTEM_NAME", "Linux") + .define("CMAKE_C_COMPILER_TARGET", MUSL_TARGET) + .define("CMAKE_CXX_COMPILER_TARGET", MUSL_TARGET) + .define("CMAKE_EXE_LINKER_FLAGS", "-static-pie") + .define("CMAKE_SHARED_LINKER_FLAGS", "-static-pie"); + } let shared_build_dir = resolve_shared_build_dir(monorepo_dir); let dst = cfg @@ -413,8 +430,28 @@ fn resolve_monorepo_dir() -> PathBuf { cargo_home.join(repo_dir) } +fn build_target() -> String { + env::var("TARGET").unwrap_or_else(|_| "unknown-target".to_owned()) +} + +fn target_os() -> String { + env::var("CARGO_CFG_TARGET_OS").unwrap_or_else(|_| { + if cfg!(target_os = "linux") { + "linux".to_owned() + } else if cfg!(target_os = "macos") { + "macos".to_owned() + } else { + "unknown".to_owned() + } + }) +} + +fn target_env() -> String { + env::var("CARGO_CFG_TARGET_ENV").unwrap_or_else(|_| "unknown".to_owned()) +} + fn resolve_shared_build_dir(monorepo_dir: &Path) -> PathBuf { - let target = env::var("TARGET").unwrap_or_else(|_| "unknown-target".to_owned()); + let target = build_target(); let profile = env::var("PROFILE").unwrap_or_else(|_| "unknown-profile".to_owned()); let feature_suffix = if cfg!(feature = "no_avx512") { "-no_avx512" From 2364ed2437de1653de0e274b4c4d951da2cdcd37 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 11:14:51 +0200 Subject: [PATCH 02/17] Avoid forcing CMake parallelism for musl --- build.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 23f597e..bace55b 100644 --- a/build.rs +++ b/build.rs @@ -176,13 +176,16 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { .define("CMAKE_BUILD_TYPE", CMAKE_BUILD_TYPE) .define("CMAKE_C_FLAGS", "-w") .define("CMAKE_CXX_FLAGS", cxx_flags) - .build_arg("-j") - .build_arg(available_parallelism().unwrap().get().to_string()) .configure_arg("-Wno-dev") .build_target(target) .always_configure(true) .very_verbose(true); + if !is_musl_target { + dst.build_arg("-j") + .build_arg(available_parallelism().unwrap().get().to_string()); + } + #[cfg(all(feature = "no_avx512", not(target_os = "macos")))] disable_avx512_for_gcc(dst); From 5363c70508b524e4c5d05d84de39104d9de461eb Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 11:25:32 +0200 Subject: [PATCH 03/17] Disable Cargo jobserver for musl CMake builds --- build.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index bace55b..38bb521 100644 --- a/build.rs +++ b/build.rs @@ -189,7 +189,23 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { #[cfg(all(feature = "no_avx512", not(target_os = "macos")))] disable_avx512_for_gcc(dst); - dst.build().display().to_string() + let cargo_makeflags = is_musl_target.then(|| env::var_os("CARGO_MAKEFLAGS")); + let makeflags = is_musl_target.then(|| env::var_os("MAKEFLAGS")); + if is_musl_target { + env::remove_var("CARGO_MAKEFLAGS"); + env::remove_var("MAKEFLAGS"); + } + + let build_dir = dst.build().display().to_string(); + + if let Some(Some(cargo_makeflags)) = cargo_makeflags { + env::set_var("CARGO_MAKEFLAGS", cargo_makeflags); + } + if let Some(Some(makeflags)) = makeflags { + env::set_var("MAKEFLAGS", makeflags); + } + + build_dir } // function must be safe to handle _lock From 56690b3113bd7a9e7ec6f3200819603920fbb570 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 11:30:22 +0200 Subject: [PATCH 04/17] Disable CMake parallel flag for musl builds --- build.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.rs b/build.rs index 38bb521..810d0ee 100644 --- a/build.rs +++ b/build.rs @@ -191,9 +191,11 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { let cargo_makeflags = is_musl_target.then(|| env::var_os("CARGO_MAKEFLAGS")); let makeflags = is_musl_target.then(|| env::var_os("MAKEFLAGS")); + let num_jobs = is_musl_target.then(|| env::var_os("NUM_JOBS")); if is_musl_target { env::remove_var("CARGO_MAKEFLAGS"); env::remove_var("MAKEFLAGS"); + env::remove_var("NUM_JOBS"); } let build_dir = dst.build().display().to_string(); @@ -204,6 +206,9 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { if let Some(Some(makeflags)) = makeflags { env::set_var("MAKEFLAGS", makeflags); } + if let Some(Some(num_jobs)) = num_jobs { + env::set_var("NUM_JOBS", num_jobs); + } build_dir } From f9755f6c5df651b7d71c82084b89a73f2c9a8962 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 12:44:36 +0200 Subject: [PATCH 05/17] Add static stdc++ search path for musl --- build.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/build.rs b/build.rs index 810d0ee..0867af2 100644 --- a/build.rs +++ b/build.rs @@ -56,6 +56,7 @@ fn build_monorepo() { } if is_linux_target { if is_musl_target { + add_static_libstdcxx_search_path(); println!("cargo:rustc-link-lib=static=stdc++"); } else { println!("cargo:rustc-link-lib=dylib=stdc++"); @@ -213,6 +214,35 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { build_dir } +fn add_static_libstdcxx_search_path() { + let cxx = env::var("CXX").unwrap_or_else(|_| "clang++-21".to_owned()); + let output = Command::new(&cxx) + .arg("--target") + .arg(MUSL_TARGET) + .arg("-print-file-name=libstdc++.a") + .output(); + + let Ok(output) = output else { + println!("cargo:warning=Failed to query {cxx} for libstdc++.a"); + return; + }; + + if !output.status.success() { + println!("cargo:warning={cxx} failed to resolve libstdc++.a"); + return; + } + + let path = PathBuf::from(String::from_utf8_lossy(&output.stdout).trim()); + if !path.is_absolute() || !path.exists() { + println!("cargo:warning=Could not resolve libstdc++.a for {MUSL_TARGET} with {cxx}"); + return; + } + + if let Some(parent) = path.parent() { + println!("cargo:rustc-link-search=native={}", parent.display()); + } +} + // function must be safe to handle _lock fn checkout_repo(monorepo_dir: &Path) -> anyhow::Result<()> { if let Some(parent_dir) = monorepo_dir.parent() { From 863fe74591a64301ec9670f0d0e79286e5984b39 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 12:55:41 +0200 Subject: [PATCH 06/17] Fix musl libstdc++ probe target flag --- build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 0867af2..1464497 100644 --- a/build.rs +++ b/build.rs @@ -217,8 +217,7 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { fn add_static_libstdcxx_search_path() { let cxx = env::var("CXX").unwrap_or_else(|_| "clang++-21".to_owned()); let output = Command::new(&cxx) - .arg("--target") - .arg(MUSL_TARGET) + .arg(format!("--target={MUSL_TARGET}")) .arg("-print-file-name=libstdc++.a") .output(); From c71d3c66dae5f072958887ffc3b373787d2321b9 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 15:21:21 +0200 Subject: [PATCH 07/17] Add musl static native library search paths --- build.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/build.rs b/build.rs index 1464497..581e231 100644 --- a/build.rs +++ b/build.rs @@ -56,7 +56,7 @@ fn build_monorepo() { } if is_linux_target { if is_musl_target { - add_static_libstdcxx_search_path(); + add_static_library_search_path("clang++-21", "libstdc++.a"); println!("cargo:rustc-link-lib=static=stdc++"); } else { println!("cargo:rustc-link-lib=dylib=stdc++"); @@ -128,6 +128,11 @@ fn build_monorepo() { } // dynamic libs let native_link_kind = if is_musl_target { "static" } else { "dylib" }; + if is_musl_target { + add_static_library_search_path("clang-21", "libz.a"); + add_static_library_search_path("clang-21", "libsodium.a"); + add_static_library_search_path("clang-21", "libsecp256k1.a"); + } println!("cargo:rustc-link-lib={native_link_kind}=z"); // zlib println!("cargo:rustc-link-lib={native_link_kind}=sodium"); println!("cargo:rustc-link-lib={native_link_kind}=secp256k1"); @@ -214,26 +219,25 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { build_dir } -fn add_static_libstdcxx_search_path() { - let cxx = env::var("CXX").unwrap_or_else(|_| "clang++-21".to_owned()); - let output = Command::new(&cxx) +fn add_static_library_search_path(compiler: &str, library: &str) { + let output = Command::new(compiler) .arg(format!("--target={MUSL_TARGET}")) - .arg("-print-file-name=libstdc++.a") + .arg(format!("-print-file-name={library}")) .output(); let Ok(output) = output else { - println!("cargo:warning=Failed to query {cxx} for libstdc++.a"); + println!("cargo:warning=Failed to query {compiler} for {library}"); return; }; if !output.status.success() { - println!("cargo:warning={cxx} failed to resolve libstdc++.a"); + println!("cargo:warning={compiler} failed to resolve {library}"); return; } let path = PathBuf::from(String::from_utf8_lossy(&output.stdout).trim()); if !path.is_absolute() || !path.exists() { - println!("cargo:warning=Could not resolve libstdc++.a for {MUSL_TARGET} with {cxx}"); + println!("cargo:warning=Could not resolve {library} for {MUSL_TARGET} with {compiler}"); return; } From 3552c5bd088e3bf2d6285ba758a448dec3fc0c37 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 15:44:13 +0200 Subject: [PATCH 08/17] Link musl math and gcc exception runtimes --- build.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/build.rs b/build.rs index 581e231..ee641d5 100644 --- a/build.rs +++ b/build.rs @@ -132,10 +132,16 @@ fn build_monorepo() { add_static_library_search_path("clang-21", "libz.a"); add_static_library_search_path("clang-21", "libsodium.a"); add_static_library_search_path("clang-21", "libsecp256k1.a"); + add_static_library_search_path("clang-21", "libgcc_eh.a"); + add_musl_library_search_path("libm.a"); } println!("cargo:rustc-link-lib={native_link_kind}=z"); // zlib println!("cargo:rustc-link-lib={native_link_kind}=sodium"); println!("cargo:rustc-link-lib={native_link_kind}=secp256k1"); + if is_musl_target { + println!("cargo:rustc-link-lib=static=gcc_eh"); + println!("cargo:rustc-link-lib=static=m"); + } println!("cargo:rustc-link-search=native={build_dir}/build/third-party/crc32c"); println!("cargo:rustc-link-lib=static=crc32c"); } @@ -246,6 +252,18 @@ fn add_static_library_search_path(compiler: &str, library: &str) { } } +fn add_musl_library_search_path(library: &str) { + for directory in ["/usr/lib/x86_64-linux-musl", "/lib/x86_64-linux-musl"] { + let path = Path::new(directory).join(library); + if path.exists() { + println!("cargo:rustc-link-search=native={directory}"); + return; + } + } + + println!("cargo:warning=Could not resolve {library} for {MUSL_TARGET}"); +} + // function must be safe to handle _lock fn checkout_repo(monorepo_dir: &Path) -> anyhow::Result<()> { if let Some(parent_dir) = monorepo_dir.parent() { From 26d6a9c8a0d0ed8e266a57b82c33f403f167f2f4 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 16:48:54 +0200 Subject: [PATCH 09/17] Avoid glibc search paths for musl libs --- build.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build.rs b/build.rs index ee641d5..e50e0e3 100644 --- a/build.rs +++ b/build.rs @@ -129,11 +129,8 @@ fn build_monorepo() { // dynamic libs let native_link_kind = if is_musl_target { "static" } else { "dylib" }; if is_musl_target { - add_static_library_search_path("clang-21", "libz.a"); - add_static_library_search_path("clang-21", "libsodium.a"); - add_static_library_search_path("clang-21", "libsecp256k1.a"); - add_static_library_search_path("clang-21", "libgcc_eh.a"); add_musl_library_search_path("libm.a"); + add_static_library_search_path("clang-21", "libgcc_eh.a"); } println!("cargo:rustc-link-lib={native_link_kind}=z"); // zlib println!("cargo:rustc-link-lib={native_link_kind}=sodium"); From fac7ba477a63d836673ce72bcfe56ec56dec2d4f Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Thu, 28 May 2026 17:12:41 +0200 Subject: [PATCH 10/17] Link TON third-party libs for musl --- build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.rs b/build.rs index e50e0e3..5ac10ac 100644 --- a/build.rs +++ b/build.rs @@ -129,6 +129,9 @@ fn build_monorepo() { // dynamic libs let native_link_kind = if is_musl_target { "static" } else { "dylib" }; if is_musl_target { + println!("cargo:rustc-link-search=native={build_dir}/build/third-party/zlib/lib"); + println!("cargo:rustc-link-search=native={build_dir}/build/third-party/sodium/lib"); + println!("cargo:rustc-link-search=native={build_dir}/build/third-party/secp256k1/lib"); add_musl_library_search_path("libm.a"); add_static_library_search_path("clang-21", "libgcc_eh.a"); } From c083330a2bbb615ded36ee7c16a0b89ad703280c Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Fri, 29 May 2026 10:09:09 +0200 Subject: [PATCH 11/17] Use Alpine musl target for C toolchain --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 5ac10ac..bf33159 100644 --- a/build.rs +++ b/build.rs @@ -12,7 +12,7 @@ use std::{env, fs}; const TON_MONOREPO_URL: &str = "https://github.com/ton-blockchain/ton"; const TON_MONOREPO_REVISION: &str = "v2026.04-1"; const TON_MONOREPO_DIR_ENV: &str = "TON_MONOREPO_DIR"; -const MUSL_TARGET: &str = "x86_64-unknown-linux-musl"; +const MUSL_TARGET: &str = "x86_64-alpine-linux-musl"; #[cfg(feature = "with_debug_info")] const CMAKE_BUILD_TYPE: &str = "RelWithDebInfo"; From 614cf683de80471d488c7638da626625bfe49a67 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Fri, 29 May 2026 12:02:12 +0200 Subject: [PATCH 12/17] Generate TLB sources for musl builds --- build.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/build.rs b/build.rs index bf33159..ecbcd9d 100644 --- a/build.rs +++ b/build.rs @@ -46,6 +46,9 @@ fn build_monorepo() { println!("cargo:rerun-if-changed=build.rs"); checkout_repo(&monorepo_dir).unwrap(); patch_macos_dsymutil_linker_hook(&monorepo_dir); + if is_musl_target { + patch_musl_tlb_generation(&monorepo_dir); + } #[cfg(target_os = "macos")] install_macos_deps(); @@ -306,6 +309,22 @@ fn patch_macos_dsymutil_linker_hook(monorepo_dir: &Path) { .unwrap_or_else(|error| panic!("Failed to patch {}: {error}", cmake_lists_path.display())); } +fn patch_musl_tlb_generation(monorepo_dir: &Path) { + let cmake_lists_path = monorepo_dir.join("crypto/CMakeLists.txt"); + let original = fs::read_to_string(&cmake_lists_path) + .unwrap_or_else(|error| panic!("Failed to read {}: {error}", cmake_lists_path.display())); + let cross_compile_guard = "if (NOT CMAKE_CROSSCOMPILING OR USE_EMSCRIPTEN)"; + let forced_generation = "if (TRUE)"; + + if !original.contains(cross_compile_guard) || original.contains(forced_generation) { + return; + } + + let patched = original.replace(cross_compile_guard, forced_generation); + fs::write(&cmake_lists_path, patched) + .unwrap_or_else(|error| panic!("Failed to patch {}: {error}", cmake_lists_path.display())); +} + fn repo_is_healthy(monorepo_dir: &Path) -> bool { if !monorepo_dir.join(".git").exists() { return false; From 7e6abbf3fe81e7ecce3132327e284b36654fd85c Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Fri, 29 May 2026 12:23:19 +0200 Subject: [PATCH 13/17] Use tlbc target path for musl generation --- build.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index ecbcd9d..fffca59 100644 --- a/build.rs +++ b/build.rs @@ -315,12 +315,18 @@ fn patch_musl_tlb_generation(monorepo_dir: &Path) { .unwrap_or_else(|error| panic!("Failed to read {}: {error}", cmake_lists_path.display())); let cross_compile_guard = "if (NOT CMAKE_CROSSCOMPILING OR USE_EMSCRIPTEN)"; let forced_generation = "if (TRUE)"; + let tlbc_command = "set(GENERATE_TLB_CMD tlbc)"; + let tlbc_target_file_command = "set(GENERATE_TLB_CMD $)"; - if !original.contains(cross_compile_guard) || original.contains(forced_generation) { + if (!original.contains(cross_compile_guard) || original.contains(forced_generation)) + && (!original.contains(tlbc_command) || original.contains(tlbc_target_file_command)) + { return; } - let patched = original.replace(cross_compile_guard, forced_generation); + let patched = original + .replace(cross_compile_guard, forced_generation) + .replace(tlbc_command, tlbc_target_file_command); fs::write(&cmake_lists_path, patched) .unwrap_or_else(|error| panic!("Failed to patch {}: {error}", cmake_lists_path.display())); } From 73d0afd6d08b14af0db294bf0fa2dc4fbcf37118 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Fri, 29 May 2026 12:44:19 +0200 Subject: [PATCH 14/17] Generate TL sources for musl builds --- build.rs | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/build.rs b/build.rs index fffca59..5b19b0d 100644 --- a/build.rs +++ b/build.rs @@ -310,23 +310,45 @@ fn patch_macos_dsymutil_linker_hook(monorepo_dir: &Path) { } fn patch_musl_tlb_generation(monorepo_dir: &Path) { - let cmake_lists_path = monorepo_dir.join("crypto/CMakeLists.txt"); + patch_cmake_file( + monorepo_dir.join("crypto/CMakeLists.txt"), + &[ + ( + "if (NOT CMAKE_CROSSCOMPILING OR USE_EMSCRIPTEN)", + "if (TRUE)", + ), + ( + "set(GENERATE_TLB_CMD tlbc)", + "set(GENERATE_TLB_CMD $)", + ), + ], + ); + patch_cmake_file( + monorepo_dir.join("tl/generate/CMakeLists.txt"), + &[ + ("if (NOT CMAKE_CROSSCOMPILING)", "if (TRUE)"), + ( + "set(GENERATE_COMMON_CMD generate_common)", + "set(GENERATE_COMMON_CMD $)", + ), + ], + ); +} + +fn patch_cmake_file(cmake_lists_path: PathBuf, replacements: &[(&str, &str); N]) { let original = fs::read_to_string(&cmake_lists_path) .unwrap_or_else(|error| panic!("Failed to read {}: {error}", cmake_lists_path.display())); - let cross_compile_guard = "if (NOT CMAKE_CROSSCOMPILING OR USE_EMSCRIPTEN)"; - let forced_generation = "if (TRUE)"; - let tlbc_command = "set(GENERATE_TLB_CMD tlbc)"; - let tlbc_target_file_command = "set(GENERATE_TLB_CMD $)"; - if (!original.contains(cross_compile_guard) || original.contains(forced_generation)) - && (!original.contains(tlbc_command) || original.contains(tlbc_target_file_command)) + if replacements + .iter() + .all(|(from, to)| !original.contains(from) || original.contains(to)) { return; } - let patched = original - .replace(cross_compile_guard, forced_generation) - .replace(tlbc_command, tlbc_target_file_command); + let patched = replacements + .iter() + .fold(original, |content, (from, to)| content.replace(from, to)); fs::write(&cmake_lists_path, patched) .unwrap_or_else(|error| panic!("Failed to patch {}: {error}", cmake_lists_path.display())); } From fff5ce81c0766b243dda27cfbf380056490ca6e5 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Fri, 29 May 2026 13:02:36 +0200 Subject: [PATCH 15/17] Generate smart contract sources for musl builds --- build.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.rs b/build.rs index 5b19b0d..1574d43 100644 --- a/build.rs +++ b/build.rs @@ -321,6 +321,15 @@ fn patch_musl_tlb_generation(monorepo_dir: &Path) { "set(GENERATE_TLB_CMD tlbc)", "set(GENERATE_TLB_CMD $)", ), + ("COMMAND func -PS -o", "COMMAND $ -PS -o"), + ( + "COMMAND fift -I${ARG_LIB_DIR} -s", + "COMMAND $ -I${ARG_LIB_DIR} -s", + ), + ( + "if (NOT CMAKE_CROSSCOMPILING)\n add_dependencies(smc-envelope gen_fif)\nendif()", + "add_dependencies(smc-envelope gen_fif)", + ), ], ); patch_cmake_file( From cbe4f850247c4f68b441503b434b4f230e074ad7 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Fri, 29 May 2026 15:52:21 +0200 Subject: [PATCH 16/17] Enable parallel CMake build for musl target The musl branch was the only one skipping `-j N`, so the TON monorepo (tonlibjson + emulator) was built single-threaded under Alpine. Pass `-j$(nproc)` for all targets; jobserver env stripping for musl is kept because explicit -j now drives parallelism. Co-authored-by: Cursor --- build.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 1574d43..d2f4785 100644 --- a/build.rs +++ b/build.rs @@ -196,14 +196,17 @@ fn run_build(target: &str, monorepo_dir: &Path) -> String { .always_configure(true) .very_verbose(true); - if !is_musl_target { - dst.build_arg("-j") - .build_arg(available_parallelism().unwrap().get().to_string()); - } + let parallelism = available_parallelism().map(|n| n.get()).unwrap_or(1); + dst.build_arg("-j").build_arg(parallelism.to_string()); #[cfg(all(feature = "no_avx512", not(target_os = "macos")))] disable_avx512_for_gcc(dst); + // Cargo's jobserver tokens (CARGO_MAKEFLAGS, MAKEFLAGS) can break under the + // musl/Alpine toolchain — file descriptors don't always propagate cleanly + // through CMake → make, leading to either jobserver warnings or, worse, + // make falling back to a single job. Strip them so the explicit `-j N` + // above is the only source of truth for parallelism. let cargo_makeflags = is_musl_target.then(|| env::var_os("CARGO_MAKEFLAGS")); let makeflags = is_musl_target.then(|| env::var_os("MAKEFLAGS")); let num_jobs = is_musl_target.then(|| env::var_os("NUM_JOBS")); From 1781d48939aa839d3e50202931d680fd758eb8c3 Mon Sep 17 00:00:00 2001 From: Aleksei Dolgii Date: Mon, 1 Jun 2026 16:50:17 +0200 Subject: [PATCH 17/17] Link Abseil static libraries for musl --- build.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/build.rs b/build.rs index d2f4785..9298c44 100644 --- a/build.rs +++ b/build.rs @@ -135,6 +135,10 @@ fn build_monorepo() { println!("cargo:rustc-link-search=native={build_dir}/build/third-party/zlib/lib"); println!("cargo:rustc-link-search=native={build_dir}/build/third-party/sodium/lib"); println!("cargo:rustc-link-search=native={build_dir}/build/third-party/secp256k1/lib"); + link_static_libraries_with_prefix( + &Path::new(&build_dir).join("build/third-party/abseil-cpp"), + "libabsl_", + ); add_musl_library_search_path("libm.a"); add_static_library_search_path("clang-21", "libgcc_eh.a"); } @@ -270,6 +274,86 @@ fn add_musl_library_search_path(library: &str) { println!("cargo:warning=Could not resolve {library} for {MUSL_TARGET}"); } +fn link_static_libraries_with_prefix(root: &Path, prefix: &str) { + let mut libraries = Vec::new(); + collect_static_libraries_with_prefix(root, prefix, &mut libraries); + libraries.sort(); + libraries.dedup(); + + if libraries.is_empty() { + println!( + "cargo:warning=Could not resolve static libraries with prefix {prefix} in {}", + root.display() + ); + return; + } + + let mut directories = libraries + .iter() + .map(|(directory, _)| directory) + .collect::>(); + directories.sort(); + directories.dedup(); + + for directory in directories { + println!("cargo:rustc-link-search=native={}", directory.display()); + } + + let mut library_names = libraries + .into_iter() + .map(|(_, library)| library) + .collect::>(); + library_names.sort_by(|left, right| { + match (left == "absl_raw_hash_set", right == "absl_raw_hash_set") { + (true, false) => std::cmp::Ordering::Less, + (false, true) => std::cmp::Ordering::Greater, + _ => left.cmp(right), + } + }); + + for _ in 0..2 { + for library in &library_names { + println!("cargo:rustc-link-lib=static={library}"); + } + } +} + +fn collect_static_libraries_with_prefix( + directory: &Path, + prefix: &str, + libraries: &mut Vec<(PathBuf, String)>, +) { + let Ok(entries) = fs::read_dir(directory) else { + return; + }; + + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + collect_static_libraries_with_prefix(&path, prefix, libraries); + continue; + } + + let Some(file_name) = path.file_name().and_then(|name| name.to_str()) else { + continue; + }; + if !file_name.starts_with(prefix) { + continue; + } + let Some(library_name) = file_name + .strip_prefix("lib") + .and_then(|name| name.strip_suffix(".a")) + else { + continue; + }; + let Some(parent) = path.parent() else { + continue; + }; + + libraries.push((parent.to_path_buf(), library_name.to_string())); + } +} + // function must be safe to handle _lock fn checkout_repo(monorepo_dir: &Path) -> anyhow::Result<()> { if let Some(parent_dir) = monorepo_dir.parent() {