001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.jk.ant;
018:
019: import java.io.ByteArrayOutputStream;
020: import java.io.File;
021: import java.io.IOException;
022: import java.io.PrintStream;
023: import java.util.Enumeration;
024: import java.util.Vector;
025:
026: import org.apache.jk.ant.compilers.CcCompiler;
027: import org.apache.jk.ant.compilers.CompilerAdapter;
028: import org.apache.jk.ant.compilers.GcjCompiler;
029: import org.apache.jk.ant.compilers.GcjLinker;
030: import org.apache.jk.ant.compilers.LibtoolCompiler;
031: import org.apache.jk.ant.compilers.LibtoolLinker;
032: import org.apache.jk.ant.compilers.LinkerAdapter;
033: import org.apache.jk.ant.compilers.MsvcCompiler;
034: import org.apache.jk.ant.compilers.MsvcLinker;
035: import org.apache.jk.ant.compilers.MwccCompiler;
036: import org.apache.jk.ant.compilers.MwldLinker;
037: import org.apache.tools.ant.BuildException;
038: import org.apache.tools.ant.DirectoryScanner;
039: import org.apache.tools.ant.Task;
040: import org.apache.tools.ant.taskdefs.Execute;
041: import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
042: import org.apache.tools.ant.taskdefs.PumpStreamHandler;
043: import org.apache.tools.ant.types.Commandline;
044: import org.apache.tools.ant.types.FileSet;
045: import org.apache.tools.ant.types.Path;
046: import org.apache.tools.ant.types.PatternSet;
047:
048: /** Global properties
049:
050: Same idea as in javac, some user .properties will set the local preferences,
051: including machine-specific. If one is not specified we'll guess it. The
052: build file will be clean.
053:
054: TODO: can we get configure to generate such a file ?
055:
056: build.native.cc=gcc
057: # Path to libtool ( used as a backup )
058: build.native.libtool=
059: # Platform-specific flags for compilation.
060: build.native.extra_cflags=
061: */
062: /* XXX add a optional "compiler" attribute
063: to not guess the compiler based on the executable name
064: present in a global property.
065:
066: */
067:
068: /**
069: * Task to generate a .so file, similar with ( or using ) libtool.
070: * I hate libtool, so long term I would like to replace most of it
071: * with decent java code. Short term it'll just use libtool and
072: * hide some of the ugliness.
073: *
074: * arguments:
075: * <ul>
076: * <li>source
077: * </ul>
078: *
079: * <p>
080: *
081: * @author Costin Manolache
082: * @author Mike Anderson
083: * @author Ignacio J. Ortega
084: */
085: public class SoTask extends Task {
086: protected String apxs;
087: // or FileSet ?
088: protected Vector src; //[FileSet]
089: protected PatternSet includes;
090: protected Path depends;
091: protected Path libs;
092: protected String module;
093: protected String soFile;
094: protected String soExt = ".so";
095: protected String cflags;
096: protected File buildDir;
097: protected int debug;
098:
099: protected boolean optG = true;
100: protected boolean optWgcc = true;
101: protected boolean optimize = false;
102: protected boolean profile = false;
103: protected Vector defines = new Vector();
104: protected Vector imports = new Vector(); // used by the NetWare, win32 linkers
105: protected Vector exports = new Vector(); // used by the NetWare, win32 linkers
106: protected Vector modules = new Vector(); // used by the NetWare linker
107: protected Vector linkOpts = new Vector(); // used by the NetWare, win32 linkers
108: protected Vector altSoFiles = new Vector(); // used by the NetWare linker
109: protected Vector resources = new Vector(); // used by the win32 linker
110:
111: // Computed fields
112: // protected Vector compileList; // [Source]
113: protected Vector srcList = new Vector();
114: protected CompilerAdapter compiler;
115:
116: // protected GlobPatternMapper co_mapper;
117:
118: public SoTask() {
119: };
120:
121: // Hack to allow individual compilers/linkers to work
122: // as regular Tasks, independnetly.
123: public void duplicateTo(SoTask so) {
124: // This will act as a proxy for the child task
125: so.project = project;
126: so.target = target;
127: so.location = location;
128: so.taskName = taskName;
129: so.taskType = taskType;
130:
131: so.apxs = apxs;
132: so.src = src;
133: so.includes = includes;
134: so.depends = depends;
135: so.libs = libs;
136: so.module = module;
137: so.soFile = soFile;
138: so.soExt = soExt;
139: so.cflags = cflags;
140: so.buildDir = buildDir;
141: so.debug = debug;
142: so.optG = optG;
143: so.optWgcc = optWgcc;
144: so.optimize = optimize;
145: so.profile = profile;
146: so.defines = defines;
147: so.imports = imports;
148: so.exports = exports;
149: so.resources = resources;
150: so.modules = modules;
151: so.linkOpts = linkOpts;
152: so.srcList = srcList;
153: // so.compileList=compileList;
154: so.compiler = compiler;
155: // so.co_mapper=co_mapper;
156: so.altSoFiles = altSoFiles;
157: }
158:
159: /** @deprecated use setTarget
160: */
161: public void setSoFile(String s) {
162: soFile = s;
163: }
164:
165: /** Add debug information
166: */
167: public void setDebug(boolean b) {
168: optG = b;
169: }
170:
171: /** Add debug information
172: */
173: public void setOptimize(boolean b) {
174: optimize = b;
175: }
176:
177: /** Add profiling information
178: */
179: public void setProfile(boolean b) {
180: profile = b;
181: }
182:
183: /** Gcc warnings
184: */
185: public void setGccWarn(boolean b) {
186: optWgcc = b;
187: }
188:
189: /** Debug the <so> task
190: */
191: public void setTaskDebug(int i) {
192: debug = i;
193: }
194:
195: /** Add a -D option. Note that each define has
196: * an if/unless attribute
197: */
198: public void addDef(Def var) {
199: var.setProject(project);
200: defines.addElement(var);
201: }
202:
203: /**
204: * Add an import file/symbol for NetWare or win32 platform
205: *
206: *
207: */
208: public void addImport(JkData imp) {
209: imp.setProject(project);
210: imports.add(imp);
211: }
212:
213: /**
214: * Add an export file/symbol for NetWare or win32 platform
215: *
216: *
217: */
218: public void addExport(JkData exp) {
219: exp.setProject(project);
220: exports.add(exp);
221: }
222:
223: /**
224: * Add an resource file on win32 platform
225: *
226: *
227: */
228: public void addResource(JkData res) {
229: res.setProject(project);
230: resources.add(res);
231: }
232:
233: /**
234: * Add a link option for NetWare or win32 platform
235: *
236: *
237: */
238: public void addLinkOpt(JkData option) {
239: option.setProject(project);
240: linkOpts.add(option);
241: }
242:
243: /**
244: * Add an NLMModule dependancy
245: *
246: *
247: */
248: public void addNLMModule(JkData module) {
249: module.setProject(project);
250: modules.add(module);
251: }
252:
253: /**
254: * Add an alternate target since some platforms (NetWare) have file name
255: * limitations.
256: *
257: */
258: public void addAltSoFile(JkData altSo) {
259: altSo.setProject(project);
260: altSoFiles.add(altSo);
261: }
262:
263: /** Set the target for this compilation. Don't include any
264: * directory or suffix ( not sure about prefix - we may want
265: * to add lib automatically for unix, and nothing on win/etc ? ).
266: */
267: public void setTarget(String s) {
268: soFile = s;
269: }
270:
271: /** Set the extension for the target. This will depend on the platform
272: * we are compiling for.
273: */
274: public void setExtension(String s) {
275: soExt = s;
276: }
277:
278: /** Directory where intermediary objects will be
279: * generated
280: */
281: public void setBuildDir(File s) {
282: buildDir = s;
283: }
284:
285: public void setCflags(String s) {
286: cflags = s;
287: }
288:
289: /** Directory where the .so file will be generated
290: */
291: public void setSoDir(String s) {
292:
293: }
294:
295: public void addJniConfig(JniConfig jniCfg) {
296:
297: }
298:
299: public void addApacheConfig(ApacheConfig apacheCfg) {
300:
301: }
302:
303: /**
304: * Source files ( .c )
305: *
306: * @return a nested src element.
307: */
308: public void addSrc(FileSet fl) {
309: if (src == null)
310: src = new Vector();
311: src.addElement(fl);
312: }
313:
314: /**
315: * Include files
316: */
317: public PatternSet createIncludes() {
318: includes = new PatternSet(); //Path(project);
319: return includes;
320: }
321:
322: /**
323: * General dependencies. If any of the files is modified
324: * ( i.e. is newer than the oldest .o ) we'll recompile everything.
325: *
326: * This can be used for headers ( until we add support for makedepend)
327: * or any important file that could invalidate the build.
328: * Another example is checking httpd or apxs ( if a new version
329: * was installed, maybe some flags or symbols changed )
330: */
331: public Path createDepends() {
332: depends = new Path(project);
333: return depends;
334: }
335:
336: /**
337: * Libraries ( .a, .so or .dll ) files to link to.
338: */
339: public Path createLibs() {
340: libs = new Path(project);
341: return libs;
342: }
343:
344: /**
345: * The name of the target file.
346: * (XXX including extension - this should be automatically added )
347: */
348: public void setModule(String modName) {
349: this .module = modName; // Should be this ?
350: }
351:
352: // XXX Add specific code for Netware, Windows and platforms where libtool
353: // is problematic
354:
355: // XXX Add specific code for Linux and platforms where things are
356: // clean, libtool should be just a fallback.
357: public void execute() throws BuildException {
358: compiler = findCompilerAdapter();
359: // co_mapper=compiler.getOMapper();
360: LinkerAdapter linker = findLinkerAdapter();
361:
362: if (soFile == null)
363: throw new BuildException("No target ( " + soExt + " file )");
364: if (src == null)
365: throw new BuildException("No source files");
366:
367: // XXX makedepend-type dependencies - how ??
368: // We could generate a dummy Makefile and parse the content...
369: findSourceFiles();
370:
371: // Copy all settings into compiler
372: this .duplicateTo(compiler);
373: compiler.compile(srcList);
374:
375: // XXX move this checking to linker
376: File soTarget = new File(buildDir, soFile + soExt);
377: if (compiler.getCompiledFiles().size() == 0
378: && soTarget.exists()) {
379: // No dependency, no need to relink
380: return;
381: }
382:
383: this .duplicateTo(linker);
384: linker.link(srcList);
385: }
386:
387: public CompilerAdapter findCompilerAdapter() {
388: CompilerAdapter compilerAdapter;
389: String cc;
390: cc = project.getProperty("build.compiler.cc");
391: if (cc != null) {
392: if ("cc".equals(cc)) {
393: compilerAdapter = new CcCompiler();
394: compilerAdapter.setSoTask(this );
395: return compilerAdapter;
396: }
397: if ("gcj".equals(cc)) {
398: compilerAdapter = new GcjCompiler();
399: compilerAdapter.setSoTask(this );
400: return compilerAdapter;
401: }
402: if (cc.indexOf("mwccnlm") != -1) {
403: compilerAdapter = new MwccCompiler();
404: compilerAdapter.setSoTask(this );
405: return compilerAdapter;
406: }
407: if (cc.indexOf("cl") != -1) {
408: compilerAdapter = new MsvcCompiler();
409: compilerAdapter.setSoTask(this );
410: return compilerAdapter;
411: }
412: }
413:
414: compilerAdapter = new LibtoolCompiler();
415: compilerAdapter.setSoTask(this );
416: return compilerAdapter;
417: }
418:
419: public LinkerAdapter findLinkerAdapter() {
420: LinkerAdapter linkerAdapter;
421: String ld = project.getProperty("build.compiler.ld");
422: if (ld != null) {
423: if (ld.indexOf("mwldnlm") != -1) {
424: linkerAdapter = new MwldLinker();
425: linkerAdapter.setSoTask(this );
426: return linkerAdapter;
427: }
428: if (ld.indexOf("link") != -1) {
429: linkerAdapter = new MsvcLinker();
430: linkerAdapter.setSoTask(this );
431: return linkerAdapter;
432: }
433: // if( "ld".equals( cc ) ) {
434: // linkerAdapter=new LdLinker();
435: // linkerAdapter.setSoTask( this );
436: // return cc;
437: // }
438: }
439:
440: String cc = project.getProperty("build.compiler.cc");
441: if ("gcj".equals(cc)) {
442: linkerAdapter = new GcjLinker();
443: linkerAdapter.setSoTask(this );
444: return linkerAdapter;
445: }
446:
447: linkerAdapter = new LibtoolLinker();
448: linkerAdapter.setSoTask(this );
449: return linkerAdapter;
450: }
451:
452: /** Find all source files declared with <src> elements
453: */
454: public void findSourceFiles() {
455: if (buildDir == null)
456: buildDir = project.getBaseDir();
457:
458: Enumeration e = src.elements();
459: while (e.hasMoreElements()) {
460: FileSet fs = (FileSet) e.nextElement();
461: DirectoryScanner ds = fs.getDirectoryScanner(project);
462: String localList[] = ds.getIncludedFiles();
463: if (localList.length == 0)
464: throw new BuildException("No source files ");
465: for (int i = 0; i < localList.length; i++) {
466: srcList.addElement(new Source(fs.getDir(project),
467: localList[i]));
468: }
469: }
470: }
471:
472: /** If any file declared in <depend> element has changed, we'll do
473: a full rebuild.
474: */
475: public boolean checkDepend(long oldestO, File oldestOFile) {
476: if (depends == null)
477: return false;
478: String dependsA[] = depends.list();
479: for (int i = 0; i < dependsA.length; i++) {
480: File f = new File(dependsA[i]);
481: if (!f.exists()) {
482: log("Depend not found " + f);
483: return true;
484: }
485: if (f.lastModified() > oldestO) {
486: log("Depend " + f + " newer than " + oldestOFile);
487: return true;
488: }
489: }
490: return false;
491: }
492:
493: // ==================== Execution utils ====================
494:
495: protected ExecuteStreamHandler streamhandler = null;
496: protected ByteArrayOutputStream outputstream = null;
497: protected ByteArrayOutputStream errorstream = null;
498:
499: public int execute(Commandline cmd) throws BuildException {
500: createStreamHandler();
501: Execute exe = new Execute(streamhandler, null);
502: exe.setAntRun(project);
503:
504: exe.setWorkingDirectory(buildDir);
505:
506: exe.setCommandline(cmd.getCommandline());
507: int result = 0;
508: try {
509: result = exe.execute();
510: } catch (IOException e) {
511: throw new BuildException(e, location);
512: }
513: return result;
514: }
515:
516: public void createStreamHandler() throws BuildException {
517: // try {
518: outputstream = new ByteArrayOutputStream();
519: errorstream = new ByteArrayOutputStream();
520:
521: streamhandler = new PumpStreamHandler(new PrintStream(
522: outputstream), new PrintStream(errorstream));
523: // } catch (IOException e) {
524: // throw new BuildException(e,location);
525: // }
526: }
527:
528: public void closeStreamHandler() {
529: try {
530: if (outputstream != null)
531: outputstream.close();
532: if (errorstream != null)
533: errorstream.close();
534: outputstream = null;
535: errorstream = null;
536: } catch (IOException e) {
537: }
538: }
539: }
|