1"""SCons.Tool.javac 2 3Tool-specific initialization for javac. 4 5There normally shouldn't be any need to import this module directly. 6It will usually be imported through the generic SCons.Tool.Tool() 7selection method. 8 9""" 10 11# 12# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation 13# 14# Permission is hereby granted, free of charge, to any person obtaining 15# a copy of this software and associated documentation files (the 16# "Software"), to deal in the Software without restriction, including 17# without limitation the rights to use, copy, modify, merge, publish, 18# distribute, sublicense, and/or sell copies of the Software, and to 19# permit persons to whom the Software is furnished to do so, subject to 20# the following conditions: 21# 22# The above copyright notice and this permission notice shall be included 23# in all copies or substantial portions of the Software. 24# 25# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 26# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 27# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32# 33 34__revision__ = "src/engine/SCons/Tool/javac.py 4369 2009/09/19 15:58:29 scons" 35 36import os 37import os.path 38import string 39 40import SCons.Action 41import SCons.Builder 42from SCons.Node.FS import _my_normcase 43from SCons.Tool.JavaCommon import parse_java_file 44import SCons.Util 45 46def classname(path): 47 """Turn a string (path name) into a Java class name.""" 48 return string.replace(os.path.normpath(path), os.sep, '.') 49 50def emit_java_classes(target, source, env): 51 """Create and return lists of source java files 52 and their corresponding target class files. 53 """ 54 java_suffix = env.get('JAVASUFFIX', '.java') 55 class_suffix = env.get('JAVACLASSSUFFIX', '.class') 56 57 target[0].must_be_same(SCons.Node.FS.Dir) 58 classdir = target[0] 59 60 s = source[0].rentry().disambiguate() 61 if isinstance(s, SCons.Node.FS.File): 62 sourcedir = s.dir.rdir() 63 elif isinstance(s, SCons.Node.FS.Dir): 64 sourcedir = s.rdir() 65 else: 66 raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % s.__class__) 67 68 slist = [] 69 js = _my_normcase(java_suffix) 70 find_java = lambda n, js=js, ljs=len(js): _my_normcase(n[-ljs:]) == js 71 for entry in source: 72 entry = entry.rentry().disambiguate() 73 if isinstance(entry, SCons.Node.FS.File): 74 slist.append(entry) 75 elif isinstance(entry, SCons.Node.FS.Dir): 76 result = SCons.Util.OrderedDict() 77 def visit(arg, dirname, names, fj=find_java, dirnode=entry.rdir()): 78 java_files = sorted(filter(fj, names)) 79 # The on-disk entries come back in arbitrary order. Sort 80 # them so our target and source lists are determinate. 81 mydir = dirnode.Dir(dirname) 82 java_paths = map(lambda f, d=mydir: d.File(f), java_files) 83 for jp in java_paths: 84 arg[jp] = True 85 86 os.path.walk(entry.rdir().get_abspath(), visit, result) 87 entry.walk(visit, result) 88 89 slist.extend(result.keys()) 90 else: 91 raise SCons.Errors.UserError("Java source must be File or Dir, not '%s'" % entry.__class__) 92 93 version = env.get('JAVAVERSION', '1.4') 94 full_tlist = [] 95 for f in slist: 96 tlist = [] 97 source_file_based = True 98 pkg_dir = None 99 if not f.is_derived(): 100 pkg_dir, classes = parse_java_file(f.rfile().get_abspath(), version) 101 if classes: 102 source_file_based = False 103 if pkg_dir: 104 d = target[0].Dir(pkg_dir) 105 p = pkg_dir + os.sep 106 else: 107 d = target[0] 108 p = '' 109 for c in classes: 110 t = d.File(c + class_suffix) 111 t.attributes.java_classdir = classdir 112 t.attributes.java_sourcedir = sourcedir 113 t.attributes.java_classname = classname(p + c) 114 tlist.append(t) 115 116 if source_file_based: 117 base = f.name[:-len(java_suffix)] 118 if pkg_dir: 119 t = target[0].Dir(pkg_dir).File(base + class_suffix) 120 else: 121 t = target[0].File(base + class_suffix) 122 t.attributes.java_classdir = classdir 123 t.attributes.java_sourcedir = f.dir 124 t.attributes.java_classname = classname(base) 125 tlist.append(t) 126 127 for t in tlist: 128 t.set_specific_source([f]) 129 130 full_tlist.extend(tlist) 131 132 return full_tlist, slist 133 134JavaAction = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') 135 136JavaBuilder = SCons.Builder.Builder(action = JavaAction, 137 emitter = emit_java_classes, 138 target_factory = SCons.Node.FS.Entry, 139 source_factory = SCons.Node.FS.Entry) 140 141class pathopt: 142 """ 143 Callable object for generating javac-style path options from 144 a construction variable (e.g. -classpath, -sourcepath). 145 """ 146 def __init__(self, opt, var, default=None): 147 self.opt = opt 148 self.var = var 149 self.default = default 150 151 def __call__(self, target, source, env, for_signature): 152 path = env[self.var] 153 if path and not SCons.Util.is_List(path): 154 path = [path] 155 if self.default: 156 path = path + [ env[self.default] ] 157 if path: 158 return [self.opt, string.join(path, os.pathsep)] 159 #return self.opt + " " + string.join(path, os.pathsep) 160 else: 161 return [] 162 #return "" 163 164def Java(env, target, source, *args, **kw): 165 """ 166 A pseudo-Builder wrapper around the separate JavaClass{File,Dir} 167 Builders. 168 """ 169 if not SCons.Util.is_List(target): 170 target = [target] 171 if not SCons.Util.is_List(source): 172 source = [source] 173 174 # Pad the target list with repetitions of the last element in the 175 # list so we have a target for every source element. 176 target = target + ([target[-1]] * (len(source) - len(target))) 177 178 java_suffix = env.subst('$JAVASUFFIX') 179 result = [] 180 181 for t, s in zip(target, source): 182 if isinstance(s, SCons.Node.FS.Base): 183 if isinstance(s, SCons.Node.FS.File): 184 b = env.JavaClassFile 185 else: 186 b = env.JavaClassDir 187 else: 188 if os.path.isfile(s): 189 b = env.JavaClassFile 190 elif os.path.isdir(s): 191 b = env.JavaClassDir 192 elif s[-len(java_suffix):] == java_suffix: 193 b = env.JavaClassFile 194 else: 195 b = env.JavaClassDir 196 result.extend(b(*(t, s) + args, **kw)) 197 198 return result 199 200def generate(env): 201 """Add Builders and construction variables for javac to an Environment.""" 202 java_file = SCons.Tool.CreateJavaFileBuilder(env) 203 java_class = SCons.Tool.CreateJavaClassFileBuilder(env) 204 java_class_dir = SCons.Tool.CreateJavaClassDirBuilder(env) 205 java_class.add_emitter(None, emit_java_classes) 206 java_class.add_emitter(env.subst('$JAVASUFFIX'), emit_java_classes) 207 java_class_dir.emitter = emit_java_classes 208 209 env.AddMethod(Java) 210 211 env['JAVAC'] = 'javac' 212 env['JAVACFLAGS'] = SCons.Util.CLVar('') 213 env['JAVABOOTCLASSPATH'] = [] 214 env['JAVACLASSPATH'] = [] 215 env['JAVASOURCEPATH'] = [] 216 env['_javapathopt'] = pathopt 217 env['_JAVABOOTCLASSPATH'] = '${_javapathopt("-bootclasspath", "JAVABOOTCLASSPATH")} ' 218 env['_JAVACLASSPATH'] = '${_javapathopt("-classpath", "JAVACLASSPATH")} ' 219 env['_JAVASOURCEPATH'] = '${_javapathopt("-sourcepath", "JAVASOURCEPATH", "_JAVASOURCEPATHDEFAULT")} ' 220 env['_JAVASOURCEPATHDEFAULT'] = '${TARGET.attributes.java_sourcedir}' 221 env['_JAVACCOM'] = '$JAVAC $JAVACFLAGS $_JAVABOOTCLASSPATH $_JAVACLASSPATH -d ${TARGET.attributes.java_classdir} $_JAVASOURCEPATH $SOURCES' 222 env['JAVACCOM'] = "${TEMPFILE('$_JAVACCOM')}" 223 env['JAVACLASSSUFFIX'] = '.class' 224 env['JAVASUFFIX'] = '.java' 225 226def exists(env): 227 return 1 228 229# Local Variables: 230# tab-width:4 231# indent-tabs-mode:nil 232# End: 233# vim: set expandtab tabstop=4 shiftwidth=4: 234