All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jtransc.build.kt Maven / Gradle / Ivy

There is a newer version: 0.6.8
Show newest version
/*
 * Copyright 2016 Carlos Ballesteros Velasco
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jtransc

import com.jtransc.ast.*
import com.jtransc.gen.GenTargetDescriptor
import com.jtransc.gen.build
import com.jtransc.input.BaseProjectContext
import com.jtransc.input.SootToAst
import com.jtransc.input.SootUtils
import com.jtransc.io.ProcessResult2
import com.jtransc.maven.MavenLocalRepository
import com.jtransc.time.measureProcess
import com.jtransc.time.measureTime
import com.jtransc.vfs.LocalVfs
import com.jtransc.vfs.MergedLocalAndJars
import com.jtransc.vfs.SyncVfsFile

fun Iterable.locateTargetByName(target: String) = this.firstOrNull { it.name == target } ?: throw Exception("Unknown target $target")
fun Iterable.locateTargetByOutExt(ext: String) = this.firstOrNull { it.outputExtension == ext } ?: throw Exception("Can't find target by extension $ext")

class AllBuild(
	val target: GenTargetDescriptor,
	val classPaths: List,
	val entryPoint: String,
	val output: String,
	val subtarget: String,
	val targetDirectory: String = System.getProperty("java.io.tmpdir")
) {
	constructor(AllBuildTargets: List, target: String, classPaths: List, entryPoint: String, output: String, subtarget: String, targetDirectory: String = System.getProperty("java.io.tmpdir")) : this(
		AllBuildTargets.locateTargetByName(target),
		classPaths, entryPoint, output, subtarget, targetDirectory
	)

	val tempdir = System.getProperty("java.io.tmpdir")

	val gen = target.getGenerator()
	val runningAvailable: Boolean = gen.runningAvailable

	/*
	fun build(release: Boolean = false, run: Boolean = false): Boolean {
		return _buildAndRun(release, redirect = true, run = run).success
	}
	*/

	fun buildAndRunCapturingOutput(settings: AstBuildSettings) = buildAndRun(captureRunOutput = true, settings = settings, run = true)
	fun buildAndRunRedirecting(settings: AstBuildSettings) = buildAndRun(captureRunOutput = false, settings = settings, run = true)
	fun buildWithoutRunning(settings: AstBuildSettings) = buildAndRun(captureRunOutput = false, settings = settings, run = false)
	fun buildAndRun(captureRunOutput: Boolean, settings: AstBuildSettings, run: Boolean = true): ProcessResult2 {
		return _buildAndRun(settings = settings, captureRunOutput = captureRunOutput, run = run)
	}

	private fun _buildAndRun(settings: AstBuildSettings, captureRunOutput: Boolean = true, run: Boolean = false): ProcessResult2 {
		val jtranscVersion = settings.jtranscVersion

		// Previously downloaded manually or with maven plugin!
		val classPaths2 = (MavenLocalRepository.locateJars(listOf(
			"com.jtransc:jtransc-rt:$jtranscVersion",
			"com.jtransc:jtransc-rt-core:$jtranscVersion"
		)) + target.extraLibraries.flatMap {
			MavenLocalRepository.locateJars(it)
		} + classPaths).distinct()

		println("AllBuild.build(): language=$target, subtarget=$subtarget, entryPoint=$entryPoint, output=$output, targetDirectory=$targetDirectory")
		for (cp in classPaths2) println("ClassPath: $cp")

		var initialClasses = listOf(
			"java.lang.Object",
			"java.lang.Void",
			"java.lang.Byte",
			"java.lang.Character",
			"java.lang.Short",
			"java.lang.Integer",
			"java.lang.Long",
			"java.lang.Float",
			"java.lang.Double",
			"java.lang.Class",
			"java.lang.reflect.Method",
			"java.lang.reflect.Field",
			"java.lang.reflect.Constructor",
			"java.lang.annotation.Annotation",
			"jtransc.internal.JTranscAnnotationBase",
			"jtransc.JTranscWrapped",
			entryPoint.fqname.fqname
		)

		var program = measureProcess("Generating AST") {
			createProgramAst(
				SootToAst(),
				initialClasses, entryPoint, classPaths2,
				LocalVfs("$tempdir/out_ast")
			)
		}
		//val programDced = measureProcess("Simplifying AST") { SimpleDCE(program, programDependencies) }
		return gen.build(program, outputFile = output, settings = settings, captureRunOutput = captureRunOutput, run = run, subtarget = subtarget, targetDirectory = targetDirectory)
	}

	fun createProgramAst(generator: AstClassGenerator, classNames: List, mainClass: String, classPaths: List, outputPath: SyncVfsFile): AstProgram {
		SootUtils.init(classPaths)
		return generateProgram(BaseProjectContext(classNames, mainClass, classPaths, outputPath, generator))
	}

	fun generateProgram(projectContext: BaseProjectContext): AstProgram {
		val generator = projectContext.generator
		val program = AstProgram(
			entrypoint = FqName(projectContext.mainClass),
			resourcesVfs = MergedLocalAndJars(projectContext.classPaths),
			generator = generator
		)

		// Preprocesses classes
		projectContext.classNames.forEach {
			program.addReference(AstClassRef(it))
		}

		print("Processing classes...")

		val (elapsed) = measureTime {
			while (program.hasClassToGenerate()) {
				val className = program.readClassToGenerate()
				//val clazz = projectContext.getSootClass(className.name)
				//val nativeClassTag = clazz.clazz.getTag("libcore.NativeClass", "")

				//print("Processing class: " + clazz.clazz.name + "...")

				//print("  CLASS: $className...");
				val time = measureTime {
					val generatedClass = generator.generateClass(program, className.name)

					for (ref in References.get(generatedClass)) {
						program.addReference(ref)
					}
				}

				//println("Ok(${time.time})");
			}

			// Add synthetic methods to abstracts to simulate in haxe
			// @TODO: Maybe we could generate those methods in haxe generator since the requirement for this
			// @TODO: is target dependant
			for (clazz in program.classes.filter { it.isAbstract }) {
				for (method in clazz.allMethodsToImplement) {
					if (clazz.getMethodInAncestors(method) == null) {
						clazz.add(generateDummyMethod(clazz, method.name, method.type, false, AstVisibility.PUBLIC))
					}
				}
			}
		}

		//for (dep in projectContext.deps2!!) println(dep)

		println("Ok classes=${projectContext.classNames.size}, time=$elapsed")

		return program
	}

	fun generateDummyMethod(containingClass: AstClass, name: String, methodType: AstType.METHOD_TYPE, isStatic: Boolean, visibility: AstVisibility) = AstMethod(
		containingClass = containingClass,
		annotations = listOf(),
		name = name,
		type = methodType,
		body = null,
		signature = methodType.mangle(),
		genericSignature = methodType.mangle(),
		defaultTag = null,
		modifiers = -1,
		isStatic = isStatic,
		visibility = visibility,
		isNative = true
	)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy