waflib: android: implement appending native libraries, make dependency graph cleaner

This commit is contained in:
Alibek Omarov 2019-05-06 19:24:41 +03:00
parent 5ec762b69c
commit c9716b87be

View file

@ -26,26 +26,26 @@ def get_latest_build_tools(sdk):
def configure(conf): def configure(conf):
conf.load('java') conf.load('java')
conf.start_msg('Checking environment variables') conf.start_msg('Checking environment variables')
sdk = None sdk = None
for i in android_sdk_home_env: for i in android_sdk_home_env:
if i in os.environ: if i in os.environ:
sdk = conf.env.ANDROID_SDK_HOME_ENV = os.environ[i] sdk = conf.env.ANDROID_SDK_HOME_ENV = os.environ[i]
break break
if not sdk: if not sdk:
conf.fatal('Can\'t find path to SDK. Check if ANDROID_SDK_HOME environment variable is set') conf.fatal('Can\'t find path to SDK. Check if ANDROID_SDK_HOME environment variable is set')
return return
conf.end_msg('ok') conf.end_msg('ok')
paths = [ os.path.join(conf.env.ANDROID_SDK_HOME_ENV, 'tools'), get_latest_build_tools(sdk) ] paths = [ os.path.join(conf.env.ANDROID_SDK_HOME_ENV, 'tools'), get_latest_build_tools(sdk) ]
paths += os.environ['PATH'].split(os.pathsep) # just in case we have installed tools paths += os.environ['PATH'].split(os.pathsep) # just in case we have installed tools
for i in ['aapt2', 'd8', 'zipalign', 'apksigner']: for i in ['aapt2', 'd8', 'zipalign', 'apksigner']:
conf.find_program(i, path_list = paths) conf.find_program(i, path_list = paths)
conf.find_program('zip') conf.find_program('zip')
# TODO: AAPT legacy support # TODO: AAPT legacy support
# TODO: dx support # TODO: dx support
@ -53,13 +53,13 @@ class aapt2compile(javaw.JTask):
color = 'GREEN' color = 'GREEN'
run_str = 'mkdir -p ${RESOUTFILE} && ${AAPT2} compile -v ${SRC} -o ${RESOUTFILE}' run_str = 'mkdir -p ${RESOUTFILE} && ${AAPT2} compile -v ${SRC} -o ${RESOUTFILE}'
vars = ['AAPT2', 'RESOUTFILE', 'RESDIR'] vars = ['AAPT2', 'RESOUTFILE', 'RESDIR']
def uid(self): def uid(self):
""" """
Hash by resource directory path Hash by resource directory path
""" """
return Utils.h_list([self.__class__.__name__, self.generator.outdir.abspath(), self.env.RESDIR]) return Utils.h_list([self.__class__.__name__, self.generator.outdir.abspath(), self.env.RESDIR])
def runnable_status(self): def runnable_status(self):
""" """
Waits for dependent tasks to be complete, then read the file system to find the input nodes. Waits for dependent tasks to be complete, then read the file system to find the input nodes.
@ -73,7 +73,7 @@ class aapt2compile(javaw.JTask):
resdir = root.make_node(self.env.RESDIR) resdir = root.make_node(self.env.RESDIR)
self.inputs = resdir.ant_glob('**/*', quiet=True) self.inputs = resdir.ant_glob('**/*', quiet=True)
return super(aapt2compile, self).runnable_status() return super(aapt2compile, self).runnable_status()
def post_run(self): def post_run(self):
""" """
List class files created List class files created
@ -84,9 +84,9 @@ class aapt2compile(javaw.JTask):
class aapt2link(javaw.JTask): class aapt2link(javaw.JTask):
color = 'GREEN' # android green :) color = 'GREEN' # android green :)
run_str = '${AAPT2} link -v --allow-reserved-package-id -o ${OUTAPK} -A ${ASSETSDIR} --manifest ${MANIFEST} --java ${OUTRDIR} -I ${CLASSPATH_ANDROID} ${SRC}' run_str = '${AAPT2} link -v --allow-reserved-package-id -o ${OUTAPK_UNALIGNED_NOCLASSES_NOJNI} -A ${ASSETSDIR} --manifest ${MANIFEST} --java ${OUTRDIR} -I ${CLASSPATH_ANDROID} ${SRC}'
vars = ['AAPT2', 'OUTAPK', 'ASSETSDIR', 'MANIFEST', 'OUTRDIR', 'CLASSPATH_ANDROID'] vars = ['AAPT2', 'OUTAPK_UNALIGNED_NOCLASSES_NOJNI', 'ASSETSDIR', 'MANIFEST', 'OUTRDIR', 'CLASSPATH_ANDROID']
def runnable_status(self): def runnable_status(self):
""" """
Waits for dependent tasks to be complete, then read the file system to find the input nodes. Waits for dependent tasks to be complete, then read the file system to find the input nodes.
@ -99,17 +99,16 @@ class aapt2link(javaw.JTask):
root = self.generator.outdir.ctx.root root = self.generator.outdir.ctx.root
resdir = root.make_node(self.env.RESOUTFILE) resdir = root.make_node(self.env.RESOUTFILE)
self.inputs = resdir.ant_glob('**/*.flat', quiet=True) self.inputs = resdir.ant_glob('**/*.flat', quiet=True)
self.outputs = [ self.generator.outdir.make_node(self.env.OUTAPK) ] self.outputs = [ self.generator.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI) ]
return super(aapt2link, self).runnable_status() return super(aapt2link, self).runnable_status()
class d8(javaw.JTask): class d8(javaw.JTask):
color = 'GREEN' # android green :) color = 'GREEN' # android green :)
run_str = '${D8} ${SRC} ${D8_FLAGS} --output ${OUTDIR} --lib ${CLASSPATH_ANDROID} ${D8_CLASSPATH}' run_str = '${D8} ${SRC} ${D8_FLAGS} --output ${OUTDIR} --lib ${CLASSPATH_ANDROID} ${D8_CLASSPATH}'
vars = ['D8', 'D8_FLAGS', 'OUTAPK', 'CLASSPATH_ANDROID', 'D8_CLASSPATH'] vars = ['D8', 'D8_FLAGS', 'OUTDIR', 'CLASSPATH_ANDROID', 'D8_CLASSPATH' ]
def runnable_status(self): def runnable_status(self):
""" """
Waits for dependent tasks to be complete, then read the file system to find the input nodes. Waits for dependent tasks to be complete, then read the file system to find the input nodes.
@ -120,7 +119,7 @@ class d8(javaw.JTask):
if not self.inputs: if not self.inputs:
self.inputs = self.generator.outdir.ant_glob('**/*.class', quiet=True) self.inputs = self.generator.outdir.ant_glob('**/*.class', quiet=True)
self.outputs = [ self.generator.outdir.make_node('classes.dex') ] self.outputs = [ self.generator.outdir.make_node('classes.dex') ]
return super(d8, self).runnable_status() return super(d8, self).runnable_status()
@ -136,10 +135,10 @@ def custom_runnable_status(self):
self.srcdir.append(outrdir) self.srcdir.append(outrdir)
return self.old_runnable_status() return self.old_runnable_status()
class apkdex(Task.Task): class apkjni(Task.Task):
color = 'GREEN' # android green :) color = 'BLUE'
run_str = '${ZIP} -uj ${OUTAPK} ${OUTDIR}/classes.dex' run_str = '${ZIP} ${OUTAPK_UNALIGNED_NOCLASSES_NOJNI} --out ${OUTAPK_UNALIGNED_NOCLASSES} && ${ZIP} -ru ${OUTAPK_UNALIGNED_NOCLASSES} ${JNIDIR}'
vars = ['ZIP', 'OUTAPK', 'OUTDIR'] vars = ['ZIP', 'JNIDIR', 'OUTAPK_UNALIGNED_NOCLASSES_NOJNI', 'OUTAPK_UNALIGNED_NOCLASSES']
def runnable_status(self): def runnable_status(self):
""" """
@ -149,18 +148,35 @@ class apkdex(Task.Task):
if not t.hasrun: if not t.hasrun:
return Task.ASK_LATER return Task.ASK_LATER
self.inputs = [ # I could use SRC here, but I need to track changes of OUTAPK_UNALIGNED_NOCLASSES_NOJNI also
self.generator.outdir.make_node('classes.dex'), self.inputs = self.generator.outdir.ant_glob('{0}/**/*'.format(self.env.JNIDIR), quiet=True)
self.generator.outdir.make_node(self.env.OUTAPK) self.inputs += self.generator.outdir.ant_glob(self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI)
] self.outputs = [self.generator.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES)]
self.outputs = [ self.generator.outdir.make_node(self.env.OUTAPK) ]
return super(apkjni, self).runnable_status()
class apkdex(Task.Task):
color = 'GREEN' # android green :)
run_str = '${ZIP} ${OUTAPK_UNALIGNED_NOCLASSES} --out ${OUTAPK_UNALIGNED} && ${ZIP} -uj ${OUTAPK_UNALIGNED} classes.dex'
vars = ['ZIP', 'OUTAPK_UNALIGNED_NOCLASSES', 'OUTAPK_UNALIGNED']
def runnable_status(self):
"""
Waits for dependent tasks to be complete, then read the file system to find the input nodes.
"""
for t in self.run_after:
if not t.hasrun:
return Task.ASK_LATER
self.inputs = [self.generator.outdir.make_node('classes.dex'), self.generator.outdir.make_node(self.env.OUTAPK_UNALIGNED_NOCLASSES)]
self.outputs = [ self.generator.outdir.make_node(self.env.OUTAPK_UNALIGNED) ]
return super(apkdex, self).runnable_status() return super(apkdex, self).runnable_status()
class apkalign(Task.Task): class apkalign(Task.Task):
color = 'GREEN' # android green :) color = 'GREEN' # android green :)
run_str = '${ZIPALIGN} -f -v 4 ${OUTAPK} ${OUTAPK_ALIGNED}' run_str = '${ZIPALIGN} -f -v 4 ${OUTAPK_UNALIGNED} ${OUTAPK}'
vars = ['ZIPALIGN', 'OUTAPK', 'OUTAPK_ALIGNED'] vars = ['ZIPALIGN', 'OUTAPK_UNALIGNED', 'OUTAPK']
def runnable_status(self): def runnable_status(self):
""" """
Waits for dependent tasks to be complete, then read the file system to find the input nodes. Waits for dependent tasks to be complete, then read the file system to find the input nodes.
@ -169,8 +185,8 @@ class apkalign(Task.Task):
if not t.hasrun: if not t.hasrun:
return Task.ASK_LATER return Task.ASK_LATER
self.inputs = [ self.generator.outdir.make_node(self.env.OUTAPK) ] self.inputs = [ self.generator.outdir.make_node(self.env.OUTAPK_UNALIGNED) ]
self.outputs = [ self.generator.outdir.make_node(self.env.OUTAPK_ALIGNED) ] self.outputs = [ self.generator.outdir.make_node(self.env.OUTAPK) ]
return super(apkalign, self).runnable_status() return super(apkalign, self).runnable_status()
@ -191,25 +207,31 @@ def apply_aapt(self):
outdir = self.path.get_bld() outdir = self.path.get_bld()
outdir.mkdir() outdir.mkdir()
self.outdir = outdir self.outdir = outdir
srcdir = self.path.find_dir('.') srcdir = self.path.find_dir('.')
sdk = self.env.ANDROID_SDK_HOME_ENV sdk = self.env.ANDROID_SDK_HOME_ENV
self.env.RESDIR = os.path.join(srcdir.abspath(), getattr(self, 'resdir', 'res')) self.env.RESDIR = os.path.join(srcdir.abspath(), getattr(self, 'resdir', 'res'))
self.env.ASSETSDIR = os.path.join(srcdir.abspath(), getattr(self, 'assetsdir', 'assets')) self.env.ASSETSDIR = os.path.join(srcdir.abspath(), getattr(self, 'assetsdir', 'assets'))
self.env.MANIFEST = os.path.join(srcdir.abspath(), getattr(self, 'manifest', 'AndroidManifest.xml')) self.env.MANIFEST = os.path.join(srcdir.abspath(), getattr(self, 'manifest', 'AndroidManifest.xml'))
apkname = getattr(self, 'apkname', self.name)
self.env.OUTAPK_UNALIGNED_NOCLASSES_NOJNI = apkname + '.unaligned.noclasses.nojni.apk'
self.env.OUTAPK_UNALIGNED_NOCLASSES = apkname + '.unaligned.noclasses.apk'
self.env.OUTAPK_UNALIGNED = apkname + '.unaligned.apk'
self.env.OUTAPK = apkname + '.apk'
self.env.OUTAPK = getattr(self, 'apkname', self.name) + '.unaligned.apk'
self.env.OUTAPK_ALIGNED = getattr(self, 'apkname', self.name) + '.apk'
self.env.OUTRDIR = os.path.join(outdir.abspath(), getattr(self, 'gendir', 'gen')) # build/gen self.env.OUTRDIR = os.path.join(outdir.abspath(), getattr(self, 'gendir', 'gen')) # build/gen
self.env.RESOUTFILE = os.path.join(outdir.abspath(), 'compiled') self.env.RESOUTFILE = os.path.join(outdir.abspath(), 'compiled')
self.env.OUTDIR = outdir.abspath() self.env.OUTDIR = outdir.abspath()
self.env.TARGET_API = getattr(self, 'target_api', 10) # Android 2.3.3 TODO: parse AndroidManifest.xml to get target API! self.env.TARGET_API = getattr(self, 'target_api', 10) # Android 2.3.3 TODO: parse AndroidManifest.xml to get target API!
self.env.CLASSPATH_ANDROID = os.path.join(sdk, 'platforms', 'android-' + str(self.env.TARGET_API), 'android.jar') self.env.CLASSPATH_ANDROID = os.path.join(sdk, 'platforms', 'android-' + str(self.env.TARGET_API), 'android.jar')
self.env.JNIDIR = getattr(self, 'jni', 'lib')
self.aapt2compile_task = self.create_task('aapt2compile') self.aapt2compile_task = self.create_task('aapt2compile')
self.aapt2compile_task.cwd = outdir self.aapt2compile_task.cwd = outdir
self.aapt2link_task = self.create_task('aapt2link') self.aapt2link_task = self.create_task('aapt2link')
self.aapt2link_task.cwd = outdir self.aapt2link_task.cwd = outdir
self.aapt2link_task.set_run_after(self.aapt2compile_task) self.aapt2link_task.set_run_after(self.aapt2compile_task)
@ -218,19 +240,23 @@ def apply_aapt(self):
@TaskGen.after_method('apply_java') @TaskGen.after_method('apply_java')
def apply_d8(self): def apply_d8(self):
self.javac_task.set_run_after(self.aapt2link_task) self.javac_task.set_run_after(self.aapt2link_task)
if getattr(self, 'debug', False): if getattr(self, 'debug', False):
self.env.D8_FLAGS = '--debug' self.env.D8_FLAGS = '--debug'
else: self.env.D8_FLAGS = '--release' else: self.env.D8_FLAGS = '--release'
self.d8_task = self.create_task('d8') self.d8_task = self.create_task('d8')
self.d8_task.cwd = self.outdir self.d8_task.cwd = self.outdir
self.d8_task.set_run_after(self.javac_task) self.d8_task.set_run_after(self.javac_task)
self.apkjni_task = self.create_task('apkjni')
self.apkjni_task.cwd = self.outdir
self.apkjni_task.set_run_after(self.d8_task)
self.apkdex_task = self.create_task('apkdex') self.apkdex_task = self.create_task('apkdex')
self.apkdex_task.cwd = self.outdir self.apkdex_task.cwd = self.outdir
self.apkdex_task.set_run_after(self.d8_task) self.apkdex_task.set_run_after(self.apkjni_task)
self.apkalign_task = self.create_task('apkalign') self.apkalign_task = self.create_task('apkalign')
self.apkalign_task.cwd = self.outdir self.apkalign_task.cwd = self.outdir
self.apkalign_task.set_run_after(self.apkdex_task) self.apkalign_task.set_run_after(self.apkdex_task)
@ -238,7 +264,7 @@ def apply_d8(self):
@TaskGen.feature('android') @TaskGen.feature('android')
@TaskGen.after_method('set_classpath') @TaskGen.after_method('set_classpath')
def set_android_classpath(self): def set_android_classpath(self):
if len(self.env.CLASSPATH) == 0: if len(self.env.CLASSPATH) == 0:
self.env.D8_CLASSPATH = '' self.env.D8_CLASSPATH = ''
else: else:
self.env.D8_CLASSPATH = '--classpath' + os.pathsep.join(self.env.CLASSPATH) + os.pathsep # old classpath without android.jar for d8 self.env.D8_CLASSPATH = '--classpath' + os.pathsep.join(self.env.CLASSPATH) + os.pathsep # old classpath without android.jar for d8