1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.compilers;
  18. import java.io.File;
  19. import java.io.FileWriter;
  20. import java.io.IOException;
  21. import java.io.PrintWriter;
  22. import org.apache.tools.ant.BuildException;
  23. import org.apache.tools.ant.Location;
  24. import org.apache.tools.ant.Project;
  25. import org.apache.tools.ant.taskdefs.Execute;
  26. import org.apache.tools.ant.taskdefs.Javac;
  27. import org.apache.tools.ant.taskdefs.LogStreamHandler;
  28. import org.apache.tools.ant.types.Commandline;
  29. import org.apache.tools.ant.types.Path;
  30. import org.apache.tools.ant.util.FileUtils;
  31. import org.apache.tools.ant.util.JavaEnvUtils;
  32. /**
  33. * This is the default implementation for the CompilerAdapter interface.
  34. * Currently, this is a cut-and-paste of the original javac task.
  35. *
  36. * @since Ant 1.3
  37. */
  38. public abstract class DefaultCompilerAdapter implements CompilerAdapter {
  39. /* jdg - TODO - all these attributes are currently protected, but they
  40. * should probably be private in the near future.
  41. */
  42. protected Path src;
  43. protected File destDir;
  44. protected String encoding;
  45. protected boolean debug = false;
  46. protected boolean optimize = false;
  47. protected boolean deprecation = false;
  48. protected boolean depend = false;
  49. protected boolean verbose = false;
  50. protected String target;
  51. protected Path bootclasspath;
  52. protected Path extdirs;
  53. protected Path compileClasspath;
  54. protected Path compileSourcepath;
  55. protected Project project;
  56. protected Location location;
  57. protected boolean includeAntRuntime;
  58. protected boolean includeJavaRuntime;
  59. protected String memoryInitialSize;
  60. protected String memoryMaximumSize;
  61. protected File[] compileList;
  62. protected static final String lSep = System.getProperty("line.separator");
  63. protected Javac attributes;
  64. private FileUtils fileUtils = FileUtils.newFileUtils();
  65. /**
  66. * Set the Javac instance which contains the configured compilation
  67. * attributes.
  68. *
  69. * @param attributes a configured Javac task.
  70. */
  71. public void setJavac(Javac attributes) {
  72. this.attributes = attributes;
  73. src = attributes.getSrcdir();
  74. destDir = attributes.getDestdir();
  75. encoding = attributes.getEncoding();
  76. debug = attributes.getDebug();
  77. optimize = attributes.getOptimize();
  78. deprecation = attributes.getDeprecation();
  79. depend = attributes.getDepend();
  80. verbose = attributes.getVerbose();
  81. target = attributes.getTarget();
  82. bootclasspath = attributes.getBootclasspath();
  83. extdirs = attributes.getExtdirs();
  84. compileList = attributes.getFileList();
  85. compileClasspath = attributes.getClasspath();
  86. compileSourcepath = attributes.getSourcepath();
  87. project = attributes.getProject();
  88. location = attributes.getLocation();
  89. includeAntRuntime = attributes.getIncludeantruntime();
  90. includeJavaRuntime = attributes.getIncludejavaruntime();
  91. memoryInitialSize = attributes.getMemoryInitialSize();
  92. memoryMaximumSize = attributes.getMemoryMaximumSize();
  93. }
  94. /**
  95. * Get the Javac task instance associated with this compiler adapter
  96. *
  97. * @return the configured Javac task instance used by this adapter.
  98. */
  99. public Javac getJavac() {
  100. return attributes;
  101. }
  102. /**
  103. * @since Ant 1.6
  104. */
  105. protected Project getProject() {
  106. return project;
  107. }
  108. /**
  109. * Builds the compilation classpath.
  110. *
  111. */
  112. protected Path getCompileClasspath() {
  113. Path classpath = new Path(project);
  114. // add dest dir to classpath so that previously compiled and
  115. // untouched classes are on classpath
  116. if (destDir != null) {
  117. classpath.setLocation(destDir);
  118. }
  119. // Combine the build classpath with the system classpath, in an
  120. // order determined by the value of build.sysclasspath
  121. Path cp = compileClasspath;
  122. if (cp == null) {
  123. cp = new Path(project);
  124. }
  125. if (includeAntRuntime) {
  126. classpath.addExisting(cp.concatSystemClasspath("last"));
  127. } else {
  128. classpath.addExisting(cp.concatSystemClasspath("ignore"));
  129. }
  130. if (includeJavaRuntime) {
  131. classpath.addJavaRuntime();
  132. }
  133. return classpath;
  134. }
  135. protected Commandline setupJavacCommandlineSwitches(Commandline cmd) {
  136. return setupJavacCommandlineSwitches(cmd, false);
  137. }
  138. /**
  139. * Does the command line argument processing common to classic and
  140. * modern. Doesn't add the files to compile.
  141. */
  142. protected Commandline setupJavacCommandlineSwitches(Commandline cmd,
  143. boolean useDebugLevel) {
  144. Path classpath = getCompileClasspath();
  145. // For -sourcepath, use the "sourcepath" value if present.
  146. // Otherwise default to the "srcdir" value.
  147. Path sourcepath = null;
  148. if (compileSourcepath != null) {
  149. sourcepath = compileSourcepath;
  150. } else {
  151. sourcepath = src;
  152. }
  153. String memoryParameterPrefix = assumeJava11() ? "-J-" : "-J-X";
  154. if (memoryInitialSize != null) {
  155. if (!attributes.isForkedJavac()) {
  156. attributes.log("Since fork is false, ignoring "
  157. + "memoryInitialSize setting.",
  158. Project.MSG_WARN);
  159. } else {
  160. cmd.createArgument().setValue(memoryParameterPrefix
  161. + "ms" + memoryInitialSize);
  162. }
  163. }
  164. if (memoryMaximumSize != null) {
  165. if (!attributes.isForkedJavac()) {
  166. attributes.log("Since fork is false, ignoring "
  167. + "memoryMaximumSize setting.",
  168. Project.MSG_WARN);
  169. } else {
  170. cmd.createArgument().setValue(memoryParameterPrefix
  171. + "mx" + memoryMaximumSize);
  172. }
  173. }
  174. if (attributes.getNowarn()) {
  175. cmd.createArgument().setValue("-nowarn");
  176. }
  177. if (deprecation == true) {
  178. cmd.createArgument().setValue("-deprecation");
  179. }
  180. if (destDir != null) {
  181. cmd.createArgument().setValue("-d");
  182. cmd.createArgument().setFile(destDir);
  183. }
  184. cmd.createArgument().setValue("-classpath");
  185. // Just add "sourcepath" to classpath ( for JDK1.1 )
  186. // as well as "bootclasspath" and "extdirs"
  187. if (assumeJava11()) {
  188. Path cp = new Path(project);
  189. /*
  190. * XXX - This doesn't mix very well with build.systemclasspath,
  191. */
  192. if (bootclasspath != null) {
  193. cp.append(bootclasspath);
  194. }
  195. if (extdirs != null) {
  196. cp.addExtdirs(extdirs);
  197. }
  198. cp.append(classpath);
  199. cp.append(sourcepath);
  200. cmd.createArgument().setPath(cp);
  201. } else {
  202. cmd.createArgument().setPath(classpath);
  203. // If the buildfile specifies sourcepath="", then don't
  204. // output any sourcepath.
  205. if (sourcepath.size() > 0) {
  206. cmd.createArgument().setValue("-sourcepath");
  207. cmd.createArgument().setPath(sourcepath);
  208. }
  209. if (target != null) {
  210. cmd.createArgument().setValue("-target");
  211. cmd.createArgument().setValue(target);
  212. }
  213. if (bootclasspath != null && bootclasspath.size() > 0) {
  214. cmd.createArgument().setValue("-bootclasspath");
  215. cmd.createArgument().setPath(bootclasspath);
  216. }
  217. if (extdirs != null && extdirs.size() > 0) {
  218. cmd.createArgument().setValue("-extdirs");
  219. cmd.createArgument().setPath(extdirs);
  220. }
  221. }
  222. if (encoding != null) {
  223. cmd.createArgument().setValue("-encoding");
  224. cmd.createArgument().setValue(encoding);
  225. }
  226. if (debug) {
  227. if (useDebugLevel && !assumeJava11()) {
  228. String debugLevel = attributes.getDebugLevel();
  229. if (debugLevel != null) {
  230. cmd.createArgument().setValue("-g:" + debugLevel);
  231. } else {
  232. cmd.createArgument().setValue("-g");
  233. }
  234. } else {
  235. cmd.createArgument().setValue("-g");
  236. }
  237. } else if (!assumeJava11()) {
  238. cmd.createArgument().setValue("-g:none");
  239. }
  240. if (optimize) {
  241. cmd.createArgument().setValue("-O");
  242. }
  243. if (depend) {
  244. if (assumeJava11()) {
  245. cmd.createArgument().setValue("-depend");
  246. } else if (assumeJava12()) {
  247. cmd.createArgument().setValue("-Xdepend");
  248. } else {
  249. attributes.log("depend attribute is not supported by the "
  250. + "modern compiler", Project.MSG_WARN);
  251. }
  252. }
  253. if (verbose) {
  254. cmd.createArgument().setValue("-verbose");
  255. }
  256. addCurrentCompilerArgs(cmd);
  257. return cmd;
  258. }
  259. /**
  260. * Does the command line argument processing for modern. Doesn't
  261. * add the files to compile.
  262. */
  263. protected Commandline setupModernJavacCommandlineSwitches(Commandline cmd) {
  264. setupJavacCommandlineSwitches(cmd, true);
  265. if (attributes.getSource() != null && !assumeJava13()) {
  266. cmd.createArgument().setValue("-source");
  267. cmd.createArgument().setValue(attributes.getSource());
  268. }
  269. return cmd;
  270. }
  271. /**
  272. * Does the command line argument processing for modern and adds
  273. * the files to compile as well.
  274. */
  275. protected Commandline setupModernJavacCommand() {
  276. Commandline cmd = new Commandline();
  277. setupModernJavacCommandlineSwitches(cmd);
  278. logAndAddFilesToCompile(cmd);
  279. return cmd;
  280. }
  281. protected Commandline setupJavacCommand() {
  282. return setupJavacCommand(false);
  283. }
  284. /**
  285. * Does the command line argument processing for classic and adds
  286. * the files to compile as well.
  287. */
  288. protected Commandline setupJavacCommand(boolean debugLevelCheck) {
  289. Commandline cmd = new Commandline();
  290. setupJavacCommandlineSwitches(cmd, debugLevelCheck);
  291. logAndAddFilesToCompile(cmd);
  292. return cmd;
  293. }
  294. /**
  295. * Logs the compilation parameters, adds the files to compile and logs the
  296. * "niceSourceList"
  297. */
  298. protected void logAndAddFilesToCompile(Commandline cmd) {
  299. attributes.log("Compilation " + cmd.describeArguments(),
  300. Project.MSG_VERBOSE);
  301. StringBuffer niceSourceList = new StringBuffer("File");
  302. if (compileList.length != 1) {
  303. niceSourceList.append("s");
  304. }
  305. niceSourceList.append(" to be compiled:");
  306. niceSourceList.append(lSep);
  307. for (int i = 0; i < compileList.length; i++) {
  308. String arg = compileList[i].getAbsolutePath();
  309. cmd.createArgument().setValue(arg);
  310. niceSourceList.append(" " + arg + lSep);
  311. }
  312. attributes.log(niceSourceList.toString(), Project.MSG_VERBOSE);
  313. }
  314. /**
  315. * Do the compile with the specified arguments.
  316. * @param args - arguments to pass to process on command line
  317. * @param firstFileName - index of the first source file in args,
  318. * if the index is negative, no temporary file will ever be
  319. * created, but this may hit the command line length limit on your
  320. * system.
  321. */
  322. protected int executeExternalCompile(String[] args, int firstFileName) {
  323. return executeExternalCompile(args, firstFileName, true);
  324. }
  325. /**
  326. * Do the compile with the specified arguments.
  327. * @param args - arguments to pass to process on command line
  328. * @param firstFileName - index of the first source file in args,
  329. * if the index is negative, no temporary file will ever be
  330. * created, but this may hit the command line length limit on your
  331. * system.
  332. * @param quoteFiles - if set to true, filenames containing
  333. * spaces will be quoted when they appear in the external file.
  334. * This is necessary when running JDK 1.4's javac and probably
  335. * others.
  336. *
  337. * @since Ant 1.6
  338. */
  339. protected int executeExternalCompile(String[] args, int firstFileName,
  340. boolean quoteFiles) {
  341. String[] commandArray = null;
  342. File tmpFile = null;
  343. try {
  344. /*
  345. * Many system have been reported to get into trouble with
  346. * long command lines - no, not only Windows ;-).
  347. *
  348. * POSIX seems to define a lower limit of 4k, so use a temporary
  349. * file if the total length of the command line exceeds this limit.
  350. */
  351. if (Commandline.toString(args).length() > 4096
  352. && firstFileName >= 0) {
  353. PrintWriter out = null;
  354. try {
  355. File userDir = getJavac().getTempdir();
  356. if (userDir == null) {
  357. String userDirName = System.getProperty("user.dir");
  358. userDir = new File(userDirName);
  359. }
  360. tmpFile = fileUtils.createTempFile("files", "", userDir);
  361. tmpFile.deleteOnExit();
  362. out = new PrintWriter(new FileWriter(tmpFile));
  363. for (int i = firstFileName; i < args.length; i++) {
  364. if (quoteFiles && args[i].indexOf(" ") > -1) {
  365. args[i] = args[i].replace('\\', '/');
  366. out.println("\"" + args[i] + "\"");
  367. } else {
  368. out.println(args[i]);
  369. }
  370. }
  371. out.flush();
  372. commandArray = new String[firstFileName + 1];
  373. System.arraycopy(args, 0, commandArray, 0, firstFileName);
  374. commandArray[firstFileName] = "@" + tmpFile;
  375. } catch (IOException e) {
  376. throw new BuildException("Error creating temporary file",
  377. e, location);
  378. } finally {
  379. if (out != null) {
  380. try {
  381. out.close();
  382. } catch (Throwable t) {
  383. // ignore
  384. }
  385. }
  386. }
  387. } else {
  388. commandArray = args;
  389. }
  390. try {
  391. Execute exe = new Execute(
  392. new LogStreamHandler(attributes,
  393. Project.MSG_INFO,
  394. Project.MSG_WARN));
  395. exe.setAntRun(project);
  396. exe.setWorkingDirectory(project.getBaseDir());
  397. exe.setCommandline(commandArray);
  398. exe.execute();
  399. return exe.getExitValue();
  400. } catch (IOException e) {
  401. throw new BuildException("Error running " + args[0]
  402. + " compiler", e, location);
  403. }
  404. } finally {
  405. if (tmpFile != null) {
  406. tmpFile.delete();
  407. }
  408. }
  409. }
  410. /**
  411. * @deprecated use org.apache.tools.ant.types.Path#addExtdirs instead
  412. */
  413. protected void addExtdirsToClasspath(Path classpath) {
  414. classpath.addExtdirs(extdirs);
  415. }
  416. /**
  417. * Adds the command line arguments specific to the current implementation.
  418. */
  419. protected void addCurrentCompilerArgs(Commandline cmd) {
  420. cmd.addArguments(getJavac().getCurrentCompilerArgs());
  421. }
  422. /**
  423. * Shall we assume JDK 1.1 command line switches?
  424. * @since Ant 1.5
  425. */
  426. protected boolean assumeJava11() {
  427. return "javac1.1".equals(attributes.getCompilerVersion())
  428. || ("classic".equals(attributes.getCompilerVersion())
  429. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1))
  430. || ("extJavac".equals(attributes.getCompilerVersion())
  431. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1));
  432. }
  433. /**
  434. * Shall we assume JDK 1.2 command line switches?
  435. * @since Ant 1.5
  436. */
  437. protected boolean assumeJava12() {
  438. return "javac1.2".equals(attributes.getCompilerVersion())
  439. || ("classic".equals(attributes.getCompilerVersion())
  440. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2))
  441. || ("extJavac".equals(attributes.getCompilerVersion())
  442. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2));
  443. }
  444. /**
  445. * Shall we assume JDK 1.3 command line switches?
  446. * @since Ant 1.5
  447. */
  448. protected boolean assumeJava13() {
  449. return "javac1.3".equals(attributes.getCompilerVersion())
  450. || ("classic".equals(attributes.getCompilerVersion())
  451. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3))
  452. || ("modern".equals(attributes.getCompilerVersion())
  453. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3))
  454. || ("extJavac".equals(attributes.getCompilerVersion())
  455. && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3));
  456. }
  457. }