From e197573e3ecd9c9d5c0070aa1404304e22b0c361 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Wed, 22 Mar 2017 15:43:19 +0300 Subject: [PATCH] Raspberry Pi target (#365) --- .../kotlin/native/interop/indexer/Indexer.kt | 9 +++- .../kotlin/native/interop/gen/jvm/main.kt | 35 ++++++++---- .../kotlin/backend/konan/KonanTarget.kt | 15 ++++-- .../kotlin/backend/konan/LinkStage.kt | 54 ++++++++++++++----- backend.native/konan.properties | 9 ++++ build.gradle | 11 +++- dependencies/build.gradle | 3 ++ samples/tetris/build | 7 ++- 8 files changed, 108 insertions(+), 35 deletions(-) diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt index 54e78b04f74..eefcc5508d9 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt @@ -90,7 +90,6 @@ internal class NativeIndexImpl(val language: Language) : NativeIndex() { this.def = def } } - assert (underlying is ConstArrayType) // So the result must feel like array: return ConstArrayType(RecordType(structDeclaration), 1) @@ -110,6 +109,12 @@ internal class NativeIndexImpl(val language: Language) : NativeIndex() { return builtinVaListType(type, name, underlying) } + + if (name == "__gnuc_va_list" || name == "va_list") { + // TODO: fix GNUC varargs support. + return UnsupportedType + } + if ((underlying is RecordType && underlying.decl.spelling.split(' ').last() == name) || (underlying is EnumType && underlying.def.spelling.split(' ').last() == name)) { @@ -346,4 +351,4 @@ private fun indexDeclarations(library: NativeLibrary, nativeIndex: NativeIndexIm clang_IndexAction_dispose(indexAction) clang_disposeIndex(index) } -} \ No newline at end of file +} diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index aa384819bcc..f9f9755048a 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -39,7 +39,8 @@ private val knownTargets = mapOf( "linux" to "linux", "macbook" to "osx", "iphone" to "osx-ios", - "iphone_sim" to "osx-ios-sim") + "iphone_sim" to "osx-ios-sim", + "raspberrypi" to "linux-raspberrypi") private fun String.targetSuffix(): String = @@ -117,10 +118,11 @@ private fun runCmd(command: Array, workDir: File, verbose: Boolean = fal private fun Properties.defaultCompilerOpts(target: String, dependencies: String): List { - val sysRootDir = this.getOsSpecific("sysRoot", target)!! - val sysRoot = "$dependencies/$sysRootDir" - val targetSysRootDir = this.getOsSpecific("targetSysRoot", target) + val hostSysRootDir = this.getOsSpecific("sysRoot", target)!! + val hostSysRoot = "$dependencies/$hostSysRootDir" + val targetSysRootDir = this.getOsSpecific("targetSysRoot", target) ?: hostSysRootDir val targetSysRoot = "$dependencies/$targetSysRootDir" + val sysRoot = targetSysRoot val llvmHomeDir = this.getOsSpecific("llvmHome", target)!! val llvmHome = "$dependencies/$llvmHomeDir" val llvmVersion = this.getProperty("llvmVersion")!! @@ -136,22 +138,22 @@ private fun Properties.defaultCompilerOpts(target: String, dependencies: String) "osx" -> return listOf( "-isystem", isystem, - "-B$sysRoot/usr/bin", + "-B$hostSysRoot/usr/bin", "--sysroot=$sysRoot", "-mmacosx-version-min=10.10") "osx-ios" -> return listOf( "-arch", "arm64", "-isystem", isystem, - "-B$sysRoot/usr/bin", - "--sysroot=$targetSysRoot", + "-B$hostSysRoot/usr/bin", + "--sysroot=$sysRoot", "-miphoneos-version-min=5.0.0") "osx-ios-sim" -> return listOf( "-arch", "x86_64", "-isystem", isystem, - "-B$sysRoot/usr/bin", - "--sysroot=$targetSysRoot", + "-B$hostSysRoot/usr/bin", + "--sysroot=$sysRoot", "-mios-simulator-version-min=5.0.0") "linux" -> { val gccToolChainDir = this.getOsSpecific("gccToolChain", target)!! @@ -161,7 +163,19 @@ private fun Properties.defaultCompilerOpts(target: String, dependencies: String) "-isystem", isystem, "--gcc-toolchain=$gccToolChain", "-L$llvmHome/lib", - "-B$sysRoot/../bin", + "-B$hostSysRoot/../bin", + "--sysroot=$sysRoot") + } + "linux-raspberrypi" -> { + val gccToolChainDir = this.getOsSpecific("gccToolChain", target)!! + val gccToolChain= "$dependencies/$gccToolChainDir" + + return listOf( + "-target", "armv7-unknown-linux-gnueabihf", + "-isystem", isystem, + "--gcc-toolchain=$gccToolChain", + "-L$llvmHome/lib", + "-B$hostSysRoot/../bin", "--sysroot=$sysRoot") } else -> error("Unexpected target: ${target}") @@ -203,7 +217,6 @@ private fun processLib(konanHome: String, val flavorName = args["-flavor"]?.single() ?: "jvm" val flavor = KotlinPlatform.values().single { it.name.equals(flavorName, ignoreCase = true) } val target = args["-target"]?.single()?.targetSuffix() ?: defaultTarget() - val defFile = args["-def"]?.single()?.let { File(it) } if (defFile == null && args["-pkg"] == null) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanTarget.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanTarget.kt index 965d66e221d..2238defcb3e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanTarget.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanTarget.kt @@ -4,10 +4,11 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration enum class KonanTarget(var enabled: Boolean = false) { - IPHONE(), - IPHONE_SIM(), - LINUX(), - MACBOOK() + IPHONE, + IPHONE_SIM, + LINUX, + MACBOOK, + RASPBERRYPI } class TargetManager(val config: CompilerConfiguration) { @@ -16,7 +17,10 @@ class TargetManager(val config: CompilerConfiguration) { init { when (host) { - KonanTarget.LINUX -> KonanTarget.LINUX.enabled = true + KonanTarget.LINUX -> { + KonanTarget.LINUX.enabled = true + KonanTarget.RASPBERRYPI.enabled = true + } KonanTarget.MACBOOK -> { KonanTarget.MACBOOK.enabled = true KonanTarget.IPHONE.enabled = true @@ -66,6 +70,7 @@ class TargetManager(val config: CompilerConfiguration) { if (host == KonanTarget.LINUX) { when (current) { KonanTarget.LINUX -> return("linux") + KonanTarget.RASPBERRYPI -> return("linux-raspberrypi") KonanTarget.IPHONE -> return("linux-ios") KonanTarget.IPHONE_SIM -> return("linux-ios-sim") else -> error("Impossible combination of $host and $current") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt index 12021253dc0..26be0890f5d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt @@ -41,7 +41,6 @@ internal open class MacOSPlatform(distribution: Distribution) open val sysRoot = distribution.sysRoot open val targetSysRoot = sysRoot - open val llvmLib = distribution.llvmLib override fun linkCommand(objectFiles: List, executable: String, optimize: Boolean): List { @@ -75,9 +74,15 @@ internal class IPhoneSimulatorFromMacOSPlatform(distribution: Distribution) override val llvmLlcFlags = properties.propertyList("llvmLlcFlags.osx-ios-sim") override val targetSysRoot = "${distribution.dependencies}/${properties.propertyString("targetSysRoot.osx-ios-sim")!!}" } -internal class LinuxPlatform(distribution: Distribution) + +internal open class LinuxPlatform(distribution: Distribution) : PlatformFlags(distribution) { + open val sysRoot = distribution.sysRoot + + val llvmLib = distribution.llvmLib + val libGcc = distribution.libGcc + override val llvmLtoFlags = properties.propertyList("llvmLtoFlags.linux") override val llvmLlcFlags = properties.propertyList("llvmLlcFlags.linux") @@ -90,11 +95,6 @@ internal class LinuxPlatform(distribution: Distribution) properties.propertyList("pluginOptimizationFlags.linux") override fun linkCommand(objectFiles: List, executable: String, optimize: Boolean): List { - - val sysRoot = distribution.sysRoot - val llvmLib = distribution.llvmLib - val libGcc = distribution.libGcc - // TODO: Can we extract more to the konan.properties? return mutableListOf("$linker", "--sysroot=${sysRoot}", @@ -116,6 +116,29 @@ internal class LinuxPlatform(distribution: Distribution) } } +internal class RaspberryPiPlatform(distribution: Distribution) + : LinuxPlatform(distribution) { + + override val sysRoot = "${distribution.dependencies}/${properties.propertyString("targetSysRoot.linux-raspberrypi")!!}" + + override fun linkCommand(objectFiles: List, executable: String, optimize: Boolean): List { + // TODO: Can we extract more to the konan.properties? + return mutableListOf("$linker", + "--sysroot=${sysRoot}", + "-export-dynamic", "-z", "relro", "--hash-style=gnu", + "--build-id", "--eh-frame-hdr", + "-dynamic-linker", "/lib/ld-linux-armhf.so.3", + "-o", executable, + "${sysRoot}/usr/lib/crt1.o", "${sysRoot}/usr/lib/crti.o", "${libGcc}/crtbegin.o", + "-L${llvmLib}", "-L${libGcc}", "-L${sysRoot}/../lib/arm-linux-gnueabihf", "-L${sysRoot}/lib/arm-linux-gnueabihf", + "-L${sysRoot}/usr/lib/arm-linux-gnueabihf", "-L${sysRoot}/../lib", "-L${sysRoot}/lib", "-L${sysRoot}/usr/lib") + + if (optimize) listOf("-plugin", "$llvmLib/LLVMgold.so") + pluginOptimizationFlags else {listOf()} + + objectFiles + + if (optimize) linkerOptimizationFlags else {listOf()} + + linkerKonanFlags + + listOf("-lgcc", "-lgcc_s", "-lc", "${libGcc}/crtend.o", "${sysRoot}/usr/lib/crtn.o") + } +} internal class LinkStage(val context: Context) { @@ -126,24 +149,28 @@ internal class LinkStage(val context: Context) { Distribution(context.config.configuration) private val properties = distribution.properties - val platform: PlatformFlags = when (TargetManager.host) { - KonanTarget.LINUX -> LinuxPlatform(distribution) + val platform = when (TargetManager.host) { + KonanTarget.LINUX -> when (targetManager.current) { + KonanTarget.LINUX -> LinuxPlatform(distribution) + KonanTarget.RASPBERRYPI -> RaspberryPiPlatform(distribution) + else -> TODO("Target not implemented yet.") + } KonanTarget.MACBOOK -> when (targetManager.current) { KonanTarget.IPHONE_SIM - -> IPhoneSimulatorFromMacOSPlatform(distribution) + -> IPhoneSimulatorFromMacOSPlatform(distribution) KonanTarget.IPHONE - -> IPhoneOSfromMacOSPlatform(distribution) + -> IPhoneOSfromMacOSPlatform(distribution) KonanTarget.MACBOOK - -> MacOSPlatform(distribution) + -> MacOSPlatform(distribution) else -> TODO("Target not implemented yet.") } else -> TODO("Target not implemented yet") } + val suffix = targetManager.currentSuffix() val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false val emitted = config.get(KonanConfigKeys.BITCODE_FILE)!! - val nostdlib = config.get(KonanConfigKeys.NOSTDLIB) ?: false val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false val libraries = context.config.librariesToLink @@ -168,7 +195,6 @@ internal class LinkStage(val context: Context) { tmpObjectFile.deleteOnExit() val objectFile = tmpObjectFile.absolutePath - val tool = distribution.llvmLlc val command = listOf(distribution.llvmLlc, "-o", objectFile, "-filetype=obj") + properties.propertyList("llvmLlcFlags.$suffix") + listOf(file) runTool(*command.toTypedArray()) diff --git a/backend.native/konan.properties b/backend.native/konan.properties index c86b20e2c0f..d765979fe9b 100644 --- a/backend.native/konan.properties +++ b/backend.native/konan.properties @@ -49,3 +49,12 @@ linkerOptimizationFlags.linux = --gc-sections pluginOptimizationFlags.linux = -plugin-opt=mcpu=x86-64 -plugin-opt=O3 entrySelector.linux = --defsym main=Konan_main +// Raspberry Pi +arch.linux-raspberrypi = armv7 +sysRoot.linux-raspberrypi = target-gcc-toolchain-3-linux-x86-64/x86_64-unknown-linux-gnu/sysroot +targetSysRoot.linux-raspberrypi = target-sysroot-1-raspberrypi +llvmHome.linux-raspberrypi = clang+llvm-3.9.0-linux-x86-64 +libGcc.linux-raspberrypi = target-sysroot-1-raspberrypi/lib/gcc/arm-linux-gnueabihf/4.8.3/ +gccToolChain.linux-raspberrypi = target-gcc-toolchain-3-linux-x86-64 +llvmLlcFlags.linux-raspberrypi = -mtriple=armv7-unknown-linux-gnueabihf --disable-fp-elim -mfloat-abi=hard +linkerKonanFlags.linux-raspberrypi = -Bstatic -lstdc++ -Bdynamic -ldl -lm -lc -lpthread -fuse-ld=gold diff --git a/build.gradle b/build.gradle index a3cf4364801..51cf7a9ae4e 100644 --- a/build.gradle +++ b/build.gradle @@ -26,7 +26,16 @@ allprojects { if (isLinux()) { ext.targetArgs << - ["host": ["--sysroot=${gccToolchainDir}/${gnuTriplet}/sysroot"]] + ["host": + ["--sysroot=${gccToolchainDir}/${gnuTriplet}/sysroot"], + "raspberrypi": + ["-target", "armv7-unknown-linux-gnueabihf", + "-mfpu=vfp", "-mfloat-abi=hard", + "--sysroot=$raspberryPiSysrootDir", + // TODO: those two are hacks. + "-I$raspberryPiSysrootDir/usr/include/c++/4.8.3", + "-I$raspberryPiSysrootDir/usr/include/c++/4.8.3/arm-linux-gnueabihf"] + ] } else { ext.targetArgs << ["host": diff --git a/dependencies/build.gradle b/dependencies/build.gradle index 5dd8eb13433..e0d18c5afe3 100644 --- a/dependencies/build.gradle +++ b/dependencies/build.gradle @@ -82,6 +82,9 @@ if (isLinux()) { task gccToolchain(type: TgzNativeDep) { baseName = "target-gcc-toolchain-3-$host" } + task raspberryPiSysroot(type: TgzNativeDep) { + baseName = "target-sysroot-1-raspberrypi" + } } else { task hostSysroot(type: TgzNativeDep) { baseName = "target-sysroot-1-$host" diff --git a/samples/tetris/build b/samples/tetris/build index 299ff7433af..be059efdc0f 100755 --- a/samples/tetris/build +++ b/samples/tetris/build @@ -3,6 +3,7 @@ DIR=. DIST=../../dist DEPS=../../dependencies/all + CFLAGS_macbook=-I/Library/Frameworks/SDL2.framework/Headers LINKER_ARGS_macbook="-F /Library/Frameworks -framework SDL2" COMPILER_ARGS_macbook= @@ -16,6 +17,8 @@ LINKER_ARGS_iphone="-framework SDL2 \ -framework AVFoundation -framework CoreGraphics -framework CoreMotion -framework Foundation -framework GameController \ -framework AudioToolbox -framework OpenGLES -framework QuartzCore -framework UIKit" COMPILER_ARGS_iphone=-nomain +CFLAGS_raspberrypi=-I$DEPS/target-sysroot-1-raspberrypi/usr/include/SDL2 +LINKER_ARGS_raspberrypi="-lSDL2" if [ x$TARGET == x ]; then case "$OSTYPE" in @@ -30,8 +33,8 @@ CFLAGS=${!var} var=LINKER_ARGS_${TARGET} LINKER_ARGS=${!var} var=COMPILER_ARGS_${TARGET} -COMPILER_ARGS=${!var} +COMPILER_ARGS=${!var} # add -opt for an optimized build. $DIST/bin/interop -def:$DIR/sdl.def -copt:"$CFLAGS" -target:$TARGET || exit 1 -$DIST/bin/konanc $COMPILER_ARGS -target $TARGET sdl $DIR/tetris.kt -nativelibrary sdlstubs.bc -linkerArgs "$LINKER_ARGS" -o tetris.kexe -verbose linker || exit 1 +$DIST/bin/konanc $COMPILER_ARGS -target $TARGET sdl $DIR/tetris.kt -nativelibrary sdlstubs.bc -linkerArgs "$LINKER_ARGS" -o tetris.kexe || exit 1 #strip tetris.kexe