diff --git a/native/executors/src/main/kotlin/org/jetbrains/kotlin/native/executors/XcodeSimulatorExecutor.kt b/native/executors/src/main/kotlin/org/jetbrains/kotlin/native/executors/XcodeSimulatorExecutor.kt index 55bd1514d88..7d25c6c5eed 100644 --- a/native/executors/src/main/kotlin/org/jetbrains/kotlin/native/executors/XcodeSimulatorExecutor.kt +++ b/native/executors/src/main/kotlin/org/jetbrains/kotlin/native/executors/XcodeSimulatorExecutor.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.* import java.io.ByteArrayOutputStream import java.io.File import java.util.logging.Logger -import kotlin.time.Duration private fun defaultDeviceId(target: KonanTarget) = when (target.family) { Family.TVOS -> "com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-4K" @@ -163,4 +162,4 @@ class XcodeSimulatorExecutor( this.environment.putAll(env) }) } -} +} \ No newline at end of file diff --git a/native/native.tests/testData/framework/objcexport/expectedLazy.h b/native/native.tests/testData/framework/objcexport/expectedLazy/expectedLazy.h similarity index 100% rename from native/native.tests/testData/framework/objcexport/expectedLazy.h rename to native/native.tests/testData/framework/objcexport/expectedLazy/expectedLazy.h diff --git a/native/native.tests/testData/framework/objcexport/expectedLazyLegacySuspendUnit.h b/native/native.tests/testData/framework/objcexport/expectedLazy/expectedLazyLegacySuspendUnit.h similarity index 100% rename from native/native.tests/testData/framework/objcexport/expectedLazyLegacySuspendUnit.h rename to native/native.tests/testData/framework/objcexport/expectedLazy/expectedLazyLegacySuspendUnit.h diff --git a/native/native.tests/testData/framework/objcexport/expectedLazyNoGenerics.h b/native/native.tests/testData/framework/objcexport/expectedLazy/expectedLazyNoGenerics.h similarity index 100% rename from native/native.tests/testData/framework/objcexport/expectedLazyNoGenerics.h rename to native/native.tests/testData/framework/objcexport/expectedLazy/expectedLazyNoGenerics.h diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/FrameworkTest.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/FrameworkTest.kt index f14cee0da31..097ce24a422 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/FrameworkTest.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/FrameworkTest.kt @@ -15,6 +15,8 @@ import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestExecutable import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestRunCheck import org.jetbrains.kotlin.konan.test.blackbox.support.runner.TestRunChecks import org.jetbrains.kotlin.konan.test.blackbox.support.settings.* +import org.jetbrains.kotlin.native.executors.runProcess +import org.jetbrains.kotlin.test.KtAssert.fail import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue import org.junit.jupiter.api.Assumptions import org.junit.jupiter.api.Tag @@ -298,37 +300,37 @@ abstract class FrameworkTestBase : AbstractNativeSimpleTest() { @Test fun objCExportTest() { - objCExportTestImpl("", emptyList(), emptyList(), false) + objCExportTestImpl("", emptyList(), emptyList(), false, true) } @Test fun objCExportTestNoGenerics() { objCExportTestImpl("NoGenerics", listOf("-Xno-objc-generics"), - listOf("-D", "NO_GENERICS"), false) + listOf("-D", "NO_GENERICS"), false, true) } @Test fun objCExportTestLegacySuspendUnit() { objCExportTestImpl("LegacySuspendUnit", listOf("-Xbinary=unitSuspendFunctionObjCExport=legacy"), - listOf("-D", "LEGACY_SUSPEND_UNIT_FUNCTION_EXPORT"), false) + listOf("-D", "LEGACY_SUSPEND_UNIT_FUNCTION_EXPORT"), false, true) } @Test fun objCExportTestNoSwiftMemberNameMangling() { objCExportTestImpl("NoSwiftMemberNameMangling", listOf("-Xbinary=objcExportDisableSwiftMemberNameMangling=true"), - listOf("-D", "DISABLE_MEMBER_NAME_MANGLING"), false) + listOf("-D", "DISABLE_MEMBER_NAME_MANGLING"), false, false) } @Test fun objCExportTestNoInterfaceMemberNameMangling() { objCExportTestImpl("NoInterfaceMemberNameMangling", listOf("-Xbinary=objcExportIgnoreInterfaceMethodCollisions=true"), - listOf("-D", "DISABLE_INTERFACE_METHOD_NAME_MANGLING"), false) + listOf("-D", "DISABLE_INTERFACE_METHOD_NAME_MANGLING"), false, false) } @Test fun objCExportTestStatic() { objCExportTestImpl("Static", listOf("-Xbinary=objcExportSuspendFunctionLaunchThreadRestriction=none"), - listOf("-D", "ALLOW_SUSPEND_ANY_THREAD"), true) + listOf("-D", "ALLOW_SUSPEND_ANY_THREAD"), true, false) } private fun objCExportTestImpl( @@ -336,8 +338,12 @@ abstract class FrameworkTestBase : AbstractNativeSimpleTest() { frameworkOpts: List, swiftOpts: List, isStaticFramework: Boolean, + needLazyHeaderCheck: Boolean, ) { Assumptions.assumeTrue(targets.testTarget.family.isAppleFamily) + val doLazyHeaderCheck = needLazyHeaderCheck && testRunSettings.get() == PipelineType.K1 + val lazyHeader: File = buildDir.resolve("lazy-$suffix.h").also { it.delete() } // Clean up lazy header after previous runs + // Compile a couple of KLIBs val library = compileToLibrary( testSuiteDir.resolve("objcexport/library"), @@ -372,6 +378,7 @@ abstract class FrameworkTestBase : AbstractNativeSimpleTest() { "-Xexport-kdoc", "-Xbinary=bundleId=foo.bar", "-module-name", frameworkName, + "-Xemit-lazy-objc-header=${lazyHeader.absolutePath}".takeIf { doLazyHeaderCheck }, ) ), givenDependencies = setOf(TestModule.Given(library.klibFile), TestModule.Given(noEnumEntries.klibFile)), @@ -411,6 +418,16 @@ abstract class FrameworkTestBase : AbstractNativeSimpleTest() { assertTrue(infoPlistContents.contains(Regex("CFBundleIdentifier\\s*foo.bar"))) { "${infoPlist.absolutePath} does not contain expected pattern with `foo.bar`:\n$infoPlistContents" } + + if (doLazyHeaderCheck) { + val expectedLazyHeaderName = "expectedLazy/expectedLazy${suffix}.h" + val expectedLazyHeader = objcExportTestSuiteDir.resolve(expectedLazyHeaderName) + if (!expectedLazyHeader.exists() || expectedLazyHeader.readLines() != lazyHeader.readLines()) { + runProcess("diff", "-u", expectedLazyHeader.absolutePath, lazyHeader.absolutePath) + lazyHeader.copyTo(expectedLazyHeader, overwrite = true) + fail("$expectedLazyHeader file patched;\nPlease review this change and commit the patch, if change is correct") + } + } } private fun generateObjCFramework( diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt index f2965d52f05..b05c2b43005 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/compilation/TestCompilation.kt @@ -86,6 +86,10 @@ internal abstract class BasicCompilation( // - klib+static_cache -> framework // option `-Xstatic-framework` can be supplied only to `-p framework` stage, so must be filtered out for other stages add(freeCompilerArgs.compilerArgs.filter { it != "-Xstatic-framework" }) + is ObjCFrameworkCompilation -> + // Lazy headers must not be generated during 2nd stage of TWO_STAGE_MULTI_MODULE mode, since no source files are passed, only klib. + // If allowed, incomplete lazy header would overwrite full lazy header generated during 1st stage, which would fail the test. + add(freeCompilerArgs.compilerArgs.filterNot { sourceModules.isEmpty() && it.startsWith("-Xemit-lazy-objc-header=") }) else -> add(freeCompilerArgs.compilerArgs) } }