You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AjcTask.java 68KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985
  1. /* *******************************************************************
  2. * Copyright (c) 2001-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC)
  4. * 2003-2004 Contributors.
  5. * All rights reserved.
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Common Public License v1.0
  8. * which accompanies this distribution and is available at
  9. * http://www.eclipse.org/legal/cpl-v10.html
  10. *
  11. * Contributors:
  12. * Xerox/PARC initial implementation
  13. * Wes Isberg 2003-2004 changes
  14. * ******************************************************************/
  15. package org.aspectj.tools.ant.taskdefs;
  16. import java.io.*;
  17. import java.util.*;
  18. import org.apache.tools.ant.*;
  19. import org.apache.tools.ant.taskdefs.*;
  20. import org.apache.tools.ant.types.*;
  21. import org.aspectj.bridge.*;
  22. import org.aspectj.tools.ajc.Main;
  23. import org.aspectj.tools.ajc.Main.MessagePrinter;
  24. import org.aspectj.tools.ajc.Main.LogModeMessagePrinter;
  25. import org.aspectj.util.*;
  26. /**
  27. * This runs the AspectJ 1.1 compiler,
  28. * supporting all the command-line options.
  29. * In 1.1.1, ajc copies resources from input jars,
  30. * but you can copy resources from the source directories
  31. * using sourceRootCopyFilter.
  32. * When not forking, things will be copied as needed
  33. * for each iterative compile,
  34. * but when forking things are only copied at the
  35. * completion of a successful compile.
  36. * <p>
  37. * See the development environment guide for
  38. * usage documentation.
  39. *
  40. * @since AspectJ 1.1, Ant 1.5
  41. */
  42. public class AjcTask extends MatchingTask {
  43. /*
  44. * This task mainly converts ant specification for ajc,
  45. * verbosely ignoring improper input.
  46. * It also has some special features for non-obvious clients:
  47. * (1) Javac compiler adapter supported in
  48. * <code>setupAjc(AjcTask, Javac, File)</code>
  49. * and
  50. * <code>readArguments(String[])</code>;
  51. * (2) testing is supported by
  52. * (a) permitting the same specification to be re-run
  53. * with added flags (settings once made cannot be
  54. * removed); and
  55. * (b) permitting recycling the task with
  56. * <code>reset()</code> (untested).
  57. *
  58. * The parts that do more than convert ant specs are
  59. * (a) code for forking;
  60. * (b) code for copying resources.
  61. *
  62. * If you maintain/upgrade this task, keep in mind:
  63. * (1) changes to the semantics of ajc (new options, new
  64. * values permitted, etc.) will have to be reflected here.
  65. * (2) the clients:
  66. * the iajc ant script, Javac compiler adapter,
  67. * maven clients of iajc, and testing code.
  68. */
  69. // XXX move static methods after static initializer
  70. /**
  71. * This method extracts javac arguments to ajc,
  72. * and add arguments to make ajc behave more like javac
  73. * in copying resources.
  74. * <p>
  75. * Pass ajc-specific options using compilerarg sub-element:
  76. * <pre>
  77. * &lt;javac srcdir="src">
  78. * &lt;compilerarg compiler="..." line="-argfile src/args.lst"/>
  79. * &lt;javac>
  80. * </pre>
  81. * Some javac arguments are not supported in this component (yet):
  82. * <pre>
  83. * String memoryInitialSize;
  84. * boolean includeAntRuntime = true;
  85. * boolean includeJavaRuntime = false;
  86. * </pre>
  87. * Other javac arguments are not supported in ajc 1.1:
  88. * <pre>
  89. * boolean optimize;
  90. * String forkedExecutable;
  91. * FacadeTaskHelper facade;
  92. * boolean depend;
  93. * String debugLevel;
  94. * Path compileSourcepath;
  95. * </pre>
  96. * @param javac the Javac command to implement (not null)
  97. * @param ajc the AjcTask to adapt (not null)
  98. * @param destDir the File class destination directory (may be null)
  99. * @return null if no error, or String error otherwise
  100. */
  101. public String setupAjc(Javac javac) {
  102. if (null == javac) {
  103. return "null javac";
  104. }
  105. AjcTask ajc = this;
  106. // no null checks b/c AjcTask handles null input gracefully
  107. ajc.setProject(javac.getProject());
  108. ajc.setLocation(javac.getLocation());
  109. ajc.setTaskName("javac-iajc");
  110. ajc.setDebug(javac.getDebug());
  111. ajc.setDeprecation(javac.getDeprecation());
  112. ajc.setFailonerror(javac.getFailonerror());
  113. final boolean fork = javac.isForkedJavac();
  114. ajc.setFork(fork);
  115. if (fork) {
  116. ajc.setMaxmem(javac.getMemoryMaximumSize());
  117. }
  118. ajc.setNowarn(javac.getNowarn());
  119. ajc.setListFileArgs(javac.getListfiles());
  120. ajc.setVerbose(javac.getVerbose());
  121. ajc.setTarget(javac.getTarget());
  122. ajc.setSource(javac.getSource());
  123. ajc.setEncoding(javac.getEncoding());
  124. File javacDestDir = javac.getDestdir();
  125. if (null != javacDestDir) {
  126. ajc.setDestdir(javacDestDir);
  127. // filter requires dest dir
  128. // mimic Javac task's behavior in copying resources,
  129. ajc.setSourceRootCopyFilter("**/CVS/*,**/*.java,**/*.aj");
  130. }
  131. ajc.setBootclasspath(javac.getBootclasspath());
  132. ajc.setExtdirs(javac.getExtdirs());
  133. ajc.setClasspath(javac.getClasspath());
  134. // ignore srcDir -- all files picked up in recalculated file list
  135. // ajc.setSrcDir(javac.getSrcdir());
  136. ajc.addFiles(javac.getFileList());
  137. // arguments can override the filter, add to paths, override options
  138. ajc.readArguments(javac.getCurrentCompilerArgs());
  139. return null;
  140. }
  141. /**
  142. * Find aspectjtools.jar on the task or system classpath.
  143. * Accept <code>aspectj{-}tools{...}.jar</code>
  144. * mainly to support build systems using maven-style
  145. * re-naming
  146. * (e.g., <code>aspectj-tools-1.1.0.jar</code>.
  147. * Note that we search the task classpath first,
  148. * though an entry on the system classpath would be loaded first,
  149. * because it seems more correct as the more specific one.
  150. * @return readable File for aspectjtools.jar, or null if not found.
  151. */
  152. public static File findAspectjtoolsJar() {
  153. File result = null;
  154. ClassLoader loader = AjcTask.class.getClassLoader();
  155. if (loader instanceof AntClassLoader) {
  156. AntClassLoader taskLoader = (AntClassLoader) loader;
  157. String cp = taskLoader.getClasspath();
  158. String[] cps = LangUtil.splitClasspath(cp);
  159. for (int i = 0; (i < cps.length) && (null == result); i++) {
  160. result = isAspectjtoolsjar(cps[i]);
  161. }
  162. }
  163. if (null == result) {
  164. final Path classpath = Path.systemClasspath;
  165. final String[] paths = classpath.list();
  166. for (int i = 0; (i < paths.length) && (null == result); i++) {
  167. result = isAspectjtoolsjar(paths[i]);
  168. }
  169. }
  170. return (null == result? null : result.getAbsoluteFile());
  171. }
  172. /** @return File if readable jar with aspectj tools name, or null */
  173. private static File isAspectjtoolsjar(String path) {
  174. if (null == path) {
  175. return null;
  176. }
  177. final String prefix = "aspectj";
  178. final String infix = "tools";
  179. final String altInfix = "-tools";
  180. final String suffix = ".jar";
  181. final int prefixLength = 7; // prefix.length();
  182. final int minLength = 16;
  183. // prefixLength + infix.length() + suffix.length();
  184. if (!path.endsWith(suffix)) {
  185. return null;
  186. }
  187. int loc = path.lastIndexOf(prefix);
  188. if ((-1 != loc) && ((loc + minLength) <= path.length())) {
  189. String rest = path.substring(loc+prefixLength);
  190. if (-1 != rest.indexOf(File.pathSeparator)) {
  191. return null;
  192. }
  193. if (rest.startsWith(infix)
  194. || rest.startsWith(altInfix)) {
  195. File result = new File(path);
  196. if (result.canRead() && result.isFile()) {
  197. return result;
  198. }
  199. }
  200. }
  201. return null;
  202. }
  203. /**
  204. * Maximum length (in chars) of command line
  205. * before converting to an argfile when forking
  206. */
  207. private static final int MAX_COMMANDLINE = 4096;
  208. private static final File DEFAULT_DESTDIR = new File(".") {
  209. public String toString() {
  210. return "(no destination dir specified)";
  211. }
  212. };
  213. /** do not throw BuildException on fail/abort message with usage */
  214. private static final String USAGE_SUBSTRING = "AspectJ-specific options";
  215. /** valid -X[...] options other than -Xlint variants */
  216. private static final List VALID_XOPTIONS;
  217. /** valid warning (-warn:[...]) variants */
  218. private static final List VALID_WARNINGS;
  219. /** valid debugging (-g:[...]) variants */
  220. private static final List VALID_DEBUG;
  221. /**
  222. * -Xlint variants (error, warning, ignore)
  223. * @see org.aspectj.weaver.Lint
  224. */
  225. private static final List VALID_XLINT;
  226. public static final String COMMAND_EDITOR_NAME
  227. = AjcTask.class.getName() + ".COMMAND_EDITOR";
  228. static final String[] TARGET_INPUTS = new String []
  229. { "1.1", "1.2", "1.3", "1.4", "1.5" };
  230. static final String[] SOURCE_INPUTS = new String []
  231. { "1.3", "1.4", "1.5" };
  232. static final String[] COMPLIANCE_INPUTS = new String []
  233. { "-1.3", "-1.4", "-1.5" };
  234. private static final ICommandEditor COMMAND_EDITOR;
  235. static {
  236. String[] xs = new String[]
  237. { "serializableAspects", "incrementalFile", "lazyTjp",
  238. "reweavable", "reweavable:compress", "noInline"
  239. //, "targetNearSource", "OcodeSize",
  240. };
  241. VALID_XOPTIONS = Collections.unmodifiableList(Arrays.asList(xs));
  242. xs = new String[]
  243. {"constructorName", "packageDefaultMethod", "deprecation",
  244. "maskedCatchBlocks", "unusedLocals", "unusedArguments",
  245. "unusedImports", "syntheticAccess", "assertIdentifier", "none" };
  246. VALID_WARNINGS = Collections.unmodifiableList(Arrays.asList(xs));
  247. xs = new String[] {"none", "lines", "vars", "source" };
  248. VALID_DEBUG = Collections.unmodifiableList(Arrays.asList(xs));
  249. xs = new String[] { "error", "warning", "ignore"};
  250. VALID_XLINT = Collections.unmodifiableList(Arrays.asList(xs));
  251. ICommandEditor editor = null;
  252. try {
  253. String editorClassName = System.getProperty(COMMAND_EDITOR_NAME);
  254. if (null != editorClassName) {
  255. ClassLoader cl = AjcTask.class.getClassLoader();
  256. Class editorClass = cl.loadClass(editorClassName);
  257. editor = (ICommandEditor) editorClass.newInstance();
  258. }
  259. } catch (Throwable t) {
  260. System.err.println("Warning: unable to load command editor");
  261. t.printStackTrace(System.err);
  262. }
  263. COMMAND_EDITOR = editor;
  264. }
  265. // ---------------------------- state and Ant interface thereto
  266. private boolean verbose;
  267. private boolean listFileArgs;
  268. private boolean loggingMode;
  269. private File logFile;
  270. private boolean failonerror;
  271. private boolean fork;
  272. private String maxMem;
  273. // ------- single entries dumped into cmd
  274. protected GuardedCommand cmd;
  275. // ------- lists resolved in addListArgs() at execute() time
  276. private Path srcdir;
  277. private Path injars;
  278. private Path inpath;
  279. private Path classpath;
  280. private Path bootclasspath;
  281. private Path forkclasspath;
  282. private Path extdirs;
  283. private Path aspectpath;
  284. private Path argfiles;
  285. private List ignored;
  286. private Path sourceRoots;
  287. private File xweaveDir;
  288. private String xdoneSignal;
  289. // ----- added by adapter - integrate better?
  290. private List /* File */ adapterFiles;
  291. private String[] adapterArguments;
  292. private IMessageHolder messageHolder;
  293. private ICommandEditor commandEditor;
  294. // -------- resource-copying
  295. /** true if copying injar non-.class files to the output jar */
  296. private boolean copyInjars;
  297. private boolean copyInpath;
  298. /** non-null if copying all source root files but the filtered ones */
  299. private String sourceRootCopyFilter;
  300. /** non-null if copying all inpath dir files but the filtered ones */
  301. private String inpathDirCopyFilter;
  302. /** directory sink for classes */
  303. private File destDir;
  304. /** zip file sink for classes */
  305. private File outjar;
  306. /** track whether we've supplied any temp outjar */
  307. private boolean outjarFixedup;
  308. /**
  309. * When possibly copying resources to the output jar,
  310. * pass ajc a fake output jar to copy from,
  311. * so we don't change the modification time of the output jar
  312. * when copying injars/inpath into the actual outjar.
  313. */
  314. private File tmpOutjar;
  315. private boolean executing;
  316. /** non-null only while executing in same vm */
  317. private Main main;
  318. /** true only when executing in other vm */
  319. private boolean executingInOtherVM;
  320. /** true if -incremental */
  321. private boolean inIncrementalMode;
  322. /** true if -XincrementalFile (i.e, setTagFile)*/
  323. private boolean inIncrementalFileMode;
  324. // also note MatchingTask grabs source files...
  325. public AjcTask() {
  326. reset();
  327. }
  328. /** to use this same Task more than once (testing) */
  329. public void reset() { // XXX possible to reset MatchingTask?
  330. // need declare for "all fields initialized in ..."
  331. adapterArguments = null;
  332. adapterFiles = new ArrayList();
  333. argfiles = null;
  334. executing = false;
  335. aspectpath = null;
  336. bootclasspath = null;
  337. classpath = null;
  338. cmd = new GuardedCommand();
  339. copyInjars = false;
  340. copyInpath = false;
  341. destDir = DEFAULT_DESTDIR;
  342. executing = false;
  343. executingInOtherVM = false;
  344. extdirs = null;
  345. failonerror = true; // non-standard default
  346. forkclasspath = null;
  347. inIncrementalMode = false;
  348. inIncrementalFileMode = false;
  349. ignored = new ArrayList();
  350. injars = null;
  351. inpath = null;
  352. listFileArgs = false;
  353. maxMem = null;
  354. messageHolder = null;
  355. outjar = null;
  356. sourceRootCopyFilter = null;
  357. inpathDirCopyFilter = null;
  358. sourceRoots = null;
  359. srcdir = null;
  360. tmpOutjar = null;
  361. verbose = false;
  362. xweaveDir = null;
  363. xdoneSignal = null;
  364. loggingMode = false;
  365. logFile = null;
  366. }
  367. protected void ignore(String ignored) {
  368. this.ignored.add(ignored + " at " + getLocation());
  369. }
  370. //---------------------- option values
  371. // used by entries with internal commas
  372. protected String validCommaList(String list, List valid, String label) {
  373. return validCommaList(list, valid, label, valid.size());
  374. }
  375. protected String validCommaList(String list, List valid, String label, int max) {
  376. StringBuffer result = new StringBuffer();
  377. StringTokenizer st = new StringTokenizer(list, ",");
  378. int num = 0;
  379. while (st.hasMoreTokens()) {
  380. String token = st.nextToken().trim();
  381. num++;
  382. if (num > max) {
  383. ignore("too many entries for -"
  384. + label
  385. + ": "
  386. + token);
  387. break;
  388. }
  389. if (!valid.contains(token)) {
  390. ignore("bad commaList entry for -"
  391. + label
  392. + ": "
  393. + token);
  394. } else {
  395. if (0 < result.length()) {
  396. result.append(",");
  397. }
  398. result.append(token);
  399. }
  400. }
  401. return (0 == result.length() ? null : result.toString());
  402. }
  403. public void setIncremental(boolean incremental) {
  404. cmd.addFlag("-incremental", incremental);
  405. inIncrementalMode = incremental;
  406. }
  407. public void setHelp(boolean help) {
  408. cmd.addFlag("-help", help);
  409. }
  410. public void setVersion(boolean version) {
  411. cmd.addFlag("-version", version);
  412. }
  413. public void setXNoweave(boolean noweave) {
  414. cmd.addFlag("-XnoWeave", noweave);
  415. }
  416. public void setXReweavable(boolean reweavable) {
  417. cmd.addFlag("-Xreweavable",reweavable);
  418. }
  419. public void setXNoInline(boolean noInline) {
  420. cmd.addFlag("-XnoInline",noInline);
  421. }
  422. public void setShowWeaveInfo(boolean showweaveinfo) {
  423. cmd.addFlag("-showWeaveInfo",showweaveinfo);
  424. }
  425. public void setNowarn(boolean nowarn) {
  426. cmd.addFlag("-nowarn", nowarn);
  427. }
  428. public void setDeprecation(boolean deprecation) {
  429. cmd.addFlag("-deprecation", deprecation);
  430. }
  431. public void setWarn(String warnings) {
  432. warnings = validCommaList(warnings, VALID_WARNINGS, "warn");
  433. cmd.addFlag("-warn:" + warnings, (null != warnings));
  434. }
  435. public void setDebug(boolean debug) {
  436. cmd.addFlag("-g", debug);
  437. }
  438. public void setDebugLevel(String level) {
  439. level = validCommaList(level, VALID_DEBUG, "g");
  440. cmd.addFlag("-g:" + level, (null != level));
  441. }
  442. public void setEmacssym(boolean emacssym) {
  443. cmd.addFlag("-emacssym", emacssym);
  444. }
  445. /**
  446. * -Xlint - set default level of -Xlint messages to warning
  447. * (same as </code>-Xlint:warning</code>)
  448. */
  449. public void setXlintwarnings(boolean xlintwarnings) {
  450. cmd.addFlag("-Xlint", xlintwarnings);
  451. }
  452. /** -Xlint:{error|warning|info} - set default level for -Xlint messages
  453. * @param xlint the String with one of error, warning, ignored
  454. */
  455. public void setXlint(String xlint) {
  456. xlint = validCommaList(xlint, VALID_XLINT, "Xlint", 1);
  457. cmd.addFlag("-Xlint:" + xlint, (null != xlint));
  458. }
  459. /**
  460. * -Xlintfile {lint.properties} - enable or disable specific forms
  461. * of -Xlint messages based on a lint properties file
  462. * (default is
  463. * <code>org/aspectj/weaver/XLintDefault.properties</code>)
  464. * @param xlintFile the File with lint properties
  465. */
  466. public void setXlintfile(File xlintFile) {
  467. cmd.addFlagged("-Xlintfile", xlintFile.getAbsolutePath());
  468. }
  469. public void setPreserveAllLocals(boolean preserveAllLocals) {
  470. cmd.addFlag("-preserveAllLocals", preserveAllLocals);
  471. }
  472. public void setNoImportError(boolean noImportError) {
  473. cmd.addFlag("-warn:-unusedImport", noImportError);
  474. }
  475. public void setEncoding(String encoding) {
  476. cmd.addFlagged("-encoding", encoding);
  477. }
  478. public void setLog(File file) {
  479. //cmd.addFlagged("-log", file.getAbsolutePath());
  480. this.loggingMode = true;
  481. this.logFile = file;
  482. }
  483. public void setProceedOnError(boolean proceedOnError) {
  484. cmd.addFlag("-proceedOnError", proceedOnError);
  485. }
  486. public void setVerbose(boolean verbose) {
  487. cmd.addFlag("-verbose", verbose);
  488. this.verbose = verbose;
  489. }
  490. public void setListFileArgs(boolean listFileArgs) {
  491. this.listFileArgs = listFileArgs;
  492. }
  493. public void setReferenceInfo(boolean referenceInfo) {
  494. cmd.addFlag("-referenceInfo", referenceInfo);
  495. }
  496. public void setTime(boolean time) {
  497. cmd.addFlag("-time", time);
  498. }
  499. public void setNoExit(boolean noExit) {
  500. cmd.addFlag("-noExit", noExit);
  501. }
  502. public void setFailonerror(boolean failonerror) {
  503. this.failonerror = failonerror;
  504. }
  505. /**
  506. * @return true if fork was set
  507. */
  508. public boolean isForked() {
  509. return fork;
  510. }
  511. public void setFork(boolean fork) {
  512. this.fork = fork;
  513. }
  514. public void setMaxmem(String maxMem) {
  515. this.maxMem = maxMem;
  516. }
  517. // ----------------
  518. public void setTagFile(File file) {
  519. inIncrementalMode = true;
  520. cmd.addFlagged(Main.CommandController.TAG_FILE_OPTION,
  521. file.getAbsolutePath());
  522. inIncrementalFileMode = true;
  523. }
  524. public void setOutjar(File file) {
  525. if (DEFAULT_DESTDIR != destDir) {
  526. String e = "specifying both output jar ("
  527. + file
  528. + ") and destination dir ("
  529. + destDir
  530. + ")";
  531. throw new BuildException(e);
  532. }
  533. outjar = file;
  534. outjarFixedup = false;
  535. tmpOutjar = null;
  536. }
  537. public void setDestdir(File dir) {
  538. if (null != outjar) {
  539. String e = "specifying both output jar ("
  540. + outjar
  541. + ") and destination dir ("
  542. + dir
  543. + ")";
  544. throw new BuildException(e);
  545. }
  546. cmd.addFlagged("-d", dir.getAbsolutePath());
  547. destDir = dir;
  548. }
  549. /**
  550. * @param input a String in TARGET_INPUTS
  551. */
  552. public void setTarget(String input) {
  553. String ignore = cmd.addOption("-target", TARGET_INPUTS, input);
  554. if (null != ignore) {
  555. ignore(ignore);
  556. }
  557. }
  558. /**
  559. * Language compliance level.
  560. * If not set explicitly, eclipse default holds.
  561. * @param input a String in COMPLIANCE_INPUTS
  562. */
  563. public void setCompliance(String input) {
  564. String ignore = cmd.addOption(null, COMPLIANCE_INPUTS, input);
  565. if (null != ignore) {
  566. ignore(ignore);
  567. }
  568. }
  569. /**
  570. * Source compliance level.
  571. * If not set explicitly, eclipse default holds.
  572. * @param input a String in SOURCE_INPUTS
  573. */
  574. public void setSource(String input) {
  575. String ignore = cmd.addOption("-source", SOURCE_INPUTS, input);
  576. if (null != ignore) {
  577. ignore(ignore);
  578. }
  579. }
  580. /**
  581. * Flag to copy all non-.class contents of injars
  582. * to outjar after compile completes.
  583. * Requires both injars and outjar.
  584. * @param doCopy
  585. */
  586. public void setCopyInjars(boolean doCopy){
  587. ignore("copyInJars");
  588. log("copyInjars not required since 1.1.1.\n", Project.MSG_WARN);
  589. //this.copyInjars = doCopy;
  590. }
  591. /**
  592. * Option to copy all files from
  593. * all source root directories
  594. * except those specified here.
  595. * If this is specified and sourceroots are specified,
  596. * then this will copy all files except
  597. * those specified in the filter pattern.
  598. * Requires sourceroots.
  599. *
  600. * @param filter a String acceptable as an excludes
  601. * filter for an Ant Zip fileset.
  602. */
  603. public void setSourceRootCopyFilter(String filter){
  604. this.sourceRootCopyFilter = filter;
  605. }
  606. /**
  607. * Option to copy all files from
  608. * all inpath directories
  609. * except the files specified here.
  610. * If this is specified and inpath directories are specified,
  611. * then this will copy all files except
  612. * those specified in the filter pattern.
  613. * Requires inpath.
  614. * If the input does not contain "**\/*.class", then
  615. * this prepends it, to avoid overwriting woven classes
  616. * with unwoven input.
  617. * @param filter a String acceptable as an excludes
  618. * filter for an Ant Zip fileset.
  619. */
  620. public void setInpathDirCopyFilter(String filter){
  621. if (null != filter) {
  622. if (-1 == filter.indexOf("**/*.class")) {
  623. filter = "**/*.class," + filter;
  624. }
  625. }
  626. this.inpathDirCopyFilter = filter;
  627. }
  628. public void setX(String input) { // ajc-only eajc-also docDone
  629. StringTokenizer tokens = new StringTokenizer(input, ",", false);
  630. while (tokens.hasMoreTokens()) {
  631. String token = tokens.nextToken().trim();
  632. if (1 < token.length()) {
  633. if (VALID_XOPTIONS.contains(token)) {
  634. cmd.addFlag("-X" + token, true);
  635. } else {
  636. ignore("-X" + token);
  637. }
  638. }
  639. }
  640. }
  641. public void setXDoneSignal(String doneSignal) {
  642. this.xdoneSignal = doneSignal;
  643. }
  644. /** direct API for testing */
  645. public void setMessageHolder(IMessageHolder holder) {
  646. this.messageHolder = holder;
  647. }
  648. /**
  649. * Setup custom message handling.
  650. * @param className the String fully-qualified-name of a class
  651. * reachable from this object's class loader,
  652. * implementing IMessageHolder, and
  653. * having a public no-argument constructor.
  654. * @throws BuildException if unable to create instance of className
  655. */
  656. public void setMessageHolderClass(String className) {
  657. try {
  658. Class mclass = Class.forName(className);
  659. IMessageHolder holder = (IMessageHolder) mclass.newInstance();
  660. setMessageHolder(holder);
  661. } catch (Throwable t) {
  662. String m = "unable to instantiate message holder: " + className;
  663. throw new BuildException(m, t);
  664. }
  665. }
  666. /** direct API for testing */
  667. public void setCommandEditor(ICommandEditor editor) {
  668. this.commandEditor = editor;
  669. }
  670. /**
  671. * Setup command-line filter.
  672. * To do this staticly, define the environment variable
  673. * <code>org.aspectj.tools.ant.taskdefs.AjcTask.COMMAND_EDITOR</code>
  674. * with the <code>className</code> parameter.
  675. * @param className the String fully-qualified-name of a class
  676. * reachable from this object's class loader,
  677. * implementing ICommandEditor, and
  678. * having a public no-argument constructor.
  679. * @throws BuildException if unable to create instance of className
  680. */
  681. public void setCommandEditorClass(String className) { // skip Ant interface?
  682. try {
  683. Class mclass = Class.forName(className);
  684. setCommandEditor((ICommandEditor) mclass.newInstance());
  685. } catch (Throwable t) {
  686. String m = "unable to instantiate command editor: " + className;
  687. throw new BuildException(m, t);
  688. }
  689. }
  690. //---------------------- Path lists
  691. /**
  692. * Add path elements to source path and return result.
  693. * Elements are added even if they do not exist.
  694. * @param source the Path to add to - may be null
  695. * @param toAdd the Path to add - may be null
  696. * @return the (never-null) Path that results
  697. */
  698. protected Path incPath(Path source, Path toAdd) {
  699. if (null == source) {
  700. source = new Path(project);
  701. }
  702. if (null != toAdd) {
  703. source.append(toAdd);
  704. }
  705. return source;
  706. }
  707. public void setSourcerootsref(Reference ref) {
  708. createSourceRoots().setRefid(ref);
  709. }
  710. public void setSourceRoots(Path roots) {
  711. sourceRoots = incPath(sourceRoots, roots);
  712. }
  713. public Path createSourceRoots() {
  714. if (sourceRoots == null) {
  715. sourceRoots = new Path(project);
  716. }
  717. return sourceRoots.createPath();
  718. }
  719. public void setXWeaveDir(File file) {
  720. if ((null != file) && file.isDirectory()
  721. && file.canRead()) {
  722. xweaveDir = file;
  723. }
  724. }
  725. public void setInjarsref(Reference ref) {
  726. createInjars().setRefid(ref);
  727. }
  728. public void setInpathref(Reference ref) {
  729. createInpath().setRefid(ref);
  730. }
  731. public void setInjars(Path path) {
  732. injars = incPath(injars, path);
  733. }
  734. public void setInpath(Path path) {
  735. inpath = incPath(inpath,path);
  736. }
  737. public Path createInjars() {
  738. if (injars == null) {
  739. injars = new Path(project);
  740. }
  741. return injars.createPath();
  742. }
  743. public Path createInpath() {
  744. if (inpath == null) {
  745. inpath = new Path(project);
  746. }
  747. return inpath.createPath();
  748. }
  749. public void setClasspath(Path path) {
  750. classpath = incPath(classpath, path);
  751. }
  752. public void setClasspathref(Reference classpathref) {
  753. createClasspath().setRefid(classpathref);
  754. }
  755. public Path createClasspath() {
  756. if (classpath == null) {
  757. classpath = new Path(project);
  758. }
  759. return classpath.createPath();
  760. }
  761. public void setBootclasspath(Path path) {
  762. bootclasspath = incPath(bootclasspath, path);
  763. }
  764. public void setBootclasspathref(Reference bootclasspathref) {
  765. createBootclasspath().setRefid(bootclasspathref);
  766. }
  767. public Path createBootclasspath() {
  768. if (bootclasspath == null) {
  769. bootclasspath = new Path(project);
  770. }
  771. return bootclasspath.createPath();
  772. }
  773. public void setForkclasspath(Path path) {
  774. forkclasspath = incPath(forkclasspath, path);
  775. }
  776. public void setForkclasspathref(Reference forkclasspathref) {
  777. createForkclasspath().setRefid(forkclasspathref);
  778. }
  779. public Path createForkclasspath() {
  780. if (forkclasspath == null) {
  781. forkclasspath = new Path(project);
  782. }
  783. return forkclasspath.createPath();
  784. }
  785. public void setExtdirs(Path path) {
  786. extdirs = incPath(extdirs, path);
  787. }
  788. public void setExtdirsref(Reference ref) {
  789. createExtdirs().setRefid(ref);
  790. }
  791. public Path createExtdirs() {
  792. if (extdirs == null) {
  793. extdirs = new Path(project);
  794. }
  795. return extdirs.createPath();
  796. }
  797. public void setAspectpathref(Reference ref) {
  798. createAspectpath().setRefid(ref);
  799. }
  800. public void setAspectpath(Path path) {
  801. aspectpath = incPath(aspectpath, path);
  802. }
  803. public Path createAspectpath() {
  804. if (aspectpath == null) {
  805. aspectpath = new Path(project);
  806. }
  807. return aspectpath.createPath();
  808. }
  809. public void setSrcDir(Path path) {
  810. srcdir = incPath(srcdir, path);
  811. }
  812. public Path createSrc() {
  813. return createSrcdir();
  814. }
  815. public Path createSrcdir() {
  816. if (srcdir == null) {
  817. srcdir = new Path(project);
  818. }
  819. return srcdir.createPath();
  820. }
  821. /** @return true if in incremental mode (command-line or file) */
  822. public boolean isInIncrementalMode() {
  823. return inIncrementalMode;
  824. }
  825. /** @return true if in incremental file mode */
  826. public boolean isInIncrementalFileMode() {
  827. return inIncrementalFileMode;
  828. }
  829. public void setArgfilesref(Reference ref) {
  830. createArgfiles().setRefid(ref);
  831. }
  832. public void setArgfiles(Path path) { // ajc-only eajc-also docDone
  833. argfiles = incPath(argfiles, path);
  834. }
  835. public Path createArgfiles() {
  836. if (argfiles == null) {
  837. argfiles = new Path(project);
  838. }
  839. return argfiles.createPath();
  840. }
  841. // ------------------------------ run
  842. /**
  843. * Compile using ajc per settings.
  844. * @exception BuildException if the compilation has problems
  845. * or if there were compiler errors and failonerror is true.
  846. */
  847. public void execute() throws BuildException {
  848. if (executing) {
  849. throw new IllegalStateException("already executing");
  850. } else {
  851. executing = true;
  852. }
  853. setupOptions();
  854. verifyOptions();
  855. try {
  856. String[] args = makeCommand();
  857. if (verbose || listFileArgs) { // XXX if listFileArgs, only do that
  858. log("ajc " + Arrays.asList(args), Project.MSG_VERBOSE);
  859. }
  860. if (!fork) {
  861. executeInSameVM(args);
  862. } else { // when forking, Adapter handles failonerror
  863. executeInOtherVM(args);
  864. }
  865. } catch (BuildException e) {
  866. throw e;
  867. } catch (Throwable x) {
  868. System.err.println(Main.renderExceptionForUser(x));
  869. throw new BuildException("IGNORE -- See "
  870. + LangUtil.unqualifiedClassName(x)
  871. + " rendered to System.err");
  872. } finally {
  873. executing = false;
  874. if (null != tmpOutjar) {
  875. tmpOutjar.delete();
  876. }
  877. }
  878. }
  879. /**
  880. * Halt processing.
  881. * This tells main in the same vm to quit.
  882. * It fails when running in forked mode.
  883. * @return true if not in forked mode
  884. * and main has quit or been told to quit
  885. */
  886. public boolean quit() {
  887. if (executingInOtherVM) {
  888. return false;
  889. }
  890. Main me = main;
  891. if (null != me) {
  892. me.quit();
  893. }
  894. return true;
  895. }
  896. // package-private for testing
  897. String[] makeCommand() {
  898. ArrayList result = new ArrayList();
  899. if (0 < ignored.size()) {
  900. for (Iterator iter = ignored.iterator(); iter.hasNext();) {
  901. log("ignored: " + iter.next(), Project.MSG_INFO);
  902. }
  903. }
  904. // when copying resources, use temp jar for class output
  905. // then copy temp jar contents and resources to output jar
  906. if ((null != outjar) && !outjarFixedup) {
  907. if (copyInjars || copyInpath || (null != sourceRootCopyFilter)
  908. || (null != inpathDirCopyFilter)) {
  909. String path = outjar.getAbsolutePath();
  910. int len = FileUtil.zipSuffixLength(path);
  911. if (len < 1) {
  912. log("not copying resources - weird outjar: " + path);
  913. } else {
  914. path = path.substring(0, path.length()-len) + ".tmp.jar";
  915. tmpOutjar = new File(path);
  916. }
  917. }
  918. if (null == tmpOutjar) {
  919. cmd.addFlagged("-outjar", outjar.getAbsolutePath());
  920. } else {
  921. cmd.addFlagged("-outjar", tmpOutjar.getAbsolutePath());
  922. }
  923. outjarFixedup = true;
  924. }
  925. result.addAll(cmd.extractArguments());
  926. addListArgs(result);
  927. String[] command = (String[]) result.toArray(new String[0]);
  928. if (null != commandEditor) {
  929. command = commandEditor.editCommand(command);
  930. } else if (null != COMMAND_EDITOR) {
  931. command = COMMAND_EDITOR.editCommand(command);
  932. }
  933. return command;
  934. }
  935. /**
  936. * Create any pseudo-options required to implement
  937. * some of the macro options
  938. * @throws BuildException if options conflict
  939. */
  940. protected void setupOptions() {
  941. if (null != xweaveDir) {
  942. if (DEFAULT_DESTDIR != destDir) {
  943. throw new BuildException("weaveDir forces destdir");
  944. }
  945. if (null != outjar) {
  946. throw new BuildException("weaveDir forces outjar");
  947. }
  948. if (null != injars) {
  949. throw new BuildException("weaveDir incompatible with injars now");
  950. }
  951. if (null != inpath) {
  952. throw new BuildException("weaveDir incompatible with inpath now");
  953. }
  954. File injar = zipDirectory(xweaveDir);
  955. setInjars(new Path(getProject(), injar.getAbsolutePath()));
  956. setDestdir(xweaveDir);
  957. }
  958. }
  959. protected File zipDirectory(File dir) {
  960. File tempDir = new File(".");
  961. try {
  962. tempDir = File.createTempFile("AjcTest", ".tmp");
  963. tempDir.mkdirs();
  964. tempDir.deleteOnExit(); // XXX remove zip explicitly..
  965. } catch (IOException e) {
  966. // ignore
  967. }
  968. // File result = new File(tempDir,
  969. String filename = "AjcTask-"
  970. + System.currentTimeMillis()
  971. + ".zip";
  972. File result = new File(filename);
  973. Zip zip = new Zip();
  974. zip.setProject(getProject());
  975. zip.setDestFile(result);
  976. zip.setTaskName(getTaskName() + " - zip");
  977. FileSet fileset = new FileSet();
  978. fileset.setDir(dir);
  979. zip.addFileset(fileset);
  980. zip.execute();
  981. Delete delete = new Delete();
  982. delete.setProject(getProject());
  983. delete.setTaskName(getTaskName() + " - delete");
  984. delete.setDir(dir);
  985. delete.execute();
  986. Mkdir mkdir = new Mkdir();
  987. mkdir.setProject(getProject());
  988. mkdir.setTaskName(getTaskName() + " - mkdir");
  989. mkdir.setDir(dir);
  990. mkdir.execute();
  991. return result;
  992. }
  993. /**
  994. * @throw BuildException if options conflict
  995. */
  996. protected void verifyOptions() {
  997. StringBuffer sb = new StringBuffer();
  998. if (fork && isInIncrementalMode() && !isInIncrementalFileMode()) {
  999. sb.append("can fork incremental only using tag file.\n");
  1000. }
  1001. if (((null != inpathDirCopyFilter) || (null != sourceRootCopyFilter))
  1002. && (null == outjar) && (DEFAULT_DESTDIR == destDir)) {
  1003. final String REQ = " requires dest dir or output jar.\n";
  1004. if (null == inpathDirCopyFilter) {
  1005. sb.append("sourceRootCopyFilter");
  1006. } else if (null == sourceRootCopyFilter) {
  1007. sb.append("inpathDirCopyFilter");
  1008. } else {
  1009. sb.append("sourceRootCopyFilter and inpathDirCopyFilter");
  1010. }
  1011. sb.append(REQ);
  1012. }
  1013. if (0 < sb.length()) {
  1014. throw new BuildException(sb.toString());
  1015. }
  1016. }
  1017. /**
  1018. * Run the compile in the same VM by
  1019. * loading the compiler (Main),
  1020. * setting up any message holders,
  1021. * doing the compile,
  1022. * and converting abort/failure and error messages
  1023. * to BuildException, as appropriate.
  1024. * @throws BuildException if abort or failure messages
  1025. * or if errors and failonerror.
  1026. *
  1027. */
  1028. protected void executeInSameVM(String[] args) {
  1029. PrintStream logStream = null;
  1030. if (null != maxMem) {
  1031. log("maxMem ignored unless forked: " + maxMem, Project.MSG_WARN);
  1032. }
  1033. IMessageHolder holder = messageHolder;
  1034. int numPreviousErrors;
  1035. if (null == holder) {
  1036. MessageHandler mhandler = new MessageHandler(true);
  1037. final IMessageHandler delegate;
  1038. if (!loggingMode){
  1039. delegate = verbose ? MessagePrinter.VERBOSE: MessagePrinter.TERSE;
  1040. }
  1041. else{
  1042. String logFileName = logFile.toString();
  1043. try {
  1044. logFile.createNewFile();
  1045. FileOutputStream fos = new FileOutputStream(logFileName, true);
  1046. logStream = new PrintStream(fos,true);
  1047. delegate = new LogModeMessagePrinter(verbose, logStream);
  1048. Date now = new Date();
  1049. logStream.println("Log started: " + now.toString());
  1050. } catch (IOException e){
  1051. if (logStream != null) {
  1052. logStream.close();
  1053. logStream = null;
  1054. }
  1055. throw new BuildException("Logfile couldn't be written to: ",e);
  1056. }
  1057. }
  1058. mhandler.setInterceptor(delegate);
  1059. if (!verbose) {
  1060. mhandler.ignore(IMessage.INFO);
  1061. }
  1062. holder = mhandler;
  1063. numPreviousErrors = 0;
  1064. } else {
  1065. numPreviousErrors = holder.numMessages(IMessage.ERROR, true);
  1066. }
  1067. {
  1068. Main newmain = new Main();
  1069. newmain.setHolder(holder);
  1070. newmain.setCompletionRunner(new Runnable() {
  1071. public void run() {
  1072. doCompletionTasks();
  1073. }
  1074. });
  1075. if (null != main) {
  1076. MessageUtil.fail(holder, "still running prior main");
  1077. return;
  1078. }
  1079. main = newmain;
  1080. }
  1081. try {
  1082. main.runMain(args, false);
  1083. } finally {
  1084. main = null;
  1085. if (logStream != null) {
  1086. logStream.close();
  1087. }
  1088. }
  1089. if (failonerror) {
  1090. int errs = holder.numMessages(IMessage.ERROR, false);
  1091. errs -= numPreviousErrors;
  1092. if (0 < errs) {
  1093. String m = errs + " errors";
  1094. MessageUtil.print(System.err, holder, "", MessageUtil.MESSAGE_ALL, MessageUtil.PICK_ERROR, true);
  1095. throw new BuildException(m);
  1096. }
  1097. }
  1098. // Throw BuildException if there are any fail or abort
  1099. // messages.
  1100. // The BuildException message text has a list of class names
  1101. // for the exceptions found in the messages, or the
  1102. // number of fail/abort messages found if there were
  1103. // no exceptions for any of the fail/abort messages.
  1104. // The interceptor message handler should have already
  1105. // printed the messages, including any stack traces.
  1106. // HACK: this ignores the Usage message
  1107. {
  1108. IMessage[] fails = holder.getMessages(IMessage.FAIL, true);
  1109. if (!LangUtil.isEmpty(fails)) {
  1110. StringBuffer sb = new StringBuffer();
  1111. String prefix = "fail due to ";
  1112. int numThrown = 0;
  1113. for (int i = 0; i < fails.length; i++) {
  1114. String message = fails[i].getMessage();
  1115. if (LangUtil.isEmpty(message)) {
  1116. message = "<no message>";
  1117. } else if (-1 != message.indexOf(USAGE_SUBSTRING)) {
  1118. continue;
  1119. }
  1120. Throwable t = fails[i].getThrown();
  1121. if (null != t) {
  1122. numThrown++;
  1123. sb.append(prefix);
  1124. sb.append(LangUtil.unqualifiedClassName(t.getClass()));
  1125. String thrownMessage = t.getMessage();
  1126. if (!LangUtil.isEmpty(thrownMessage)) {
  1127. sb.append(" \"" + thrownMessage + "\"");
  1128. }
  1129. }
  1130. sb.append("\"" + message + "\"");
  1131. prefix = ", ";
  1132. }
  1133. if (0 < sb.length()) {
  1134. sb.append(" (" + numThrown + " exceptions)");
  1135. throw new BuildException(sb.toString());
  1136. }
  1137. }
  1138. }
  1139. }
  1140. /**
  1141. * Execute in a separate VM.
  1142. * Differences from normal same-VM execution:
  1143. * <ul>
  1144. * <li>ignores any message holder {class} set</li>
  1145. * <li>No resource-copying between interative runs</li>
  1146. * <li>failonerror fails when process interface fails
  1147. * to return negative values</li>
  1148. * </ul>
  1149. * @param args String[] of the complete compiler command to execute
  1150. *
  1151. * @see DefaultCompilerAdapter#executeExternalCompile(String[], int)
  1152. * @throws BuildException if ajc aborts (negative value)
  1153. * or if failonerror and there were compile errors.
  1154. */
  1155. protected void executeInOtherVM(String[] args) {
  1156. if (null != messageHolder) {
  1157. log("message holder ignored when forking: "
  1158. + messageHolder.getClass().getName(), Project.MSG_WARN);
  1159. }
  1160. CommandlineJava javaCmd = new CommandlineJava();
  1161. javaCmd.setClassname(org.aspectj.tools.ajc.Main.class.getName());
  1162. final Path vmClasspath = javaCmd.createClasspath(getProject());
  1163. {
  1164. File aspectjtools = null;
  1165. int vmClasspathSize = vmClasspath.size();
  1166. if ((null != forkclasspath)
  1167. && (0 != forkclasspath.size())) {
  1168. vmClasspath.addExisting(forkclasspath);
  1169. } else {
  1170. aspectjtools = findAspectjtoolsJar();
  1171. if (null != aspectjtools) {
  1172. vmClasspath.createPathElement().setLocation(aspectjtools);
  1173. }
  1174. }
  1175. int newVmClasspathSize = vmClasspath.size();
  1176. if (vmClasspathSize == newVmClasspathSize) {
  1177. String m = "unable to find aspectjtools to fork - ";
  1178. if (null != aspectjtools) {
  1179. m += "tried " + aspectjtools.toString();
  1180. } else if (null != forkclasspath) {
  1181. m += "tried " + forkclasspath.toString();
  1182. } else {
  1183. m += "define forkclasspath or put aspectjtools on classpath";
  1184. }
  1185. throw new BuildException(m);
  1186. }
  1187. }
  1188. if (null != maxMem) {
  1189. javaCmd.setMaxmemory(maxMem);
  1190. }
  1191. File tempFile = null;
  1192. int numArgs = args.length;
  1193. args = GuardedCommand.limitTo(args, MAX_COMMANDLINE, getLocation());
  1194. if (args.length != numArgs) {
  1195. tempFile = new File(args[1]);
  1196. }
  1197. try {
  1198. String[] javaArgs = javaCmd.getCommandline();
  1199. String[] both = new String[javaArgs.length + args.length];
  1200. System.arraycopy(javaArgs,0,both,0,javaArgs.length);
  1201. System.arraycopy(args,0,both,javaArgs.length,args.length);
  1202. // try to use javaw instead on windows
  1203. if (both[0].endsWith("java.exe")) {
  1204. String path = both[0];
  1205. path = path.substring(0, path.length()-4);
  1206. path = path + "w.exe";
  1207. File javaw = new File(path);
  1208. if (javaw.canRead() && javaw.isFile()) {
  1209. both[0] = path;
  1210. }
  1211. }
  1212. if (verbose) { // XXX also when ant is verbose...
  1213. log("forking " + Arrays.asList(both));
  1214. }
  1215. int result = execInOtherVM(both);
  1216. if (0 > result) {
  1217. throw new BuildException("failure[" + result + "] running ajc");
  1218. } else if (failonerror && (0 < result)) {
  1219. throw new BuildException("compile errors: " + result);
  1220. }
  1221. // when forking, do completion only at end and when successful
  1222. doCompletionTasks();
  1223. } finally {
  1224. if (null != tempFile) {
  1225. tempFile.delete();
  1226. }
  1227. }
  1228. }
  1229. /**
  1230. * Execute in another process using the same JDK
  1231. * and the base directory of the project. XXX correct?
  1232. * @param args
  1233. * @return
  1234. */
  1235. protected int execInOtherVM(String[] args) {
  1236. try {
  1237. Project project = getProject();
  1238. LogStreamHandler handler = new LogStreamHandler(this,
  1239. Project.MSG_INFO, Project.MSG_WARN);
  1240. // replace above two lines with what follows as an aid to debugging when running the unit tests....
  1241. // LogStreamHandler handler = new LogStreamHandler(this,
  1242. // Project.MSG_INFO, Project.MSG_WARN) {
  1243. //
  1244. // ByteArrayOutputStream baos = new ByteArrayOutputStream();
  1245. // /* (non-Javadoc)
  1246. // * @see org.apache.tools.ant.taskdefs.PumpStreamHandler#createProcessOutputPump(java.io.InputStream, java.io.OutputStream)
  1247. // */
  1248. // protected void createProcessErrorPump(InputStream is,
  1249. // OutputStream os) {
  1250. // super.createProcessErrorPump(is, baos);
  1251. // }
  1252. //
  1253. // /* (non-Javadoc)
  1254. // * @see org.apache.tools.ant.taskdefs.LogStreamHandler#stop()
  1255. // */
  1256. // public void stop() {
  1257. // byte[] written = baos.toByteArray();
  1258. // System.err.print(new String(written));
  1259. // super.stop();
  1260. // }
  1261. // };
  1262. Execute exe = new Execute(handler);
  1263. exe.setAntRun(project);
  1264. exe.setWorkingDirectory(project.getBaseDir());
  1265. exe.setCommandline(args);
  1266. try {
  1267. if (executingInOtherVM) {
  1268. String s = "already running in other vm?";
  1269. throw new BuildException(s, location);
  1270. }
  1271. executingInOtherVM = true;
  1272. exe.execute();
  1273. } finally {
  1274. executingInOtherVM = false;
  1275. }
  1276. return exe.getExitValue();
  1277. } catch (IOException e) {
  1278. String m = "Error executing command " + Arrays.asList(args);
  1279. throw new BuildException(m, e, location);
  1280. }
  1281. }
  1282. // ------------------------------ setup and reporting
  1283. /** @return null if path null or empty, String rendition otherwise */
  1284. protected static void addFlaggedPath(String flag, Path path, List list) {
  1285. if (!LangUtil.isEmpty(flag)
  1286. && ((null != path) && (0 < path.size()))) {
  1287. list.add(flag);
  1288. list.add(path.toString());
  1289. }
  1290. }
  1291. /**
  1292. * Add to list any path or plural arguments.
  1293. */
  1294. protected void addListArgs(List list) throws BuildException {
  1295. addFlaggedPath("-classpath", classpath, list);
  1296. addFlaggedPath("-bootclasspath", bootclasspath, list);
  1297. addFlaggedPath("-extdirs", extdirs, list);
  1298. addFlaggedPath("-aspectpath", aspectpath, list);
  1299. addFlaggedPath("-injars", injars, list);
  1300. addFlaggedPath("-inpath", inpath, list);
  1301. addFlaggedPath("-sourceroots", sourceRoots, list);
  1302. if (argfiles != null) {
  1303. String[] files = argfiles.list();
  1304. for (int i = 0; i < files.length; i++) {
  1305. File argfile = project.resolveFile(files[i]);
  1306. if (check(argfile, files[i], false, location)) {
  1307. list.add("-argfile");
  1308. list.add(argfile.getAbsolutePath());
  1309. }
  1310. }
  1311. }
  1312. if (srcdir != null) {
  1313. // todo: ignore any srcdir if any argfiles and no explicit includes
  1314. String[] dirs = srcdir.list();
  1315. for (int i = 0; i < dirs.length; i++) {
  1316. File dir = project.resolveFile(dirs[i]);
  1317. check(dir, dirs[i], true, location);
  1318. // relies on compiler to prune non-source files
  1319. String[] files = getDirectoryScanner(dir).getIncludedFiles();
  1320. for (int j = 0; j < files.length; j++) {
  1321. File file = new File(dir, files[j]);
  1322. if (FileUtil.hasSourceSuffix(file)) {
  1323. list.add(file.getAbsolutePath());
  1324. }
  1325. }
  1326. }
  1327. }
  1328. if (0 < adapterFiles.size()) {
  1329. for (Iterator iter = adapterFiles.iterator(); iter.hasNext();) {
  1330. File file = (File) iter.next();
  1331. if (file.canRead() && FileUtil.hasSourceSuffix(file)) {
  1332. list.add(file.getAbsolutePath());
  1333. } else {
  1334. log("skipping file: " + file, Project.MSG_WARN);
  1335. }
  1336. }
  1337. }
  1338. }
  1339. /**
  1340. * Throw BuildException unless file is valid.
  1341. * @param file the File to check
  1342. * @param name the symbolic name to print on error
  1343. * @param isDir if true, verify file is a directory
  1344. * @param loc the Location used to create sensible BuildException
  1345. * @return
  1346. * @throws BuildException unless file valid
  1347. */
  1348. protected final boolean check(File file, String name,
  1349. boolean isDir, Location loc) {
  1350. loc = loc != null ? loc : location;
  1351. if (file == null) {
  1352. throw new BuildException(name + " is null!", loc);
  1353. }
  1354. if (!file.exists()) {
  1355. throw new BuildException(file + " doesn't exist!", loc);
  1356. }
  1357. if (isDir ^ file.isDirectory()) {
  1358. String e = file + " should" + (isDir ? "" : "n't") +
  1359. " be a directory!";
  1360. throw new BuildException(e, loc);
  1361. }
  1362. return true;
  1363. }
  1364. /**
  1365. * Called when compile or incremental compile is completing,
  1366. * this completes the output jar or directory
  1367. * by copying resources if requested.
  1368. * Note: this is a callback run synchronously by the compiler.
  1369. * That means exceptions thrown here are caught by Main.run(..)
  1370. * and passed to the message handler.
  1371. */
  1372. protected void doCompletionTasks() {
  1373. if (!executing) {
  1374. throw new IllegalStateException("should be executing");
  1375. }
  1376. if (null != outjar) {
  1377. completeOutjar();
  1378. } else {
  1379. completeDestdir();
  1380. }
  1381. if (null != xdoneSignal) {
  1382. MessageUtil.info(messageHolder, xdoneSignal);
  1383. }
  1384. }
  1385. /**
  1386. * Complete the destination directory
  1387. * by copying resources from the source root directories
  1388. * (if the filter is specified)
  1389. * and non-.class files from the input jars
  1390. * (if XCopyInjars is enabled).
  1391. */
  1392. private void completeDestdir() {
  1393. if (!copyInjars && (null == sourceRootCopyFilter)
  1394. && (null == inpathDirCopyFilter)) {
  1395. return;
  1396. } else if ((destDir == DEFAULT_DESTDIR)
  1397. || !destDir.canWrite()) {
  1398. String s = "unable to copy resources to destDir: " + destDir;
  1399. throw new BuildException(s);
  1400. }
  1401. final Project project = getProject();
  1402. if (copyInjars) { // XXXX remove as unused since 1.1.1
  1403. if (null != inpath) {
  1404. log("copyInjars does not support inpath.\n", Project.MSG_WARN);
  1405. }
  1406. String taskName = getTaskName() + " - unzip";
  1407. String[] paths = injars.list();
  1408. if (!LangUtil.isEmpty(paths)) {
  1409. PatternSet patternSet = new PatternSet();
  1410. patternSet.setProject(project);
  1411. patternSet.setIncludes("**/*");
  1412. patternSet.setExcludes("**/*.class");
  1413. for (int i = 0; i < paths.length; i++) {
  1414. Expand unzip = new Expand();
  1415. unzip.setProject(project);
  1416. unzip.setTaskName(taskName);
  1417. unzip.setDest(destDir);
  1418. unzip.setSrc(new File(paths[i]));
  1419. unzip.addPatternset(patternSet);
  1420. unzip.execute();
  1421. }
  1422. }
  1423. }
  1424. if ((null != sourceRootCopyFilter) && (null != sourceRoots)) {
  1425. String[] paths = sourceRoots.list();
  1426. if (!LangUtil.isEmpty(paths)) {
  1427. Copy copy = new Copy();
  1428. copy.setProject(project);
  1429. copy.setTodir(destDir);
  1430. for (int i = 0; i < paths.length; i++) {
  1431. FileSet fileSet = new FileSet();
  1432. fileSet.setDir(new File(paths[i]));
  1433. fileSet.setIncludes("**/*");
  1434. fileSet.setExcludes(sourceRootCopyFilter);
  1435. copy.addFileset(fileSet);
  1436. }
  1437. copy.execute();
  1438. }
  1439. }
  1440. if ((null != inpathDirCopyFilter) && (null != inpath)) {
  1441. String[] paths = inpath.list();
  1442. if (!LangUtil.isEmpty(paths)) {
  1443. Copy copy = new Copy();
  1444. copy.setProject(project);
  1445. copy.setTodir(destDir);
  1446. boolean gotDir = false;
  1447. for (int i = 0; i < paths.length; i++) {
  1448. File inpathDir = new File(paths[i]);
  1449. if (inpathDir.isDirectory() && inpathDir.canRead()) {
  1450. if (!gotDir) {
  1451. gotDir = true;
  1452. }
  1453. FileSet fileSet = new FileSet();
  1454. fileSet.setDir(inpathDir);
  1455. fileSet.setIncludes("**/*");
  1456. fileSet.setExcludes(inpathDirCopyFilter);
  1457. copy.addFileset(fileSet);
  1458. }
  1459. }
  1460. if (gotDir) {
  1461. copy.execute();
  1462. }
  1463. }
  1464. }
  1465. }
  1466. /**
  1467. * Complete the output jar
  1468. * by copying resources from the source root directories
  1469. * if the filter is specified.
  1470. * and non-.class files from the input jars if enabled.
  1471. */
  1472. private void completeOutjar() {
  1473. if (((null == tmpOutjar) || !tmpOutjar.canRead())
  1474. || (!copyInjars && (null == sourceRootCopyFilter)
  1475. && (null == inpathDirCopyFilter))) {
  1476. return;
  1477. }
  1478. Zip zip = new Zip();
  1479. Project project = getProject();
  1480. zip.setProject(project);
  1481. zip.setTaskName(getTaskName() + " - zip");
  1482. zip.setDestFile(outjar);
  1483. ZipFileSet zipfileset = new ZipFileSet();
  1484. zipfileset.setProject(project);
  1485. zipfileset.setSrc(tmpOutjar);
  1486. zipfileset.setIncludes("**/*.class");
  1487. zip.addZipfileset(zipfileset);
  1488. if (copyInjars) {
  1489. String[] paths = injars.list();
  1490. if (!LangUtil.isEmpty(paths)) {
  1491. for (int i = 0; i < paths.length; i++) {
  1492. File jarFile = new File(paths[i]);
  1493. zipfileset = new ZipFileSet();
  1494. zipfileset.setProject(project);
  1495. zipfileset.setSrc(jarFile);
  1496. zipfileset.setIncludes("**/*");
  1497. zipfileset.setExcludes("**/*.class");
  1498. zip.addZipfileset(zipfileset);
  1499. }
  1500. }
  1501. }
  1502. if ((null != sourceRootCopyFilter) && (null != sourceRoots)) {
  1503. String[] paths = sourceRoots.list();
  1504. if (!LangUtil.isEmpty(paths)) {
  1505. for (int i = 0; i < paths.length; i++) {
  1506. File srcRoot = new File(paths[i]);
  1507. FileSet fileset = new FileSet();
  1508. fileset.setProject(project);
  1509. fileset.setDir(srcRoot);
  1510. fileset.setIncludes("**/*");
  1511. fileset.setExcludes(sourceRootCopyFilter);
  1512. zip.addFileset(fileset);
  1513. }
  1514. }
  1515. }
  1516. if ((null != inpathDirCopyFilter) && (null != inpath)) {
  1517. String[] paths = inpath.list();
  1518. if (!LangUtil.isEmpty(paths)) {
  1519. for (int i = 0; i < paths.length; i++) {
  1520. File inpathDir = new File(paths[i]);
  1521. if (inpathDir.isDirectory() && inpathDir.canRead()) {
  1522. FileSet fileset = new FileSet();
  1523. fileset.setProject(project);
  1524. fileset.setDir(inpathDir);
  1525. fileset.setIncludes("**/*");
  1526. fileset.setExcludes(inpathDirCopyFilter);
  1527. zip.addFileset(fileset);
  1528. }
  1529. }
  1530. }
  1531. }
  1532. zip.execute();
  1533. }
  1534. // -------------------------- compiler adapter interface extras
  1535. /**
  1536. * Add specified source files.
  1537. */
  1538. void addFiles(File[] paths) {
  1539. for (int i = 0; i < paths.length; i++) {
  1540. addFile(paths[i]);
  1541. }
  1542. }
  1543. /**
  1544. * Add specified source file.
  1545. */
  1546. void addFile(File path) {
  1547. if (null != path) {
  1548. adapterFiles.add(path);
  1549. }
  1550. }
  1551. /**
  1552. * Read arguments in as if from a command line,
  1553. * mainly to support compiler adapter compilerarg subelement.
  1554. *
  1555. * @param args the String[] of arguments to read
  1556. */
  1557. public void readArguments(String[] args) { // XXX slow, stupid, unmaintainable
  1558. if ((null == args) || (0 == args.length)) {
  1559. return;
  1560. }
  1561. /** String[] wrapper with increment, error reporting */
  1562. class Args {
  1563. final String[] args;
  1564. int index = 0;
  1565. Args(String[] args) {
  1566. this.args = args; // not null or empty
  1567. }
  1568. boolean hasNext() {
  1569. return index < args.length;
  1570. }
  1571. String next() {
  1572. String err = null;
  1573. if (!hasNext()) {
  1574. err = "need arg for flag " + args[args.length-1];
  1575. } else {
  1576. String s = args[index++];
  1577. if (null == s) {
  1578. err = "null value";
  1579. } else {
  1580. s = s.trim();
  1581. if (0 == s.trim().length()) {
  1582. err = "no value";
  1583. } else {
  1584. return s;
  1585. }
  1586. }
  1587. }
  1588. err += " at [" + index + "] of " + Arrays.asList(args);
  1589. throw new BuildException(err);
  1590. }
  1591. } // class Args
  1592. Args in = new Args(args);
  1593. String flag;
  1594. while (in.hasNext()) {
  1595. flag = in.next();
  1596. if ("-1.3".equals(flag)) {
  1597. setCompliance(flag);
  1598. } else if ("-1.4".equals(flag)) {
  1599. setCompliance(flag);
  1600. } else if ("-1.5".equals(flag)) {
  1601. setCompliance("1.5");
  1602. } else if ("-argfile".equals(flag)) {
  1603. setArgfiles(new Path(project, in.next()));
  1604. } else if ("-aspectpath".equals(flag)) {
  1605. setAspectpath(new Path(project, in.next()));
  1606. } else if ("-classpath".equals(flag)) {
  1607. setClasspath(new Path(project, in.next()));
  1608. } else if ("-extdirs".equals(flag)) {
  1609. setExtdirs(new Path(project, in.next()));
  1610. } else if ("-Xcopyinjars".equals(flag)) {
  1611. setCopyInjars(true); // ignored - will be flagged by setter
  1612. } else if ("-g".equals(flag)) {
  1613. setDebug(true);
  1614. } else if (flag.startsWith("-g:")) {
  1615. setDebugLevel(flag.substring(2));
  1616. } else if ("-deprecation".equals(flag)) {
  1617. setDeprecation(true);
  1618. } else if ("-d".equals(flag)) {
  1619. setDestdir(new File(in.next()));
  1620. } else if ("-emacssym".equals(flag)) {
  1621. setEmacssym(true);
  1622. } else if ("-encoding".equals(flag)) {
  1623. setEncoding(in.next());
  1624. } else if ("-Xfailonerror".equals(flag)) {
  1625. setFailonerror(true);
  1626. } else if ("-fork".equals(flag)) {
  1627. setFork(true);
  1628. } else if ("-forkclasspath".equals(flag)) {
  1629. setForkclasspath(new Path(project, in.next()));
  1630. } else if ("-help".equals(flag)) {
  1631. setHelp(true);
  1632. } else if ("-incremental".equals(flag)) {
  1633. setIncremental(true);
  1634. } else if ("-injars".equals(flag)) {
  1635. setInjars(new Path(project, in.next()));
  1636. } else if ("-inpath".equals(flag)) {
  1637. setInpath(new Path(project,in.next()));
  1638. } else if ("-Xlistfileargs".equals(flag)) {
  1639. setListFileArgs(true);
  1640. } else if ("-Xmaxmem".equals(flag)) {
  1641. setMaxmem(in.next());
  1642. } else if ("-Xmessageholderclass".equals(flag)) {
  1643. setMessageHolderClass(in.next());
  1644. } else if ("-noexit".equals(flag)) {
  1645. setNoExit(true);
  1646. } else if ("-noimport".equals(flag)) {
  1647. setNoExit(true);
  1648. } else if ("-noExit".equals(flag)) {
  1649. setNoExit(true);
  1650. } else if ("-noImportError".equals(flag)) {
  1651. setNoImportError(true);
  1652. } else if ("-noWarn".equals(flag)) {
  1653. setNowarn(true);
  1654. } else if ("-noexit".equals(flag)) {
  1655. setNoExit(true);
  1656. } else if ("-outjar".equals(flag)) {
  1657. setOutjar(new File(in.next()));
  1658. } else if ("-preserveAllLocals".equals(flag)) {
  1659. setPreserveAllLocals(true);
  1660. } else if ("-proceedOnError".equals(flag)) {
  1661. setProceedOnError(true);
  1662. } else if ("-referenceInfo".equals(flag)) {
  1663. setReferenceInfo(true);
  1664. } else if ("-source".equals(flag)) {
  1665. setSource(in.next());
  1666. } else if ("-Xsourcerootcopyfilter".equals(flag)) {
  1667. setSourceRootCopyFilter(in.next());
  1668. } else if ("-sourceroots".equals(flag)) {
  1669. setSourceRoots(new Path(project, in.next()));
  1670. } else if ("-Xsrcdir".equals(flag)) {
  1671. setSrcDir(new Path(project, in.next()));
  1672. } else if ("-Xtagfile".equals(flag)) {
  1673. setTagFile(new File(in.next()));
  1674. } else if ("-target".equals(flag)) {
  1675. setTarget(in.next());
  1676. } else if ("-time".equals(flag)) {
  1677. setTime(true);
  1678. } else if ("-time".equals(flag)) {
  1679. setTime(true);
  1680. } else if ("-verbose".equals(flag)) {
  1681. setVerbose(true);
  1682. } else if ("-showWeaveInfo".equals(flag)) {
  1683. setShowWeaveInfo(true);
  1684. } else if ("-version".equals(flag)) {
  1685. setVersion(true);
  1686. } else if ("-warn".equals(flag)) {
  1687. setWarn(in.next());
  1688. } else if (flag.startsWith("-warn:")) {
  1689. setWarn(flag.substring(6));
  1690. } else if ("-Xlint".equals(flag)) {
  1691. setXlintwarnings(true);
  1692. } else if (flag.startsWith("-Xlint:")) {
  1693. setXlint(flag.substring(7));
  1694. } else if ("-Xlintfile".equals(flag)) {
  1695. setXlintfile(new File(in.next()));
  1696. } else if ("-Xnoweave".equals(flag)) {
  1697. setXNoweave(true);
  1698. } else if ("-Xreweavable".equals(flag)) {
  1699. setXReweavable(true);
  1700. } else if (flag.startsWith("@")) {
  1701. File file = new File(flag.substring(1));
  1702. if (file.canRead()) {
  1703. setArgfiles(new Path(project, file.getPath()));
  1704. } else {
  1705. ignore(flag);
  1706. }
  1707. } else {
  1708. File file = new File(flag);
  1709. if (file.isFile()
  1710. && file.canRead()
  1711. && FileUtil.hasSourceSuffix(file)) {
  1712. addFile(file);
  1713. } else {
  1714. ignore(flag);
  1715. }
  1716. }
  1717. }
  1718. }
  1719. /**
  1720. * Commandline wrapper that
  1721. * only permits addition of non-empty values
  1722. * and converts to argfile form if necessary.
  1723. */
  1724. public static class GuardedCommand {
  1725. Commandline command;
  1726. //int size;
  1727. static boolean isEmpty(String s) {
  1728. return ((null == s) || (0 == s.trim().length()));
  1729. }
  1730. GuardedCommand() {
  1731. command = new Commandline();
  1732. }
  1733. void addFlag(String flag, boolean doAdd) {
  1734. if (doAdd && !isEmpty(flag)) {
  1735. command.createArgument().setValue(flag);
  1736. //size += 1 + flag.length();
  1737. }
  1738. }
  1739. /** @return null if added or ignoreString otherwise */
  1740. String addOption(String prefix, String[] validOptions, String input) {
  1741. if (isEmpty(input)) {
  1742. return null;
  1743. }
  1744. for (int i = 0; i < validOptions.length; i++) {
  1745. if (input.equals(validOptions[i])) {
  1746. if (isEmpty(prefix)) {
  1747. addFlag(input, true);
  1748. } else {
  1749. addFlagged(prefix, input);
  1750. }
  1751. return null;
  1752. }
  1753. }
  1754. return (null == prefix ? input : prefix + " " + input);
  1755. }
  1756. void addFlagged(String flag, String argument) {
  1757. if (!isEmpty(flag) && !isEmpty(argument)) {
  1758. command.addArguments(new String[] {flag, argument});
  1759. //size += 1 + flag.length() + argument.length();
  1760. }
  1761. }
  1762. // private void addFile(File file) {
  1763. // if (null != file) {
  1764. // String path = file.getAbsolutePath();
  1765. // addFlag(path, true);
  1766. // }
  1767. // }
  1768. List extractArguments() {
  1769. ArrayList result = new ArrayList();
  1770. String[] cmds = command.getArguments();
  1771. if (!LangUtil.isEmpty(cmds)) {
  1772. result.addAll(Arrays.asList(cmds));
  1773. }
  1774. return result;
  1775. }
  1776. /**
  1777. * Adjust args for size if necessary by creating
  1778. * an argument file, which should be deleted by the client
  1779. * after the compiler run has completed.
  1780. * @param max the int maximum length of the command line (in char)
  1781. * @return the temp File for the arguments (if generated),
  1782. * for deletion when done.
  1783. * @throws IllegalArgumentException if max is negative
  1784. */
  1785. static String[] limitTo(String[] args, int max,
  1786. Location location) {
  1787. if (max < 0) {
  1788. throw new IllegalArgumentException("negative max: " + max);
  1789. }
  1790. // sigh - have to count anyway for now
  1791. int size = 0;
  1792. for (int i = 0; (i < args.length) && (size < max); i++) {
  1793. size += 1 + (null == args[i] ? 0 : args[i].length());
  1794. }
  1795. if (size <= max) {
  1796. return args;
  1797. }
  1798. File tmpFile = null;
  1799. PrintWriter out = null;
  1800. // adapted from DefaultCompilerAdapter.executeExternalCompile
  1801. try {
  1802. String userDirName = System.getProperty("user.dir");
  1803. File userDir = new File(userDirName);
  1804. tmpFile = File.createTempFile("argfile", "", userDir);
  1805. out = new PrintWriter(new FileWriter(tmpFile));
  1806. for (int i = 0; i < args.length; i++) {
  1807. out.println(args[i]);
  1808. }
  1809. out.flush();
  1810. return new String[] {"-argfile", tmpFile.getAbsolutePath()};
  1811. } catch (IOException e) {
  1812. throw new BuildException("Error creating temporary file",
  1813. e, location);
  1814. } finally {
  1815. if (out != null) {
  1816. try {out.close();} catch (Throwable t) {}
  1817. }
  1818. }
  1819. }
  1820. }
  1821. }