/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2010. */ package x10cpp.visit; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import polyglot.ast.Assert; import polyglot.ast.Block; import polyglot.ast.Branch; import polyglot.ast.Catch; import polyglot.ast.ClassDecl; import polyglot.ast.ClassMember; import polyglot.ast.CompoundStmt; import polyglot.ast.ConstructorCall.Kind; import polyglot.ast.ConstructorDecl; import polyglot.ast.Eval; import polyglot.ast.FieldDecl; import polyglot.ast.For; import polyglot.ast.Formal; import polyglot.ast.If; import polyglot.ast.LocalDecl; import polyglot.ast.MethodDecl; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.ProcedureDecl; import polyglot.ast.Return; import polyglot.ast.SourceCollection; import polyglot.ast.SourceFile; import polyglot.ast.Stmt; import polyglot.ast.SwitchBlock; import polyglot.ast.Term; import polyglot.ast.TopLevelDecl; import polyglot.ast.Try; import polyglot.frontend.Compiler; import polyglot.frontend.ExtensionInfo; import polyglot.frontend.Job; import polyglot.frontend.Source; import polyglot.frontend.TargetFactory; import polyglot.main.Options; import polyglot.main.Reporter; import polyglot.types.ClassType; import polyglot.types.Context; import polyglot.types.MemberDef; import polyglot.types.MethodDef; import polyglot.types.Package; import polyglot.types.QName; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.CodeWriter; import polyglot.util.DiffWriter; import polyglot.util.ErrorInfo; import polyglot.util.ErrorQueue; import polyglot.util.InternalCompilerError; import polyglot.util.SimpleCodeWriter; import polyglot.util.StdErrorQueue; import polyglot.util.StringUtil; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; import polyglot.visit.Translator; import x10.ast.Closure; import x10.ast.ForLoop; import x10.ast.X10ClassDecl; import x10.ast.X10ConstructorCall; import x10.ast.X10ConstructorDecl; import x10.extension.X10Ext; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.util.ClassifiedStream; import x10.util.StreamWrapper; import x10.util.WriterStreams; import x10.visit.StaticNestedClassRemover; import x10cpp.Configuration; import x10cpp.X10CPPCompilerOptions; import x10cpp.X10CPPJobExt; import x10cpp.debug.LineNumberMap; import x10cpp.postcompiler.AIX_CXXCommandBuilder; import x10cpp.postcompiler.CXXCommandBuilder; import x10cpp.postcompiler.Cygwin_CXXCommandBuilder; import x10cpp.postcompiler.Linux_CXXCommandBuilder; import x10cpp.postcompiler.PostCompileProperties; import x10cpp.postcompiler.SharedLibProperties; import x10cpp.postcompiler.SunOS_CXXCommandBuilder; import x10cpp.postcompiler.CXXMakeBuilder; import x10cpp.types.X10CPPContext_c; import static x10cpp.visit.ASTQuery.getCppRep; import static x10cpp.visit.ASTQuery.getStringPropertyInit; import static x10cpp.visit.SharedVarsMethods.*; public class X10CPPTranslator extends Translator { public X10CPPTranslator(Job job, TypeSystem ts, NodeFactory nf, TargetFactory tf) { super(job, ts, nf, tf); } /** Return the dir where classes in the given package will be compiled. Does not include output directory prefix. * Accepts null input. Note that if appending more paths to this directory, it is necessary to use '/' as a * separator regardless of the platform. */ public static String packagePath (String pkg) { return (pkg==null ? "" : pkg.replace('.', '/') + '/'); } /** Return the filename of the c++ file for the given class. Does not include output directory prefix. * If no package then give null. Note that if further processing the returned value, it is necessary to use '/' as a * separator regardless of the platform. */ public static String outputFileName (String pkg, String c, String ext) { return packagePath(pkg) + Emitter.mangled_non_method_name(c) + "." + ext; } /** Return the c++ file for the given class. */ public static File outputFile (Options opts, String pkg, String c, String ext) { return new File(opts.output_directory, outputFileName(pkg, c, ext)); } private static int adjustSLNForNode(int outputLine, Node n) { // FIXME: Debugger HACK: adjust for loops if (n instanceof For || n instanceof ForLoop) return outputLine + 1; return outputLine; } private static int adjustELNForNode(int outputLine, Node n) { if (n instanceof For || n instanceof ForLoop) return outputLine - 2; if (n instanceof Return && ((Return) n).expr() == null) return outputLine; if (n instanceof Eval || n instanceof Branch || n instanceof Try) return outputLine; if (n instanceof Block) return outputLine; return outputLine - 1; } static final String FILE_TO_LINE_NUMBER_MAP = "FileToLineNumberMap"; public void print(Node parent, Node n, CodeWriter w_) { if (w_ == null) return; // FIXME HACK StreamWrapper w = (StreamWrapper) w_; assert (n != null); final int line = n.position().line(); final int column = n.position().column(); final String file = n.position().file(); if (line > 0 && ((n instanceof Stmt && !(n instanceof Block) && !(n instanceof Catch)) || (n instanceof FieldDecl) || (n instanceof MethodDecl) || (n instanceof ConstructorDecl) || (n instanceof ClassDecl))) { String nodeName = n instanceof Eval ? ("Eval of "+(((Eval)n).expr().getClass().getName())) : n.getClass().getName(); w.forceNewline(0); w.write("//#line " + line + " \"" + file + "\": "+nodeName); w.newline(); } X10CPPCompilerOptions opts = (X10CPPCompilerOptions) job.extensionInfo().getOptions(); final int startLine = w.currentStream().getStreamLineNumber(); // for debug info // FIXME: [IP] Some nodes have no del() -- warn in that case super.print(parent, n, w_); final int endLine = w.currentStream().getStreamLineNumber() - w.currentStream().getOmittedLines(); // for debug info if (opts.x10_config.DEBUG && line > 0 && ((n instanceof Stmt && !(n instanceof SwitchBlock) && !(n instanceof Catch)) || (n instanceof ClassMember))) { final String cppFile = w.getStreamName(w.currentStream().ext); String key = w.getStreamName(StreamWrapper.CC); X10CPPContext_c c = (X10CPPContext_c) context; Map<String, LineNumberMap> fileToLineNumberMap = c.<Map<String, LineNumberMap>>findData(FILE_TO_LINE_NUMBER_MAP); if (fileToLineNumberMap != null) { final LineNumberMap lineNumberMap = fileToLineNumberMap.get(key); // [DC] avoid NPE when writing to .cu files // [DC] avoid NPE when parent is null, e.g. generating initialisation for cuda shm if (lineNumberMap != null && parent != null) { final MemberDef def = (n instanceof ConstructorDecl) ? ((ConstructorDecl) n).constructorDef() : (n instanceof Block) ? (parent instanceof MethodDecl) ? ((MethodDecl) parent).methodDef() : null : null; final int lastX10Line = (n instanceof ConstructorDecl)? n.position().endLine() : parent.position().endLine(); if (n instanceof Stmt || n instanceof ProcedureDecl) { final int adjustedStartLine = adjustSLNForNode(startLine, n); final int adjustedEndLine = adjustELNForNode(endLine, n); final int fixedEndLine = adjustedEndLine < adjustedStartLine ? adjustedStartLine : adjustedEndLine; //final boolean generated = n.position().isCompilerGenerated(); // || ((parent instanceof Closure) && (!(n instanceof ProcedureDecl) || (n instanceof ProcedureDecl && ((ProcedureDecl)n).reachable()))); final boolean isBlock = (n instanceof polyglot.ast.Block_c); final boolean addLastLine = ((n instanceof ConstructorDecl) || (n instanceof Block && !((Block)n).statements().isEmpty() && ((Block)n).position().endLine() != ((Block)n).statements().get(((Block)n).statements().size()-1).position().endLine())); w.currentStream().registerCommitListener(new ClassifiedStream.CommitListener() { public void run(ClassifiedStream s) { int cppStartLine = s.getStartLineOffset()+adjustedStartLine; int cppEndLine = s.getStartLineOffset()+fixedEndLine; if (def != null && !def.position().isCompilerGenerated()) { lineNumberMap.addMethodMapping(def, cppFile, cppStartLine, cppEndLine, lastX10Line); lineNumberMap.put(cppFile, cppStartLine, cppEndLine, file, line, column); if (addLastLine) lineNumberMap.put(cppFile, cppEndLine, cppEndLine, file, lastX10Line, column); } else if (!isBlock) { lineNumberMap.put(cppFile, cppStartLine, cppEndLine, file, line, column); if (addLastLine) lineNumberMap.put(cppFile, cppEndLine, cppEndLine, file, lastX10Line, column); } } }); } if (parent instanceof For && n instanceof LocalDecl) { Term t = ((For)parent).body().firstChild(); if (t instanceof LocalDecl) lineNumberMap.rememberLoopVariable(((LocalDecl)t).name().toString(), ((LocalDecl)n).name().toString(), line, lastX10Line); } if (n instanceof FieldDecl && !c.inTemplate() && !((FieldDecl)n).flags().flags().isStatic() && !n.position().isCompilerGenerated()) // the c.inTemplate() skips mappings for templates, which don't have a fixed size. lineNumberMap.addClassMemberVariable(((FieldDecl)n).name().toString(), ((FieldDecl)n).type().toString(), Emitter.mangled_non_method_name(context.currentClass().toString()), context.currentClass().isX10Struct(), false, false); else if (n instanceof LocalDecl && !((LocalDecl)n).position().isCompilerGenerated()) { X10ClassType t = ((LocalDecl)n).type().type().toClass(); lineNumberMap.addLocalVariableMapping(((LocalDecl)n).name().toString(), ((LocalDecl)n).type().toString(), line, lastX10Line, file, false, -1, (t==null?false:t.isX10Struct())); } else if (def != null) { // include method arguments in the local variable tables ProcedureDecl defSource; if (n instanceof ConstructorDecl) { defSource = (ProcedureDecl)n; // add the hack reference to the outer class if (n instanceof X10ConstructorDecl) { X10ConstructorDecl cd = (X10ConstructorDecl)n; String thisClass = cd.returnType().toString(); if (cd.returnType().toString().contains("$")) { String parentClass = thisClass.substring(0, thisClass.lastIndexOf('$')); List<Formal> args = defSource.formals(); if (args.size() == 1) { Formal arg = args.get(0); if (arg.type().toString().equals(parentClass)) { X10ClassType t = arg.type().type().toClass(); lineNumberMap.addClassMemberVariable(arg.name().toString(), parentClass, Emitter.mangled_non_method_name(thisClass), (t==null?false:t.isX10Struct()), true, false); } } } if (cd.body().statements().size() > 0) { Stmt s = cd.body().statements().get(0); if (s instanceof X10ConstructorCall && ((X10ConstructorCall)s).kind().equals(Kind.SUPER)) { String superClass = ((X10ConstructorCall)s).constructorInstance().returnType().toString(); lineNumberMap.addClassMemberVariable(superClass, superClass, Emitter.mangled_non_method_name(thisClass), ((X10ConstructorCall)s).constructorInstance().returnType().toClass().isX10Struct(), false, true); } } } } else defSource = (ProcedureDecl)parent; List<Formal> args = defSource.formals(); for (int i=0; i<args.size(); i++) { Formal arg = args.get(i); if (!arg.position().isCompilerGenerated()) { X10ClassType t = arg.type().type().toClass(); lineNumberMap.addLocalVariableMapping(arg.name().toString(), arg.type().toString(), line, lastX10Line, file, false, -1, (t==null?false:t.isX10Struct())); } } // include "this" for non-static methods if (!def.flags().isStatic() && defSource.reachable() != null && defSource.reachable() && !c.inTemplate()) { boolean isStruct = context.currentClass().isX10Struct(); if (!defSource.position().isCompilerGenerated()) lineNumberMap.addLocalVariableMapping("this", Emitter.mangled_non_method_name(context.currentClass().toString()), line, lastX10Line, file, true, -1, isStruct); lineNumberMap.addClassMemberVariable(null, null, Emitter.mangled_non_method_name(context.currentClass().toString()), isStruct, false, false); } } } } } } /** * Only for the backend -- use with care! * FIXME: HACK!!! HACK!!! HACK!!! */ public void setContext(Context c) { context = c; } private static void maybeCopyTo (String file, String src_path_, String dest_path_) { File src_path = new File(src_path_); File dest_path = new File(dest_path_); // don't copy if the two dirs are the same... if (src_path.equals(dest_path)) return; // don't copy if the file path is absolute... if (new File(file).isAbsolute()) return; // TODO: fix issue with NativeCPPInclude // TODO: disambiguate #include <header.h> vs #include "header.h" // TODO: system header with relative path should not be copied if (!dest_path.exists()) dest_path.mkdir(); assert src_path.isDirectory() : src_path_+" is not a directory"; assert dest_path.isDirectory() : dest_path_+" is not a directory"; try { dest_path.mkdirs(); FileInputStream src = new FileInputStream(new File(src_path_+file)); DiffWriter dest = new DiffWriter(new File(dest_path_+file)); int b; while ((b = src.read()) != -1) { dest.write(b); } dest.close(); } catch (IOException e) { System.err.println("While copying "+file + " from "+src_path_+" to "+dest_path_); System.err.println(e); } } /* (non-Javadoc) * @see polyglot.visit.Translator#translateSource(polyglot.ast.SourceFile) */ protected boolean translateSource(SourceFile sfn) { int outputWidth = job.compiler().outputWidth(); try { String pkg = null; if (sfn.package_() != null) { Package p = sfn.package_().package_().get(); pkg = p.fullName().toString(); } X10CPPContext_c c = (X10CPPContext_c) context; X10CPPCompilerOptions opts = (X10CPPCompilerOptions) job.extensionInfo().getOptions(); TypeSystem xts = typeSystem(); if (opts.x10_config.DEBUG) c.addData(FILE_TO_LINE_NUMBER_MAP, CollectionFactory.newHashMap()); // Use the source file name as the basename for the output .cc file String fname = sfn.source().name(); fname = fname.substring(0, fname.lastIndexOf(".x10")); boolean generatedCode = false; WriterStreams fstreams = new WriterStreams(fname, pkg, job, tf); if (opts.x10_config.DEBUG) { Map<String, LineNumberMap> fileToLineNumberMap = c.<Map<String, LineNumberMap>>getData(FILE_TO_LINE_NUMBER_MAP); fileToLineNumberMap.put(fstreams.getStreamName(StreamWrapper.CC), new LineNumberMap()); } for (TopLevelDecl decl : sfn.decls()) { if (!(decl instanceof X10ClassDecl)) continue; X10ClassDecl cd = (X10ClassDecl) decl; // Skip output of all files for a native rep class. X10Ext ext = (X10Ext) cd.ext(); try { String path = new File(cd.position().file()).getParent(); if (path==null) path = ""; else path = path + '/'; String out_path = opts.output_directory.toString(); if (out_path==null) out_path = ""; else out_path = out_path + '/'; String pkg_ = packagePath(pkg); List<X10ClassType> as = ext.annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.NativeCPPInclude"))); for (Type at : as) { ASTQuery.assertNumberOfInitializers(at, 1); String include = getStringPropertyInit(at, 0); job.compiler().addOutputFile(sfn, pkg_+include); maybeCopyTo(include, path, out_path+pkg_); } as = ext.annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.NativeCPPOutputFile"))); for (Type at : as) { ASTQuery.assertNumberOfInitializers(at, 1); String file = getStringPropertyInit(at, 0); job.compiler().addOutputFile(sfn, pkg_+file); maybeCopyTo(file, path, out_path+pkg_); } as = ext.annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.NativeCPPCompilationUnit"))); for (Type at : as) { ASTQuery.assertNumberOfInitializers(at, 1); String compilation_unit = getStringPropertyInit(at, 0); job.compiler().addOutputFile(sfn, pkg_+compilation_unit); opts.compilationUnits().add(pkg_+compilation_unit); maybeCopyTo(compilation_unit, path, out_path+pkg_); } } catch (SemanticException e) { assert false : e; } if (getCppRep((X10ClassDef)cd.classDef()) != null) { continue; } generatedCode = true; // Use the name of the class to get the name of the header files. String className = cd.classDef().name().toString(); WriterStreams wstreams = new WriterStreams(className, pkg, job, tf); StreamWrapper sw = new StreamWrapper(fstreams, wstreams, outputWidth); // [DC] TODO: This hack is to ensure the .h is always generated. sw.getNewStream(StreamWrapper.Header, true); String header = wstreams.getStreamName(StreamWrapper.Header); job.compiler().addOutputFile(sfn, header); if (opts.x10_config.DEBUG) { Map<String, LineNumberMap> fileToLineNumberMap = c.<Map<String, LineNumberMap>>getData(FILE_TO_LINE_NUMBER_MAP); fileToLineNumberMap.put(header, new LineNumberMap()); } ClassifiedStream tmp = sw.getNewStream(StreamWrapper.CC, false); tmp.writeln("/*************************************************/"); tmp.writeln("/* START of "+className+" */"); translateTopLevelDecl(sw, sfn, decl); ClassifiedStream tmp2 = sw.getNewStream(StreamWrapper.CC, false); tmp2.writeln("/* END of "+className+" */"); tmp2.writeln("/*************************************************/"); wstreams.commitStreams(); } if (generatedCode) { String cc = fstreams.getStreamName(StreamWrapper.CC); job.compiler().addOutputFile(sfn, cc); opts.compilationUnits().add(cc); if (opts.x10_config.DEBUG) { Map<String, LineNumberMap> fileToLineNumberMap = c.<Map<String, LineNumberMap>>getData(FILE_TO_LINE_NUMBER_MAP); ClassifiedStream debugStream = fstreams.getNewStream(StreamWrapper.CC, false); printLineNumberMapForCPPDebugger(debugStream, fstreams.getStreamName(StreamWrapper.CC), fileToLineNumberMap); } fstreams.commitStreams(); } return true; } catch (IOException e) { job.compiler().errorQueue().enqueue(ErrorInfo.IO_ERROR, "I/O error while translating: " + e.getMessage()); return false; } } private void printLineNumberMapForCPPDebugger(ClassifiedStream stream, String streamName, Map<String, LineNumberMap> fileToLineNumberMap) { final LineNumberMap map = fileToLineNumberMap.get(streamName); stream.registerCommitListener(new ClassifiedStream.CommitListener() { public void run(ClassifiedStream s) { // if (map.isEmpty()) // return; s.forceNewline(); map.exportForCPPDebugger(s, map); } }); } private void printLineNumberMap(StreamWrapper sw, String pkg, String className, final String ext, Map<String, LineNumberMap> fileToLineNumberMap) { String fName = sw.getStreamName(ext); final LineNumberMap map = fileToLineNumberMap.get(fName); final String lnmName = Emitter.translate_mangled_FQN(pkg, "_")+"_"+Emitter.mangled_non_method_name(className); sw.currentStream().registerCommitListener(new ClassifiedStream.CommitListener() { public void run(ClassifiedStream s) { if (map.isEmpty()) return; s.forceNewline(); // sw.write("struct LNMAP_"+lnmName+"_"+ext+" { static const char* map; };"); // sw.newline(); // sw.write("const char* LNMAP_"+lnmName+"_"+ext+"::map = \""); s.write("extern \"C\" { const char* LNMAP_"+lnmName+"_"+ext+" = \""); s.write(StringUtil.escape(map.exportMap())); // String v = map.exportMap(); // LineNumberMap m = LineNumberMap.importMap(v); s.write("\"; }"); s.newline(); } }); } /* (non-Javadoc) * @see polyglot.visit.Translator#translate(polyglot.ast.Node) */ public boolean translate(Node ast) { if (ast instanceof SourceFile) { SourceFile sfn = (SourceFile) ast; boolean okay = translateSource(sfn); final ExtensionInfo ext = job.extensionInfo(); final Options options = ext.getOptions(); final ErrorQueue eq = new StdErrorQueue(System.err, options.error_count, ext.compilerName()); if (!okay) return false; return true; } else if (ast instanceof SourceCollection) { SourceCollection sc = (SourceCollection) ast; // TODO: [IP] separate compilation // if (true) throw new InternalCompilerError("Source collections not supported"); return translateSourceCollection(sc); } else { throw new InternalCompilerError("AST root must be a SourceFile; " + "found a " + ast.getClass().getName()); } } public static final String postcompile = "postcompile"; /** * The post-compiler option has the following structure: * "[pre-command with options (usually g++)] [(#|%) [post-options (usually extra files)] [(#|%) [library options]]]". * Using '%' instead of '#' to delimit a section will cause the default values in that section to be omitted. */ public static boolean postCompile(X10CPPCompilerOptions options, Compiler compiler, ErrorQueue eq) { if (eq.hasErrors()) return false; if (options.post_compiler != null && !options.output_stdout) { // use set to avoid duplicates Set<String> compilationUnits = CollectionFactory.newHashSet(options.compilationUnits()); if (options.buildX10Lib == null) { try { final File file = outputFile(options, null, options.x10cpp_config.MAIN_STUB_NAME, "cc"); ExtensionInfo ext = compiler.sourceExtension(); SimpleCodeWriter sw = new SimpleCodeWriter(ext.targetFactory().outputWriter(file), compiler.outputWidth()); List<MethodDef> mainMethods = new ArrayList<MethodDef>(); for (Job job : ext.scheduler().commandLineJobs()) { mainMethods.addAll(getMainMethods(job)); } if (mainMethods.size() < 1) { // If there are no main() methods in the command-line jobs, try other files for (Job job : ext.scheduler().jobs()) { mainMethods.addAll(getMainMethods(job)); } } if (mainMethods.size() < 1) { eq.enqueue(ErrorInfo.SEMANTIC_ERROR, "No main method found"); return false; } else if (mainMethods.size() > 1) { eq.enqueue(ErrorInfo.SEMANTIC_ERROR, "Multiple main() methods found, please specify MAIN_CLASS:"+listMethods(mainMethods)); return false; } assert (mainMethods.size() == 1); X10ClassType container = (X10ClassType) Types.get(mainMethods.get(0).container()); MessagePassingCodeGenerator.processMain(container, sw, options); sw.flush(); sw.close(); compilationUnits.add(file.getName()); } catch (IOException e) { eq.enqueue(ErrorInfo.IO_ERROR, "I/O error while translating: " + e.getMessage()); return false; } } PostCompileProperties x10rt = loadX10RTProperties(options); SharedLibProperties shared_lib_props = loadSharedLibProperties(); CXXCommandBuilder ccb = CXXCommandBuilder.getCXXCommandBuilder(options, x10rt, shared_lib_props, eq); String[] cxxCmd = ccb.buildCXXCommandLine(compilationUnits); if (!doPostCompile(options, eq, compilationUnits, cxxCmd)) return false; if (options.buildX10Lib != null) { if (shared_lib_props.staticLib) { ArrayList<String> arCmd = new ArrayList<String>(); arCmd.add(shared_lib_props.ar); arCmd.add(shared_lib_props.arFlags); arCmd.add(ccb.targetFilePath().getPath()); ArrayList<String> objFiles = new ArrayList<String>(); for (String file : compiler.flatOutputFiles()) { int lastPeriod = file.lastIndexOf('.'); if (-1 == lastPeriod) continue; String suffix = file.substring(lastPeriod+1, file.length()); if (suffix.equals("cc") || suffix.equals("c") || suffix.equals("cpp") || suffix.equals("cxx")) { objFiles.add(file.substring(file.lastIndexOf(File.separatorChar)+1, lastPeriod)+".o"); } } if (!objFiles.isEmpty()) { arCmd.addAll(objFiles); boolean savedKeepOutputFiles = options.keep_output_files; options.keep_output_files = false; try { if (!doPostCompile(options, eq, objFiles, arCmd.toArray(new String[arCmd.size()]))) return false; } finally { options.keep_output_files = savedKeepOutputFiles; } } } if (!emitPropertiesFile(options, ccb)) return false; } // FIXME: [IP] HACK: Prevent the java post-compiler from running options.post_compiler = null; } return true; } private static String quoteSeparated (List<String> list) { StringBuilder sb = new StringBuilder(); boolean first = true; for (String s : list) { sb.append((first?"":" ")+"\""+s+"\""); first = false; } return sb.toString(); } public static boolean emitPropertiesFile(X10CPPCompilerOptions options, CXXCommandBuilder ccb) { try { File f = new File(options.buildX10Lib + "/"+options.executable_path+".properties"); PrintStream dest = new PrintStream(new FileOutputStream(f)); dest.println("X10LIB_PLATFORM="+ccb.getPlatform()); dest.println("X10LIB_TIMESTAMP="+"UNSUPPORTED"); dest.println("X10LIB_CXX="+ccb.getPostCompiler()); dest.println("X10LIB_CXXFLAGS="+quoteSeparated(options.extraPreArgs)); dest.println("X10LIB_LDFLAGS="); dest.println("X10LIB_LDLIBS=-l"+options.executable_path+" "+quoteSeparated(options.extraPostArgs)); dest.println("X10LIB_SRC_JAR="+options.executable_path+".jar"); dest.close(); return true; } catch (IOException e) { System.out.println(e); return false; } } public static PostCompileProperties loadX10RTProperties(X10CPPCompilerOptions options) { // TODO: get options.distPath external to this method String dp = System.getProperty("x10.dist"); options.setDistPath(dp); // TODO: get properties file external to this method and pass it as an argument String rtimpl = System.getenv("X10RT_IMPL"); // allow the user to give an explicit path, otherwise look in etc if (!rtimpl.endsWith(".properties")) { rtimpl = dp + "/etc/x10rt_"+rtimpl+".properties"; } Properties x10rt = loadPropertyFile(rtimpl); PostCompileProperties x10rt_props = new PostCompileProperties(x10rt); return x10rt_props; } public static SharedLibProperties loadSharedLibProperties() { String dp = System.getProperty("x10.dist"); return new SharedLibProperties(loadPropertyFile(dp+"/etc/sharedlib.properties")); } private static Properties loadPropertyFile(String filename) { Properties properties = new Properties(); try { properties.load(new FileInputStream(filename)); } catch(IOException e) { throw new InternalCompilerError("Unable to load property file "+filename+" "+ e.getMessage(), e); } return properties; } private static List<MethodDef> getMainMethods(Job job) { X10CPPCompilerOptions opts = (X10CPPCompilerOptions) job.extensionInfo().getOptions(); X10CPPJobExt jobext = (X10CPPJobExt) job.ext(); if (opts.x10_config.MAIN_CLASS != null) { if (opts.x10_config.MAIN_CLASS.length() == 0) { return Collections.<MethodDef>emptyList(); } QName mainClass = QName.make(opts.x10_config.MAIN_CLASS); try { ClassType mct = (ClassType) job.extensionInfo().typeSystem().forName(mainClass); QName pkgName = mct.package_() == null ? null : mct.package_().fullName(); mainClass = QName.make(pkgName, StaticNestedClassRemover.mangleName(mct.def())); } catch (SemanticException e) { } for (MethodDef md : jobext.mainMethods()) { QName containerName = ((X10ClassType) Types.get(md.container())).fullName(); if (containerName.equals(mainClass)) { return Collections.singletonList(md); } } return Collections.<MethodDef>emptyList(); } else { return jobext.mainMethods(); } } private static String listMethods(List<MethodDef> mainMethods) { StringBuilder sb = new StringBuilder(); for (MethodDef md : mainMethods) { sb.append("\n\t").append(md.toString()); } return sb.toString(); } public static boolean doPostCompile(Options options, ErrorQueue eq, Collection<String> outputFiles, String[] cxxCmd) { return doPostCompile(options, eq, outputFiles, cxxCmd, false); } public static boolean doPostCompile(Options options, ErrorQueue eq, Collection<String> outputFiles, String[] cxxCmd, boolean noError) { Reporter reporter = options.reporter; if (reporter.should_report(postcompile, 1)) { StringBuffer cmdStr = new StringBuffer(); for (int i = 0; i < cxxCmd.length; i++) cmdStr.append(cxxCmd[i]+" "); reporter.report(1, "Executing post-compiler " + cmdStr); } try { Runtime runtime = Runtime.getRuntime(); Process proc = runtime.exec(cxxCmd, null, options.output_directory); InputStreamReader err = new InputStreamReader(proc.getErrorStream()); String output = null; try { char[] c = new char[72]; int len; StringBuffer sb = new StringBuffer(); while((len = err.read(c)) > 0) { sb.append(String.valueOf(c, 0, len)); } if (sb.length() != 0) { output = sb.toString(); } } finally { err.close(); } proc.waitFor(); if (!options.keep_output_files && outputFiles != null) { String[] rmCmd = new String[1+outputFiles.size()]; rmCmd[0] = "rm"; Iterator<String> iter = outputFiles.iterator(); for (int i = 1; iter.hasNext(); i++) rmCmd[i] = iter.next(); runtime.exec(rmCmd, null, options.output_directory); } if (output != null) eq.enqueue((proc.exitValue() > 0 && !noError) ? ErrorInfo.POST_COMPILER_ERROR : ErrorInfo.WARNING, output); if (proc.exitValue() > 0) { eq.enqueue(noError?ErrorInfo.WARNING:ErrorInfo.POST_COMPILER_ERROR, "Non-zero return code: " + proc.exitValue()); return false; } } catch(Exception e) { eq.enqueue(noError?ErrorInfo.WARNING:ErrorInfo.POST_COMPILER_ERROR, e.getMessage() != null ? e.getMessage() : e.toString()); return false; } return true; } private boolean translateSourceCollection(SourceCollection sc) { boolean okay = true; for (SourceFile sfn : sc.sources()) { okay &= translateSource(sfn); } if (true) throw new InternalCompilerError("Don't yet know how to translate source collections"); return okay; } }