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.

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