diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dfd3da2b..8773a526 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,48 +18,73 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v2 - - uses: actions/cache@v2 + uses: actions/checkout@v4 with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Build and Test ${{ env.PACKAGE_NAME }} - run: | - python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')" - chmod a+x builder.pyz - echo "kotlinWarningsAsErrors=true" >> $GITHUB_WORKSPACE/local.properties - ./builder.pyz build -p ${{ env.PACKAGE_NAME }} - - macos-compat: - runs-on: macos-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - uses: actions/cache@v2 + submodules: true + - name: Configure JDK + uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: 17 + cache: 'gradle' + # Cache the Kotlin/Native toolchain based on the input Kotlin version from version catalog + # see https://kotlinlang.org/docs/native-improving-compilation-time.html + - uses: actions/cache@v4 with: path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + ~/.konan + key: ${{ runner.os }}-konan-${{ hashFiles('gradle/libs.versions.toml') }} restore-keys: | - ${{ runner.os }}-gradle- - - name: Build and Test ${{ env.PACKAGE_NAME }} + ${{ runner.os }}-konan- + # FIXME - we will need to migrate this to ECR to avoid throttle limits from dockerhub, for now rebuild the images during CI + - name: Configure Docker Images run: | - python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')" - chmod a+x builder.pyz - echo "kotlinWarningsAsErrors=true" >> $GITHUB_WORKSPACE/local.properties - ./builder.pyz build -p ${{ env.PACKAGE_NAME }} - - windows-compat: - runs-on: windows-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 + ./docker-images/build-all.sh + docker images - name: Build and Test ${{ env.PACKAGE_NAME }} run: | - python3 -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')" - python3 builder.pyz build -p ${{ env.PACKAGE_NAME }} + docker images + ./gradlew apiCheck + ./gradlew allTests + +# macos-compat: +# runs-on: macos-latest +# steps: +# - name: Checkout sources +# uses: actions/checkout@v4 +# with: +# submodules: true +# - name: Configure JDK +# uses: actions/setup-java@v3 +# with: +# distribution: 'corretto' +# java-version: 17 +# cache: 'gradle' +# - name: Configure Docker Images +# run: | +# ./docker-images/build-all.sh +# - name: Build and Test ${{ env.PACKAGE_NAME }} +# run: | +# ./gradlew apiCheck +# ./gradlew allTests +# +# windows-compat: +# runs-on: windows-latest +# steps: +# - name: Checkout sources +# uses: actions/checkout@v4 +# with: +# submodules: true +# - name: Configure JDK +# uses: actions/setup-java@v3 +# with: +# distribution: 'corretto' +# java-version: 17 +# cache: 'gradle' +# - name: Configure Docker Images +# run: | +# ./docker-images/build-all.sh +# - name: Build and Test ${{ env.PACKAGE_NAME }} +# run: | +# ./gradlew apiCheck +# ./gradlew allTests diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..0bfea074 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,33 @@ +[submodule "crt/aws-c-common"] + path = crt/aws-c-common + url = https://github.com/awslabs/aws-c-common +[submodule "crt/aws-c-auth"] + path = crt/aws-c-auth + url = https://github.com/awslabs/aws-c-auth +[submodule "crt/aws-c-cal"] + path = crt/aws-c-cal + url = https://github.com/awslabs/aws-c-cal +[submodule "crt/aws-c-compression"] + path = crt/aws-c-compression + url = https://github.com/awslabs/aws-c-compression +[submodule "crt/aws-c-http"] + path = crt/aws-c-http + url = https://github.com/awslabs/aws-c-http +[submodule "crt/aws-c-io"] + path = crt/aws-c-io + url = https://github.com/awslabs/aws-c-io +[submodule "crt/aws-checksums"] + path = crt/aws-checksums + url = https://github.com/awslabs/aws-checksums +[submodule "crt/aws-c-mqtt"] + path = crt/aws-c-mqtt + url = https://github.com/awslabs/aws-c-mqtt +[submodule "crt/s2n"] + path = crt/s2n + url = https://github.com/aws/s2n-tls +[submodule "crt/aws-lc"] + path = crt/aws-lc + url = https://github.com/aws/aws-lc +[submodule "crt/aws-c-sdkutils"] + path = crt/aws-c-sdkutils + url = https://github.com/awslabs/aws-c-sdkutils diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..4a32523b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,105 @@ +cmake_minimum_required(VERSION 3.1) +project(aws-crt-kotlin C) +message(STATUS "CMake ${CMAKE_VERSION}") + +option(BUILD_DEPS "Builds aws common runtime dependencies as part of build. Turn off if you want to control your dependency chain." ON) +option(BUILD_SHARED_LIBS "Build shared library for FFI: default: ON" ON) + +if (POLICY CMP0069) + cmake_policy(SET CMP0069 NEW) # Enable LTO/IPO if available in the compiler +endif() + +if (DEFINED CMAKE_PREFIX_PATH) + file(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH) +endif() + +if (NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + +if (UNIX AND NOT APPLE) + set(FIND_LIBRARY_USE_LIB64_PATHS true) +endif() + +# This is required in order to append /lib/cmake to each element in CMAKE_PREFIX_PATH +set(AWS_MODULE_DIR "/${CMAKE_INSTALL_LIBDIR}/cmake") +string(REPLACE ";" "${AWS_MODULE_DIR};" AWS_MODULE_PATH "${CMAKE_PREFIX_PATH}${AWS_MODULE_DIR}") +# Append that generated list to the module search path +list(APPEND CMAKE_MODULE_PATH ${AWS_MODULE_PATH}) + + +if (BUILD_DEPS) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/crt/aws-c-common/cmake") + + include(AwsFindPackage) + + set(IN_SOURCE_BUILD ON) + set(SEARCH_LIBCRYPTO OFF CACHE BOOL "Let S2N use libcrypto from AWS-LC.") + + # Don't compile tests in subdirectories. + # Turn off using `option` instead of `set`, or CTest will declare + # it as an option later and override the existing variable. + set(BUILD_TESTING OFF) + + # Disable BUILD_SHARED_LIBS for all CRT libs + set(SHARED_FFI_LIB ${BUILD_SHARED_LIBS}) + set(BUILD_SHARED_LIBS OFF) + + # CRT Libraries + add_subdirectory(crt/aws-c-common) + if (UNIX AND NOT APPLE) + if (NOT USE_OPENSSL) + if (NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) AND + NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)) + set(DISABLE_PERL ON) + endif() + if(CMAKE_C_COMPILER_ID MATCHES "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "5.0") + set(DISABLE_PERL OFF CACHE BOOL "Build with Perl to avoid using pre-compiled binary with AVX512") + set(MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX ON CACHE BOOL "Disable AVX512 on old GCC that not supports it") + endif() + set(DISABLE_GO ON) + set(SEARCH_LIBCRYPTO OFF) + set(BUILD_LIBSSL OFF) + add_subdirectory(crt/aws-lc) + else() + set(SEARCH_LIBCRYPTO ON) + # Find the system libcrypto and propagate its location to s2n's find script + find_package(OpenSSL REQUIRED) + set(LibCrypto_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) + set(LibCrypto_LIBRARY ${OPENSSL_CRYPTO_LIBRARY}) + if (LibCrypto_LIBRARY MATCHES ".so$") + set(LibCrypto_SHARED_LIBRARY ${LibCrypto_LIBRARY}) + else() + set(LibCrypto_STATIC_LIBRARY ${LibCrypto_LIBRARY}) + endif() + endif() + add_subdirectory(crt/s2n) + endif() + add_subdirectory(crt/aws-c-sdkutils) + add_subdirectory(crt/aws-c-io) + add_subdirectory(crt/aws-c-cal) + add_subdirectory(crt/aws-c-compression) + add_subdirectory(crt/aws-c-http) + add_subdirectory(crt/aws-c-auth) + add_subdirectory(crt/aws-checksums) +else() + include(AwsFindPackage) + set(IN_SOURCE_BUILD OFF) +endif() + +# Restore BUILD_SHARED_LIBS for this project +set(BUILD_SHARED_LIBS ${SHARED_FFI_LIB}) + +include(AwsCFlags) +include(AwsSharedLibSetup) +include(AwsSanitizers) + +aws_use_package(aws-c-common) +aws_use_package(aws-c-sdkutils) +aws_use_package(aws-c-io) +aws_use_package(aws-c-cal) +aws_use_package(aws-c-compression) +aws_use_package(aws-c-http) +aws_use_package(aws-c-auth) +aws_use_package(aws-checksums) + diff --git a/README.md b/README.md index 803ecfb4..904965c0 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ This project is licensed under the Apache-2.0 License. ## Building -Kotlin Multiplatform projects are in [Alpha](https://kotlinlang.org/docs/reference/evolution/components-stability.html). The CRT interfaces are subject to change. +CRT interfaces are subject to change. ### Linux/Unix Install some version of libcrypto on which s2n depends. See the [s2n](https://github.com/awslabs/s2n) documentation. @@ -23,6 +23,7 @@ apt-get install libssl-dev ``` OR + ```sh yum install openssl-devel ``` @@ -32,6 +33,36 @@ Set the path to `libcrypto.a` either as a command line argument to gradle `-Plib ### OSX +#### Debugging simulator test issues + +**Xcode does not support simulator tests for \** + +``` +* What went wrong: +Execution failed for task ':aws-crt-kotlin:iosX64Test'. +> Error while evaluating property 'device' of task ':aws-crt-kotlin:iosX64Test'. + > Failed to calculate the value of task ':aws-crt-kotlin:iosX64Test' property 'device'. + > Xcode does not support simulator tests for ios_x64. Check that requested SDK is installed. +``` + +Ensure that you have an appropriate simulator runtime installed. + +e.g. to install `iOS` platform support including simulator runtimes: +```sh +xcodebuild -downloadPlatform iOS +``` + +List simulator runtimes with: + +```sh +xcrun simctl list devices available +``` + + +See also: + +* https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes +* https://www.iosdev.recipes/simctl/ ### Windows @@ -69,3 +100,4 @@ CRTDEBUG=trace=2 ./elasticurl/bin/macosX64/elasticurl.kexe -v trace https://aws. Run the simple elasticurl integration test script `./scripts/elasticurl-test.sh` + diff --git a/aws-crt-kotlin/build.gradle.kts b/aws-crt-kotlin/build.gradle.kts index 8deaf68d..48746014 100644 --- a/aws-crt-kotlin/build.gradle.kts +++ b/aws-crt-kotlin/build.gradle.kts @@ -2,12 +2,17 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ +import aws.sdk.kotlin.gradle.crt.cmakeInstallDir +import aws.sdk.kotlin.gradle.crt.configureCrtCMakeBuild import aws.sdk.kotlin.gradle.dsl.configurePublishing import aws.sdk.kotlin.gradle.kmp.IDEA_ACTIVE import aws.sdk.kotlin.gradle.kmp.configureKmpTargets +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.aws.kotlin.repo.tools.kmp) + id("crt-build-support") } val sdkVersion: String by project @@ -24,6 +29,10 @@ configureKmpTargets() kotlin { explicitApi() + iosArm64() + iosSimulatorArm64() + iosX64() + jvm { attributes { attribute( @@ -60,10 +69,6 @@ kotlin { } } - val kotlinVersion: String by project - val coroutinesVersion: String by project - val mockServerVersion: String by project - sourceSets { val commonMain by getting { dependencies { @@ -116,6 +121,37 @@ kotlin { sourceSets.all { optinAnnotations.forEach { languageSettings.optIn(it) } } + + // create a single "umbrella" cinterop will all the aws-c-* API's we want to consume + // see: https://github.com/JetBrains/kotlin-native/issues/2423#issuecomment-466300153 + targets.withType { + val knTarget = this + logger.info("configuring $knTarget: ${knTarget.name}") + val cmakeInstallTask = configureCrtCMakeBuild(knTarget) + val targetInstallDir = project.cmakeInstallDir(knTarget) + val headerDir = targetInstallDir.resolve("include") + val libDir = targetInstallDir.resolve("lib") + + compilations["main"].cinterops { + val interopDir = "$projectDir/native/interop" + println("configuring crt cinterop for: ${knTarget.name}") + val interopSettings = create("aws-crt") { + defFile("$interopDir/crt.def") + includeDirs(headerDir) + compilerOpts("-L${libDir.absolutePath}") + } + + // cinterop tasks processes header files which requires the corresponding CMake build/install to run + val cinteropTask = tasks.named(interopSettings.interopProcessingTaskName) + cinteropTask.configure { + dependsOn(cmakeInstallTask) + } + } + + compilations["test"].compilerOptions.configure { + freeCompilerArgs.addAll(listOf("-linker-options", "-L${libDir.absolutePath}")) + } + } } // Publishing diff --git a/aws-crt-kotlin/native/interop/crt.def b/aws-crt-kotlin/native/interop/crt.def new file mode 100644 index 00000000..1ae6eab2 --- /dev/null +++ b/aws-crt-kotlin/native/interop/crt.def @@ -0,0 +1,77 @@ +package = libcrt +headers = aws/common/allocator.h aws/common/error.h \ + aws/common/byte_buf.h aws/common/string.h aws/common/logging.h aws/common/date_time.h \ + aws/io/io.h aws/io/event_loop.h aws/io/host_resolver.h aws/io/stream.h \ + aws/io/channel_bootstrap.h aws/io/tls_channel_handler.h aws/io/socket.h \ + aws/io/uri.h \ + aws/http/http.h aws/http/connection.h aws/http/connection_manager.h aws/http/request_response.h \ + aws/compression/compression.h +headerFilter = aws/common/* aws/io/* aws/http/* aws/compression/* + +linkerOpts = -laws-c-common -laws-c-cal -laws-c-io -laws-c-http -laws-c-compression +linkerOpts.osx = -framework Security +linkerOpts.linux = -ls2n -lcrypto + +--- + +// prototypes +static void s_crt_kotlin_init_allocator(int trace_level); +static void s_crt_kotlin_clean_up(void); +static void s_crt_kotlin_logger_cleanup(void); +static void s_crt_kotlin_log(enum aws_log_level level, aws_log_subject_t subject, const char *message); + +// definitions +static struct aws_allocator *s_crt_kotlin_allocator = NULL; +int g_memtrace_level = 0; + +static void s_crt_kotlin_init_allocator(int trace_level) { + if (trace_level > 0) { + g_memtrace_level = trace_level; + struct aws_allocator *allocator = aws_default_allocator(); + allocator = aws_mem_tracer_new(allocator, NULL, (enum aws_mem_trace_level)trace_level, 8); + s_crt_kotlin_allocator = allocator; + } else { + s_crt_kotlin_allocator = aws_default_allocator(); + } +} + +/** + * Cleans up allocator and logging. This should be the absolute last thing called after cleaning up all the other + * initialized CRT* libs. + */ +static void s_crt_kotlin_clean_up(void) { + if (g_memtrace_level) { + aws_mem_tracer_dump(s_crt_kotlin_allocator); + } + + s_crt_kotlin_logger_cleanup(); + + if (g_memtrace_level) { + aws_mem_tracer_destroy(s_crt_kotlin_allocator); + } +} + + +/** + * Obtaining static variables is difficult in kn, this gives us a stable variable to wire up that works + * with the kn memory model + */ +static struct aws_logger s_crt_kotlin_logger; + + +/** + * macros not available through generated kn bridge + */ +static void s_crt_kotlin_log(enum aws_log_level level, aws_log_subject_t subject, const char *message) { + AWS_LOGF(level, subject, "%s", message); +} + +/** + * Cleanup runs after kn runtime has been torn down, we need to do this outside of kotlin's world + */ +static void s_crt_kotlin_logger_cleanup(void) { + if (aws_logger_get() == &s_crt_kotlin_logger) { + aws_logger_set(NULL); + aws_logger_clean_up(&s_crt_kotlin_logger); + } +} \ No newline at end of file diff --git a/build-support/build.gradle.kts b/build-support/build.gradle.kts new file mode 100644 index 00000000..ca25bd95 --- /dev/null +++ b/build-support/build.gradle.kts @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +plugins { + `kotlin-dsl` + `java-gradle-plugin` +} + +group = "aws.sdk.kotlin" + +repositories { + mavenCentral() +} + +dependencies { + compileOnly(kotlin("gradle-plugin")) + compileOnly(kotlin("gradle-plugin-api")) + + testImplementation(libs.junit.jupiter) + testImplementation(libs.junit.jupiter.params) + testImplementation(libs.kotlin.test.junit5) +} + +gradlePlugin { + plugins { + create("build-support") { + id = "crt-build-support" + implementationClass = "aws.sdk.kotlin.gradle.crt.BuildSupport" + } + } +} + +tasks.test { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + showStandardStreams = true + showStackTraces = true + showExceptions = true + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + } +} diff --git a/build-support/settings.gradle.kts b/build-support/settings.gradle.kts new file mode 100644 index 00000000..30752294 --- /dev/null +++ b/build-support/settings.gradle.kts @@ -0,0 +1,13 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +rootProject.name = "build-support" + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/BuildSupport.kt b/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/BuildSupport.kt new file mode 100644 index 00000000..c723cc52 --- /dev/null +++ b/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/BuildSupport.kt @@ -0,0 +1,12 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.gradle.crt + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class BuildSupport : Plugin { + override fun apply(target: Project) { } +} diff --git a/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/CMakeTasks.kt b/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/CMakeTasks.kt new file mode 100644 index 00000000..4360b5ec --- /dev/null +++ b/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/CMakeTasks.kt @@ -0,0 +1,221 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.gradle.crt + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.tasks.Delete +import org.gradle.api.tasks.TaskProvider +import org.gradle.kotlin.dsl.named +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.konan.target.KonanTarget + +/** + * See [CMAKE_BUILD_TYPE](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html) + */ +enum class CMakeBuildType { + Debug, + RelWithDebInfo, + Release, +} + +/** + * Configure CMake tasks for building and installing CRT locally for a given Kotlin/Native target. + * + * This function sets up the following tasks: + * * cmakeConfigure -- e.g. cmakeConfigureLinuxX64 + * * cmakeBuild -- e.g. cmakeBuildLinuxX64 + * * cmakeInstall -- e.g. cmakeInstallLinuxX64 + * + * CMake tasks may or may not run inside of a docker container depending on the native target being built. + * All linux targets are built in a container. + * + * @param knTarget the native target to build CRT for + * @param buildType the [CMakeBuildType] to build for CMake build type. Defaults to `RelWithDebInfo` since end users + * can always strip the binary of all debug info. + * @return the `cmakeInstall` task for the target which can be used to wire up additional task dependency relationships +*/ +fun Project.configureCrtCMakeBuild( + knTarget: KotlinNativeTarget, + buildType: CMakeBuildType = CMakeBuildType.RelWithDebInfo, +): TaskProvider { + val cmakeConfigure = registerCmakeConfigureTask(knTarget, buildType) + + val cmakeBuild = registerCmakeBuildTask(knTarget, buildType) + cmakeBuild.configure { + dependsOn(cmakeConfigure) + } + + val cmakeInstall = registerCmakeInstallTask(knTarget, buildType) + cmakeInstall.configure { + dependsOn(cmakeBuild) + } + + // only enable cmake* tasks if that target is enabled + // FIXME - fix CI to not use CRT builder (or rationilize why we would keep it) + val hm = HostManager() + listOf(cmakeConfigure, cmakeBuild, cmakeInstall).forEach { task -> + task.configure { + onlyIf { + hm.isEnabled(knTarget.konanTarget) + } + } + } + + // TODO - add separate `cleanCMake` tasks and make the parent `clean` task depend on the individuals + tasks.named("clean") { + delete(project.rootProject.layout.buildDirectory.dir("cmake-build")) + delete(project.rootProject.layout.buildDirectory.dir("crt-libs")) + } + + return cmakeInstall +} + +private fun Project.registerCmakeConfigureTask( + knTarget: KotlinNativeTarget, + buildType: CMakeBuildType, +): TaskProvider { + val cmakeBuildDir = project.cmakeBuildDir(knTarget) + val installDir = project.cmakeInstallDir(knTarget) + + val relativeBuildDir = cmakeBuildDir.relativeTo(project.rootDir).path + val relativeInstallDir = installDir.relativeTo(project.rootDir).path + val cmakeLists = project.rootProject.projectDir.resolve("CMakeLists.txt") + + return project.tasks.register(knTarget.namedSuffix("cmakeConfigure", capitalized = true)) { + group = "ffi" + + inputs.property("buildType", buildType.toString()) + inputs.file(cmakeLists) + outputs.file(cmakeBuildDir.resolve("CMakeCache.txt")) + + doLast { + val args = mutableListOf( + "-B$relativeBuildDir", + "-DCMAKE_BUILD_TYPE=$buildType", + "-DCMAKE_INSTALL_PREFIX=$relativeInstallDir", + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "-DBUILD_DEPS=ON", + "-DBUILD_TESTING=OFF", + ) + + if (HostManager.hostIsMac && knTarget.konanTarget.family.isAppleFamily) { + args.add("-GXcode") + + // FIXME - What should the min target for ios be? Does it matter for our build? DCMAKE_OSX_DEPLOYMENT_TARGET + knTarget.konanTarget.osxArchitectureName?.let { + args.add("-DCMAKE_OSX_ARCHITECTURES=$it") + } + + knTarget.konanTarget.osxSystemName?.let { + args.add("-DCMAKE_SYSTEM_NAME=$it") + } + + // Xcode allows switching between device and simulator (via -sdk) even if we only configure one. + // Unfortunately this breaks during install as there is no way to override and pass `-sdk` for + // install like there is for `--build`. For simulator devices we set the name explicitly to + // ensure the correct directory is searched. + if (knTarget.konanTarget.isSimulatorSdk) { + args.add("-DCMAKE_OSX_SYSROOT=${knTarget.konanTarget.osxDeviceSdkName}") + } + } + + // executed from root build dir which is where CMakeLists.txt is + // We _could_ use the undocumented -H flag but that will be harder to make work inside docker + args.add(".") + + runCmake(project, knTarget, args) + } + } +} + +private fun Project.registerCmakeBuildTask( + knTarget: KotlinNativeTarget, + buildType: CMakeBuildType, +): TaskProvider { + val cmakeBuildDir = project.cmakeBuildDir(knTarget) + val relativeBuildDir = cmakeBuildDir.relativeTo(project.rootDir).path + + return project.tasks.register(knTarget.namedSuffix("cmakeBuild", capitalized = true)) { + group = "ffi" + + inputs.property("buildType", buildType.toString()) + inputs.file(project.cmakeLists) + inputs.files( + fileTree("$rootDir/crt").matching { + include(listOf("**/CMakeLists.txt", "**/*.c", "**/*.h")) + }, + ) + + outputs.dir(cmakeBuildDir) + + doLast { + val args = mutableListOf( + "--build", + relativeBuildDir, + "--config", + buildType.toString(), + ) + + val osxSdk = knTarget.konanTarget.osxDeviceSdkName + if (osxSdk != null) { + // see https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#switching-between-device-and-simulator + // assumes Xcode generator + args.add("--") + args.add("-sdk") + args.add(osxSdk) + } + + runCmake(project, knTarget, args) + } + } +} + +private fun Project.registerCmakeInstallTask( + knTarget: KotlinNativeTarget, + buildType: CMakeBuildType, +): TaskProvider { + val cmakeBuildDir = project.cmakeBuildDir(knTarget) + val relativeBuildDir = cmakeBuildDir.relativeTo(project.rootDir).path + val installDir = project.cmakeInstallDir(knTarget) + + return project.tasks.register(knTarget.namedSuffix("cmakeInstall", capitalized = true)) { + group = "ffi" + + inputs.file(project.cmakeLists) + outputs.dir(installDir) + + doLast { + val args = mutableListOf( + "--install", + relativeBuildDir, + "--config", + buildType.toString(), + ) + runCmake(project, knTarget, args) + } + } +} + +private fun runCmake(project: Project, target: KotlinNativeTarget, cmakeArgs: List) { + project.exec { + workingDir(project.rootDir) + val exeArgs = cmakeArgs.toMutableList() + val exeName = when (target.konanTarget) { + KonanTarget.LINUX_X64, KonanTarget.LINUX_ARM64 -> { + // cross compiling via dockcross - set the docker exe to cmake + val containerScriptArgs = listOf("--args", "--pull=never", "--", "cmake") + exeArgs.addAll(0, containerScriptArgs) + "./dockcross-" + target.konanTarget.name.replace("_", "-") + } + else -> "cmake" + } + + project.logger.info("$exeName ${exeArgs.joinToString(separator = " ")}") + executable(exeName) + args(exeArgs) + } +} diff --git a/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/CMakeUtils.kt b/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/CMakeUtils.kt new file mode 100644 index 00000000..7621c53d --- /dev/null +++ b/build-support/src/main/kotlin/aws/sdk/kotlin/gradle/crt/CMakeUtils.kt @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.gradle.crt + +import org.gradle.api.Project +import org.gradle.configurationcache.extensions.capitalized +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.Architecture +import org.jetbrains.kotlin.konan.target.Family +import org.jetbrains.kotlin.konan.target.KonanTarget +import java.io.File + +fun KotlinNativeTarget.namedSuffix(prefix: String, capitalized: Boolean = false): String = + prefix + if (capitalized) name.capitalized() else name + +val KonanTarget.isSimulatorSdk: Boolean + get() = when (this) { + KonanTarget.IOS_SIMULATOR_ARM64, KonanTarget.IOS_X64, + KonanTarget.TVOS_SIMULATOR_ARM64, KonanTarget.TVOS_X64, + KonanTarget.WATCHOS_SIMULATOR_ARM64, + KonanTarget.WATCHOS_X64, + KonanTarget.WATCHOS_X86, + -> true + else -> false + } + +// See https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos +const val IOS_DEVICE_SDK = "iphoneos" +const val IOS_SIMULATOR_SDK = "iphonesimulator" +const val TVOS_DEVICE_SDK = "appletvos" +const val TVOS_SIMULATOR_SDK = "appletvsimulator" +const val WATCHOS_DEVICE_SDK = "watchos" +const val WATCHOS_SIMULATOR_SDK = "watchsimulator" + +val KonanTarget.osxDeviceSdkName: String? + get() = when (this) { + KonanTarget.IOS_ARM64 -> IOS_DEVICE_SDK + KonanTarget.IOS_SIMULATOR_ARM64, KonanTarget.IOS_X64 -> IOS_SIMULATOR_SDK + KonanTarget.TVOS_ARM64 -> TVOS_DEVICE_SDK + KonanTarget.TVOS_SIMULATOR_ARM64, KonanTarget.TVOS_X64 -> TVOS_SIMULATOR_SDK + KonanTarget.WATCHOS_ARM32, + KonanTarget.WATCHOS_ARM64, + KonanTarget.WATCHOS_DEVICE_ARM64, + -> WATCHOS_DEVICE_SDK + KonanTarget.WATCHOS_SIMULATOR_ARM64, + KonanTarget.WATCHOS_X64, + KonanTarget.WATCHOS_X86, + -> WATCHOS_SIMULATOR_SDK + else -> null + } + +val KonanTarget.osxSystemName: String? + get() = when (family) { + Family.IOS -> "iOS" + Family.TVOS -> "tvOS" + Family.WATCHOS -> "watchOS" + else -> null + } + +val KonanTarget.osxArchitectureName + get() = when (architecture) { + Architecture.X64 -> "x86_64" + Architecture.X86 -> "i386" + Architecture.ARM64 -> "arm64" + Architecture.ARM32 -> when (this) { + KonanTarget.WATCHOS_ARM32 -> "armv7k" + KonanTarget.WATCHOS_ARM64 -> "arm64_32" + else -> null + } + else -> null + } + +fun Project.cmakeBuildDir(target: KotlinNativeTarget): File = + project.rootProject.layout.buildDirectory.file(target.namedSuffix("cmake-build/")).get().asFile + +fun Project.cmakeInstallDir(target: KotlinNativeTarget): File = + project.rootProject.layout.buildDirectory.file(target.namedSuffix("crt-libs/")).get().asFile + +val Project.cmakeLists: File + get() = rootProject.projectDir.resolve("CMakeLists.txt") diff --git a/build.gradle.kts b/build.gradle.kts index 942fea26..b99a0406 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,12 +12,17 @@ buildscript { mavenCentral() mavenLocal() } + // NOTE: buildscript classpath for the root project is the parent classloader for all subprojects. + // Anything included in the root buildscript classpath is added to the classpath for all projects! + dependencies { + // Add our custom gradle build logic to buildscript classpath + classpath(libs.aws.kotlin.repo.tools.build.support) + } } plugins { id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.13.2" alias(libs.plugins.kotlin.multiplatform) apply false - alias(libs.plugins.aws.kotlin.repo.tools.kmp) } allprojects { @@ -55,6 +60,7 @@ configureNexus() // Code Style val lintPaths = listOf( "**/*.{kt,kts}", + "!crt/**", ) configureLinting(lintPaths) diff --git a/crt/aws-c-auth b/crt/aws-c-auth new file mode 160000 index 00000000..8e5e4618 --- /dev/null +++ b/crt/aws-c-auth @@ -0,0 +1 @@ +Subproject commit 8e5e46188105c2072f06da366a02378074e40177 diff --git a/crt/aws-c-cal b/crt/aws-c-cal new file mode 160000 index 00000000..3d4c08b6 --- /dev/null +++ b/crt/aws-c-cal @@ -0,0 +1 @@ +Subproject commit 3d4c08b60ffa8698cda14bb8d56e5d6a27542f17 diff --git a/crt/aws-c-common b/crt/aws-c-common new file mode 160000 index 00000000..04c60b03 --- /dev/null +++ b/crt/aws-c-common @@ -0,0 +1 @@ +Subproject commit 04c60b033179e24919b3c8e452c05050683ae420 diff --git a/crt/aws-c-compression b/crt/aws-c-compression new file mode 160000 index 00000000..94f748ae --- /dev/null +++ b/crt/aws-c-compression @@ -0,0 +1 @@ +Subproject commit 94f748ae244c72a2e42c63818259ce8877ad6a5a diff --git a/crt/aws-c-http b/crt/aws-c-http new file mode 160000 index 00000000..0bb96ce5 --- /dev/null +++ b/crt/aws-c-http @@ -0,0 +1 @@ +Subproject commit 0bb96ce50261c6537d4def25c237f45fbc203d81 diff --git a/crt/aws-c-io b/crt/aws-c-io new file mode 160000 index 00000000..4c65ce51 --- /dev/null +++ b/crt/aws-c-io @@ -0,0 +1 @@ +Subproject commit 4c65ce51d2d7050e1ce1030881b6a4df22d33544 diff --git a/crt/aws-c-mqtt b/crt/aws-c-mqtt new file mode 160000 index 00000000..171840f9 --- /dev/null +++ b/crt/aws-c-mqtt @@ -0,0 +1 @@ +Subproject commit 171840f98dd628e60113c4033cc5b16a66079a7a diff --git a/crt/aws-c-sdkutils b/crt/aws-c-sdkutils new file mode 160000 index 00000000..6c7764ee --- /dev/null +++ b/crt/aws-c-sdkutils @@ -0,0 +1 @@ +Subproject commit 6c7764eed43a528b6577906a993e47018b06095f diff --git a/crt/aws-checksums b/crt/aws-checksums new file mode 160000 index 00000000..180ac988 --- /dev/null +++ b/crt/aws-checksums @@ -0,0 +1 @@ +Subproject commit 180ac988547edcda6d081dff7bd4b99a987342fd diff --git a/crt/aws-lc b/crt/aws-lc new file mode 160000 index 00000000..56def5a2 --- /dev/null +++ b/crt/aws-lc @@ -0,0 +1 @@ +Subproject commit 56def5a253d27280f3b7bd6564cfa5a11211aee8 diff --git a/crt/s2n b/crt/s2n new file mode 160000 index 00000000..5e3fc019 --- /dev/null +++ b/crt/s2n @@ -0,0 +1 @@ +Subproject commit 5e3fc019e16bf27f6c9a069d594bf7396ad2b3bd diff --git a/dockcross-linux-arm64 b/dockcross-linux-arm64 new file mode 100755 index 00000000..d9ded854 --- /dev/null +++ b/dockcross-linux-arm64 @@ -0,0 +1,278 @@ +#!/usr/bin/env bash + +DEFAULT_DOCKCROSS_IMAGE=aws-crt-kotlin/linux-arm64:latest + +#------------------------------------------------------------------------------ +# Helpers +# +err() { + echo -e >&2 "ERROR: $*\n" +} + +die() { + err "$*" + exit 1 +} + +has() { + # eg. has command update + local kind=$1 + local name=$2 + + type -t $kind:$name | grep -q function +} + +# If OCI_EXE is not already set, search for a container executor (OCI stands for "Open Container Initiative") +if [ -z "$OCI_EXE" ]; then + if which podman >/dev/null 2>/dev/null; then + OCI_EXE=podman + elif which docker >/dev/null 2>/dev/null; then + OCI_EXE=docker + else + die "Cannot find a container executor. Search for docker and podman." + fi +fi + +#------------------------------------------------------------------------------ +# Command handlers +# +command:update-image() { + $OCI_EXE pull $FINAL_IMAGE +} + +help:update-image() { + echo "Pull the latest $FINAL_IMAGE ." +} + +command:update-script() { + if cmp -s <( $OCI_EXE run --rm $FINAL_IMAGE ) $0; then + echo "$0 is up to date" + else + echo -n "Updating $0 ... " + $OCI_EXE run --rm $FINAL_IMAGE > $0 && echo ok + fi +} + +help:update-script() { + echo "Update $0 from $FINAL_IMAGE ." +} + +command:update() { + command:update-image + command:update-script +} + +help:update() { + echo "Pull the latest $FINAL_IMAGE, and then update $0 from that." +} + +command:help() { + if [[ $# != 0 ]]; then + if ! has command $1; then + err \"$1\" is not an dockcross command + command:help + elif ! has help $1; then + err No help found for \"$1\" + else + help:$1 + fi + else + cat >&2 < +ENDHELP + exit 1 + fi +} + +#------------------------------------------------------------------------------ +# Option processing +# +special_update_command='' +while [[ $# != 0 ]]; do + case $1 in + + --) + shift + break + ;; + + --args|-a) + ARG_ARGS="$2" + shift 2 + ;; + + --config|-c) + ARG_CONFIG="$2" + shift 2 + ;; + + --image|-i) + ARG_IMAGE="$2" + shift 2 + ;; + update|update-image|update-script) + special_update_command=$1 + break + ;; + -*) + err Unknown option \"$1\" + command:help + exit + ;; + + *) + break + ;; + + esac +done + +# The precedence for options is: +# 1. command-line arguments +# 2. environment variables +# 3. defaults + +# Source the config file if it exists +DEFAULT_DOCKCROSS_CONFIG=~/.dockcross +FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}} + +[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG" + +# Set the docker image +FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}} + +# Handle special update command +if [ "$special_update_command" != "" ]; then + case $special_update_command in + + update) + command:update + exit $? + ;; + + update-image) + command:update-image + exit $? + ;; + + update-script) + command:update-script + exit $? + ;; + + esac +fi + +# Set the docker run extra args (if any) +FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}} + +# Bash on Ubuntu on Windows +UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "") +# MSYS, Git Bash, etc. +MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "") +# CYGWIN +CYGWIN=$([ -e /proc/version ] && grep -l CYGWIN /proc/version || echo "") + +if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" -a "$OCI_EXE" != "podman" ]; then + USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )") +fi + +# Change the PWD when working in Docker on Windows +if [ -n "$UBUNTU_ON_WINDOWS" ]; then + WSL_ROOT="/mnt/" + CFG_FILE=/etc/wsl.conf + if [ -f "$CFG_FILE" ]; then + CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g') + eval "$CFG_CONTENT" + if [ -n "$root" ]; then + WSL_ROOT=$root + fi + fi + HOST_PWD=`pwd -P` + HOST_PWD=${HOST_PWD/$WSL_ROOT//} +elif [ -n "$MSYS" ]; then + HOST_PWD=$PWD + HOST_PWD=${HOST_PWD/\//} + HOST_PWD=${HOST_PWD/\//:\/} +elif [ -n "$CYGWIN" ]; then + for f in pwd readlink cygpath ; do + test -n "$(type "${f}" )" || { echo >&2 "Missing functionality (${f}) (in cygwin)." ; exit 1 ; } ; + done ; + HOST_PWD="$( cygpath -w "$( readlink -f "$( pwd ;)" ; )" ; )" ; +else + HOST_PWD=$PWD + [ -L $HOST_PWD ] && HOST_PWD=$(readlink $HOST_PWD) +fi + +# Mount Additional Volumes +if [ -z "$SSH_DIR" ]; then + SSH_DIR="$HOME/.ssh" +fi + +HOST_VOLUMES= +if [ -e "$SSH_DIR" -a -z "$MSYS" ]; then + if test -n "${CYGWIN}" ; then + HOST_VOLUMES+="-v $(cygpath -w ${SSH_DIR} ; ):/home/$(id -un)/.ssh" ; + else + HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh" ; + fi ; +fi + +#------------------------------------------------------------------------------ +# Now, finally, run the command in a container +# +TTY_ARGS= +tty -s && [ -z "$MSYS" ] && TTY_ARGS=-ti +CONTAINER_NAME=dockcross_$RANDOM +$OCI_EXE run $TTY_ARGS --name $CONTAINER_NAME \ + -v "$HOST_PWD":/work \ + $HOST_VOLUMES \ + "${USER_IDS[@]}" \ + $FINAL_ARGS \ + $FINAL_IMAGE "$@" +run_exit_code=$? + +# Attempt to delete container +rm_output=$($OCI_EXE rm -f $CONTAINER_NAME 2>&1) +rm_exit_code=$? +if [[ $rm_exit_code != 0 ]]; then + if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then + : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/ + else + echo "$rm_output" + exit $rm_exit_code + fi +fi + +exit $run_exit_code + +################################################################################ +# +# This image is not intended to be run manually. +# +# To create a dockcross helper script for the +# aws-crt-kotlin/linux-arm64:latest image, run: +# +# docker run --rm aws-crt-kotlin/linux-arm64:latest > aws-crt-kotlin-linux-arm64-latest +# chmod +x aws-crt-kotlin-linux-arm64-latest +# +# You may then wish to move the dockcross script to your PATH. +# +################################################################################ diff --git a/dockcross-linux-x64 b/dockcross-linux-x64 new file mode 100755 index 00000000..2a7dfd51 --- /dev/null +++ b/dockcross-linux-x64 @@ -0,0 +1,278 @@ +#!/usr/bin/env bash + +DEFAULT_DOCKCROSS_IMAGE=aws-crt-kotlin/linux-x64:latest + +#------------------------------------------------------------------------------ +# Helpers +# +err() { + echo -e >&2 "ERROR: $*\n" +} + +die() { + err "$*" + exit 1 +} + +has() { + # eg. has command update + local kind=$1 + local name=$2 + + type -t $kind:$name | grep -q function +} + +# If OCI_EXE is not already set, search for a container executor (OCI stands for "Open Container Initiative") +if [ -z "$OCI_EXE" ]; then + if which podman >/dev/null 2>/dev/null; then + OCI_EXE=podman + elif which docker >/dev/null 2>/dev/null; then + OCI_EXE=docker + else + die "Cannot find a container executor. Search for docker and podman." + fi +fi + +#------------------------------------------------------------------------------ +# Command handlers +# +command:update-image() { + $OCI_EXE pull $FINAL_IMAGE +} + +help:update-image() { + echo "Pull the latest $FINAL_IMAGE ." +} + +command:update-script() { + if cmp -s <( $OCI_EXE run --rm $FINAL_IMAGE ) $0; then + echo "$0 is up to date" + else + echo -n "Updating $0 ... " + $OCI_EXE run --rm $FINAL_IMAGE > $0 && echo ok + fi +} + +help:update-script() { + echo "Update $0 from $FINAL_IMAGE ." +} + +command:update() { + command:update-image + command:update-script +} + +help:update() { + echo "Pull the latest $FINAL_IMAGE, and then update $0 from that." +} + +command:help() { + if [[ $# != 0 ]]; then + if ! has command $1; then + err \"$1\" is not an dockcross command + command:help + elif ! has help $1; then + err No help found for \"$1\" + else + help:$1 + fi + else + cat >&2 < +ENDHELP + exit 1 + fi +} + +#------------------------------------------------------------------------------ +# Option processing +# +special_update_command='' +while [[ $# != 0 ]]; do + case $1 in + + --) + shift + break + ;; + + --args|-a) + ARG_ARGS="$2" + shift 2 + ;; + + --config|-c) + ARG_CONFIG="$2" + shift 2 + ;; + + --image|-i) + ARG_IMAGE="$2" + shift 2 + ;; + update|update-image|update-script) + special_update_command=$1 + break + ;; + -*) + err Unknown option \"$1\" + command:help + exit + ;; + + *) + break + ;; + + esac +done + +# The precedence for options is: +# 1. command-line arguments +# 2. environment variables +# 3. defaults + +# Source the config file if it exists +DEFAULT_DOCKCROSS_CONFIG=~/.dockcross +FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}} + +[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG" + +# Set the docker image +FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}} + +# Handle special update command +if [ "$special_update_command" != "" ]; then + case $special_update_command in + + update) + command:update + exit $? + ;; + + update-image) + command:update-image + exit $? + ;; + + update-script) + command:update-script + exit $? + ;; + + esac +fi + +# Set the docker run extra args (if any) +FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}} + +# Bash on Ubuntu on Windows +UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "") +# MSYS, Git Bash, etc. +MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "") +# CYGWIN +CYGWIN=$([ -e /proc/version ] && grep -l CYGWIN /proc/version || echo "") + +if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" -a "$OCI_EXE" != "podman" ]; then + USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )") +fi + +# Change the PWD when working in Docker on Windows +if [ -n "$UBUNTU_ON_WINDOWS" ]; then + WSL_ROOT="/mnt/" + CFG_FILE=/etc/wsl.conf + if [ -f "$CFG_FILE" ]; then + CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g') + eval "$CFG_CONTENT" + if [ -n "$root" ]; then + WSL_ROOT=$root + fi + fi + HOST_PWD=`pwd -P` + HOST_PWD=${HOST_PWD/$WSL_ROOT//} +elif [ -n "$MSYS" ]; then + HOST_PWD=$PWD + HOST_PWD=${HOST_PWD/\//} + HOST_PWD=${HOST_PWD/\//:\/} +elif [ -n "$CYGWIN" ]; then + for f in pwd readlink cygpath ; do + test -n "$(type "${f}" )" || { echo >&2 "Missing functionality (${f}) (in cygwin)." ; exit 1 ; } ; + done ; + HOST_PWD="$( cygpath -w "$( readlink -f "$( pwd ;)" ; )" ; )" ; +else + HOST_PWD=$PWD + [ -L $HOST_PWD ] && HOST_PWD=$(readlink $HOST_PWD) +fi + +# Mount Additional Volumes +if [ -z "$SSH_DIR" ]; then + SSH_DIR="$HOME/.ssh" +fi + +HOST_VOLUMES= +if [ -e "$SSH_DIR" -a -z "$MSYS" ]; then + if test -n "${CYGWIN}" ; then + HOST_VOLUMES+="-v $(cygpath -w ${SSH_DIR} ; ):/home/$(id -un)/.ssh" ; + else + HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh" ; + fi ; +fi + +#------------------------------------------------------------------------------ +# Now, finally, run the command in a container +# +TTY_ARGS= +tty -s && [ -z "$MSYS" ] && TTY_ARGS=-ti +CONTAINER_NAME=dockcross_$RANDOM +$OCI_EXE run $TTY_ARGS --name $CONTAINER_NAME \ + -v "$HOST_PWD":/work \ + $HOST_VOLUMES \ + "${USER_IDS[@]}" \ + $FINAL_ARGS \ + $FINAL_IMAGE "$@" +run_exit_code=$? + +# Attempt to delete container +rm_output=$($OCI_EXE rm -f $CONTAINER_NAME 2>&1) +rm_exit_code=$? +if [[ $rm_exit_code != 0 ]]; then + if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then + : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/ + else + echo "$rm_output" + exit $rm_exit_code + fi +fi + +exit $run_exit_code + +################################################################################ +# +# This image is not intended to be run manually. +# +# To create a dockcross helper script for the +# aws-crt-kotlin/linux-x64:latest image, run: +# +# docker run --rm aws-crt-kotlin/linux-x64:latest > aws-crt-kotlin-linux-x64-latest +# chmod +x aws-crt-kotlin-linux-x64-latest +# +# You may then wish to move the dockcross script to your PATH. +# +################################################################################ diff --git a/docker-images/build-all.sh b/docker-images/build-all.sh new file mode 100755 index 00000000..f29bb305 --- /dev/null +++ b/docker-images/build-all.sh @@ -0,0 +1,13 @@ +#!/bin/bash +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +PROJ_ROOT=$(realpath "$SCRIPT_DIR/..") + +# linxuX64 +docker build -f "$SCRIPT_DIR/linux-x64/Dockerfile" -t aws-crt-kotlin/linux-x64:latest "$PROJ_ROOT" +docker run --rm aws-crt-kotlin/linux-x64:latest > "$PROJ_ROOT/dockcross-linux-x64" +chmod ug+x "$PROJ_ROOT/dockcross-linux-x64" + +# linuxArm64 +docker build -f "$SCRIPT_DIR/linux-arm64/Dockerfile" -t aws-crt-kotlin/linux-arm64:latest "$PROJ_ROOT" +docker run --rm aws-crt-kotlin/linux-arm64:latest > "$PROJ_ROOT/dockcross-linux-arm64" +chmod ug+x "$PROJ_ROOT/dockcross-linux-arm64" diff --git a/docker-images/linux-arm64/Dockerfile b/docker-images/linux-arm64/Dockerfile new file mode 100644 index 00000000..f41784a1 --- /dev/null +++ b/docker-images/linux-arm64/Dockerfile @@ -0,0 +1,2 @@ +FROM dockcross/linux-arm64:20240104-6eda627 +ENV DEFAULT_DOCKCROSS_IMAGE aws-crt-kotlin/linux-arm64:latest diff --git a/docker-images/linux-x64/Dockerfile b/docker-images/linux-x64/Dockerfile new file mode 100644 index 00000000..514c30c8 --- /dev/null +++ b/docker-images/linux-x64/Dockerfile @@ -0,0 +1,2 @@ +FROM dockcross/linux-x64:20240104-6eda627 +ENV DEFAULT_DOCKCROSS_IMAGE aws-crt-kotlin/linux-x64:latest diff --git a/gradle.properties b/gradle.properties index 66e53cbf..50fa165a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,8 @@ +# kotlin kotlin.code.style=official kotlin.mpp.stability.nowarn=true +kotlin.mpp.enableCInteropCommonization=true +kotlin.daemon.jvmargs=-Xmx6g -XX:+HeapDumpOnOutOfMemoryError # gradle org.gradle.jvmargs=-Xmx2G -XX:MaxMetaspaceSize=1G diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7446c35b..d1da542a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] -kotlin-version = "1.9.21" +kotlin-version = "1.9.22" -aws-kotlin-repo-tools-version = "0.3.2" +aws-kotlin-repo-tools-version = "0.4.0" # libs crt-java-version = "0.29.6" @@ -16,6 +16,7 @@ kotlinx-cli-version = "0.3.6" [libraries] +aws-kotlin-repo-tools-build-support = { module="aws.sdk.kotlin.gradle:build-support", version.ref = "aws-kotlin-repo-tools-version" } crt-java = { module = "software.amazon.awssdk.crt:aws-crt", version.ref = "crt-java-version" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin-version"} @@ -40,4 +41,4 @@ mockserver-netty = { module = "org.mock-server:mockserver-netty", version.ref = [plugins] kotlin-multiplatform = {id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin-version" } -aws-kotlin-repo-tools-kmp = { id = "aws.sdk.kotlin.kmp", version.ref = "aws-kotlin-repo-tools-version" } +aws-kotlin-repo-tools-kmp = { id = "aws.sdk.kotlin.gradle.kmp", version.ref = "aws-kotlin-repo-tools-version" } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 4cf4beae..8168f850 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,6 +16,8 @@ pluginManagement { } } +includeBuild("./build-support") + rootProject.name = "aws-crt-kotlin-parent" include(":aws-crt-kotlin")