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

Javac.java 54 kB

8 years ago
8 years ago
8 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
8 years ago
11 years ago
11 years ago
11 years ago
8 years ago
11 years ago
8 years ago
11 years ago
11 years ago
7 years ago
8 years ago
11 years ago
11 years ago
11 years ago
8 years ago
8 years ago
8 years ago
11 years ago
8 years ago
11 years ago
11 years ago
8 years ago
11 years ago
11 years ago
8 years ago
11 years ago
11 years ago
11 years ago
8 years ago
11 years ago
11 years ago
11 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * https://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package org.apache.tools.ant.taskdefs;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.nio.charset.StandardCharsets;
  23. import java.nio.file.Files;
  24. import java.util.ArrayList;
  25. import java.util.Collection;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.TreeMap;
  30. import org.apache.tools.ant.BuildException;
  31. import org.apache.tools.ant.DirectoryScanner;
  32. import org.apache.tools.ant.MagicNames;
  33. import org.apache.tools.ant.Project;
  34. import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter;
  35. import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterExtension;
  36. import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory;
  37. import org.apache.tools.ant.types.Path;
  38. import org.apache.tools.ant.types.Reference;
  39. import org.apache.tools.ant.util.FileUtils;
  40. import org.apache.tools.ant.util.GlobPatternMapper;
  41. import org.apache.tools.ant.util.JavaEnvUtils;
  42. import org.apache.tools.ant.util.SourceFileScanner;
  43. import org.apache.tools.ant.util.facade.FacadeTaskHelper;
  44. /**
  45. * Compiles Java source files. This task can take the following
  46. * arguments:
  47. * <ul>
  48. * <li>sourcedir
  49. * <li>destdir
  50. * <li>deprecation
  51. * <li>classpath
  52. * <li>bootclasspath
  53. * <li>extdirs
  54. * <li>optimize
  55. * <li>debug
  56. * <li>encoding
  57. * <li>target
  58. * <li>depend
  59. * <li>verbose
  60. * <li>failonerror
  61. * <li>includeantruntime
  62. * <li>includejavaruntime
  63. * <li>source
  64. * <li>compiler
  65. * <li>release
  66. * </ul>
  67. * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required.
  68. * <p>
  69. * When this task executes, it will recursively scan the sourcedir and
  70. * destdir looking for Java source files to compile. This task makes its
  71. * compile decision based on timestamp.
  72. *
  73. *
  74. * @since Ant 1.1
  75. *
  76. * @ant.task category="java"
  77. */
  78. public class Javac extends MatchingTask {
  79. private static final String FAIL_MSG
  80. = "Compile failed; see the compiler error output for details.";
  81. private static final char GROUP_START_MARK = '{'; //modulesourcepath group start character
  82. private static final char GROUP_END_MARK = '}'; //modulesourcepath group end character
  83. private static final char GROUP_SEP_MARK = ','; //modulesourcepath group element separator character
  84. private static final String MODULE_MARKER = "*"; //modulesourcepath module name marker
  85. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  86. private Path src;
  87. private File destDir;
  88. private File nativeHeaderDir;
  89. private Path compileClasspath;
  90. private Path modulepath;
  91. private Path upgrademodulepath;
  92. private Path compileSourcepath;
  93. private Path moduleSourcepath;
  94. private String encoding;
  95. private boolean debug = false;
  96. private boolean optimize = false;
  97. private boolean deprecation = false;
  98. private boolean depend = false;
  99. private boolean verbose = false;
  100. private String targetAttribute;
  101. private String release;
  102. private Path bootclasspath;
  103. private Path extdirs;
  104. private Boolean includeAntRuntime;
  105. private boolean includeJavaRuntime = false;
  106. private boolean fork = false;
  107. private String forkedExecutable = null;
  108. private boolean nowarn = false;
  109. private String memoryInitialSize;
  110. private String memoryMaximumSize;
  111. private FacadeTaskHelper facade = null;
  112. // CheckStyle:VisibilityModifier OFF - bc
  113. protected boolean failOnError = true;
  114. protected boolean listFiles = false;
  115. protected File[] compileList = new File[0];
  116. private Map<String, Long> packageInfos = new HashMap<>();
  117. // CheckStyle:VisibilityModifier ON
  118. private String source;
  119. private String debugLevel;
  120. private File tmpDir;
  121. private String updatedProperty;
  122. private String errorProperty;
  123. private boolean taskSuccess = true; // assume the best
  124. private boolean includeDestClasses = true;
  125. private CompilerAdapter nestedAdapter = null;
  126. private boolean createMissingPackageInfoClass = true;
  127. /**
  128. * Javac task for compilation of Java files.
  129. */
  130. public Javac() {
  131. facade = new FacadeTaskHelper(assumedJavaVersion());
  132. }
  133. private String assumedJavaVersion() {
  134. if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_8)) {
  135. return CompilerAdapterFactory.COMPILER_JAVAC_1_8;
  136. }
  137. if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_9)) {
  138. return CompilerAdapterFactory.COMPILER_JAVAC_9;
  139. }
  140. if (JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_10)) {
  141. return CompilerAdapterFactory.COMPILER_JAVAC_10_PLUS;
  142. }
  143. // as we are assumed to be 1.8+ and classic refers to the really old ones, default to modern
  144. return CompilerAdapterFactory.COMPILER_MODERN;
  145. }
  146. /**
  147. * Get the value of debugLevel.
  148. * @return value of debugLevel.
  149. */
  150. public String getDebugLevel() {
  151. return debugLevel;
  152. }
  153. /**
  154. * Keyword list to be appended to the -g command-line switch.
  155. *
  156. * This will be ignored by all implementations except modern
  157. * and classic(ver &gt;= 1.2). Legal values are none or a
  158. * comma-separated list of the following keywords: lines, vars,
  159. * and source. If debuglevel is not specified, by default, :none
  160. * will be appended to -g. If debug is not turned on, this attribute
  161. * will be ignored.
  162. *
  163. * @param v Value to assign to debugLevel.
  164. */
  165. public void setDebugLevel(final String v) {
  166. this.debugLevel = v;
  167. }
  168. /**
  169. * Get the value of source.
  170. * @return value of source.
  171. */
  172. public String getSource() {
  173. return source != null
  174. ? source : getProject().getProperty(MagicNames.BUILD_JAVAC_SOURCE);
  175. }
  176. /**
  177. * Value of the -source command-line switch; will be ignored by
  178. * all implementations except modern, jikes and gcj (gcj uses
  179. * -fsource).
  180. *
  181. * <p>If you use this attribute together with jikes or gcj, you
  182. * must make sure that your version of jikes supports the -source
  183. * switch.</p>
  184. *
  185. * <p>Legal values are 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, and any integral number bigger than 4
  186. * - by default, no -source argument will be used at all.</p>
  187. *
  188. * @param v Value to assign to source.
  189. */
  190. public void setSource(final String v) {
  191. this.source = v;
  192. }
  193. /**
  194. * Adds a path for source compilation.
  195. *
  196. * @return a nested src element.
  197. */
  198. public Path createSrc() {
  199. if (src == null) {
  200. src = new Path(getProject());
  201. }
  202. return src.createPath();
  203. }
  204. /**
  205. * Recreate src.
  206. *
  207. * @return a nested src element.
  208. */
  209. protected Path recreateSrc() {
  210. src = null;
  211. return createSrc();
  212. }
  213. /**
  214. * Set the source directories to find the source Java files.
  215. * @param srcDir the source directories as a path
  216. */
  217. public void setSrcdir(final Path srcDir) {
  218. if (src == null) {
  219. src = srcDir;
  220. } else {
  221. src.append(srcDir);
  222. }
  223. }
  224. /**
  225. * Gets the source dirs to find the source java files.
  226. * @return the source directories as a path
  227. */
  228. public Path getSrcdir() {
  229. return src;
  230. }
  231. /**
  232. * Set the destination directory into which the Java source
  233. * files should be compiled.
  234. * @param destDir the destination director
  235. */
  236. public void setDestdir(final File destDir) {
  237. this.destDir = destDir;
  238. }
  239. /**
  240. * Gets the destination directory into which the java source files
  241. * should be compiled.
  242. * @return the destination directory
  243. */
  244. public File getDestdir() {
  245. return destDir;
  246. }
  247. /**
  248. * Set the destination directory into which the generated native
  249. * header files should be placed.
  250. * @param nhDir where to place generated native header files
  251. * @since Ant 1.9.8
  252. */
  253. public void setNativeHeaderDir(final File nhDir) {
  254. this.nativeHeaderDir = nhDir;
  255. }
  256. /**
  257. * Gets the destination directory into which the generated native
  258. * header files should be placed.
  259. * @return where to place generated native header files
  260. * @since Ant 1.9.8
  261. */
  262. public File getNativeHeaderDir() {
  263. return nativeHeaderDir;
  264. }
  265. /**
  266. * Set the sourcepath to be used for this compilation.
  267. * @param sourcepath the source path
  268. */
  269. public void setSourcepath(final Path sourcepath) {
  270. if (compileSourcepath == null) {
  271. compileSourcepath = sourcepath;
  272. } else {
  273. compileSourcepath.append(sourcepath);
  274. }
  275. }
  276. /**
  277. * Gets the sourcepath to be used for this compilation.
  278. * @return the source path
  279. */
  280. public Path getSourcepath() {
  281. return compileSourcepath;
  282. }
  283. /**
  284. * Adds a path to sourcepath.
  285. * @return a sourcepath to be configured
  286. */
  287. public Path createSourcepath() {
  288. if (compileSourcepath == null) {
  289. compileSourcepath = new Path(getProject());
  290. }
  291. return compileSourcepath.createPath();
  292. }
  293. /**
  294. * Adds a reference to a source path defined elsewhere.
  295. * @param r a reference to a source path
  296. */
  297. public void setSourcepathRef(final Reference r) {
  298. createSourcepath().setRefid(r);
  299. }
  300. /**
  301. * Set the modulesourcepath to be used for this compilation.
  302. * @param msp the modulesourcepath
  303. * @since 1.9.7
  304. */
  305. public void setModulesourcepath(final Path msp) {
  306. if (moduleSourcepath == null) {
  307. moduleSourcepath = msp;
  308. } else {
  309. moduleSourcepath.append(msp);
  310. }
  311. }
  312. /**
  313. * Gets the modulesourcepath to be used for this compilation.
  314. * @return the modulesourcepath
  315. * @since 1.9.7
  316. */
  317. public Path getModulesourcepath() {
  318. return moduleSourcepath;
  319. }
  320. /**
  321. * Adds a path to modulesourcepath.
  322. * @return a modulesourcepath to be configured
  323. * @since 1.9.7
  324. */
  325. public Path createModulesourcepath() {
  326. if (moduleSourcepath == null) {
  327. moduleSourcepath = new Path(getProject());
  328. }
  329. return moduleSourcepath.createPath();
  330. }
  331. /**
  332. * Adds a reference to a modulesourcepath defined elsewhere.
  333. * @param r a reference to a modulesourcepath
  334. * @since 1.9.7
  335. */
  336. public void setModulesourcepathRef(final Reference r) {
  337. createModulesourcepath().setRefid(r);
  338. }
  339. /**
  340. * Set the classpath to be used for this compilation.
  341. *
  342. * @param classpath an Ant Path object containing the compilation classpath.
  343. */
  344. public void setClasspath(final Path classpath) {
  345. if (compileClasspath == null) {
  346. compileClasspath = classpath;
  347. } else {
  348. compileClasspath.append(classpath);
  349. }
  350. }
  351. /**
  352. * Gets the classpath to be used for this compilation.
  353. * @return the class path
  354. */
  355. public Path getClasspath() {
  356. return compileClasspath;
  357. }
  358. /**
  359. * Adds a path to the classpath.
  360. * @return a class path to be configured
  361. */
  362. public Path createClasspath() {
  363. if (compileClasspath == null) {
  364. compileClasspath = new Path(getProject());
  365. }
  366. return compileClasspath.createPath();
  367. }
  368. /**
  369. * Adds a reference to a classpath defined elsewhere.
  370. * @param r a reference to a classpath
  371. */
  372. public void setClasspathRef(final Reference r) {
  373. createClasspath().setRefid(r);
  374. }
  375. /**
  376. * Set the modulepath to be used for this compilation.
  377. * @param mp an Ant Path object containing the modulepath.
  378. * @since 1.9.7
  379. */
  380. public void setModulepath(final Path mp) {
  381. if (modulepath == null) {
  382. modulepath = mp;
  383. } else {
  384. modulepath.append(mp);
  385. }
  386. }
  387. /**
  388. * Gets the modulepath to be used for this compilation.
  389. * @return the modulepath
  390. * @since 1.9.7
  391. */
  392. public Path getModulepath() {
  393. return modulepath;
  394. }
  395. /**
  396. * Adds a path to the modulepath.
  397. * @return a modulepath to be configured
  398. * @since 1.9.7
  399. */
  400. public Path createModulepath() {
  401. if (modulepath == null) {
  402. modulepath = new Path(getProject());
  403. }
  404. return modulepath.createPath();
  405. }
  406. /**
  407. * Adds a reference to a modulepath defined elsewhere.
  408. * @param r a reference to a modulepath
  409. * @since 1.9.7
  410. */
  411. public void setModulepathRef(final Reference r) {
  412. createModulepath().setRefid(r);
  413. }
  414. /**
  415. * Set the upgrademodulepath to be used for this compilation.
  416. * @param ump an Ant Path object containing the upgrademodulepath.
  417. * @since 1.9.7
  418. */
  419. public void setUpgrademodulepath(final Path ump) {
  420. if (upgrademodulepath == null) {
  421. upgrademodulepath = ump;
  422. } else {
  423. upgrademodulepath.append(ump);
  424. }
  425. }
  426. /**
  427. * Gets the upgrademodulepath to be used for this compilation.
  428. * @return the upgrademodulepath
  429. * @since 1.9.7
  430. */
  431. public Path getUpgrademodulepath() {
  432. return upgrademodulepath;
  433. }
  434. /**
  435. * Adds a path to the upgrademodulepath.
  436. * @return an upgrademodulepath to be configured
  437. * @since 1.9.7
  438. */
  439. public Path createUpgrademodulepath() {
  440. if (upgrademodulepath == null) {
  441. upgrademodulepath = new Path(getProject());
  442. }
  443. return upgrademodulepath.createPath();
  444. }
  445. /**
  446. * Adds a reference to the upgrademodulepath defined elsewhere.
  447. * @param r a reference to an upgrademodulepath
  448. * @since 1.9.7
  449. */
  450. public void setUpgrademodulepathRef(final Reference r) {
  451. createUpgrademodulepath().setRefid(r);
  452. }
  453. /**
  454. * Sets the bootclasspath that will be used to compile the classes
  455. * against.
  456. * @param bootclasspath a path to use as a boot class path (may be more
  457. * than one)
  458. */
  459. public void setBootclasspath(final Path bootclasspath) {
  460. if (this.bootclasspath == null) {
  461. this.bootclasspath = bootclasspath;
  462. } else {
  463. this.bootclasspath.append(bootclasspath);
  464. }
  465. }
  466. /**
  467. * Gets the bootclasspath that will be used to compile the classes
  468. * against.
  469. * @return the boot path
  470. */
  471. public Path getBootclasspath() {
  472. return bootclasspath;
  473. }
  474. /**
  475. * Adds a path to the bootclasspath.
  476. * @return a path to be configured
  477. */
  478. public Path createBootclasspath() {
  479. if (bootclasspath == null) {
  480. bootclasspath = new Path(getProject());
  481. }
  482. return bootclasspath.createPath();
  483. }
  484. /**
  485. * Adds a reference to a classpath defined elsewhere.
  486. * @param r a reference to a classpath
  487. */
  488. public void setBootClasspathRef(final Reference r) {
  489. createBootclasspath().setRefid(r);
  490. }
  491. /**
  492. * Sets the extension directories that will be used during the
  493. * compilation.
  494. * @param extdirs a path
  495. */
  496. public void setExtdirs(final Path extdirs) {
  497. if (this.extdirs == null) {
  498. this.extdirs = extdirs;
  499. } else {
  500. this.extdirs.append(extdirs);
  501. }
  502. }
  503. /**
  504. * Gets the extension directories that will be used during the
  505. * compilation.
  506. * @return the extension directories as a path
  507. */
  508. public Path getExtdirs() {
  509. return extdirs;
  510. }
  511. /**
  512. * Adds a path to extdirs.
  513. * @return a path to be configured
  514. */
  515. public Path createExtdirs() {
  516. if (extdirs == null) {
  517. extdirs = new Path(getProject());
  518. }
  519. return extdirs.createPath();
  520. }
  521. /**
  522. * If true, list the source files being handed off to the compiler.
  523. * @param list if true list the source files
  524. */
  525. public void setListfiles(final boolean list) {
  526. listFiles = list;
  527. }
  528. /**
  529. * Get the listfiles flag.
  530. * @return the listfiles flag
  531. */
  532. public boolean getListfiles() {
  533. return listFiles;
  534. }
  535. /**
  536. * Indicates whether the build will continue
  537. * even if there are compilation errors; defaults to true.
  538. * @param fail if true halt the build on failure
  539. */
  540. public void setFailonerror(final boolean fail) {
  541. failOnError = fail;
  542. }
  543. /**
  544. * @ant.attribute ignore="true"
  545. * @param proceed inverse of failoferror
  546. */
  547. public void setProceed(final boolean proceed) {
  548. failOnError = !proceed;
  549. }
  550. /**
  551. * Gets the failonerror flag.
  552. * @return the failonerror flag
  553. */
  554. public boolean getFailonerror() {
  555. return failOnError;
  556. }
  557. /**
  558. * Indicates whether source should be
  559. * compiled with deprecation information; defaults to off.
  560. * @param deprecation if true turn on deprecation information
  561. */
  562. public void setDeprecation(final boolean deprecation) {
  563. this.deprecation = deprecation;
  564. }
  565. /**
  566. * Gets the deprecation flag.
  567. * @return the deprecation flag
  568. */
  569. public boolean getDeprecation() {
  570. return deprecation;
  571. }
  572. /**
  573. * The initial size of the memory for the underlying VM
  574. * if javac is run externally; ignored otherwise.
  575. * Defaults to the standard VM memory setting.
  576. * (Examples: 83886080, 81920k, or 80m)
  577. * @param memoryInitialSize string to pass to VM
  578. */
  579. public void setMemoryInitialSize(final String memoryInitialSize) {
  580. this.memoryInitialSize = memoryInitialSize;
  581. }
  582. /**
  583. * Gets the memoryInitialSize flag.
  584. * @return the memoryInitialSize flag
  585. */
  586. public String getMemoryInitialSize() {
  587. return memoryInitialSize;
  588. }
  589. /**
  590. * The maximum size of the memory for the underlying VM
  591. * if javac is run externally; ignored otherwise.
  592. * Defaults to the standard VM memory setting.
  593. * (Examples: 83886080, 81920k, or 80m)
  594. * @param memoryMaximumSize string to pass to VM
  595. */
  596. public void setMemoryMaximumSize(final String memoryMaximumSize) {
  597. this.memoryMaximumSize = memoryMaximumSize;
  598. }
  599. /**
  600. * Gets the memoryMaximumSize flag.
  601. * @return the memoryMaximumSize flag
  602. */
  603. public String getMemoryMaximumSize() {
  604. return memoryMaximumSize;
  605. }
  606. /**
  607. * Set the Java source file encoding name.
  608. * @param encoding the source file encoding
  609. */
  610. public void setEncoding(final String encoding) {
  611. this.encoding = encoding;
  612. }
  613. /**
  614. * Gets the java source file encoding name.
  615. * @return the source file encoding name
  616. */
  617. public String getEncoding() {
  618. return encoding;
  619. }
  620. /**
  621. * Indicates whether source should be compiled
  622. * with debug information; defaults to off.
  623. * @param debug if true compile with debug information
  624. */
  625. public void setDebug(final boolean debug) {
  626. this.debug = debug;
  627. }
  628. /**
  629. * Gets the debug flag.
  630. * @return the debug flag
  631. */
  632. public boolean getDebug() {
  633. return debug;
  634. }
  635. /**
  636. * If true, compiles with optimization enabled.
  637. * @param optimize if true compile with optimization enabled
  638. */
  639. public void setOptimize(final boolean optimize) {
  640. this.optimize = optimize;
  641. }
  642. /**
  643. * Gets the optimize flag.
  644. * @return the optimize flag
  645. */
  646. public boolean getOptimize() {
  647. return optimize;
  648. }
  649. /**
  650. * Enables dependency-tracking for compilers
  651. * that support this (jikes and classic).
  652. * @param depend if true enable dependency-tracking
  653. */
  654. public void setDepend(final boolean depend) {
  655. this.depend = depend;
  656. }
  657. /**
  658. * Gets the depend flag.
  659. * @return the depend flag
  660. */
  661. public boolean getDepend() {
  662. return depend;
  663. }
  664. /**
  665. * If true, asks the compiler for verbose output.
  666. * @param verbose if true, asks the compiler for verbose output
  667. */
  668. public void setVerbose(final boolean verbose) {
  669. this.verbose = verbose;
  670. }
  671. /**
  672. * Gets the verbose flag.
  673. * @return the verbose flag
  674. */
  675. public boolean getVerbose() {
  676. return verbose;
  677. }
  678. /**
  679. * Sets the target VM that the classes will be compiled for. Valid
  680. * values depend on the compiler, for jdk 1.4 the valid values are
  681. * "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9" and any integral number bigger than 4
  682. * @param target the target VM
  683. */
  684. public void setTarget(final String target) {
  685. this.targetAttribute = target;
  686. }
  687. /**
  688. * Gets the target VM that the classes will be compiled for.
  689. * @return the target VM
  690. */
  691. public String getTarget() {
  692. return targetAttribute != null
  693. ? targetAttribute
  694. : getProject().getProperty(MagicNames.BUILD_JAVAC_TARGET);
  695. }
  696. /**
  697. * Sets the version to use for the {@code --release} switch that
  698. * combines {@code source}, {@code target} and setting the
  699. * bootclasspath.
  700. *
  701. * Values depend on the compiler, for jdk 9 the valid values are
  702. * "6", "7", "8", "9".
  703. * @param release the value of the release attribute
  704. * @since Ant 1.9.8
  705. */
  706. public void setRelease(final String release) {
  707. this.release = release;
  708. }
  709. /**
  710. * Gets the version to use for the {@code --release} switch that
  711. * combines {@code source}, {@code target} and setting the
  712. * bootclasspath.
  713. *
  714. * @return the value of the release attribute
  715. * @since Ant 1.9.8
  716. */
  717. public String getRelease() {
  718. return release;
  719. }
  720. /**
  721. * If true, includes Ant's own classpath in the classpath.
  722. * @param include if true, includes Ant's own classpath in the classpath
  723. */
  724. public void setIncludeantruntime(final boolean include) {
  725. includeAntRuntime = include;
  726. }
  727. /**
  728. * Gets whether or not the ant classpath is to be included in the classpath.
  729. * @return whether or not the ant classpath is to be included in the classpath
  730. */
  731. public boolean getIncludeantruntime() {
  732. return includeAntRuntime == null || includeAntRuntime;
  733. }
  734. /**
  735. * If true, includes the Java runtime libraries in the classpath.
  736. * @param include if true, includes the Java runtime libraries in the classpath
  737. */
  738. public void setIncludejavaruntime(final boolean include) {
  739. includeJavaRuntime = include;
  740. }
  741. /**
  742. * Gets whether or not the java runtime should be included in this
  743. * task's classpath.
  744. * @return the includejavaruntime attribute
  745. */
  746. public boolean getIncludejavaruntime() {
  747. return includeJavaRuntime;
  748. }
  749. /**
  750. * If true, forks the javac compiler.
  751. *
  752. * @param f "true|false|on|off|yes|no"
  753. */
  754. public void setFork(final boolean f) {
  755. fork = f;
  756. }
  757. /**
  758. * Sets the name of the javac executable.
  759. *
  760. * <p>Ignored unless fork is true or extJavac has been specified
  761. * as the compiler.</p>
  762. * @param forkExec the name of the executable
  763. */
  764. public void setExecutable(final String forkExec) {
  765. forkedExecutable = forkExec;
  766. }
  767. /**
  768. * The value of the executable attribute, if any.
  769. *
  770. * @since Ant 1.6
  771. * @return the name of the java executable
  772. */
  773. public String getExecutable() {
  774. return forkedExecutable;
  775. }
  776. /**
  777. * Is this a forked invocation of JDK's javac?
  778. * @return true if this is a forked invocation
  779. */
  780. public boolean isForkedJavac() {
  781. return fork || CompilerAdapterFactory.isForkedJavac(getCompiler());
  782. }
  783. /**
  784. * The name of the javac executable to use in fork-mode.
  785. *
  786. * <p>This is either the name specified with the executable
  787. * attribute or the full path of the javac compiler of the VM Ant
  788. * is currently running in - guessed by Ant.</p>
  789. *
  790. * <p>You should <strong>not</strong> invoke this method if you
  791. * want to get the value of the executable command - use {@link
  792. * #getExecutable getExecutable} for this.</p>
  793. * @return the name of the javac executable
  794. */
  795. public String getJavacExecutable() {
  796. if (forkedExecutable == null && isForkedJavac()) {
  797. forkedExecutable = getSystemJavac();
  798. } else if (forkedExecutable != null && !isForkedJavac()) {
  799. forkedExecutable = null;
  800. }
  801. return forkedExecutable;
  802. }
  803. /**
  804. * If true, enables the -nowarn option.
  805. * @param flag if true, enable the -nowarn option
  806. */
  807. public void setNowarn(final boolean flag) {
  808. this.nowarn = flag;
  809. }
  810. /**
  811. * Should the -nowarn option be used.
  812. * @return true if the -nowarn option should be used
  813. */
  814. public boolean getNowarn() {
  815. return nowarn;
  816. }
  817. /**
  818. * Adds an implementation specific command-line argument.
  819. * @return a ImplementationSpecificArgument to be configured
  820. */
  821. public ImplementationSpecificArgument createCompilerArg() {
  822. final ImplementationSpecificArgument arg =
  823. new ImplementationSpecificArgument();
  824. facade.addImplementationArgument(arg);
  825. return arg;
  826. }
  827. /**
  828. * Get the additional implementation specific command line arguments.
  829. * @return array of command line arguments, guaranteed to be non-null.
  830. */
  831. public String[] getCurrentCompilerArgs() {
  832. final String chosen = facade.getExplicitChoice();
  833. try {
  834. // make sure facade knows about magic properties and fork setting
  835. final String appliedCompiler = getCompiler();
  836. facade.setImplementation(appliedCompiler);
  837. String[] result = facade.getArgs();
  838. final String altCompilerName = getAltCompilerName(facade.getImplementation());
  839. if (result.length == 0 && altCompilerName != null) {
  840. facade.setImplementation(altCompilerName);
  841. result = facade.getArgs();
  842. }
  843. return result;
  844. } finally {
  845. facade.setImplementation(chosen);
  846. }
  847. }
  848. private String getAltCompilerName(final String anImplementation) {
  849. if (CompilerAdapterFactory.isModernJdkCompiler(anImplementation)) {
  850. return CompilerAdapterFactory.COMPILER_MODERN;
  851. }
  852. if (CompilerAdapterFactory.isClassicJdkCompiler(anImplementation)) {
  853. return CompilerAdapterFactory.COMPILER_CLASSIC;
  854. }
  855. if (CompilerAdapterFactory.COMPILER_MODERN.equalsIgnoreCase(anImplementation)) {
  856. final String nextSelected = assumedJavaVersion();
  857. if (CompilerAdapterFactory.isModernJdkCompiler(nextSelected)) {
  858. return nextSelected;
  859. }
  860. }
  861. if (CompilerAdapterFactory.COMPILER_CLASSIC.equalsIgnoreCase(anImplementation)) {
  862. return assumedJavaVersion();
  863. }
  864. if (CompilerAdapterFactory.isForkedJavac(anImplementation)) {
  865. return assumedJavaVersion();
  866. }
  867. return null;
  868. }
  869. /**
  870. * Where Ant should place temporary files.
  871. *
  872. * @since Ant 1.6
  873. * @param tmpDir the temporary directory
  874. */
  875. public void setTempdir(final File tmpDir) {
  876. this.tmpDir = tmpDir;
  877. }
  878. /**
  879. * Where Ant should place temporary files.
  880. *
  881. * @since Ant 1.6
  882. * @return the temporary directory
  883. */
  884. public File getTempdir() {
  885. return tmpDir;
  886. }
  887. /**
  888. * The property to set on compilation success.
  889. * This property will not be set if the compilation
  890. * fails, or if there are no files to compile.
  891. * @param updatedProperty the property name to use.
  892. * @since Ant 1.7.1.
  893. */
  894. public void setUpdatedProperty(final String updatedProperty) {
  895. this.updatedProperty = updatedProperty;
  896. }
  897. /**
  898. * The property to set on compilation failure.
  899. * This property will be set if the compilation
  900. * fails.
  901. * @param errorProperty the property name to use.
  902. * @since Ant 1.7.1.
  903. */
  904. public void setErrorProperty(final String errorProperty) {
  905. this.errorProperty = errorProperty;
  906. }
  907. /**
  908. * This property controls whether to include the
  909. * destination classes directory in the classpath
  910. * given to the compiler.
  911. * The default value is "true".
  912. * @param includeDestClasses the value to use.
  913. */
  914. public void setIncludeDestClasses(final boolean includeDestClasses) {
  915. this.includeDestClasses = includeDestClasses;
  916. }
  917. /**
  918. * Get the value of the includeDestClasses property.
  919. * @return the value.
  920. */
  921. public boolean isIncludeDestClasses() {
  922. return includeDestClasses;
  923. }
  924. /**
  925. * Get the result of the javac task (success or failure).
  926. * @return true if compilation succeeded, or
  927. * was not necessary, false if the compilation failed.
  928. */
  929. public boolean getTaskSuccess() {
  930. return taskSuccess;
  931. }
  932. /**
  933. * The classpath to use when loading the compiler implementation
  934. * if it is not a built-in one.
  935. *
  936. * @return Path
  937. * @since Ant 1.8.0
  938. */
  939. public Path createCompilerClasspath() {
  940. return facade.getImplementationClasspath(getProject());
  941. }
  942. /**
  943. * Set the compiler adapter explicitly.
  944. *
  945. * @param adapter CompilerAdapter
  946. * @since Ant 1.8.0
  947. */
  948. public void add(final CompilerAdapter adapter) {
  949. if (nestedAdapter != null) {
  950. throw new BuildException(
  951. "Can't have more than one compiler adapter");
  952. }
  953. nestedAdapter = adapter;
  954. }
  955. /**
  956. * Whether package-info.class files will be created by Ant
  957. * matching package-info.java files that have been compiled but
  958. * didn't create class files themselves.
  959. *
  960. * @param b boolean
  961. * @since Ant 1.8.3
  962. */
  963. public void setCreateMissingPackageInfoClass(final boolean b) {
  964. createMissingPackageInfoClass = b;
  965. }
  966. /**
  967. * Executes the task.
  968. * @exception BuildException if an error occurs
  969. */
  970. @Override
  971. public void execute() throws BuildException {
  972. checkParameters();
  973. resetFileLists();
  974. // scan source directories and dest directory to build up
  975. // compile list
  976. if (hasPath(src)) {
  977. collectFileListFromSourcePath();
  978. } else {
  979. assert hasPath(moduleSourcepath) : "Either srcDir or moduleSourcepath must be given";
  980. collectFileListFromModulePath();
  981. }
  982. compile();
  983. if (updatedProperty != null
  984. && taskSuccess
  985. && compileList.length != 0) {
  986. getProject().setNewProperty(updatedProperty, "true");
  987. }
  988. }
  989. /**
  990. * Clear the list of files to be compiled and copied..
  991. */
  992. protected void resetFileLists() {
  993. compileList = new File[0];
  994. packageInfos = new HashMap<>();
  995. }
  996. /**
  997. * Scans the directory looking for source files to be compiled.
  998. * The results are returned in the class variable compileList
  999. *
  1000. * @param srcDir The source directory
  1001. * @param destDir The destination directory
  1002. * @param files An array of filenames
  1003. */
  1004. protected void scanDir(final File srcDir, final File destDir, final String[] files) {
  1005. final GlobPatternMapper m = new GlobPatternMapper();
  1006. for (String extension : findSupportedFileExtensions()) {
  1007. m.setFrom(extension);
  1008. m.setTo("*.class");
  1009. final SourceFileScanner sfs = new SourceFileScanner(this);
  1010. final File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
  1011. if (newFiles.length > 0) {
  1012. lookForPackageInfos(srcDir, newFiles);
  1013. final File[] newCompileList
  1014. = new File[compileList.length + newFiles.length];
  1015. System.arraycopy(compileList, 0, newCompileList, 0,
  1016. compileList.length);
  1017. System.arraycopy(newFiles, 0, newCompileList,
  1018. compileList.length, newFiles.length);
  1019. compileList = newCompileList;
  1020. }
  1021. }
  1022. }
  1023. private void collectFileListFromSourcePath() {
  1024. for (String filename : src.list()) {
  1025. final File srcDir = getProject().resolveFile(filename);
  1026. if (!srcDir.exists()) {
  1027. throw new BuildException("srcdir \""
  1028. + srcDir.getPath()
  1029. + "\" does not exist!", getLocation());
  1030. }
  1031. final DirectoryScanner ds = this.getDirectoryScanner(srcDir);
  1032. scanDir(srcDir, destDir != null ? destDir : srcDir, ds.getIncludedFiles());
  1033. }
  1034. }
  1035. private void collectFileListFromModulePath() {
  1036. final FileUtils fu = FileUtils.getFileUtils();
  1037. for (String pathElement : moduleSourcepath.list()) {
  1038. boolean valid = false;
  1039. for (Map.Entry<String, Collection<File>> modules : resolveModuleSourcePathElement(
  1040. getProject().getBaseDir(), pathElement).entrySet()) {
  1041. final String moduleName = modules.getKey();
  1042. for (File srcDir : modules.getValue()) {
  1043. if (srcDir.exists()) {
  1044. valid = true;
  1045. final DirectoryScanner ds = getDirectoryScanner(srcDir);
  1046. final String[] files = ds.getIncludedFiles();
  1047. scanDir(srcDir, fu.resolveFile(destDir, moduleName), files);
  1048. }
  1049. }
  1050. }
  1051. if (!valid) {
  1052. throw new BuildException("modulesourcepath \""
  1053. + pathElement
  1054. + "\" does not exist!", getLocation());
  1055. }
  1056. }
  1057. }
  1058. private String[] findSupportedFileExtensions() {
  1059. final String compilerImpl = getCompiler();
  1060. final CompilerAdapter adapter =
  1061. nestedAdapter != null ? nestedAdapter :
  1062. CompilerAdapterFactory.getCompiler(compilerImpl, this,
  1063. createCompilerClasspath());
  1064. String[] extensions = null;
  1065. if (adapter instanceof CompilerAdapterExtension) {
  1066. extensions =
  1067. ((CompilerAdapterExtension) adapter).getSupportedFileExtensions();
  1068. }
  1069. if (extensions == null) {
  1070. extensions = new String[] {"java"};
  1071. }
  1072. // now process the extensions to ensure that they are the
  1073. // right format
  1074. for (int i = 0; i < extensions.length; i++) {
  1075. if (!extensions[i].startsWith("*.")) {
  1076. extensions[i] = "*." + extensions[i];
  1077. }
  1078. }
  1079. return extensions;
  1080. }
  1081. /**
  1082. * Gets the list of files to be compiled.
  1083. * @return the list of files as an array
  1084. */
  1085. public File[] getFileList() {
  1086. return compileList;
  1087. }
  1088. /**
  1089. * Is the compiler implementation a jdk compiler
  1090. *
  1091. * @param compilerImpl the name of the compiler implementation
  1092. * @return true if compilerImpl is "modern", "classic",
  1093. * "javac1.1", "javac1.2", "javac1.3", "javac1.4", "javac1.5",
  1094. * "javac1.6", "javac1.7", "javac1.8", "javac1.9", "javac9" or "javac10+".
  1095. */
  1096. protected boolean isJdkCompiler(final String compilerImpl) {
  1097. return CompilerAdapterFactory.isJdkCompiler(compilerImpl);
  1098. }
  1099. /**
  1100. * @return the executable name of the java compiler
  1101. */
  1102. protected String getSystemJavac() {
  1103. return JavaEnvUtils.getJdkExecutable("javac");
  1104. }
  1105. /**
  1106. * Choose the implementation for this particular task.
  1107. * @param compiler the name of the compiler
  1108. * @since Ant 1.5
  1109. */
  1110. public void setCompiler(final String compiler) {
  1111. facade.setImplementation(compiler);
  1112. }
  1113. /**
  1114. * The implementation for this particular task.
  1115. *
  1116. * <p>Defaults to the build.compiler property but can be overridden
  1117. * via the compiler and fork attributes.</p>
  1118. *
  1119. * <p>If fork has been set to true, the result will be extJavac
  1120. * and not classic or java1.2 - no matter what the compiler
  1121. * attribute looks like.</p>
  1122. *
  1123. * @see #getCompilerVersion
  1124. * @return the compiler.
  1125. * @since Ant 1.5
  1126. */
  1127. public String getCompiler() {
  1128. String compilerImpl = getCompilerVersion();
  1129. if (fork) {
  1130. if (isJdkCompiler(compilerImpl)) {
  1131. compilerImpl = CompilerAdapterFactory.COMPILER_EXTJAVAC;
  1132. } else {
  1133. log("Since compiler setting isn't classic or modern, ignoring fork setting.",
  1134. Project.MSG_WARN);
  1135. }
  1136. }
  1137. return compilerImpl;
  1138. }
  1139. /**
  1140. * The implementation for this particular task.
  1141. *
  1142. * <p>Defaults to the build.compiler property but can be overridden
  1143. * via the compiler attribute.</p>
  1144. *
  1145. * <p>This method does not take the fork attribute into
  1146. * account.</p>
  1147. *
  1148. * @see #getCompiler
  1149. * @return the compiler.
  1150. *
  1151. * @since Ant 1.5
  1152. */
  1153. public String getCompilerVersion() {
  1154. facade.setMagicValue(getProject().getProperty("build.compiler"));
  1155. return facade.getImplementation();
  1156. }
  1157. /**
  1158. * Check that all required attributes have been set and nothing
  1159. * silly has been entered.
  1160. *
  1161. * @since Ant 1.5
  1162. * @exception BuildException if an error occurs
  1163. */
  1164. protected void checkParameters() throws BuildException {
  1165. if (hasPath(src)) {
  1166. if (hasPath(moduleSourcepath)) {
  1167. throw new BuildException("modulesourcepath cannot be combined with srcdir attribute!",
  1168. getLocation());
  1169. }
  1170. } else if (hasPath(moduleSourcepath)) {
  1171. if (hasPath(src) || hasPath(compileSourcepath)) {
  1172. throw new BuildException("modulesourcepath cannot be combined with srcdir or sourcepath !",
  1173. getLocation());
  1174. }
  1175. if (destDir == null) {
  1176. throw new BuildException("modulesourcepath requires destdir attribute to be set!",
  1177. getLocation());
  1178. }
  1179. } else {
  1180. throw new BuildException("either srcdir or modulesourcepath attribute must be set!",
  1181. getLocation());
  1182. }
  1183. if (destDir != null && !destDir.isDirectory()) {
  1184. throw new BuildException("destination directory \""
  1185. + destDir
  1186. + "\" does not exist or is not a directory", getLocation());
  1187. }
  1188. if (includeAntRuntime == null && getProject().getProperty(MagicNames.BUILD_SYSCLASSPATH) == null) {
  1189. log(getLocation() + "warning: 'includeantruntime' was not set, defaulting to "
  1190. + MagicNames.BUILD_SYSCLASSPATH + "=last; set to false for repeatable builds",
  1191. Project.MSG_WARN);
  1192. }
  1193. }
  1194. /**
  1195. * Perform the compilation.
  1196. *
  1197. * @since Ant 1.5
  1198. */
  1199. protected void compile() {
  1200. final String compilerImpl = getCompiler();
  1201. if (compileList.length > 0) {
  1202. log("Compiling " + compileList.length + " source file"
  1203. + (compileList.length == 1 ? "" : "s")
  1204. + (destDir != null ? " to " + destDir : ""));
  1205. if (listFiles) {
  1206. for (File element : compileList) {
  1207. log(element.getAbsolutePath());
  1208. }
  1209. }
  1210. final CompilerAdapter adapter =
  1211. nestedAdapter != null ? nestedAdapter :
  1212. CompilerAdapterFactory.getCompiler(compilerImpl, this,
  1213. createCompilerClasspath());
  1214. // now we need to populate the compiler adapter
  1215. adapter.setJavac(this);
  1216. // finally, lets execute the compiler!!
  1217. if (adapter.execute()) {
  1218. // Success
  1219. if (createMissingPackageInfoClass) {
  1220. try {
  1221. generateMissingPackageInfoClasses(destDir != null
  1222. ? destDir
  1223. : getProject()
  1224. .resolveFile(src.list()[0]));
  1225. } catch (final IOException x) {
  1226. // Should this be made a nonfatal warning?
  1227. throw new BuildException(x, getLocation());
  1228. }
  1229. }
  1230. } else {
  1231. // Fail path
  1232. this.taskSuccess = false;
  1233. if (errorProperty != null) {
  1234. getProject().setNewProperty(
  1235. errorProperty, "true");
  1236. }
  1237. if (failOnError) {
  1238. throw new BuildException(FAIL_MSG, getLocation());
  1239. }
  1240. log(FAIL_MSG, Project.MSG_ERR);
  1241. }
  1242. }
  1243. }
  1244. /**
  1245. * Adds an "compiler" attribute to Commandline$Attribute used to
  1246. * filter command line attributes based on the current
  1247. * implementation.
  1248. */
  1249. public class ImplementationSpecificArgument extends
  1250. org.apache.tools.ant.util.facade.ImplementationSpecificArgument {
  1251. /**
  1252. * @param impl the name of the compiler
  1253. */
  1254. public void setCompiler(final String impl) {
  1255. super.setImplementation(impl);
  1256. }
  1257. }
  1258. private void lookForPackageInfos(final File srcDir, final File[] newFiles) {
  1259. for (File f : newFiles) {
  1260. if (!"package-info.java".equals(f.getName())) {
  1261. continue;
  1262. }
  1263. final String path = FILE_UTILS.removeLeadingPath(srcDir, f)
  1264. .replace(File.separatorChar, '/');
  1265. final String suffix = "/package-info.java";
  1266. if (!path.endsWith(suffix)) {
  1267. log("anomalous package-info.java path: " + path, Project.MSG_WARN);
  1268. continue;
  1269. }
  1270. final String pkg = path.substring(0, path.length() - suffix.length());
  1271. packageInfos.put(pkg, f.lastModified());
  1272. }
  1273. }
  1274. /**
  1275. * Ensure that every {@code package-info.java} produced a {@code package-info.class}.
  1276. * Otherwise this task's up-to-date tracking mechanisms do not work.
  1277. * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=43114">Bug #43114</a>
  1278. */
  1279. private void generateMissingPackageInfoClasses(final File dest) throws IOException {
  1280. for (final Map.Entry<String, Long> entry : packageInfos.entrySet()) {
  1281. final String pkg = entry.getKey();
  1282. final Long sourceLastMod = entry.getValue();
  1283. final File pkgBinDir = new File(dest, pkg.replace('/', File.separatorChar));
  1284. pkgBinDir.mkdirs();
  1285. final File pkgInfoClass = new File(pkgBinDir, "package-info.class");
  1286. if (pkgInfoClass.isFile() && pkgInfoClass.lastModified() >= sourceLastMod) {
  1287. continue;
  1288. }
  1289. log("Creating empty " + pkgInfoClass);
  1290. try (OutputStream os = Files.newOutputStream(pkgInfoClass.toPath())) {
  1291. os.write(PACKAGE_INFO_CLASS_HEADER);
  1292. final byte[] name = pkg.getBytes(StandardCharsets.UTF_8);
  1293. final int length = name.length + /* "/package-info" */ 13;
  1294. os.write((byte) length / 256);
  1295. os.write((byte) length % 256);
  1296. os.write(name);
  1297. os.write(PACKAGE_INFO_CLASS_FOOTER);
  1298. }
  1299. }
  1300. }
  1301. /**
  1302. * Checks if a path exists and is non empty.
  1303. * @param path to be checked
  1304. * @return true if the path is non <code>null</code> and non empty.
  1305. * @since 1.9.7
  1306. */
  1307. private static boolean hasPath(final Path path) {
  1308. return path != null && !path.isEmpty();
  1309. }
  1310. /**
  1311. * Resolves the modulesourcepath element possibly containing groups
  1312. * and module marks to module names and source roots.
  1313. * @param projectDir the project directory
  1314. * @param element the modulesourcepath elemement
  1315. * @return a mapping from module name to module source roots
  1316. * @since 1.9.7
  1317. */
  1318. private static Map<String, Collection<File>> resolveModuleSourcePathElement(
  1319. final File projectDir,
  1320. final String element) {
  1321. final Map<String, Collection<File>> result = new TreeMap<>();
  1322. for (CharSequence resolvedElement : expandGroups(element)) {
  1323. findModules(projectDir, resolvedElement.toString(), result);
  1324. }
  1325. return result;
  1326. }
  1327. /**
  1328. * Expands the groups in the modulesourcepath entry to alternatives.
  1329. * <p>
  1330. * The <code>'*'</code> is a token representing the name of any of the modules in the compilation module set.
  1331. * The <code>'{' ... ',' ... '}'</code> express alternates for expansion.
  1332. * An example of the modulesourcepath entry is <code>src/&#42;/{linux,share}/classes</code>
  1333. * </p>
  1334. * @param element the entry to expand groups in
  1335. * @return the possible alternatives
  1336. * @since 1.9.7
  1337. */
  1338. private static Collection<? extends CharSequence> expandGroups(
  1339. final CharSequence element) {
  1340. List<StringBuilder> result = new ArrayList<>();
  1341. result.add(new StringBuilder());
  1342. StringBuilder resolved = new StringBuilder();
  1343. for (int i = 0; i < element.length(); i++) {
  1344. final char c = element.charAt(i);
  1345. switch (c) {
  1346. case GROUP_START_MARK:
  1347. final int end = getGroupEndIndex(element, i);
  1348. if (end < 0) {
  1349. throw new BuildException(String.format(
  1350. "Unclosed group %s, starting at: %d",
  1351. element,
  1352. i));
  1353. }
  1354. final Collection<? extends CharSequence> parts = resolveGroup(element.subSequence(i + 1, end));
  1355. switch (parts.size()) {
  1356. case 0:
  1357. break;
  1358. case 1:
  1359. resolved.append(parts.iterator().next());
  1360. break;
  1361. default:
  1362. final List<StringBuilder> oldRes = result;
  1363. result = new ArrayList<>(oldRes.size() * parts.size());
  1364. for (CharSequence part : parts) {
  1365. for (CharSequence prefix : oldRes) {
  1366. result.add(new StringBuilder(prefix).append(resolved).append(part));
  1367. }
  1368. }
  1369. resolved = new StringBuilder();
  1370. }
  1371. i = end;
  1372. break;
  1373. default:
  1374. resolved.append(c);
  1375. }
  1376. }
  1377. for (StringBuilder prefix : result) {
  1378. prefix.append(resolved);
  1379. }
  1380. return result;
  1381. }
  1382. /**
  1383. * Resolves the group to alternatives.
  1384. * @param group the group to resolve
  1385. * @return the possible alternatives
  1386. * @since 1.9.7
  1387. */
  1388. private static Collection<? extends CharSequence> resolveGroup(final CharSequence group) {
  1389. final Collection<CharSequence> result = new ArrayList<>();
  1390. int start = 0;
  1391. int depth = 0;
  1392. for (int i = 0; i < group.length(); i++) {
  1393. final char c = group.charAt(i);
  1394. switch (c) {
  1395. case GROUP_START_MARK:
  1396. depth++;
  1397. break;
  1398. case GROUP_END_MARK:
  1399. depth--;
  1400. break;
  1401. case GROUP_SEP_MARK:
  1402. if (depth == 0) {
  1403. result.addAll(expandGroups(group.subSequence(start, i)));
  1404. start = i + 1;
  1405. }
  1406. break;
  1407. }
  1408. }
  1409. result.addAll(expandGroups(group.subSequence(start, group.length())));
  1410. return result;
  1411. }
  1412. /**
  1413. * Finds the index of an enclosing brace of the group.
  1414. * @param element the element to find the enclosing brace in
  1415. * @param start the index of the opening brace.
  1416. * @return return the index of an enclosing brace of the group or -1 if not found
  1417. * @since 1.9.7
  1418. */
  1419. private static int getGroupEndIndex(
  1420. final CharSequence element,
  1421. final int start) {
  1422. int depth = 0;
  1423. for (int i = start; i < element.length(); i++) {
  1424. final char c = element.charAt(i);
  1425. switch (c) {
  1426. case GROUP_START_MARK:
  1427. depth++;
  1428. break;
  1429. case GROUP_END_MARK:
  1430. depth--;
  1431. if (depth == 0) {
  1432. return i;
  1433. }
  1434. break;
  1435. }
  1436. }
  1437. return -1;
  1438. }
  1439. /**
  1440. * Finds modules in the expanded modulesourcepath entry.
  1441. * @param root the project root
  1442. * @param pattern the expanded modulesourcepath entry
  1443. * @param collector the map to put modules into
  1444. * @since 1.9.7
  1445. */
  1446. private static void findModules(
  1447. final File root,
  1448. String pattern,
  1449. final Map<String, Collection<File>> collector) {
  1450. pattern = pattern
  1451. .replace('/', File.separatorChar)
  1452. .replace('\\', File.separatorChar);
  1453. final int startIndex = pattern.indexOf(MODULE_MARKER);
  1454. if (startIndex == -1) {
  1455. findModules(root, pattern, null, collector);
  1456. return;
  1457. }
  1458. if (startIndex == 0) {
  1459. throw new BuildException("The modulesourcepath entry must be a folder.");
  1460. }
  1461. final int endIndex = startIndex + MODULE_MARKER.length();
  1462. if (pattern.charAt(startIndex - 1) != File.separatorChar) {
  1463. throw new BuildException("The module mark must be preceded by separator");
  1464. }
  1465. if (endIndex < pattern.length() && pattern.charAt(endIndex) != File.separatorChar) {
  1466. throw new BuildException("The module mark must be followed by separator");
  1467. }
  1468. if (pattern.indexOf(MODULE_MARKER, endIndex) != -1) {
  1469. throw new BuildException("The modulesourcepath entry must contain at most one module mark");
  1470. }
  1471. final String pathToModule = pattern.substring(0, startIndex);
  1472. final String pathInModule = endIndex == pattern.length()
  1473. ? null : pattern.substring(endIndex + 1); //+1 the separator
  1474. findModules(root, pathToModule, pathInModule, collector);
  1475. }
  1476. /**
  1477. * Finds modules in the expanded modulesourcepath entry.
  1478. * @param root the project root
  1479. * @param pathToModule the path to modules folder
  1480. * @param pathInModule the path in module to source folder
  1481. * @param collector the map to put modules into
  1482. * @since 1.9.7
  1483. */
  1484. private static void findModules(
  1485. final File root,
  1486. final String pathToModule,
  1487. final String pathInModule,
  1488. final Map<String,Collection<File>> collector) {
  1489. final File f = FileUtils.getFileUtils().resolveFile(root, pathToModule);
  1490. if (!f.isDirectory()) {
  1491. return;
  1492. }
  1493. for (File module : f.listFiles(File::isDirectory)) {
  1494. final String moduleName = module.getName();
  1495. final File moduleSourceRoot = pathInModule == null
  1496. ? module : new File(module, pathInModule);
  1497. Collection<File> moduleRoots = collector.computeIfAbsent(moduleName, k -> new ArrayList<>());
  1498. moduleRoots.add(moduleSourceRoot);
  1499. }
  1500. }
  1501. private static final byte[] PACKAGE_INFO_CLASS_HEADER = {
  1502. (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, 0x00, 0x00, 0x00,
  1503. 0x31, 0x00, 0x07, 0x07, 0x00, 0x05, 0x07, 0x00, 0x06, 0x01, 0x00, 0x0a,
  1504. 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x00,
  1505. 0x11, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
  1506. 0x6f, 0x2e, 0x6a, 0x61, 0x76, 0x61, 0x01
  1507. };
  1508. private static final byte[] PACKAGE_INFO_CLASS_FOOTER = {
  1509. 0x2f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x6e, 0x66,
  1510. 0x6f, 0x01, 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
  1511. 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x02, 0x00, 0x00, 0x01,
  1512. 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
  1513. 0x00, 0x00, 0x00, 0x02, 0x00, 0x04
  1514. };
  1515. }