source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetCompile.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 25.7 KB
Line 
1/*
2 * Copyright 2001-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18/*
19 * build notes
20 * -The reference CD to listen to while editing this file is
21 * nap:Cream+Live+2001+CD+2
22 */
23
24// place in the optional ant tasks package
25// but in its own dotnet group
26
27package org.apache.tools.ant.taskdefs.optional.dotnet;
28
29// imports
30
31import java.io.File;
32import java.util.Vector;
33import java.util.Enumeration;
34import java.util.Hashtable;
35
36import org.apache.tools.ant.BuildException;
37import org.apache.tools.ant.Project;
38import org.apache.tools.ant.types.Commandline;
39import org.apache.tools.ant.types.Path;
40import org.apache.tools.ant.types.FileSet;
41import org.apache.tools.ant.types.EnumeratedAttribute;
42
43
44/**
45 * Abstract superclass for dotnet compiler tasks.
46 *
47 * History
48 * <table>
49 * <tr>
50 * <td>
51 * 0.1
52 * </td>
53 * <td>
54 * First creation
55 * </td>
56 * <td>
57 * Most of the code here was copied verbatim from v0.3 of
58 * Steve Loughran's CSharp optional task. Abstracted functionality
59 * to allow subclassing of other dotnet compiler types.
60 * </td>
61 * </tr>
62 *
63 * </table>
64 *
65 *
66 * @version 0.1
67 */
68
69public abstract class DotnetCompile
70 extends DotnetBaseMatchingTask {
71
72 /**
73 * list of reference classes. (pretty much a classpath equivalent)
74 */
75 private String references;
76
77 /**
78 * flag to enable automatic reference inclusion
79 */
80 private boolean includeDefaultReferences = true;
81
82 /**
83 * icon for incorporation into apps
84 */
85 private File win32icon;
86
87 /**
88 * icon for incorporation into apps
89 */
90 private File win32res;
91
92 /**
93 * flag to control action on execution trouble
94 */
95 private boolean failOnError;
96
97 /**
98 * using the path approach didn't work as it could not handle the implicit
99 * execution path. Perhaps that could be extracted from the runtime and
100 * then the path approach would be viable
101 */
102 private Path referenceFiles;
103
104 /**
105 * optimise flag
106 */
107 private boolean optimize;
108
109 /**
110 * a list of definitions to support;
111 */
112 protected Vector definitionList = new Vector();
113
114 /**
115 * our resources
116 */
117 protected Vector resources = new Vector();
118
119 /**
120 * executable
121 */
122
123 protected String executable;
124
125 protected static final String REFERENCE_OPTION = "/reference:";
126
127 /**
128 * debug flag. Controls generation of debug information.
129 */
130 protected boolean debug;
131
132 /**
133 * warning level: 0-4, with 4 being most verbose
134 */
135 private int warnLevel;
136
137 /**
138 * main class (or null for automatic choice)
139 */
140 protected String mainClass;
141
142 /**
143 * any extra command options?
144 */
145 protected String extraOptions;
146
147 /**
148 * type of target. Should be one of exe|library|module|winexe|(null)
149 * default is exe; the actual value (if not null) is fed to the command
150 * line. <br>
151 * See /target
152 */
153 protected String targetType;
154
155 /**
156 * utf out flag
157 */
158
159 protected boolean utf8output = false;
160
161 /**
162 * list of extra modules to refer to
163 */
164 protected String additionalModules;
165 /**
166 * filesets of references
167 */
168 protected Vector referenceFilesets = new Vector();
169
170 /**
171 * flag to set to to use @file based command cache
172 */
173 private boolean useResponseFile = false;
174 private static final int AUTOMATIC_RESPONSE_FILE_THRESHOLD = 64;
175
176 /**
177 * constructor inits everything and set up the search pattern
178 */
179
180 public DotnetCompile() {
181 clear();
182 setIncludes(getFilePattern());
183 }
184
185 /**
186 * reset all contents.
187 */
188 public void clear() {
189 targetType = null;
190 win32icon = null;
191 srcDir = null;
192 mainClass = null;
193 warnLevel = 3;
194 optimize = false;
195 debug = true;
196 references = null;
197 failOnError = true;
198 additionalModules = null;
199 includeDefaultReferences = true;
200 extraOptions = null;
201 }
202
203
204 /**
205 * Semicolon separated list of DLLs to refer to.
206 *
207 *@param s The new References value
208 */
209 public void setReferences(String s) {
210 references = s;
211 }
212
213
214 /**
215 * get the reference string or null for no argument needed
216 *
217 *@return The References Parameter to CSC
218 */
219 protected String getReferencesParameter() {
220 //bail on no references
221 if (notEmpty(references)) {
222 return REFERENCE_OPTION + references;
223 } else {
224 return null;
225 }
226 }
227
228 /**
229 * Path of references to include.
230 * Wildcards should work.
231 *
232 *@param path another path to append
233 */
234 public void setReferenceFiles(Path path) {
235 //demand create pathlist
236 if (referenceFiles == null) {
237 referenceFiles = new Path(this.getProject());
238 }
239 referenceFiles.append(path);
240 }
241
242 /**
243 * add a new reference fileset to the compilation
244 * @param reference
245 */
246 public void addReference(FileSet reference) {
247 referenceFilesets.add(reference);
248 }
249
250
251
252 /**
253 * turn the path list into a list of files and a /references argument
254 *
255 *@return null or a string of references.
256 */
257 protected String getReferenceFilesParameter() {
258 //bail on no references
259 if (references == null) {
260 return null;
261 }
262 //iterate through the ref list & generate an entry for each
263 //or just rely on the fact that the toString operator does this, but
264 //noting that the separator is ';' on windows, ':' on unix
265 String refpath = references.toString();
266
267 //bail on no references listed
268 if (refpath.length() == 0) {
269 return null;
270 }
271
272 StringBuffer s = new StringBuffer(REFERENCE_OPTION);
273 s.append(refpath);
274 return new String(s);
275 }
276
277
278 /**
279 * If true, automatically includes the common assemblies
280 * in dotnet, and tells the compiler to link in mscore.dll.
281 *
282 * set the automatic reference inclusion flag on or off this flag controls
283 * the /nostdlib option in CSC
284 *
285 *@param f on/off flag
286 */
287 public void setIncludeDefaultReferences(boolean f) {
288 includeDefaultReferences = f;
289 }
290
291
292 /**
293 * query automatic reference inclusion flag
294 *
295 *@return true if flag is turned on
296 */
297 public boolean getIncludeDefaultReferences() {
298 return includeDefaultReferences;
299 }
300
301
302 /**
303 * get the include default references flag or null for no argument needed
304 *
305 *@return The Parameter to CSC
306 */
307 protected String getIncludeDefaultReferencesParameter() {
308 return "/nostdlib" + (includeDefaultReferences ? "-" : "+");
309 }
310
311
312
313 /**
314 * If true, enables optimization flag.
315 *
316 *@param f on/off flag
317 */
318 public void setOptimize(boolean f) {
319 optimize = f;
320 }
321
322
323 /**
324 * query the optimise flag
325 *
326 *@return true if optimise is turned on
327 */
328 public boolean getOptimize() {
329 return optimize;
330 }
331
332
333 /**
334 * get the optimise flag or null for no argument needed
335 *
336 *@return The Optimize Parameter to CSC
337 */
338 protected String getOptimizeParameter() {
339 return "/optimize" + (optimize ? "+" : "-");
340 }
341
342
343 /**
344 * set the debug flag on or off.
345 *
346 *@param f on/off flag
347 */
348 public void setDebug(boolean f) {
349 debug = f;
350 }
351
352
353 /**
354 * query the debug flag
355 *
356 *@return true if debug is turned on
357 */
358 public boolean getDebug() {
359 return debug;
360 }
361
362
363 /**
364 * get the debug switch argument
365 *
366 *@return The Debug Parameter to CSC
367 */
368 protected String getDebugParameter() {
369 return "/debug" + (debug ? "+" : "-");
370 }
371
372
373 /**
374 * Level of warning currently between 1 and 4
375 * with 4 being the strictest.
376 *
377 *@param warnLevel warn level -see .net docs for valid range (probably
378 * 0-4)
379 */
380 public void setWarnLevel(int warnLevel) {
381 this.warnLevel = warnLevel;
382 }
383
384
385 /**
386 * query warn level
387 *
388 *@return current value
389 */
390 public int getWarnLevel() {
391 return warnLevel;
392 }
393
394
395 /**
396 * get the warn level switch
397 *
398 *@return The WarnLevel Parameter to CSC
399 */
400 protected String getWarnLevelParameter() {
401 return "/warn:" + warnLevel;
402 }
403
404
405 /**
406 * Sets the name of main class for executables.
407 *
408 *@param mainClass The new MainClass value
409 */
410 public void setMainClass(String mainClass) {
411 this.mainClass = mainClass;
412 }
413
414
415 /**
416 * Gets the MainClass attribute
417 *
418 *@return The MainClass value
419 */
420 public String getMainClass() {
421 return this.mainClass;
422 }
423
424
425 /**
426 * get the /main argument or null for no argument needed
427 *
428 *@return The MainClass Parameter to CSC
429 */
430 protected String getMainClassParameter() {
431 if (mainClass != null && mainClass.length() != 0) {
432 return "/main:" + mainClass;
433 } else {
434 return null;
435 }
436 }
437
438
439 /**
440 * Any extra options which are not explicitly supported
441 * by this task.
442 *
443 *@param extraOptions The new ExtraOptions value
444 */
445 public void setExtraOptions(String extraOptions) {
446 this.extraOptions = extraOptions;
447 }
448
449
450 /**
451 * Gets the ExtraOptions attribute
452 *
453 *@return The ExtraOptions value
454 */
455 public String getExtraOptions() {
456 return this.extraOptions;
457 }
458
459
460 /**
461 * get any extra options or null for no argument needed
462 *
463 *@return The ExtraOptions Parameter to CSC
464 */
465 protected String getExtraOptionsParameter() {
466 if (extraOptions != null && extraOptions.length() != 0) {
467 return extraOptions;
468 } else {
469 return null;
470 }
471 }
472
473 /**
474 * get any extra options or null for no argument needed, split
475 * them if they represent multiple options.
476 *
477 * @return The ExtraOptions Parameter to CSC
478 */
479 protected String[] getExtraOptionsParameters() {
480 String extra = getExtraOptionsParameter();
481 return extra == null ? null : Commandline.translateCommandline(extra);
482 }
483
484 /**
485 * Set the destination directory of files to be compiled.
486 *
487 *@param dirName The new DestDir value
488 */
489 public void setDestDir(File dirName) {
490 log("DestDir currently unused", Project.MSG_WARN);
491 }
492
493
494 /**
495 * set the target type to one of exe|library|module|winexe
496 * @param targetType
497 */
498 public void setTargetType(TargetTypes targetType) {
499 this.targetType = targetType.getValue();
500 }
501 /**
502 * Set the type of target.
503 *
504 *@param ttype The new TargetType value
505 *@exception BuildException if target is not one of
506 * exe|library|module|winexe
507 */
508 public void setTargetType(String ttype)
509 throws BuildException {
510 ttype = ttype.toLowerCase();
511 if (ttype.equals("exe") || ttype.equals("library")
512 || ttype.equals("module") || ttype.equals("winexe")) {
513 targetType = ttype;
514 } else {
515 throw new BuildException("targetType " + ttype
516 + " is not one of 'exe', 'module', 'winexe' or 'library'");
517 }
518 }
519
520
521 /**
522 * Gets the TargetType attribute
523 *
524 *@return The TargetType value
525 */
526 public String getTargetType() {
527 return targetType;
528 }
529
530
531 /**
532 * get the argument or null for no argument needed
533 *
534 *@return The TargetType Parameter to CSC
535 */
536 protected String getTargetTypeParameter() {
537 if (notEmpty(targetType)) {
538 return "/target:" + targetType;
539 } else {
540 return null;
541 }
542 }
543
544
545 /**
546 * Set the filename of icon to include.
547 *
548 *@param fileName path to the file. Can be relative, absolute, whatever.
549 */
550 public void setWin32Icon(File fileName) {
551 win32icon = fileName;
552 }
553
554
555 /**
556 * get the argument or null for no argument needed
557 *
558 *@return The Win32Icon Parameter to CSC
559 */
560 protected String getWin32IconParameter() {
561 if (win32icon != null) {
562 return "/win32icon:" + win32icon.toString();
563 } else {
564 return null;
565 }
566 }
567
568
569 /**
570 * Sets the filename of a win32 resource (.RES) file to include.
571 * This is not a .NET resource, but what Windows is used to.
572 *
573 *@param fileName path to the file. Can be relative, absolute, whatever.
574 */
575 public void setWin32Res(File fileName) {
576 win32res = fileName;
577 }
578
579 /**
580 * Gets the file of the win32 .res file to include.
581 * @return path to the file.
582 */
583 public File getWin32Res() {
584 return win32res;
585 }
586
587
588 /**
589 * get the argument or null for no argument needed
590 *
591 *@return The Win32Res Parameter to CSC
592 */
593 protected String getWin32ResParameter() {
594 if (win32res != null) {
595 return "/win32res:" + win32res.toString();
596 } else {
597 return null;
598 }
599 }
600
601
602 /**
603 * If true, require all compiler output to be in UTF8 format.
604 *
605 *@param enabled The new utf8Output value
606 */
607 public void setUtf8Output(boolean enabled) {
608 utf8output = enabled;
609 }
610
611
612 /**
613 * Gets the utf8OutpuParameter attribute of the CSharp object
614 *
615 *@return The utf8OutpuParameter value
616 */
617 protected String getUtf8OutputParameter() {
618 return utf8output ? "/utf8output" : null;
619 }
620
621
622 /**
623 * add a define to the list of definitions
624 * @param define
625 */
626 public void addDefine(DotnetDefine define) {
627 definitionList.addElement(define);
628 }
629
630
631 /**
632 * get a list of definitions or null
633 * @return a string beginning /D: or null for no definitions
634 */
635 protected String getDefinitionsParameter() throws BuildException {
636 StringBuffer defines = new StringBuffer();
637 Enumeration defEnum = definitionList.elements();
638 boolean firstDefinition = true;
639 while (defEnum.hasMoreElements()) {
640 //loop through all definitions
641 DotnetDefine define = (DotnetDefine) defEnum.nextElement();
642 if (define.isSet(this)) {
643 //add those that are set, and a delimiter
644 if (!firstDefinition) {
645 defines.append(getDefinitionsDelimiter());
646 }
647 defines.append(define.getValue(this));
648 firstDefinition = false;
649 }
650 }
651 if (defines.length() == 0) {
652 return null;
653 } else {
654 return "/d:" + defines;
655 }
656 }
657
658
659 /**
660 * Semicolon separated list of modules to refer to.
661 *
662 *@param params The new additionalModules value
663 */
664 public void setAdditionalModules(String params) {
665 additionalModules = params;
666 }
667
668
669 /**
670 * get the argument or null for no argument needed
671 *
672 *@return The AdditionalModules Parameter to CSC
673 */
674 protected String getAdditionalModulesParameter() {
675 if (notEmpty(additionalModules)) {
676 return "/addmodule:" + additionalModules;
677 } else {
678 return null;
679 }
680 }
681
682
683 /**
684 * get the argument or null for no argument needed
685 *
686 *@return The OutputFile Parameter to CSC
687 */
688 protected String getDestFileParameter() {
689 if (outputFile != null) {
690 return "/out:" + outputFile.toString();
691 } else {
692 return null;
693 }
694 }
695
696
697 /**
698 * If true, fail on compilation errors.
699 *
700 *@param b The new FailOnError value
701 */
702 public void setFailOnError(boolean b) {
703 failOnError = b;
704 }
705
706
707 /**
708 * query fail on error flag
709 *
710 *@return The FailFailOnError value
711 */
712 public boolean getFailOnError() {
713 return failOnError;
714 }
715
716 /**
717 * link or embed a resource
718 * @param resource
719 */
720 public void addResource(DotnetResource resource) {
721 resources.add(resource);
722 }
723
724 /**
725 * This method gets the name of the executable.
726 * @return the name of the executable
727 */
728 protected String getExecutable() {
729 return executable;
730 }
731
732 /**
733 * set the name of the program, overriding the defaults.
734 * Can be used to set the full path to a program, or to switch
735 * to an alternate implementation of the command, such as the Mono or Rotor
736 * versions -provided they use the same command line arguments as the
737 * .NET framework edition
738 * @param executable
739 */
740 public void setExecutable(String executable) {
741 this.executable = executable;
742 }
743
744 /**
745 * test for a string containing something useful
746 *
747 *@param s string in
748 *@return true if the argument is not null or empty
749 */
750 protected boolean notEmpty(String s) {
751 return s != null && s.length() != 0;
752 }
753
754 /**
755 * validation code
756 * @throws BuildException if validation failed
757 */
758 protected void validate()
759 throws BuildException {
760 if (outputFile != null && outputFile.isDirectory()) {
761 throw new BuildException("destFile cannot be a directory");
762 }
763 if (getExecutable() == null) {
764 throw new BuildException("There is no executable defined for this task");
765 }
766 }
767
768 /**
769 * Get the pattern for files to compile.
770 * @return The compilation file pattern.
771 */
772 public String getFilePattern() {
773 return "**/*." + getFileExtension();
774 }
775
776 /**
777 * getter for flag
778 * @return The flag indicating whether the compilation is using a response file.
779 */
780 public boolean isUseResponseFile() {
781 return useResponseFile;
782 }
783
784 /**
785 * Flag to turn on response file use; default=false.
786 * When set the command params are saved to a file and
787 * this is passed in with @file. The task automatically switches
788 * to this mode with big commands; this option is here for
789 * testing and emergencies
790 * @param useResponseFile
791 */
792 public void setUseResponseFile(boolean useResponseFile) {
793 this.useResponseFile = useResponseFile;
794 }
795
796 /**
797 * do the work by building the command line and then calling it
798 *
799 *@throws BuildException if validation or execution failed
800 */
801 public void execute()
802 throws BuildException {
803 validate();
804 NetCommand command = createNetCommand();
805 //set up response file options
806 command.setAutomaticResponseFileThreshold(AUTOMATIC_RESPONSE_FILE_THRESHOLD);
807 command.setUseResponseFile(useResponseFile);
808 //fill in args
809 fillInSharedParameters(command);
810 addResources(command);
811 addCompilerSpecificOptions(command);
812 int referencesOutOfDate
813 = addReferenceFilesets(command, getOutputFileTimestamp());
814 //if the refs are out of date, force a build.
815 boolean forceBuild = referencesOutOfDate > 0;
816 addFilesAndExecute(command, forceBuild);
817
818 }
819
820 /**
821 * Get the delimiter that the compiler uses between references.
822 * For example, c# will return ";"; VB.NET will return ","
823 * @return The string delimiter for the reference string.
824 */
825 public abstract String getReferenceDelimiter();
826
827 /**
828 * Get the extension of filenames to compile.
829 * @return The string extension of files to compile.
830 */
831 public abstract String getFileExtension();
832
833
834 /**
835 * fill in the common information
836 * @param command
837 */
838 protected void fillInSharedParameters(NetCommand command) {
839 command.setFailOnError(getFailOnError());
840 //fill in args
841 command.addArgument("/nologo");
842 command.addArgument(getAdditionalModulesParameter());
843 command.addArgument(getDebugParameter());
844 command.addArgument(getDefinitionsParameter());
845 command.addArguments(getExtraOptionsParameters());
846 command.addArgument(getMainClassParameter());
847 command.addArgument(getOptimizeParameter());
848 command.addArgument(getDestFileParameter());
849 command.addArgument(getReferencesParameter());
850 command.addArgument(getTargetTypeParameter());
851 command.addArgument(getUtf8OutputParameter());
852 command.addArgument(getWin32IconParameter());
853 command.addArgument(getWin32ResParameter());
854 }
855
856 /**
857 * for every resource declared, we get the (language specific)
858 * resource setting
859 */
860 protected void addResources(NetCommand command) {
861 Enumeration e = resources.elements();
862 while (e.hasMoreElements()) {
863 DotnetResource resource = (DotnetResource) e.nextElement();
864 command.addArgument(createResourceParameter(resource));
865 }
866 }
867
868 /**
869 * from a resource, get the
870 * @param resource
871 * @return a string containing the resource param, or a null string
872 * to conditionally exclude a resource.
873 */
874 protected abstract String createResourceParameter(DotnetResource resource);
875
876
877 /**
878 * run through the list of reference files and add them to the command
879 * @param outputTimestamp timestamp to compare against
880 * @return number of files out of date
881 */
882
883 protected int addReferenceFilesets(NetCommand command, long outputTimestamp) {
884 int filesOutOfDate = 0;
885 Hashtable filesToBuild = new Hashtable();
886 for (int i = 0; i < referenceFilesets.size(); i++) {
887 FileSet fs = (FileSet) referenceFilesets.elementAt(i);
888 filesOutOfDate += command.scanOneFileset(
889 fs.getDirectoryScanner(getProject()),
890 filesToBuild,
891 outputTimestamp);
892 }
893 //bail out early if there were no files
894 if (filesToBuild.size() == 0) {
895 return 0;
896 }
897 StringBuffer referenceList = new StringBuffer(REFERENCE_OPTION);
898 //now scan the hashtable and add the files
899 Enumeration files = filesToBuild.elements();
900 boolean firstEntry = true;
901 while (files.hasMoreElements()) {
902 File file = (File) files.nextElement();
903 if (isFileManagedBinary(file)) {
904 if (!firstEntry) {
905 referenceList.append(getReferenceDelimiter());
906 }
907 referenceList.append(file.toString());
908 firstEntry = false;
909 } else {
910 log("ignoring " + file + " as it is not a managed executable",
911 Project.MSG_VERBOSE);
912 }
913
914 }
915 //add it all to an argument
916 command.addArgument(referenceList.toString());
917 return filesOutOfDate;
918 }
919
920 /**
921 * create our helper command
922 * @return a command prefilled with the exe name and task name
923 */
924 protected NetCommand createNetCommand() {
925 NetCommand command = new NetCommand(this, getTaskName(), getExecutable());
926 return command;
927 }
928
929 /**
930 * add any compiler specifics
931 * @param command
932 */
933 protected abstract void addCompilerSpecificOptions(NetCommand command);
934
935 /**
936 * override point for delimiting definitions.
937 * @return The definitions limiter, i.e., ";"
938 */
939 public String getDefinitionsDelimiter() {
940 return ";";
941 }
942
943
944 /**
945 * test for a file being managed or not
946 * @return true if we think this is a managed executable, and thus OK
947 * for linking
948 * @todo look at the PE header of the exe and see if it is managed or not.
949 */
950 protected static boolean isFileManagedBinary(File file) {
951 String filename = file.toString().toLowerCase();
952 return filename.endsWith(".exe") || filename.endsWith(".dll")
953 || filename.endsWith(".netmodule");
954 }
955
956 /**
957 * Target types to build.
958 * valid build types are exe|library|module|winexe
959 */
960 public static class TargetTypes extends EnumeratedAttribute {
961 public String[] getValues() {
962 return new String[] {
963 "exe",
964 "library",
965 "module",
966 "winexe"
967 };
968 }
969 }
970
971
972}
973
974
Note: See TracBrowser for help on using the repository browser.