/* * Copyright 2011 Google Inc. All Rights Reserved. * * 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.google.devtools.j2objc; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.devtools.j2objc.Options.TimingLevel; import com.google.devtools.j2objc.pipeline.GenerationBatch; import com.google.devtools.j2objc.pipeline.InputFilePreprocessor; import com.google.devtools.j2objc.pipeline.ProcessingContext; import com.google.devtools.j2objc.pipeline.TranslationProcessor; import com.google.devtools.j2objc.util.CodeReferenceMap; import com.google.devtools.j2objc.util.ErrorUtil; import com.google.devtools.j2objc.util.FileUtil; import com.google.devtools.j2objc.util.Parser; import com.google.devtools.j2objc.util.ProGuardUsageParser; import com.google.devtools.j2objc.util.UnicodeUtils; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Set; /** * Translation tool for generating Objective C source files from Java sources. * This tool is not intended to be a general purpose converter, but instead is * focused on what is needed for business logic libraries written in Java to * run natively on iOS. In particular, no attempt is made to translate Java * UI framework code to any iOS frameworks. * * @author Tom Ball */ public class J2ObjC { static { // Always enable assertions in translator. ClassLoader loader = J2ObjC.class.getClassLoader(); if (loader != null) { loader.setPackageAssertionStatus(J2ObjC.class.getPackage().getName(), true); } } public static String getFileHeader(String sourceFileName) { return UnicodeUtils.format(Options.getFileHeader(), sourceFileName); } private static void checkErrors(boolean treatWarningsAsErrors) { int errors = ErrorUtil.errorCount(); if (treatWarningsAsErrors) { errors += ErrorUtil.warningCount(); } if (errors > 0) { System.exit(errors); } } @VisibleForTesting public static Parser createParser(Options options) { Parser parser = Parser.newParser(options); parser.addClasspathEntries(options.fileUtil().getClassPathEntries()); parser.addClasspathEntries(options.getBootClasspath()); parser.addSourcepathEntries(options.fileUtil().getSourcePathEntries()); parser.setIncludeRunningVMBootclasspath(false); parser.setEnableDocComments(options.docCommentsEnabled()); return parser; } private static CodeReferenceMap loadDeadCodeMap() { return ProGuardUsageParser.parseDeadCodeFile(Options.getProGuardUsageFile()); } /** * Runs the entire J2ObjC pipeline. * @param fileArgs the files to process, same format as command-line args to {@link #main}. */ public static void run(List<String> fileArgs, Options options) { File preProcessorTempDir = null; File strippedSourcesDir = null; Parser parser = null; try { List<ProcessingContext> inputs = Lists.newArrayList(); GenerationBatch batch = new GenerationBatch(options); batch.processFileArgs(fileArgs); inputs.addAll(batch.getInputs()); if (ErrorUtil.errorCount() > 0) { return; } parser = createParser(options); Parser.ProcessingResult processingResult = parser.processAnnotations(fileArgs, inputs); List<ProcessingContext> generatedInputs = processingResult.getGeneratedSources(); inputs.addAll(generatedInputs); // Ensure all generatedInputs are at end of input list. preProcessorTempDir = processingResult.getSourceOutputDirectory(); if (ErrorUtil.errorCount() > 0) { return; } if (preProcessorTempDir != null) { parser.addSourcepathEntry(preProcessorTempDir.getAbsolutePath()); } InputFilePreprocessor inputFilePreprocessor = new InputFilePreprocessor(parser); inputFilePreprocessor.processInputs(inputs); if (ErrorUtil.errorCount() > 0) { return; } strippedSourcesDir = inputFilePreprocessor.getStrippedSourcesDir(); if (strippedSourcesDir != null) { parser.prependSourcepathEntry(strippedSourcesDir.getPath()); } options.getHeaderMap().loadMappings(); TranslationProcessor translationProcessor = new TranslationProcessor(parser, loadDeadCodeMap()); translationProcessor.processInputs(inputs); translationProcessor.processBuildClosureDependencies(); if (ErrorUtil.errorCount() > 0) { return; } translationProcessor.postProcess(); options.getHeaderMap().printMappings(); } finally { if (parser != null) { try { parser.close(); } catch (IOException e) { ErrorUtil.error(e.getMessage()); } } Set<String> tempDirs = options.fileUtil().getTempDirs(); for (String dir : tempDirs) { FileUtil.deleteTempDir(new File(dir)); } FileUtil.deleteTempDir(preProcessorTempDir); FileUtil.deleteTempDir(strippedSourcesDir); } } /** * Entry point for tool. * Initializes {@link Options}, calls {@link #run}, and exits. * * @param args command-line arguments: flags and source file names */ public static void main(String[] args) { if (args.length == 0) { Options.help(true); } long startTime = System.currentTimeMillis(); String[] files = null; Options options = new Options(); try { files = options.load(args); if (files.length == 0) { Options.usage("no source files"); } } catch (IOException e) { ErrorUtil.error(e.getMessage()); System.exit(1); } run(Arrays.asList(files), options); TimingLevel timingLevel = options.timingLevel(); if (timingLevel == TimingLevel.TOTAL || timingLevel == TimingLevel.ALL) { System.out.printf("j2objc execution time: %d ms\n", System.currentTimeMillis() - startTime); } // Run last, since it calls System.exit() with the number of errors. checkErrors(options.treatWarningsAsErrors()); } }