diff --git a/cinterop-c/.bazelrc b/cinterop-c/.bazelrc index 20da163f7..8f27c1876 100644 --- a/cinterop-c/.bazelrc +++ b/cinterop-c/.bazelrc @@ -1,4 +1,12 @@ -# we build the cc_static library bundled with all dependencies build --experimental_cc_static_library --experimental_platform_in_output_dir -build:release --compilation_mode=opt --strip=always \ No newline at end of file +build:release --compilation_mode=opt --strip=always + +build:macos_arm64 --platforms=@build_bazel_apple_support//platforms:macos_arm64 --apple_platform_type=macos +build:macos_x64 --platforms=@build_bazel_apple_support//platforms:macos_x86_64 --apple_platform_type=macos +build:ios_arm64 --platforms=@build_bazel_apple_support//platforms:ios_arm64 --apple_platform_type=ios +build:ios_simulator_arm64 --platforms=@build_bazel_apple_support//platforms:ios_sim_arm64 --apple_platform_type=ios +build:ios_x64 --platforms=@build_bazel_apple_support//platforms:ios_x86_64 --apple_platform_type=ios + +build:linux_arm64 --platforms=//platforms:linux_arm64 +build:linux_x64 --platforms=//platforms:linux_x86_64 diff --git a/cinterop-c/BUILD.bazel b/cinterop-c/BUILD.bazel index 7fa7c5b5c..cb61cb61c 100644 --- a/cinterop-c/BUILD.bazel +++ b/cinterop-c/BUILD.bazel @@ -1,11 +1,17 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") load("@rules_cc//cc:defs.bzl", "cc_library") -cc_library( +cc_static_library( name = "kgrpc", + deps = [ + ":kgrpc_lib", + ], +) + +cc_library( + name = "kgrpc_lib", srcs = ["src/kgrpc.cpp"], hdrs = glob(["include/kgrpc.h"]), - copts = ["-std=c++20"], includes = ["include"], visibility = ["//visibility:public"], deps = [ @@ -24,7 +30,6 @@ cc_library( name = "protowire", srcs = ["src/protowire.cpp"], hdrs = glob(["include/protowire.h"]), - copts = ["-std=c++20"], includes = ["include"], visibility = ["//visibility:public"], deps = [ diff --git a/cinterop-c/MODULE.bazel b/cinterop-c/MODULE.bazel index ba132687f..962279775 100644 --- a/cinterop-c/MODULE.bazel +++ b/cinterop-c/MODULE.bazel @@ -4,10 +4,7 @@ module( ) # rules_cc for cc_library support -bazel_dep( - name = "rules_cc", - version = "0.1.1", -) +bazel_dep(name = "rules_cc", version = "0.2.0") # required to build for apple targets (like iOS) bazel_dep(name = "apple_support", version = "1.22.1", repo_name = "build_bazel_apple_support") @@ -24,9 +21,15 @@ bazel_dep( GRPC_VERSION = "1.74.1" ## gRPC source dependency - bazel_dep( name = "grpc", version = GRPC_VERSION, repo_name = "com_github_grpc_grpc", ) + +# Linux toolchain setup (cross-compile) + +register_toolchains( + "//toolchain:toolchain_linux_x64_konan", + "//toolchain:toolchain_linux_arm64_konan", +) diff --git a/cinterop-c/MODULE.bazel.lock b/cinterop-c/MODULE.bazel.lock index 6e65d1ad5..43b3be81c 100644 --- a/cinterop-c/MODULE.bazel.lock +++ b/cinterop-c/MODULE.bazel.lock @@ -42,6 +42,7 @@ "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", "https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a", "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", + "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9", "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", @@ -213,7 +214,8 @@ "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", - "https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c", + "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", + "https://bcr.bazel.build/modules/rules_cc/0.2.0/source.json": "5f7f4e578e950adbf194217d4b607237a8197fc53ba46c367b3d61a86ecf35c2", "https://bcr.bazel.build/modules/rules_foreign_cc/0.10.1/MODULE.bazel": "b9527010e5fef060af92b6724edb3691970a5b1f76f74b21d39f7d433641be60", "https://bcr.bazel.build/modules/rules_foreign_cc/0.10.1/source.json": "9300e71df0cdde0952f10afff1401fa664e9fc5d9ae6204660ba1b158d90d6a6", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", diff --git a/cinterop-c/README.md b/cinterop-c/README.md new file mode 100644 index 000000000..c4b47384b --- /dev/null +++ b/cinterop-c/README.md @@ -0,0 +1,32 @@ +This subdirectory contains the C sources required by native targets. +It uses the Bazel build system and contains two libraries: protowire and kgrpc. + +### Protowire + +Is a thin layer over the CodedStream implementation of the C++ protobuf library. +To build (e.g. ios_arm64) run +```bash +bazel build :protowire_fat --config=ios_arm64 --config=release +``` + +### KgRPC + +We are using the gRPC-core library, which already exports its API with a C ABI. +Therefore, the KgRPC library is almost empty primarily used for convenient functions +or API that is not exposed by the C API. + +Because the gRPC takes a while to build when compiling for multiple targets, we store +it as a prebuilt static (fat) in `prebuilt-deps/grpc_fat`. +The binary can be updated by running +```bash +./gradlew :grpc:grpc-core:buildDependencyCLibGrpc_fat_iosArm64 +``` + +### Compiling for Linux + +To produce K/N compatible static libraries, we use the Konan toolchain for compilation. +The Bazel toolchain is specified in `toolchain/` and requires the user to specify the +`KONAN_HOME` variable like +```bash +bazel build //:protowire --config=linux_arm64 --define=KONAN_HOME=$HOME/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.10 +``` \ No newline at end of file diff --git a/cinterop-c/build_target.sh b/cinterop-c/build_target.sh index d07493472..787fbcb86 100755 --- a/cinterop-c/build_target.sh +++ b/cinterop-c/build_target.sh @@ -9,26 +9,28 @@ trap 'echo "ERROR: Build failed at ${BASH_SOURCE}:${LINENO}" >&2' ERR # Builds a static library for a specific platform (os/arch). # # Usage: -# ./build_target.sh //path:libtarget out_dir +# ./build_target.sh //path:libtarget dest konan_target konan_home # Example: -# ./build_target.sh :protowire_static out @build_bazel_apple_support//platforms:ios_arm64 ios_arm64 ios +# ./build_target.sh :protowire_static out/libprotowire_static.ios_arm64.a ios_arm64 \ +# $HOME/.konan/kotlin-native-prebuilt-macos-aarch64-2.2.10 # # The example will produce ./out/libprotowire_static.ios_arm64.a LABEL="${1:?need bazel target label}" DST="${2:?need output destination}" -PLATFORM="${3:?need a platform for bazel build command}" -OS="${4:?need the operating system of the target platform}" +KONAN_TARGET="${3:?need the konan_target name}" +KONAN_HOME="${4:?need the konan_home path}" CONFIG=release -mkdir -p $(dirname "$DST") +mkdir -p "$(dirname "$DST")" echo "==> Building $LABEL to $DST" >&2 -bazel build "$LABEL" --platforms="$PLATFORM" --apple_platform_type="$OS" --config="$CONFIG" --announce_rc >/dev/null +KONAN_DEP="--define=KONAN_DEPS=/Users/johannes.zottele/.konan//dependencies" +bazel build "$LABEL" --config="$KONAN_TARGET" --config="$CONFIG" $KONAN_DEP "--define=KONAN_HOME=$KONAN_HOME" >/dev/null # Ask Bazel what file(s) this target produced under this platform -out="$(bazel cquery "$LABEL" --platforms="$PLATFORM" --apple_platform_type="$OS" --config="$CONFIG" --output=files | head -n1)" +out="$(bazel cquery "$LABEL" --config="$KONAN_TARGET" --config="$CONFIG" $KONAN_DEP "--define=KONAN_HOME=$KONAN_HOME" --output=files | head -n1)" [[ -n "$out" ]] || { echo "No output for $LABEL ($SHORT)"; exit 1; } cp -f "$out" "$DST" diff --git a/cinterop-c/platforms/BUILD.bazel b/cinterop-c/platforms/BUILD.bazel new file mode 100644 index 000000000..edec07f93 --- /dev/null +++ b/cinterop-c/platforms/BUILD.bazel @@ -0,0 +1,15 @@ +platform( + name = "linux_x86_64", + constraint_values = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], +) + +platform( + name = "linux_arm64", + constraint_values = [ + "@platforms//os:linux", + "@platforms//cpu:aarch64", + ], +) diff --git a/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_arm64.a b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_arm64.a new file mode 100755 index 000000000..8f4caf684 Binary files /dev/null and b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_arm64.a differ diff --git a/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_arm64.a.sha256 b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_arm64.a.sha256 new file mode 100644 index 000000000..822960047 --- /dev/null +++ b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_arm64.a.sha256 @@ -0,0 +1 @@ +5eab3ed3bebb20944f053cacf34c755173832ab65e1c7f199a5d70fb3f1e7d55 diff --git a/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_x64.a b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_x64.a new file mode 100755 index 000000000..914000f30 Binary files /dev/null and b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_x64.a differ diff --git a/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_x64.a.sha256 b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_x64.a.sha256 new file mode 100644 index 000000000..3e06f3802 --- /dev/null +++ b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.linux_x64.a.sha256 @@ -0,0 +1 @@ +511c10750585f1a7c7cd8801acaab10cf21cd8e098c381a07102496e3569b085 diff --git a/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.macos_x64.a b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.macos_x64.a new file mode 100755 index 000000000..dfc996420 Binary files /dev/null and b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.macos_x64.a differ diff --git a/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.macos_x64.a.sha256 b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.macos_x64.a.sha256 new file mode 100644 index 000000000..089bf78e3 --- /dev/null +++ b/cinterop-c/prebuilt-deps/grpc_fat/libgrpc_fat.macos_x64.a.sha256 @@ -0,0 +1 @@ +b1023a3c07c18bd1be3066bd101380d99b56b22a725e15fed6f2bb67e6548765 diff --git a/cinterop-c/toolchain/BUILD.bazel b/cinterop-c/toolchain/BUILD.bazel new file mode 100644 index 000000000..167613638 --- /dev/null +++ b/cinterop-c/toolchain/BUILD.bazel @@ -0,0 +1,67 @@ +load(":cc_toolchain_config.bzl", "cc_toolchain_config") + +cc_toolchain_config( + name = "cfg_linux_x64_konan", + target = "linux_x64", +) + +cc_toolchain_config( + name = "cfg_linux_arm64_konan", + target = "linux_arm64", +) + +filegroup( + name = "wrappers", + srcs = [ + "run_konan", + "run_konan_ar.sh", + "run_konan_clang.sh", + "run_konan_clangxx.sh", + ], +) + +cc_toolchain( + name = "tc_linux_x64_konan", + all_files = ":wrappers", + ar_files = ":wrappers", + compiler_files = ":wrappers", + dwp_files = ":wrappers", + linker_files = ":wrappers", + objcopy_files = ":wrappers", + strip_files = ":wrappers", + toolchain_config = ":cfg_linux_x64_konan", + toolchain_identifier = "konan_linux_x64", +) + +cc_toolchain( + name = "tc_linux_arm64_konan", + all_files = ":wrappers", + ar_files = ":wrappers", + compiler_files = ":wrappers", + dwp_files = ":wrappers", + linker_files = ":wrappers", + objcopy_files = ":wrappers", + strip_files = ":wrappers", + toolchain_config = ":cfg_linux_arm64_konan", + toolchain_identifier = "konan_linux_arm64", +) + +toolchain( + name = "toolchain_linux_x64_konan", + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":tc_linux_x64_konan", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +toolchain( + name = "toolchain_linux_arm64_konan", + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:arm64", + ], + toolchain = ":tc_linux_arm64_konan", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) diff --git a/cinterop-c/toolchain/cc_toolchain_config.bzl b/cinterop-c/toolchain/cc_toolchain_config.bzl new file mode 100644 index 000000000..421b57d64 --- /dev/null +++ b/cinterop-c/toolchain/cc_toolchain_config.bzl @@ -0,0 +1,206 @@ +load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") +load( + "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + "env_entry", + "env_set", + "feature", + "flag_group", + "flag_set", + "tool_path", + "with_feature_set", +) + +ALL_ACTIONS = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ACTION_NAMES.cpp_link_static_library, +] + +# Constructs the toolchain configuration by defining all necessary flags and toolchain wrapper scripts. +# The wrapper scripts call Konan which delegates all requests to the corresponding clang/llvm tools. +# Additionally it includes all built-in include directories from the Konan toolchain and sysroot. +def _impl(ctx): + target = ctx.attr.target + home = ctx.var.get("KONAN_HOME") + if not home: + fail("Set --define=KONAN_HOME=/path/to/.konan/kotlin-native-prebuilt-*") + deps = home + "/../dependencies" + + if target == "linux_x64": + cpu = "x86_64" + elif target == "linux_arm64": + cpu = "aarch64" + else: + fail("Unsupported target: {}".format(target)) + + tool_paths = [ + tool_path(name = "gcc", path = "run_konan_clang.sh"), + tool_path(name = "cpp", path = "run_konan_clangxx.sh"), + tool_path(name = "ar", path = "run_konan_ar.sh"), + tool_path(name = "ld", path = "/usr/bin/false"), + tool_path(name = "nm", path = "/usr/bin/false"), + tool_path(name = "objdump", path = "/usr/bin/false"), + tool_path(name = "strip", path = "/usr/bin/false"), + ] + + features = [ + feature( + name = "export_konan_home", + enabled = True, + env_sets = [env_set( + actions = ALL_ACTIONS, + env_entries = [ + env_entry(key = "KONAN_HOME", value = home), + env_entry(key = "KONAN_TARGET", value = target), + ], + )], + ), + + # One feature, multiple flag_sets: common + per-mode. + feature( + name = "konan_compile", + enabled = True, + flag_sets = [ + # Common C/C++ flags (always applied) + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ], + flag_groups = [flag_group(flags = [ + # Reproducibility / diagnostics + "-no-canonical-prefixes", + "-Wno-builtin-macro-redefined", + '-D__DATE__="redacted"', + '-D__TIMESTAMP__="redacted"', + '-D__TIME__="redacted"', + "-fcolor-diagnostics", + + "-U_FORTIFY_SOURCE", + "-fstack-protector", + "-fno-omit-frame-pointer", + + "-Wall", + "-Wthread-safety", + "-Wself-assign", + + "--target=" + ("x86_64-unknown-linux-gnu" if target == "linux_x64" else "aarch64-unknown-linux-gnu"), + ])], + ), + # C++-only flags + flag_set( + actions = [ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = [ + "-std=c++17", + "-stdlib=libstdc++", + ])], + ), + # dbg mode + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + with_features = [with_feature_set(features = ["dbg"])], + flag_groups = [flag_group(flags = [ + "-g", + "-fstandalone-debug", + ])], + ), + # opt mode + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + with_features = [with_feature_set(features = ["opt"])], + flag_groups = [flag_group(flags = [ + "-g0", + "-O2", + "-D_FORTIFY_SOURCE=1", + "-DNDEBUG", + "-ffunction-sections", + "-fdata-sections", + ])], + ), + ], + ), + + # Linker flags in one place; lld is preferred on linux/konan + feature( + name = "konan_link", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [flag_group(flags = [ + "--target=" + ("x86_64-unknown-linux-gnu" if target == "linux_x64" else "aarch64-unknown-linux-gnu"), + "-no-canonical-prefixes", + "-fuse-ld=lld", + "-Wl,--build-id=md5", + "-Wl,--hash-style=gnu", + "-Wl,-z,relro,-z,now", + ])], + ), + # Link-time GC (opt only) + flag_set( + actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + with_features = [with_feature_set(features = ["opt"])], + flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])], + ), + ], + ), + + feature(name = "opt"), + feature(name = "dbg"), + feature(name = "fastbuild"), + ] + + includes = [] + if target == "linux_x64": + includes += [ + deps + "/x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2/lib/gcc/x86_64-unknown-linux-gnu/8.3.0/include", + deps + "/x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2/x86_64-unknown-linux-gnu/include/c++/8.3.0", + deps + "/x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2/x86_64-unknown-linux-gnu/include/c++/8.3.0/x86_64-unknown-linux-gnu", + deps + "/x86_64-unknown-linux-gnu-gcc-8.3.0-glibc-2.19-kernel-4.9-2/x86_64-unknown-linux-gnu/sysroot/usr/include", + ] + elif target == "linux_arm64": + includes += [ + deps + "/aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2/lib/gcc/aarch64-unknown-linux-gnu/8.3.0/include", + deps + "/aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2/aarch64-unknown-linux-gnu/include/c++/8.3.0", + deps + "/aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2/aarch64-unknown-linux-gnu/include/c++/8.3.0/aarch64-unknown-linux-gnu", + deps + "/aarch64-unknown-linux-gnu-gcc-8.3.0-glibc-2.25-kernel-4.9-2/aarch64-unknown-linux-gnu/sysroot/usr/include", + ] + + return cc_common.create_cc_toolchain_config_info( + ctx = ctx, + toolchain_identifier = "konan_" + target, + abi_libc_version = "glibc", + abi_version = "glibc", + compiler = "clang", + host_system_name = "local", + target_cpu = cpu, + target_system_name = "linux", + tool_paths = tool_paths, + features = features, + cxx_builtin_include_directories = [ + deps + "/llvm-19-aarch64-macos-essentials-75/lib/clang/19/include", + ] + includes, + ) + +cc_toolchain_config = rule( + implementation = _impl, + attrs = { + "target": attr.string(mandatory = True), + }, + provides = [CcToolchainConfigInfo], +) diff --git a/cinterop-c/toolchain/run_konan b/cinterop-c/toolchain/run_konan new file mode 100755 index 000000000..6de9c8f33 --- /dev/null +++ b/cinterop-c/toolchain/run_konan @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +: "${KONAN_HOME:?KONAN_HOME must be set}" + +TOOL_NAME="$1" +shift + +if [ -z "$JAVACMD" -a -n "$JAVA_HOME" -a -x "$JAVA_HOME/bin/java" ]; then + JAVACMD="$JAVA_HOME/bin/java" +else + JAVACMD=java +fi +[ -n "$JAVACMD" ] || JAVACMD=java + +declare -a java_args +declare -a java_opts +declare -a konan_args + +pass_rest=false +while [ $# -gt 0 ]; do + if [ "$pass_rest" = true ]; then + konan_args+=("$1") + shift + continue + fi + + case "$1" in + --) + pass_rest=true + shift + ;; + -D*) + java_args+=("$1") + shift + ;; + -J*) + java_args+=("${1:2}") + shift + ;; + --time) + konan_args+=("--time") + java_args+=("-Dkonan.profile=true") + TIMECMD=time + shift + ;; + *) + konan_args+=("$1") + shift + ;; + esac +done + +java_opts=(-ea \ + -Xmx3G \ + -XX:TieredStopAtLevel=1 \ + -Dfile.encoding=UTF-8 \ + -Dkonan.home="$KONAN_HOME" \ + ${JAVA_OPTS}) + +# Unset some environment variables which are set by XCode and may potentially affect the tool executed. +while IFS=$'\r' read -r line || [[ -n "$line" ]]; do + unset $line +done < "${KONAN_HOME}/tools/env_blacklist" + +KONAN_JAR="${KONAN_HOME}/konan/lib/kotlin-native-compiler-embeddable.jar" +KONAN_CLASSPATH="$KONAN_JAR" +TOOL_CLASS=org.jetbrains.kotlin.cli.utilities.MainKt +LIBCLANG_DISABLE_CRASH_RECOVERY=1 \ +$TIMECMD "$JAVACMD" "${java_opts[@]}" "${java_args[@]}" -cp "$KONAN_CLASSPATH" "$TOOL_CLASS" "$TOOL_NAME" "${konan_args[@]}" \ No newline at end of file diff --git a/cinterop-c/toolchain/run_konan_ar.sh b/cinterop-c/toolchain/run_konan_ar.sh new file mode 100755 index 000000000..99484275e --- /dev/null +++ b/cinterop-c/toolchain/run_konan_ar.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +set -euo pipefail +: "${KONAN_HOME:?KONAN_HOME must be set}" + + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "$SCRIPT_DIR/run_konan" llvm llvm-ar -- "$@" diff --git a/cinterop-c/toolchain/run_konan_clang.sh b/cinterop-c/toolchain/run_konan_clang.sh new file mode 100755 index 000000000..19dccf6b8 --- /dev/null +++ b/cinterop-c/toolchain/run_konan_clang.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +set -euo pipefail +: "${KONAN_HOME:?KONAN_HOME must be set}" +: "${KONAN_TARGET:?KONAN_TARGET must be set}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "$SCRIPT_DIR/run_konan" clang clang "$KONAN_TARGET" -- "$@" \ No newline at end of file diff --git a/cinterop-c/toolchain/run_konan_clangxx.sh b/cinterop-c/toolchain/run_konan_clangxx.sh new file mode 100755 index 000000000..e6b622f1d --- /dev/null +++ b/cinterop-c/toolchain/run_konan_clangxx.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +set -euo pipefail +: "${KONAN_HOME:?KONAN_HOME must be set}" +: "${KONAN_TARGET:?KONAN_TARGET must be set}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "$SCRIPT_DIR/run_konan" clang clang++ "$KONAN_TARGET" -- "$@" \ No newline at end of file diff --git a/gradle-conventions/src/main/kotlin/util/cinterop.kt b/gradle-conventions/src/main/kotlin/util/cinterop.kt index 4f888336e..175d00d1c 100644 --- a/gradle-conventions/src/main/kotlin/util/cinterop.kt +++ b/gradle-conventions/src/main/kotlin/util/cinterop.kt @@ -12,13 +12,16 @@ import org.gradle.api.tasks.Exec import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskProvider import org.gradle.internal.extensions.stdlib.capitalized -import org.gradle.kotlin.dsl.* +import org.gradle.kotlin.dsl.extra +import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.provideDelegate +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultCInteropSettings import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.tasks.CInteropProcess -import org.jetbrains.kotlin.konan.target.Family -import org.jetbrains.kotlin.konan.target.KonanTarget +import util.other.libs import java.io.File // works with the cinterop-c Bazel project @@ -154,12 +157,12 @@ private fun TaskContainer.registerBuildClibTask( target: KotlinNativeTarget, ): TaskProvider { return register(name) { - val platform = target.bazelPlatformName - val os = target.bazelOsName + val konanTarget = target.konanTarget.visibleName + val konanHome = project.findKonanHome() group = "build" workingDir = project.cinteropLibDir - commandLine("bash", "-c", "./build_target.sh $bazelTask $outFile $platform $os") + commandLine("bash", "-c", "./build_target.sh $bazelTask $outFile $konanTarget $konanHome") inputs.files(project.fileTree(project.cinteropLibDir) { exclude("bazel-*/**", "prebuilt-deps/**") }) outputs.files(outFile) @@ -173,47 +176,22 @@ private val Project.cinteropLibDir: File return layout.projectDirectory.dir("$globalRootDir/cinterop-c").asFile.absoluteFile } -/** - * Returns the Bazel platform name for the given [KotlinNativeTarget]. - * - * For Apple targets, compare the following two lists: - * - https://kotlinlang.org/docs/native-target-support.html - * - https://github.com/bazelbuild/apple_support/blob/master/configs/platforms.bzl - */ -private val KotlinNativeTarget.bazelPlatformName: String - get() { - val appleSupport = "@build_bazel_apple_support//platforms" - return when (konanTarget) { - KonanTarget.MACOS_ARM64 -> "$appleSupport:macos_arm64" - KonanTarget.MACOS_X64 -> "$appleSupport:macos_x86_64" - KonanTarget.IOS_ARM64 -> "$appleSupport:ios_arm64" - KonanTarget.IOS_SIMULATOR_ARM64 -> "$appleSupport:ios_sim_arm64" - KonanTarget.IOS_X64 -> "$appleSupport:ios_x86_64" - KonanTarget.WATCHOS_ARM32 -> "$appleSupport:watchos_armv7k" - // WATCHOS_ARM64 is the "older" arm64_32 target, not arm64 (which is WATCH_DEVICE_ARM64) - KonanTarget.WATCHOS_ARM64 -> "$appleSupport:watchos_arm64_32" - KonanTarget.WATCHOS_DEVICE_ARM64 -> "$appleSupport:watchos_device_arm64" - KonanTarget.WATCHOS_SIMULATOR_ARM64 -> "$appleSupport:watchos_arm64" - KonanTarget.WATCHOS_X64 -> "$appleSupport:watchos_x86_64" - KonanTarget.TVOS_ARM64 -> "$appleSupport:tvos_arm64" - KonanTarget.TVOS_SIMULATOR_ARM64 -> "$appleSupport:tvos_sim_arm64" - KonanTarget.TVOS_X64 -> "$appleSupport:tvos_x86_64" - KonanTarget.LINUX_ARM32_HFP -> TODO() - KonanTarget.LINUX_ARM64 -> TODO() - KonanTarget.LINUX_X64 -> TODO() - KonanTarget.ANDROID_ARM32 -> TODO() - KonanTarget.ANDROID_ARM64 -> TODO() - KonanTarget.ANDROID_X64 -> TODO() - KonanTarget.ANDROID_X86 -> TODO() - KonanTarget.MINGW_X64 -> TODO() - } +private fun Project.findKonanHome(): String { + val userHome = System.getProperty("user.home") + val osName = System.getProperty("os.name").lowercase() + val hostOs = when { + osName.contains("mac") -> "macos" + osName.contains("linux") -> "linux" + osName.contains("windows") -> "windows" + else -> error("Unsupported OS: $osName") } - -private val KotlinNativeTarget.bazelOsName - get() = when (konanTarget.family) { - Family.OSX -> "macos" - Family.IOS -> "ios" - Family.TVOS -> "tvos" - Family.WATCHOS -> "watchos" - else -> TODO() + val hostArch = System.getProperty("os.arch").lowercase().let { + when { + it.contains("aarch64") || it.contains("arm64") -> "aarch64" + it.contains("x86_64") || it.contains("amd64") -> "x64" + else -> error("Unsupported arch: $it") + } } + val kotlinVersion = project.libs.versions.kotlin.compiler.get() + return "$userHome/.konan/kotlin-native-prebuilt-$hostOs-$hostArch-$kotlinVersion" +} \ No newline at end of file diff --git a/grpc/grpc-core/gradle.properties b/grpc/grpc-core/gradle.properties index 1eda57d1b..1603c27c0 100644 --- a/grpc/grpc-core/gradle.properties +++ b/grpc/grpc-core/gradle.properties @@ -4,9 +4,6 @@ kotlinx.rpc.exclude.wasmWasi=true kotlinx.rpc.exclude.js=true kotlinx.rpc.exclude.wasmJs=true -kotlinx.rpc.exclude.linuxArm64=true -kotlinx.rpc.exclude.linuxX64=true -kotlinx.rpc.exclude.macosX64=true kotlinx.rpc.exclude.mingwX64=true kotlinx.rpc.exclude.tvosArm64=true kotlinx.rpc.exclude.tvosSimulatorArm64=true diff --git a/grpc/grpc-core/src/nativeInterop/cinterop/libkgrpc.def b/grpc/grpc-core/src/nativeInterop/cinterop/libkgrpc.def index 27211bb19..c86979d6f 100644 --- a/grpc/grpc-core/src/nativeInterop/cinterop/libkgrpc.def +++ b/grpc/grpc-core/src/nativeInterop/cinterop/libkgrpc.def @@ -9,9 +9,12 @@ noStringConversion = grpc_slice_from_copied_buffer my_grpc_slice_from_copied_buf strictEnums = grpc_status_code grpc_connectivity_state grpc_call_error staticLibraries.macos_arm64 = libkgrpc.macos_arm64.a libgrpc_fat.macos_arm64.a +staticLibraries.macos_x64 = libkgrpc.macos_x64.a libgrpc_fat.macos_x64.a staticLibraries.ios_arm64 = libkgrpc.ios_arm64.a libgrpc_fat.ios_arm64.a staticLibraries.ios_simulator_arm64 = libkgrpc.ios_simulator_arm64.a libgrpc_fat.ios_simulator_arm64.a -staticLibraries.ios_simulator_x64 = libkgrpc.ios_simulator_x64.a libgrpc_fat.ios_simulator_x64.a +staticLibraries.ios_x64 = libkgrpc.ios_x64.a libgrpc_fat.ios_x64.a +staticLibraries.linux_arm64 = libkgrpc.linux_arm64.a libgrpc_fat.linux_arm64.a +staticLibraries.linux_x64 = libkgrpc.linux_x64.a libgrpc_fat.linux_x64.a # TODO: Uncomment when activating WatchOS # staticLibraries.watchos_arm64 = libkgrpc_fat.watchos_arm64.a # staticLibraries.watchos_simulator_arm64 = libkgrpc_fat.watchos_simulator_arm64.a diff --git a/protobuf/protobuf-core/gradle.properties b/protobuf/protobuf-core/gradle.properties index 1eda57d1b..1603c27c0 100644 --- a/protobuf/protobuf-core/gradle.properties +++ b/protobuf/protobuf-core/gradle.properties @@ -4,9 +4,6 @@ kotlinx.rpc.exclude.wasmWasi=true kotlinx.rpc.exclude.js=true kotlinx.rpc.exclude.wasmJs=true -kotlinx.rpc.exclude.linuxArm64=true -kotlinx.rpc.exclude.linuxX64=true -kotlinx.rpc.exclude.macosX64=true kotlinx.rpc.exclude.mingwX64=true kotlinx.rpc.exclude.tvosArm64=true kotlinx.rpc.exclude.tvosSimulatorArm64=true diff --git a/protobuf/protobuf-core/src/nativeInterop/cinterop/libprotowire.def b/protobuf/protobuf-core/src/nativeInterop/cinterop/libprotowire.def index 8d1c717f1..a6d030cce 100644 --- a/protobuf/protobuf-core/src/nativeInterop/cinterop/libprotowire.def +++ b/protobuf/protobuf-core/src/nativeInterop/cinterop/libprotowire.def @@ -5,9 +5,12 @@ noStringConversion = pw_encoder_write_string staticLibraries.macos_arm64 = libprotowire_fat.macos_arm64.a +staticLibraries.macos_x64 = libprotowire_fat.macos_x64.a staticLibraries.ios_arm64 = libprotowire_fat.ios_arm64.a staticLibraries.ios_simulator_arm64 = libprotowire_fat.ios_simulator_arm64.a -staticLibraries.ios_simulator_x64 = libprotowire_fat.ios_simulator_x64.a +staticLibraries.ios_x64 = libprotowire_fat.ios_x64.a +staticLibraries.linux_arm64 = libprotowire_fat.linux_arm64.a +staticLibraries.linux_x64 = libprotowire_fat.linux_x64.a # TODO: Uncomment when activating WatchOS # staticLibraries.watchos_arm64 = libprotowire_fat.watchos_arm64_32.a # staticLibraries.watchos_simulator_arm64 = libprotowire_fat.watchos_sim_arm64.a \ No newline at end of file