Include waf as an extracted source directory, rather than as a one-in-a-file script.
[ira/wip.git] / buildtools / wafadmin / Tools / javaw.py
diff --git a/buildtools/wafadmin/Tools/javaw.py b/buildtools/wafadmin/Tools/javaw.py
new file mode 100644 (file)
index 0000000..301ebc4
--- /dev/null
@@ -0,0 +1,255 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2008 (ita)
+
+"""
+Java support
+
+Javac is one of the few compilers that behaves very badly:
+* it outputs files where it wants to (-d is only for the package root)
+* it recompiles files silently behind your back
+* it outputs an undefined amount of files (inner classes)
+
+Fortunately, the convention makes it possible to use the build dir without
+too many problems for the moment
+
+Inner classes must be located and cleaned when a problem arise,
+for the moment waf does not track the production of inner classes.
+
+Adding all the files to a task and executing it if any of the input files
+change is only annoying for the compilation times
+
+Compilation can be run using Jython[1] rather than regular Python. Instead of
+running one of the following commands:
+    ./waf configure
+    python waf configure
+You would have to run:
+    java -jar /path/to/jython.jar waf configure
+
+[1] http://www.jython.org/
+"""
+
+import os, re
+from Configure import conf
+import TaskGen, Task, Utils, Options, Build
+from TaskGen import feature, before, taskgen
+
+class_check_source = '''
+public class Test {
+       public static void main(String[] argv) {
+               Class lib;
+               if (argv.length < 1) {
+                       System.err.println("Missing argument");
+                       System.exit(77);
+               }
+               try {
+                       lib = Class.forName(argv[0]);
+               } catch (ClassNotFoundException e) {
+                       System.err.println("ClassNotFoundException");
+                       System.exit(1);
+               }
+               lib = null;
+               System.exit(0);
+       }
+}
+'''
+
+@feature('jar')
+@before('apply_core')
+def jar_files(self):
+       basedir = getattr(self, 'basedir', '.')
+       destfile = getattr(self, 'destfile', 'test.jar')
+       jaropts = getattr(self, 'jaropts', [])
+       jarcreate = getattr(self, 'jarcreate', 'cf')
+
+       dir = self.path.find_dir(basedir)
+       if not dir: raise
+
+       jaropts.append('-C')
+       jaropts.append(dir.abspath(self.env))
+       jaropts.append('.')
+
+       out = self.path.find_or_declare(destfile)
+
+       tsk = self.create_task('jar_create')
+       tsk.set_outputs(out)
+       tsk.inputs = [x for x in dir.find_iter(src=0, bld=1) if x.id != out.id]
+       tsk.env['JAROPTS'] = jaropts
+       tsk.env['JARCREATE'] = jarcreate
+
+@feature('javac')
+@before('apply_core')
+def apply_java(self):
+       Utils.def_attrs(self, jarname='', jaropts='', classpath='',
+               sourcepath='.', srcdir='.', source_re='**/*.java',
+               jar_mf_attributes={}, jar_mf_classpath=[])
+
+       if getattr(self, 'source_root', None):
+               # old stuff
+               self.srcdir = self.source_root
+
+
+       nodes_lst = []
+
+       if not self.classpath:
+               if not self.env['CLASSPATH']:
+                       self.env['CLASSPATH'] = '..' + os.pathsep + '.'
+       else:
+               self.env['CLASSPATH'] = self.classpath
+
+       srcdir_node = self.path.find_dir(self.srcdir)
+       if not srcdir_node:
+               raise Utils.WafError('could not find srcdir %r' % self.srcdir)
+
+       src_nodes = [x for x in srcdir_node.ant_glob(self.source_re, flat=False)]
+       bld_nodes = [x.change_ext('.class') for x in src_nodes]
+
+       self.env['OUTDIR'] = [srcdir_node.bldpath(self.env)]
+
+       tsk = self.create_task('javac')
+       tsk.set_inputs(src_nodes)
+       tsk.set_outputs(bld_nodes)
+
+       if getattr(self, 'compat', None):
+               tsk.env.append_value('JAVACFLAGS', ['-source', self.compat])
+
+       if hasattr(self, 'sourcepath'):
+               fold = [self.path.find_dir(x) for x in self.to_list(self.sourcepath)]
+               names = os.pathsep.join([x.srcpath() for x in fold])
+       else:
+               names = srcdir_node.srcpath()
+
+       if names:
+               tsk.env.append_value('JAVACFLAGS', ['-sourcepath', names])
+
+       if self.jarname:
+               jtsk = self.create_task('jar_create', bld_nodes, self.path.find_or_declare(self.jarname))
+               jtsk.set_run_after(tsk)
+
+               if not self.env.JAROPTS:
+                       if self.jaropts:
+                               self.env.JAROPTS = self.jaropts
+                       else:
+                               dirs = '.'
+                               self.env.JAROPTS = ['-C', ''.join(self.env['OUTDIR']), dirs]
+
+Task.simple_task_type('jar_create', '${JAR} ${JARCREATE} ${TGT} ${JAROPTS}', color='GREEN', shell=False)
+cls = Task.simple_task_type('javac', '${JAVAC} -classpath ${CLASSPATH} -d ${OUTDIR} ${JAVACFLAGS} ${SRC}', shell=False)
+cls.color = 'BLUE'
+def post_run_javac(self):
+       """this is for cleaning the folder
+       javac creates single files for inner classes
+       but it is not possible to know which inner classes in advance"""
+
+       par = {}
+       for x in self.inputs:
+               par[x.parent.id] = x.parent
+
+       inner = {}
+       for k in par.values():
+               path = k.abspath(self.env)
+               lst = os.listdir(path)
+
+               for u in lst:
+                       if u.find('$') >= 0:
+                               inner_class_node = k.find_or_declare(u)
+                               inner[inner_class_node.id] = inner_class_node
+
+       to_add = set(inner.keys()) - set([x.id for x in self.outputs])
+       for x in to_add:
+               self.outputs.append(inner[x])
+
+       self.cached = True # disable the cache here - inner classes are a problem
+       return Task.Task.post_run(self)
+cls.post_run = post_run_javac
+
+def detect(conf):
+       # If JAVA_PATH is set, we prepend it to the path list
+       java_path = conf.environ['PATH'].split(os.pathsep)
+       v = conf.env
+
+       if 'JAVA_HOME' in conf.environ:
+               java_path = [os.path.join(conf.environ['JAVA_HOME'], 'bin')] + java_path
+               conf.env['JAVA_HOME'] = [conf.environ['JAVA_HOME']]
+
+       for x in 'javac java jar'.split():
+               conf.find_program(x, var=x.upper(), path_list=java_path)
+               conf.env[x.upper()] = conf.cmd_to_list(conf.env[x.upper()])
+       v['JAVA_EXT'] = ['.java']
+
+       if 'CLASSPATH' in conf.environ:
+               v['CLASSPATH'] = conf.environ['CLASSPATH']
+
+       if not v['JAR']: conf.fatal('jar is required for making java packages')
+       if not v['JAVAC']: conf.fatal('javac is required for compiling java classes')
+       v['JARCREATE'] = 'cf' # can use cvf
+
+@conf
+def check_java_class(self, classname, with_classpath=None):
+       """Check if the specified java class is installed"""
+
+       import shutil
+
+       javatestdir = '.waf-javatest'
+
+       classpath = javatestdir
+       if self.env['CLASSPATH']:
+               classpath += os.pathsep + self.env['CLASSPATH']
+       if isinstance(with_classpath, str):
+               classpath += os.pathsep + with_classpath
+
+       shutil.rmtree(javatestdir, True)
+       os.mkdir(javatestdir)
+
+       java_file = open(os.path.join(javatestdir, 'Test.java'), 'w')
+       java_file.write(class_check_source)
+       java_file.close()
+
+       # Compile the source
+       Utils.exec_command(self.env['JAVAC'] + [os.path.join(javatestdir, 'Test.java')], shell=False)
+
+       # Try to run the app
+       cmd = self.env['JAVA'] + ['-cp', classpath, 'Test', classname]
+       self.log.write("%s\n" % str(cmd))
+       found = Utils.exec_command(cmd, shell=False, log=self.log)
+
+       self.check_message('Java class %s' % classname, "", not found)
+
+       shutil.rmtree(javatestdir, True)
+
+       return found
+
+@conf
+def check_jni_headers(conf):
+       """
+       Check for jni headers and libraries
+
+       On success the environment variable xxx_JAVA is added for uselib
+       """
+
+       if not conf.env.CC_NAME and not conf.env.CXX_NAME:
+               conf.fatal('load a compiler first (gcc, g++, ..)')
+
+       if not conf.env.JAVA_HOME:
+               conf.fatal('set JAVA_HOME in the system environment')
+
+       # jni requires the jvm
+       javaHome = conf.env['JAVA_HOME'][0]
+
+       b = Build.BuildContext()
+       b.load_dirs(conf.srcdir, conf.blddir)
+       dir = b.root.find_dir(conf.env.JAVA_HOME[0] + '/include')
+       f = dir.ant_glob('**/(jni|jni_md).h', flat=False)
+       incDirs = [x.parent.abspath() for x in f]
+
+       dir = b.root.find_dir(conf.env.JAVA_HOME[0])
+       f = dir.ant_glob('**/*jvm.(so|dll)', flat=False)
+       libDirs = [x.parent.abspath() for x in f] or [javaHome]
+
+       for i, d in enumerate(libDirs):
+               if conf.check(header_name='jni.h', define_name='HAVE_JNI_H', lib='jvm',
+                               libpath=d, includes=incDirs, uselib_store='JAVA', uselib='JAVA'):
+                       break
+       else:
+               conf.fatal('could not find lib jvm in %r (see config.log)' % libDirs)
+