Skip to content

Commit e2faed2

Browse files
author
Jonas Thiem
committed
Fix debug build missing symbols and other related issues
- fixes that a debug (non-`--release`) `.apk` build won't actually enable gdb debugging in the manifest - renames `build.py`'s `parse_args` to `parse_args_and_make_package` because that is what it appears to be actually doing 😄 - makes SDL2 and any standard `NDKRecipe` build with `NDK_DEBUG=1` when `--release` is not specified to add debugging symbols - fixes debugging symbols being stripped even when not using `--releaase` which makes using gdb a hassle
1 parent c261db5 commit e2faed2

File tree

11 files changed

+85
-16
lines changed

11 files changed

+85
-16
lines changed

pythonforandroid/bootstraps/common/build/build.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,8 @@ def make_package(args):
486486
"args": args,
487487
"service": service,
488488
"service_names": service_names,
489-
"android_api": android_api
489+
"android_api": android_api,
490+
"debug": "debug" in args.build_mode,
490491
}
491492
if get_bootstrap_name() == "sdl2":
492493
render_args["url_scheme"] = url_scheme
@@ -509,7 +510,8 @@ def make_package(args):
509510
aars=aars,
510511
jars=jars,
511512
android_api=android_api,
512-
build_tools_version=build_tools_version
513+
build_tools_version=build_tools_version,
514+
debug_build="debug" in args.build_mode,
513515
)
514516

515517
# ant build templates
@@ -574,7 +576,7 @@ def make_package(args):
574576
raise e
575577

576578

577-
def parse_args(args=None):
579+
def parse_args_and_make_package(args=None):
578580
global BLACKLIST_PATTERNS, WHITELIST_PATTERNS, PYTHON
579581

580582
# Get the default minsdk, equal to the NDK API that this dist is built against
@@ -674,6 +676,10 @@ def parse_args(args=None):
674676
default=join(curdir, 'whitelist.txt'),
675677
help=('Use a whitelist file to prevent blacklisting of '
676678
'file in the final APK'))
679+
ap.add_argument('--release', dest='build_mode', action='store_const',
680+
const='release', default='debug',
681+
help='Build your app as a non-debug release build. '
682+
'(Disables gdb debugging among other things)')
677683
ap.add_argument('--add-jar', dest='add_jar', action='append',
678684
help=('Add a Java .jar to the libs, so you can access its '
679685
'classes with pyjnius. You can specify this '
@@ -817,4 +823,4 @@ def _read_configuration():
817823

818824

819825
if __name__ == "__main__":
820-
parse_args()
826+
parse_args_and_make_package()

pythonforandroid/bootstraps/common/build/templates/build.tmpl.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ android {
3131
versionName '{{ args.version }}'
3232
}
3333

34+
{% if debug_build -%}
35+
packagingOptions {
36+
doNotStrip '**/*.so'
37+
}
38+
{%- endif %}
39+
3440
{% if args.sign -%}
3541
signingConfigs {
3642
release {

pythonforandroid/bootstraps/sdl2/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ def run_distribute(self):
4747
with open('blacklist.txt', 'a') as fileh:
4848
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
4949

50-
self.strip_libraries(arch)
50+
if not self.ctx.build_as_debuggable:
51+
self.strip_libraries(arch)
5152
self.fry_eggs(site_packages_dir)
5253
super(SDL2GradleBootstrap, self).run_distribute()
5354

pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
An example Java class can be found in README-android.txt
5353
-->
5454
<application android:label="@string/app_name"
55+
{% if debug %}android:debuggable="true"{% endif %}
5556
android:icon="@drawable/icon"
5657
android:allowBackup="{{ args.allow_backup }}"
5758
android:theme="@android:style/Theme.NoTitleBar{% if not args.window %}.Fullscreen{% endif %}"

pythonforandroid/bootstraps/service_only/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ def run_distribute(self):
4545
with open('blacklist.txt', 'a') as fileh:
4646
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
4747

48-
self.strip_libraries(arch)
48+
if not self.ctx.build_as_debuggable:
49+
self.strip_libraries(arch)
4950
self.fry_eggs(site_packages_dir)
5051
super(ServiceOnlyBootstrap, self).run_distribute()
5152

pythonforandroid/bootstraps/webview/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ def run_distribute(self):
4242
with open('blacklist.txt', 'a') as fileh:
4343
fileh.write('\nsqlite3/*\nlib-dynload/_sqlite3.so\n')
4444

45-
self.strip_libraries(arch)
45+
if not self.ctx.build_as_debuggable:
46+
self.strip_libraries(arch)
4647
self.fry_eggs(site_packages_dir)
4748
super(WebViewBootstrap, self).run_distribute()
4849

pythonforandroid/build.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class Context(object):
8383
'''A build context. If anything will be built, an instance this class
8484
will be instantiated and used to hold all the build state.'''
8585

86+
# Whether to build with debugging symbols
87+
build_as_debuggable = False
88+
8689
env = environ.copy()
8790
# the filepath of toolchain.py
8891
root_dir = None
@@ -601,8 +604,6 @@ def build_recipes(build_order, python_modules, ctx, project_dir,
601604
ignore_setup_py=ignore_project_setup_py
602605
)
603606

604-
return
605-
606607

607608
def project_has_setup_py(project_dir):
608609
if project_dir is not None and \
@@ -847,8 +848,10 @@ def run_pymodules_install(ctx, modules, project_dir=None,
847848
)
848849

849850
# Strip object files after potential Cython or native code builds:
850-
standard_recipe.strip_object_files(ctx.archs[0], env,
851-
build_dir=ctx.build_dir)
851+
if not ctx.build_as_debuggable:
852+
standard_recipe.strip_object_files(
853+
ctx.archs[0], env, build_dir=ctx.build_dir
854+
)
852855

853856

854857
def biglink(ctx, arch):

pythonforandroid/recipe.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,7 @@ def build_arch(self, arch, *extra_args):
695695
shprint(
696696
sh.ndk_build,
697697
'V=1',
698+
'NDK_DEBUG=' + ("1" if self.ctx.build_as_debuggable else "0"),
698699
'APP_PLATFORM=android-' + str(self.ctx.ndk_api),
699700
'APP_ABI=' + arch.arch,
700701
*extra_args, _env=env
@@ -998,7 +999,8 @@ def build_cython_components(self, arch):
998999
info('First build appeared to complete correctly, skipping manual'
9991000
'cythonising.')
10001001

1001-
self.strip_object_files(arch, env)
1002+
if not self.ctx.build_as_debuggable:
1003+
self.strip_object_files(arch, env)
10021004

10031005
def strip_object_files(self, arch, env, build_dir=None):
10041006
if build_dir is None:

pythonforandroid/recipes/sdl2/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ def build_arch(self, arch):
2222
env = self.get_recipe_env(arch)
2323

2424
with current_directory(self.get_jni_dir()):
25-
shprint(sh.ndk_build, "V=1", _env=env)
25+
shprint(
26+
sh.ndk_build,
27+
"V=1",
28+
"NDK_DEBUG=" + ("1" if self.ctx.build_as_debuggable else "0"),
29+
_env=env
30+
)
2631

2732

2833
recipe = LibSDL2Recipe()

pythonforandroid/toolchain.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ def build_dist_from_args(ctx, dist, args):
193193
ctx.recipe_build_order))
194194
info('Dist will also contain modules ({}) installed from pip'.format(
195195
', '.join(ctx.python_modules)))
196+
if hasattr(args, "build_mode") and args.build_mode == "debug":
197+
info('Building WITH debugging symbols (no --release option used')
198+
else:
199+
info('Building WITHOUT debugging symbols (--release option used)')
196200

197201
ctx.dist_name = bs.distribution.name
198202
ctx.prepare_bootstrap(bs)
@@ -495,7 +499,8 @@ def add_parser(subparsers, *args, **kwargs):
495499
parser_apk.add_argument(
496500
'--release', dest='build_mode', action='store_const',
497501
const='release', default='debug',
498-
help='Build the PARSER_APK. in Release mode')
502+
help='Build your app as a non-debug release build. '
503+
'(Disables gdb debugging among other things)')
499504
parser_apk.add_argument(
500505
'--use-setup-py', dest="use_setup_py",
501506
action='store_true', default=False,
@@ -571,6 +576,8 @@ def add_parser(subparsers, *args, **kwargs):
571576
if hasattr(args, "private") and args.private is not None:
572577
# Pass this value on to the internal bootstrap build.py:
573578
args.unknown_args += ["--private", args.private]
579+
if hasattr(args, "build_mode") and args.build_mode == "release":
580+
args.unknown_args += ["--release"]
574581
if hasattr(args, "ignore_setup_py") and args.ignore_setup_py:
575582
args.use_setup_py = False
576583

@@ -587,6 +594,9 @@ def add_parser(subparsers, *args, **kwargs):
587594

588595
self.ctx = Context()
589596
self.ctx.use_setup_py = getattr(args, "use_setup_py", True)
597+
self.ctx.build_as_debuggable = getattr(
598+
args, "build_mode", "debug"
599+
) == "release"
590600

591601
have_setup_py_or_similar = False
592602
if getattr(args, "private", None) is not None:
@@ -953,7 +963,9 @@ def apk(self, args):
953963
with current_directory(dist.dist_dir):
954964
self.hook("before_apk_build")
955965
os.environ["ANDROID_API"] = str(self.ctx.android_api)
956-
build_args = build.parse_args(args.unknown_args)
966+
build_args = build.parse_args_and_make_package(
967+
args.unknown_args
968+
)
957969
self.hook("after_apk_build")
958970
self.hook("before_apk_assemble")
959971

@@ -1003,7 +1015,9 @@ def apk(self, args):
10031015
gradle_task = "assembleRelease"
10041016
else:
10051017
raise BuildInterruptingException(
1006-
"Unknown build mode {} for apk()".format(args.build_mode))
1018+
"Unknown build mode {} for apk()".
1019+
format(args.build_mode)
1020+
)
10071021
output = shprint(gradlew, gradle_task, _tail=20,
10081022
_critical=True, _env=env)
10091023

tests/test_build.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,32 @@ def test_run_pymodules_install_optional_project_dir(self):
2323
assert run_pymodules_install(ctx, modules, project_dir) is None
2424
assert m_info.call_args_list[-1] == mock.call(
2525
'No Python modules and no setup.py to process, skipping')
26+
27+
def test_strip_if_debuggable(self):
28+
ctx = mock.Mock()
29+
ctx.python_recipe.major_minor_version_string = "python3.6"
30+
ctx.get_site_packages_dir.return_value = "test-doesntexist"
31+
ctx.build_dir = "nonexistant_directory"
32+
ctx.archs = ["arm64"]
33+
34+
modules = ["mymodule"]
35+
project_dir = None
36+
with mock.patch('pythonforandroid.build.info'), \
37+
mock.patch('sh.Command'),\
38+
mock.patch('pythonforandroid.build.open'),\
39+
mock.patch('pythonforandroid.build.shprint'),\
40+
mock.patch('pythonforandroid.build.current_directory'),\
41+
mock.patch('pythonforandroid.build.CythonRecipe') as m_CythonRecipe, \
42+
mock.patch('pythonforandroid.build.project_has_setup_py') as m_project_has_setup_py, \
43+
mock.patch('pythonforandroid.build.run_setuppy_install'):
44+
m_project_has_setup_py.return_value = False
45+
46+
# Make sure it is NOT called when debug build:
47+
ctx.build_as_debuggable = True
48+
assert run_pymodules_install(ctx, modules, project_dir) is None
49+
self.assertFalse(m_CythonRecipe().strip_object_files.called)
50+
51+
# Make sure strip object files IS called when release build:
52+
ctx.build_as_debuggable = False
53+
assert run_pymodules_install(ctx, modules, project_dir) is None
54+
self.assertTrue(m_CythonRecipe().strip_object_files.called)

0 commit comments

Comments
 (0)