| /* |
| * Copyright 1999-2004 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jk.ant; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.PrintStream; |
| import java.util.Enumeration; |
| import java.util.Vector; |
| |
| import org.apache.jk.ant.compilers.CcCompiler; |
| import org.apache.jk.ant.compilers.CompilerAdapter; |
| import org.apache.jk.ant.compilers.GcjCompiler; |
| import org.apache.jk.ant.compilers.GcjLinker; |
| import org.apache.jk.ant.compilers.LibtoolCompiler; |
| import org.apache.jk.ant.compilers.LibtoolLinker; |
| import org.apache.jk.ant.compilers.LinkerAdapter; |
| import org.apache.jk.ant.compilers.MsvcCompiler; |
| import org.apache.jk.ant.compilers.MsvcLinker; |
| import org.apache.jk.ant.compilers.MwccCompiler; |
| import org.apache.jk.ant.compilers.MwldLinker; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.DirectoryScanner; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.taskdefs.Execute; |
| import org.apache.tools.ant.taskdefs.ExecuteStreamHandler; |
| import org.apache.tools.ant.taskdefs.PumpStreamHandler; |
| import org.apache.tools.ant.types.Commandline; |
| import org.apache.tools.ant.types.FileSet; |
| import org.apache.tools.ant.types.Path; |
| import org.apache.tools.ant.types.PatternSet; |
| |
| /** Global properties |
| |
| Same idea as in javac, some user .properties will set the local preferences, |
| including machine-specific. If one is not specified we'll guess it. The |
| build file will be clean. |
| |
| TODO: can we get configure to generate such a file ? |
| |
| build.native.cc=gcc |
| # Path to libtool ( used as a backup ) |
| build.native.libtool= |
| # Platform-specific flags for compilation. |
| build.native.extra_cflags= |
| */ |
| /* XXX add a optional "compiler" attribute |
| to not guess the compiler based on the executable name |
| present in a global property. |
| |
| */ |
| |
| |
| /** |
| * Task to generate a .so file, similar with ( or using ) libtool. |
| * I hate libtool, so long term I would like to replace most of it |
| * with decent java code. Short term it'll just use libtool and |
| * hide some of the ugliness. |
| * |
| * arguments: |
| * <ul> |
| * <li>source |
| * </ul> |
| * |
| * <p> |
| * |
| * @author Costin Manolache |
| * @author Mike Anderson |
| * @author Ignacio J. Ortega |
| */ |
| public class SoTask extends Task { |
| protected String apxs; |
| // or FileSet ? |
| protected Vector src; //[FileSet] |
| protected PatternSet includes; |
| protected Path depends; |
| protected Path libs; |
| protected String module; |
| protected String soFile; |
| protected String soExt = ".so"; |
| protected String cflags; |
| protected File buildDir; |
| protected int debug; |
| |
| protected boolean optG=true; |
| protected boolean optWgcc=true; |
| protected boolean optimize=false; |
| protected boolean profile=false; |
| protected Vector defines = new Vector(); |
| protected Vector imports = new Vector(); // used by the NetWare, win32 linkers |
| protected Vector exports = new Vector(); // used by the NetWare, win32 linkers |
| protected Vector modules = new Vector(); // used by the NetWare linker |
| protected Vector linkOpts = new Vector(); // used by the NetWare, win32 linkers |
| protected Vector altSoFiles = new Vector(); // used by the NetWare linker |
| protected Vector resources = new Vector(); // used by the win32 linker |
| |
| // Computed fields |
| // protected Vector compileList; // [Source] |
| protected Vector srcList=new Vector(); |
| protected CompilerAdapter compiler; |
| // protected GlobPatternMapper co_mapper; |
| |
| public SoTask() {}; |
| |
| // Hack to allow individual compilers/linkers to work |
| // as regular Tasks, independnetly. |
| public void duplicateTo(SoTask so) { |
| // This will act as a proxy for the child task |
| so.project=project; |
| so.target=target; |
| so.location=location; |
| so.taskName=taskName; |
| so.taskType=taskType; |
| |
| so.apxs=apxs; |
| so.src=src; |
| so.includes=includes; |
| so.depends=depends; |
| so.libs=libs; |
| so.module=module; |
| so.soFile=soFile; |
| so.soExt=soExt; |
| so.cflags=cflags; |
| so.buildDir=buildDir; |
| so.debug=debug; |
| so.optG=optG; |
| so.optWgcc=optWgcc; |
| so.optimize=optimize; |
| so.profile=profile; |
| so.defines=defines; |
| so.imports=imports; |
| so.exports=exports; |
| so.resources=resources; |
| so.modules=modules; |
| so.linkOpts=linkOpts; |
| so.srcList=srcList; |
| // so.compileList=compileList; |
| so.compiler=compiler; |
| // so.co_mapper=co_mapper; |
| so.altSoFiles=altSoFiles; |
| } |
| |
| /** @deprecated use setTarget |
| */ |
| public void setSoFile(String s ) { |
| soFile=s; |
| } |
| |
| /** Add debug information |
| */ |
| public void setDebug(boolean b) { |
| optG=b; |
| } |
| |
| /** Add debug information |
| */ |
| public void setOptimize(boolean b) { |
| optimize=b; |
| } |
| |
| /** Add profiling information |
| */ |
| public void setProfile(boolean b) { |
| profile=b; |
| } |
| |
| /** Gcc warnings |
| */ |
| public void setGccWarn(boolean b) { |
| optWgcc=b; |
| } |
| |
| /** Debug the <so> task |
| */ |
| public void setTaskDebug(int i) { |
| debug=i; |
| } |
| |
| /** Add a -D option. Note that each define has |
| * an if/unless attribute |
| */ |
| public void addDef(Def var ) { |
| var.setProject( project ); |
| defines.addElement(var); |
| } |
| |
| /** |
| * Add an import file/symbol for NetWare or win32 platform |
| * |
| * |
| */ |
| public void addImport(JkData imp) { |
| imp.setProject( project ); |
| imports.add(imp); |
| } |
| |
| /** |
| * Add an export file/symbol for NetWare or win32 platform |
| * |
| * |
| */ |
| public void addExport(JkData exp) { |
| exp.setProject( project ); |
| exports.add(exp); |
| } |
| |
| /** |
| * Add an resource file on win32 platform |
| * |
| * |
| */ |
| public void addResource(JkData res) { |
| res.setProject( project ); |
| resources.add(res); |
| } |
| |
| /** |
| * Add a link option for NetWare or win32 platform |
| * |
| * |
| */ |
| public void addLinkOpt(JkData option) { |
| option.setProject( project ); |
| linkOpts.add(option); |
| } |
| |
| /** |
| * Add an NLMModule dependancy |
| * |
| * |
| */ |
| public void addNLMModule(JkData module) { |
| module.setProject( project ); |
| modules.add(module); |
| } |
| |
| /** |
| * Add an alternate target since some platforms (NetWare) have file name |
| * limitations. |
| * |
| */ |
| public void addAltSoFile(JkData altSo) { |
| altSo.setProject( project ); |
| altSoFiles.add(altSo); |
| } |
| |
| /** Set the target for this compilation. Don't include any |
| * directory or suffix ( not sure about prefix - we may want |
| * to add lib automatically for unix, and nothing on win/etc ? ). |
| */ |
| public void setTarget(String s ) { |
| soFile=s; |
| } |
| |
| /** Set the extension for the target. This will depend on the platform |
| * we are compiling for. |
| */ |
| public void setExtension(String s ) { |
| soExt=s; |
| } |
| |
| /** Directory where intermediary objects will be |
| * generated |
| */ |
| public void setBuildDir( File s ) { |
| buildDir=s; |
| } |
| |
| public void setCflags(String s ) { |
| cflags=s; |
| } |
| |
| /** Directory where the .so file will be generated |
| */ |
| public void setSoDir( String s ) { |
| |
| } |
| |
| public void addJniConfig( JniConfig jniCfg ) { |
| |
| } |
| |
| public void addApacheConfig( ApacheConfig apacheCfg ) { |
| |
| } |
| |
| |
| /** |
| * Source files ( .c ) |
| * |
| * @return a nested src element. |
| */ |
| public void addSrc(FileSet fl) { |
| if( src==null ) src=new Vector(); |
| src.addElement(fl); |
| } |
| |
| /** |
| * Include files |
| */ |
| public PatternSet createIncludes() { |
| includes=new PatternSet(); //Path(project); |
| return includes; |
| } |
| |
| /** |
| * General dependencies. If any of the files is modified |
| * ( i.e. is newer than the oldest .o ) we'll recompile everything. |
| * |
| * This can be used for headers ( until we add support for makedepend) |
| * or any important file that could invalidate the build. |
| * Another example is checking httpd or apxs ( if a new version |
| * was installed, maybe some flags or symbols changed ) |
| */ |
| public Path createDepends() { |
| depends=new Path(project); |
| return depends; |
| } |
| |
| /** |
| * Libraries ( .a, .so or .dll ) files to link to. |
| */ |
| public Path createLibs() { |
| libs=new Path(project); |
| return libs; |
| } |
| |
| |
| /** |
| * The name of the target file. |
| * (XXX including extension - this should be automatically added ) |
| */ |
| public void setModule(String modName) { |
| this.module = modName; // Should be this ? |
| } |
| |
| // XXX Add specific code for Netware, Windows and platforms where libtool |
| // is problematic |
| |
| // XXX Add specific code for Linux and platforms where things are |
| // clean, libtool should be just a fallback. |
| public void execute() throws BuildException { |
| compiler=findCompilerAdapter(); |
| // co_mapper=compiler.getOMapper(); |
| LinkerAdapter linker=findLinkerAdapter(); |
| |
| if( soFile==null ) |
| throw new BuildException("No target ( " + soExt + " file )"); |
| if (src == null) |
| throw new BuildException("No source files"); |
| |
| // XXX makedepend-type dependencies - how ?? |
| // We could generate a dummy Makefile and parse the content... |
| findSourceFiles(); |
| |
| // Copy all settings into compiler |
| this.duplicateTo(compiler); |
| compiler.compile( srcList ); |
| |
| // XXX move this checking to linker |
| File soTarget=new File( buildDir, soFile + soExt ); |
| if( compiler.getCompiledFiles().size() == 0 && soTarget.exists()) { |
| // No dependency, no need to relink |
| return; |
| } |
| |
| this.duplicateTo(linker); |
| linker.link(srcList); |
| } |
| |
| public CompilerAdapter findCompilerAdapter() { |
| CompilerAdapter compilerAdapter; |
| String cc; |
| cc=project.getProperty("build.compiler.cc"); |
| if( cc!=null ) { |
| if( "cc".equals( cc ) ) { |
| compilerAdapter=new CcCompiler(); |
| compilerAdapter.setSoTask( this ); |
| return compilerAdapter; |
| } |
| if( "gcj".equals( cc ) ) { |
| compilerAdapter=new GcjCompiler(); |
| compilerAdapter.setSoTask( this ); |
| return compilerAdapter; |
| } |
| if( cc.indexOf("mwccnlm") != -1 ) { |
| compilerAdapter=new MwccCompiler(); |
| compilerAdapter.setSoTask( this ); |
| return compilerAdapter; |
| } |
| if( cc.indexOf("cl") != -1 ) { |
| compilerAdapter=new MsvcCompiler(); |
| compilerAdapter.setSoTask( this ); |
| return compilerAdapter; |
| } |
| } |
| |
| compilerAdapter=new LibtoolCompiler(); |
| compilerAdapter.setSoTask( this ); |
| return compilerAdapter; |
| } |
| |
| public LinkerAdapter findLinkerAdapter() { |
| LinkerAdapter linkerAdapter; |
| String ld=project.getProperty("build.compiler.ld"); |
| if( ld!=null ) { |
| if( ld.indexOf("mwldnlm") != -1 ) { |
| linkerAdapter=new MwldLinker(); |
| linkerAdapter.setSoTask( this ); |
| return linkerAdapter; |
| } |
| if( ld.indexOf("link") != -1 ) { |
| linkerAdapter=new MsvcLinker(); |
| linkerAdapter.setSoTask( this ); |
| return linkerAdapter; |
| } |
| // if( "ld".equals( cc ) ) { |
| // linkerAdapter=new LdLinker(); |
| // linkerAdapter.setSoTask( this ); |
| // return cc; |
| // } |
| } |
| |
| String cc=project.getProperty("build.compiler.cc"); |
| if( "gcj".equals( cc ) ) { |
| linkerAdapter=new GcjLinker(); |
| linkerAdapter.setSoTask( this ); |
| return linkerAdapter; |
| } |
| |
| |
| linkerAdapter=new LibtoolLinker(); |
| linkerAdapter.setSoTask( this ); |
| return linkerAdapter; |
| } |
| |
| /** Find all source files declared with <src> elements |
| */ |
| public void findSourceFiles() { |
| if (buildDir == null) buildDir = project.getBaseDir(); |
| |
| Enumeration e=src.elements(); |
| while( e.hasMoreElements() ) { |
| FileSet fs=(FileSet)e.nextElement(); |
| DirectoryScanner ds=fs.getDirectoryScanner( project ); |
| String localList[]= ds.getIncludedFiles(); |
| if (localList.length == 0) |
| throw new BuildException("No source files "); |
| for( int i=0; i<localList.length; i++ ) { |
| srcList.addElement( new Source( fs.getDir(project), localList[i])); |
| } |
| } |
| } |
| |
| /** If any file declared in <depend> element has changed, we'll do |
| a full rebuild. |
| */ |
| public boolean checkDepend(long oldestO, File oldestOFile) { |
| if( depends==null ) |
| return false; |
| String dependsA[]=depends.list(); |
| for( int i=0; i< dependsA.length; i++ ) { |
| File f=new File( dependsA[i] ); |
| if( ! f.exists() ) { |
| log("Depend not found " + f ); |
| return true; |
| } |
| if( f.lastModified() > oldestO ) { |
| log( "Depend " + f + " newer than " + oldestOFile ); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // ==================== Execution utils ==================== |
| |
| protected ExecuteStreamHandler streamhandler = null; |
| protected ByteArrayOutputStream outputstream = null; |
| protected ByteArrayOutputStream errorstream = null; |
| |
| public int execute( Commandline cmd ) throws BuildException |
| { |
| createStreamHandler(); |
| Execute exe = new Execute(streamhandler, null); |
| exe.setAntRun(project); |
| |
| exe.setWorkingDirectory(buildDir); |
| |
| exe.setCommandline(cmd.getCommandline()); |
| int result=0; |
| try { |
| result=exe.execute(); |
| } catch (IOException e) { |
| throw new BuildException(e, location); |
| } |
| return result; |
| } |
| |
| public void createStreamHandler() throws BuildException { |
| // try { |
| outputstream= new ByteArrayOutputStream(); |
| errorstream = new ByteArrayOutputStream(); |
| |
| streamhandler = |
| new PumpStreamHandler(new PrintStream(outputstream), |
| new PrintStream(errorstream)); |
| // } catch (IOException e) { |
| // throw new BuildException(e,location); |
| // } |
| } |
| |
| public void closeStreamHandler() { |
| try { |
| if (outputstream != null) |
| outputstream.close(); |
| if (errorstream != null) |
| errorstream.close(); |
| outputstream=null; |
| errorstream=null; |
| } catch (IOException e) {} |
| } |
| } |
| |