/* * 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.postcompiler; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import polyglot.frontend.Compiler; import polyglot.main.Options; import polyglot.util.ErrorInfo; import polyglot.util.ErrorQueue; import polyglot.util.InternalCompilerError; import polyglot.util.QuotedStringTokenizer; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; import x10.Configuration; import x10.X10CompilerOptions; import x10cpp.X10CPPCompilerOptions; import x10cpp.visit.X10CPPTranslator; public class CXXCommandBuilder { private static final String UNKNOWN = "unknown"; protected X10CPPCompilerOptions options; protected PostCompileProperties x10rt; protected SharedLibProperties sharedLibProps; // avoid threading loads of things through constructors -- set this stuff here protected void setData(Options options, PostCompileProperties x10rt, SharedLibProperties shared_lib_props, ErrorQueue eq) { this.options = (X10CPPCompilerOptions) options; this.x10rt = x10rt; this.sharedLibProps = shared_lib_props; } private String cxxCompiler = UNKNOWN; protected String defaultPostCompiler() { if (cxxCompiler.equals(UNKNOWN)) { String pc = x10rt.props.getProperty("X10LIB_CXX"); if (pc != null && (pc.startsWith("mpi") || pc.startsWith("mpCC"))) { // ignore all other settings; mpicxx/mpCC win ties, and also // prevent sanity checking because they will be a wrapper on an unknown compiler // So, if things don't match, the user will just find out via link time errors. } else { // If we're compiling for AIX, then we try to prevent mixing of g++ and xlC compiled // code because they do not have binary compatible ABIs on AIX. if (getPlatform().contains("aix")) { for (PrecompiledLibrary pcl: options.x10libs) { String pc2 = pcl.props.getProperty("X10LIB_CXX"); if (pc2 != null) { if (pc != null && !pc2.equals(pc)) { throw new InternalCompilerError("Conflicting postcompilers. Both "+pc+" and "+pc2+" requested"); } pc = pc2; } } } } cxxCompiler = pc == null ? "g++" : pc; } return cxxCompiler; } private String platform = UNKNOWN; public String getPlatform() { if (platform.equals(UNKNOWN)) { String p1 = x10rt.props.getProperty("X10LIB_PLATFORM"); // Sanity check that x10rt and all the precompiled libraries were built for the same platform for (PrecompiledLibrary pcl: options.x10libs) { String p2 = pcl.props.getProperty("X10LIB_PLATFORM"); if (p2 != null) { if (p1 != null && !p2.equals(p1)) { throw new InternalCompilerError("Conflicting platforms. Both "+p1+" and "+p2+" specified"); } p1 = p2; } } if (p1 == null) { throw new InternalCompilerError("No platform specified by given property files"); } platform = p1; } return platform; } protected final boolean usingXLC() { return defaultPostCompiler().contains("xlC"); } protected final boolean bluegene() { return bluegeneP() || bluegeneQ(); } protected final boolean bluegeneP() { return platform.contains("bgp"); } protected final boolean bluegeneQ() { return platform.contains("bgq"); } /** * Add all command line arguments to the C++ compiler * that go before the list of input files to the end of * the argument cxxCmd. * @param cxxCmd the container to which to append the arguments. */ public void addPreArgs(ArrayList<String> cxxCmd) { if (options.x10_config.DEBUG) { cxxCmd.add("-g"); } // x10rt and other misc header files cxxCmd.add("-I"+options.distPath()+"/include"); // header files for all prebuilt-libraries for (PrecompiledLibrary pcl:options.x10libs) { if (options.x10_config.DEBUG) { cxxCmd.add("-I"+pcl.absolutePathToRoot+"/include-dbg"); } cxxCmd.add("-I"+pcl.absolutePathToRoot+"/include"); } // header files generated by the compilation cxxCmd.add("-I"+options.output_directory); cxxCmd.add("-I."); if (options.x10_config.OPTIMIZE) { cxxCmd.add(usingXLC() ? "-O3" : "-O2"); cxxCmd.add(usingXLC() ? "-qinline" : "-finline-functions"); cxxCmd.add("-DNO_TRACING"); if (usingXLC() && !bluegene()) { cxxCmd.add("-qhot"); cxxCmd.add("-qtune=auto"); cxxCmd.add("-qarch=auto"); } } if (usingXLC()) { cxxCmd.add("-qsuppress=1540-0809" // Do not warn about empty sources + ":1540-1101" // Do not warn about non-void functions with no return + ":1540-1102" // Do not warn about uninitialized variables + ":1500-029"); // Do not warn about being unable to inline when optimizing } else { cxxCmd.add("-Wno-long-long"); // Do not warn about using long long cxxCmd.add("-Wno-unused-parameter"); // Do not warn about unused parameters // DISABLED due to XTENLANG-2215; finally block rewriting has (dynamically unreachable) path in which there is no return // cxxCmd.add("-Wreturn-type"); // Do warn about non-void functions with no return } if (options.x10_config.NO_CHECKS) { cxxCmd.add("-DNO_CHECKS"); } if (options.pg) { cxxCmd.add("-pg"); } if (options.gpt) { cxxCmd.add("-g"); } cxxCmd.addAll(x10rt.cxxFlags); for (PrecompiledLibrary pcl:options.x10libs) { cxxCmd.addAll(pcl.cxxFlags); } if (options.buildX10Lib != null) { cxxCmd.addAll(sharedLibProps.cxxFlags); } cxxCmd.addAll(options.extraPreArgs); } /** * Add all command line arguments to the C++ compiler * that go after the list of input files to the end of * the argument cxxCmd. * The majority of these flags are actually targeted at the linker, * and have to do with linking dependent libraries. * @param cxxCmd the container to which to append the arguments. */ public void addPostArgs(ArrayList<String> cxxCmd) { if (sharedLibProps.staticLib && !usingXLC()) { cxxCmd.add("-Wl,--start-group"); } for (PrecompiledLibrary pcl:options.x10libs) { if (options.x10_config.DEBUG && !options.x10_config.DEBUG_APP_ONLY) { cxxCmd.add("-L"+pcl.absolutePathToRoot+"/lib-dbg"); } cxxCmd.add("-L"+pcl.absolutePathToRoot+"/lib"); cxxCmd.addAll(pcl.ldFlags); cxxCmd.addAll(pcl.libs); } if (sharedLibProps.staticLib && !usingXLC()) { cxxCmd.add("-Wl,--end-group"); } // x10rt cxxCmd.add("-L"+options.distPath()+"/lib"); cxxCmd.addAll(x10rt.ldFlags); cxxCmd.addAll(x10rt.libs); if (options.gpt) { cxxCmd.add("-lprofiler"); } if (options.buildX10Lib != null) { cxxCmd.addAll(sharedLibProps.ldFlags); } cxxCmd.addAll(options.extraPostArgs); } /** * Adds the target executable (-o <file>) to the cxxCmd * * @param cxxCmd the container to which to append the arguments. */ public void addExecutablePath(ArrayList<String> cxxCmd) { File exe = targetFilePath(); if (exe != null) { cxxCmd.add("-o"); cxxCmd.add(exe.getAbsolutePath().replace(File.separatorChar,'/')); } } public File targetFilePath() { File target = null; if (options.buildX10Lib != null) { if (options.executable_path != null) { target = new File(options.buildX10Lib + "/lib/" + sharedLibProps.libPrefix + options.executable_path + sharedLibProps.libSuffix); } } else { if (options.executable_path != null) { target = new File(options.executable_path); } else if (options.x10_config.MAIN_CLASS != null) { target = new File(options.output_directory, options.x10_config.MAIN_CLASS); } } return target; } /** Construct the C++ compilation command */ public String[] buildCXXCommandLine(Collection<String> outputFiles) { String post_compiler = options.post_compiler; if (post_compiler.contains("javac")) { post_compiler = defaultPostCompiler(); } QuotedStringTokenizer st = new QuotedStringTokenizer(post_compiler); int pc_size = st.countTokens(); ArrayList<String> cxxCmd = new ArrayList<String>(); String token = ""; for (int i = 0; i < pc_size; i++) { token = st.nextToken(); // A # as the first token signifies that the default postcompiler for this platform be used if (i==0 && token.equals("#")) { cxxCmd.add(defaultPostCompiler()); continue; } // consume all tokens up until the next # (or %) whereupon we will insert (or not) // default CXXFLAGS parameters and generated compilation units if (token.equals("#") || token.equals("%")) { break; } cxxCmd.add(token); } boolean skipArgs = token.equals("%"); if (!skipArgs) { addPreArgs(cxxCmd); if (options.buildX10Lib != null && sharedLibProps.staticLib) { cxxCmd.add("-c"); } else { addExecutablePath(cxxCmd); } } for (String file : outputFiles) { file = file.replace(File.separatorChar,'/'); if (file.endsWith(".cu")) continue; cxxCmd.add(file); } while (st.hasMoreTokens()) { token = st.nextToken(); // The second '#' delimits the libraries that have to go at the end if (token.equals("#") || token.equals("%")) { break; } cxxCmd.add(token); } boolean skipLibs = token.equals("%"); if (!skipLibs) { addPostArgs(cxxCmd); } while (st.hasMoreTokens()) { cxxCmd.add(st.nextToken()); } return cxxCmd.toArray(new String[cxxCmd.size()]); } /** * @return the name of the C++ compiler (g++/xlC/mpcixx, etc) */ public String getPostCompiler() { return defaultPostCompiler(); } /** * @return all command line arguments for a compilation command that go * before the files to be compiled (typically compilation options). */ public List<String> getPreFileArgs() { ArrayList<String> ans = new ArrayList<String>(); addPreArgs(ans); return ans; } /** * @return all command line arguments for a compilation command that go * after the files to be compiled (typically linker options). */ public List<String> getPostFileArgs() { ArrayList<String> ans = new ArrayList<String>(); addPostArgs(ans); return ans; } /** * Return a CXXCommandBuilder that will use the given options and x10rt properties to * construct compilation commands. * * @param options The compiler options to use when constructing commands * @param x10rt_props The property file describing the x10rt implementation * to be used for this compilation * @param eq The error queue to use to report warnings and errors during compilation. * @return a CXXCommandBuilder instance that will use options and x10rt_props */ public static CXXCommandBuilder getCXXCommandBuilder(X10CPPCompilerOptions options, PostCompileProperties x10rt_props, SharedLibProperties shared_lib_props, ErrorQueue eq) { String platform = x10rt_props.props.getProperty("X10LIB_PLATFORM", "unknown"); CXXCommandBuilder cbb; if (platform.startsWith("win32_") || platform.startsWith("cygwin")) { cbb = new Cygwin_CXXCommandBuilder(); } else if (platform.startsWith("linux_")) { cbb = new Linux_CXXCommandBuilder(); } else if (platform.startsWith("aix_")) { cbb = new AIX_CXXCommandBuilder(); } else if (platform.startsWith("sunos_")) { cbb = new SunOS_CXXCommandBuilder(); } else if (platform.startsWith("macosx_") || platform.startsWith("darwin")) { cbb = new MacOSX_CXXCommandBuilder(); } else if (platform.startsWith("freebsd_")) { cbb = new FreeBSD_CXXCommandBuilder(); } else if (platform.startsWith("bgp")) { cbb = new Linux_CXXCommandBuilder(); } else if (platform.startsWith("bgq")) { cbb = new Linux_CXXCommandBuilder(); } else { eq.enqueue(ErrorInfo.WARNING, "Unknown platform '"+platform+"'; using the default post-compiler (g++)"); cbb = new CXXCommandBuilder(); } cbb.setData(options, x10rt_props, shared_lib_props, eq); if(options.make) { CXXMakeBuilder cmb = new CXXMakeBuilder(cbb); cmb.setData(options, x10rt_props, shared_lib_props, eq); return cmb; } return cbb; } public String getCUDAPostCompiler() { return "nvcc"; } public List<String> getCUDAArchitectures() { ArrayList<String> ans = new ArrayList<String>(); ans.add("sm_10"); ans.add("sm_11"); ans.add("sm_12"); ans.add("sm_13"); ans.add("sm_20"); ans.add("sm_21"); //ans.add("sm_30"); return ans; } public List<String> getCUDAPreFileArgs() { ArrayList<String> ans = new ArrayList<String>(); ans.add("-cubin"); //ans.add("-Xptxas"); //ans.add("-v"); for (PrecompiledLibrary pcl : options.x10libs) { ans.add("-I"+pcl.absolutePathToRoot+"/include"); } return ans; } }