Get rid of imp, started giving deprecation warning every time in Python 3.7 in Ubuntu 19.04.

Please python stop torturing me with refactors.

Make ./run -u blow up if executable not found, otherwise I go crazy.

Get ./test-gdb back to life after the ./run relative path refactor, forgot to test this.
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-05-11 00:00:01 +00:00
parent 300671cd39
commit 3cc1b793cb
19 changed files with 108 additions and 113 deletions

View File

@@ -3910,20 +3910,10 @@ Similarly to <<qemu-user-mode-does-not-show-stdout-immediately>>, QEMU error mes
In particular, it does not say anything if you pass it a non-existing executable: In particular, it does not say anything if you pass it a non-existing executable:
.... ....
./build-userland --clean userland/c/hello.c qemu-x86_64 asdf | cat
./run --userland userland/c/hello.c
echo $?
.... ....
does not output anything, except for the `1` exit status. So we just check ourselves manually
If you run however the raw command without a pipe manually, it shows a helpful error message:
....
Error while loading /path/to/linux-kernel-module-cheat/out/userland/default/x86_64/c/hello.out: No such file or directory
....
Tested in de77c62c091f6418e73b64e8a0a19639c587a103 + 1.
== Kernel module utilities == Kernel module utilities

View File

@@ -1,13 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import imp
import os import os
import shutil import shutil
import sys import sys
import common import common
build_linux = imp.load_source('build-linux', os.path.join(kwargs['root_dir'], 'build_linux'))
run = imp.load_source('run', os.path.join(kwargs['root_dir'], 'run')) build_linux = common.import_path_relative_root('build-linux')
run = common.import_path_relative_root('run')
parser = self.get_argparse( parser = self.get_argparse(
argparse_args={ argparse_args={

2
build
View File

@@ -403,7 +403,7 @@ Which components to build. Default: qemu-buildroot
args = self.get_common_args() args = self.get_common_args()
args.update(extra_args) args.update(extra_args)
args['show_time'] = False args['show_time'] = False
self.import_path_main(component_file)(**args) common.import_path_main(component_file)(**args)
return f return f
def timed_main(self): def timed_main(self):

View File

@@ -133,7 +133,7 @@ Build the baremetal examples with crosstool-NG.
in_name, in_ext = os.path.splitext(in_basename) in_name, in_ext = os.path.splitext(in_basename)
if ( if (
os.path.isfile(in_path) and os.path.isfile(in_path) and
in_ext in (self.env['c_ext'], self.env['asm_ext']) in_ext in self.env['build_in_exts']
): ):
out = os.path.join(out_dir, in_name + self.env['baremetal_build_ext']) out = os.path.join(out_dir, in_name + self.env['baremetal_build_ext'])
src = os.path.join(self.env['baremetal_source_dir'], in_path) src = os.path.join(self.env['baremetal_source_dir'], in_path)

View File

@@ -88,7 +88,7 @@ Default: build all examples that have their package dependencies met, e.g.:
for path, in_dirnames, in_filenames in self.sh.walk(target): for path, in_dirnames, in_filenames in self.sh.walk(target):
for in_filename in in_filenames: for in_filename in in_filenames:
in_ext = os.path.splitext(in_filename)[1] in_ext = os.path.splitext(in_filename)[1]
if not in_ext in self.env['userland_in_exts']: if not in_ext in self.env['build_in_exts']:
continue continue
in_path = os.path.join(path, in_filename) in_path = os.path.join(path, in_filename)
error = thread_pool.submit({ error = thread_pool.submit({

View File

@@ -1,18 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import imp
import os import os
import subprocess import subprocess
git_root = subprocess.check_output([ import common
'git',
'rev-parse', build_userland = common.import_path_relative_root('build-userland')
'--show-toplevel',
]).decode().rstrip()
build_userland = imp.load_source(
'build_userland',
os.path.join(git_root, 'build-userland')
)
class Main(build_userland.Main): class Main(build_userland.Main):
def __init__(self): def __init__(self):

View File

@@ -11,10 +11,11 @@ made to this file.
import argparse import argparse
import bisect import bisect
import collections import collections
import imp
import os import os
import sys import sys
import common
class _Argument: class _Argument:
def __init__( def __init__(
self, self,
@@ -188,7 +189,7 @@ class CliFunction:
if config_file is not None: if config_file is not None:
if os.path.exists(config_file): if os.path.exists(config_file):
config_configs = {} config_configs = {}
config = imp.load_source('config', config_file) config = common.import_path(config_file)
if self.extra_config_params is None: if self.extra_config_params is None:
config.set_args(config_configs) config.set_args(config_configs)
else: else:

View File

@@ -8,7 +8,7 @@ import datetime
import enum import enum
import functools import functools
import glob import glob
import imp import importlib
import inspect import inspect
import itertools import itertools
import json import json
@@ -105,7 +105,7 @@ consts['cxx_ext'] = '.cpp'
consts['header_ext'] = '.h' consts['header_ext'] = '.h'
consts['kernel_module_ext'] = '.ko' consts['kernel_module_ext'] = '.ko'
consts['obj_ext'] = '.o' consts['obj_ext'] = '.o'
consts['userland_in_exts'] = [ consts['build_in_exts'] = [
consts['asm_ext'], consts['asm_ext'],
consts['c_ext'], consts['c_ext'],
consts['cxx_ext'], consts['cxx_ext'],
@@ -136,6 +136,32 @@ for key in consts['emulator_short_to_long_dict']:
consts['emulator_choices'].add(consts['emulator_short_to_long_dict'][key]) consts['emulator_choices'].add(consts['emulator_short_to_long_dict'][key])
consts['host_arch'] = platform.processor() consts['host_arch'] = platform.processor()
def import_path(path):
'''
https://stackoverflow.com/questions/2601047/import-a-python-module-without-the-py-extension
https://stackoverflow.com/questions/31773310/what-does-the-first-argument-of-the-imp-load-source-method-do
'''
module_name = os.path.basename(path).replace('-', '_')
spec = importlib.util.spec_from_loader(
module_name,
importlib.machinery.SourceFileLoader(module_name, path)
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
sys.modules[module_name] = module
return module
def import_path_relative_root(basename):
return import_path(os.path.join(consts['root_dir'], basename))
def import_path_main(basename):
'''
Import an object of the Main class of a given file.
By convention, we call the main object of all our CLI scripts as Main.
'''
return import_path_relative_root(basename).Main()
class ExitLoop(Exception): class ExitLoop(Exception):
pass pass
@@ -905,6 +931,8 @@ Incompatible archs are skipped.
env['source_path'] = source_path env['source_path'] = source_path
break break
env['image'] = path env['image'] = path
elif env['userland'] is not None:
env['image'] = self.resolve_userland_executable(env['userland'])
else: else:
if env['emulator'] == 'gem5': if env['emulator'] == 'gem5':
env['image'] = env['vmlinux'] env['image'] = env['vmlinux']
@@ -1084,24 +1112,6 @@ lunch aosp_{}-eng
_json = {} _json = {}
return _json return _json
def import_path(self, basename):
'''
https://stackoverflow.com/questions/2601047/import-a-python-module-without-the-py-extension
https://stackoverflow.com/questions/31773310/what-does-the-first-argument-of-the-imp-load-source-method-do
'''
return imp.load_source(
basename.replace('-', '_'),
os.path.join(self.env['root_dir'], basename)
)
def import_path_main(self, path):
'''
Import an object of the Main class of a given file.
By convention, we call the main object of all our CLI scripts as Main.
'''
return self.import_path(path).Main()
def is_arch_supported(self, arch): def is_arch_supported(self, arch):
return self.supported_archs is None or arch in self.supported_archs return self.supported_archs is None or arch in self.supported_archs
@@ -1270,6 +1280,8 @@ lunch aosp_{}-eng
If the input path is a file, add the executable extension automatically. If the input path is a file, add the executable extension automatically.
''' '''
if not self.env['dry_run'] and not os.path.exists(in_path):
raise Exception('Input path does not exist: ' + in_path)
if self.is_subpath(in_path, magic_in_dir): if self.is_subpath(in_path, magic_in_dir):
# Abspath needed to remove the trailing `/.` which makes e.g. rmrf fail. # Abspath needed to remove the trailing `/.` which makes e.g. rmrf fail.
out = os.path.abspath(os.path.join( out = os.path.abspath(os.path.join(

16
run
View File

@@ -404,12 +404,12 @@ Extra options to append at the end of the emulator command line.
if not self.env['dry_run']: if not self.env['dry_run']:
raise Exception('Root filesystem not found. Did you build it? ' \ raise Exception('Root filesystem not found. Did you build it? ' \
'Tried to use: ' + self.env['disk_image']) 'Tried to use: ' + self.env['disk_image'])
def raise_image_not_found(): def raise_image_not_found(image):
if not self.env['dry_run']: if not self.env['dry_run']:
raise Exception('Executable image not found. Did you build it? ' \ raise Exception('Executable image not found. Did you build it? ' \
'Tried to use: ' + self.env['image']) 'Tried to use: ' + image)
if self.env['image'] is None: if not os.path.exists(self.env['image']):
raise Exception('Baremetal ELF file not found. Tried:\n' + '\n'.join(paths)) raise_image_not_found(self.env['image'])
cmd = debug_vm.copy() cmd = debug_vm.copy()
if self.env['emulator'] == 'gem5': if self.env['emulator'] == 'gem5':
if self.env['quiet']: if self.env['quiet']:
@@ -430,7 +430,7 @@ Extra options to append at the end of the emulator command line.
self.env['userland'] is None self.env['userland'] is None
): ):
if not os.path.exists(self.env['linux_image']): if not os.path.exists(self.env['linux_image']):
raise_image_not_found() raise_image_not_found(self.env['image'])
self.sh.run_cmd([os.path.join(self.env['extract_vmlinux'], self.env['linux_image'])]) self.sh.run_cmd([os.path.join(self.env['extract_vmlinux'], self.env['linux_image'])])
os.makedirs(os.path.dirname(self.env['gem5_readfile']), exist_ok=True) os.makedirs(os.path.dirname(self.env['gem5_readfile']), exist_ok=True)
self.sh.write_string_to_file(self.env['gem5_readfile'], self.env['gem5_readfile']) self.sh.write_string_to_file(self.env['gem5_readfile'], self.env['gem5_readfile'])
@@ -457,7 +457,7 @@ Extra options to append at the end of the emulator command line.
if self.env['userland'] is not None: if self.env['userland'] is not None:
cmd.extend([ cmd.extend([
self.env['gem5_se_file'], LF, self.env['gem5_se_file'], LF,
'--cmd', self.resolve_userland_executable(self.env['userland']), LF, '--cmd', self.env['image'], LF,
]) ])
if self.env['userland_args'] is not None: if self.env['userland_args'] is not None:
cmd.extend(['--options', self.env['userland_args'], LF]) cmd.extend(['--options', self.env['userland_args'], LF])
@@ -551,8 +551,6 @@ Extra options to append at the end of the emulator command line.
debug_args debug_args
) )
else: else:
if not os.path.exists(self.env['image']):
raise_image_not_found()
extra_emulator_args.extend(extra_qemu_args) extra_emulator_args.extend(extra_qemu_args)
self.make_run_dirs() self.make_run_dirs()
if self.env['debug_vm']: if self.env['debug_vm']:
@@ -725,7 +723,7 @@ Extra options to append at the end of the emulator command line.
cmd.extend(self.env['extra_emulator_args']) cmd.extend(self.env['extra_emulator_args'])
if self.env['userland'] and self.env['emulator'] in ('qemu', 'native'): if self.env['userland'] and self.env['emulator'] in ('qemu', 'native'):
# The program and arguments must come at the every end of the CLI. # The program and arguments must come at the every end of the CLI.
cmd.extend([self.resolve_userland_executable(self.env['userland']), LF]) cmd.extend([self.env['image'], LF])
if self.env['userland_args'] is not None: if self.env['userland_args'] is not None:
cmd.extend(self.sh.shlex_split(self.env['userland_args'])) cmd.extend(self.sh.shlex_split(self.env['userland_args']))
if debug_vm or self.env['terminal']: if debug_vm or self.env['terminal']:

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import imp
import os import os
import signal import signal
import subprocess import subprocess
@@ -34,7 +33,7 @@ class GdbTestcase:
self.child.setecho(False) self.child.setecho(False)
self.child.waitnoecho() self.child.waitnoecho()
self.child.expect(self.prompt) self.child.expect(self.prompt)
test = imp.load_source('test', test_script_path) test = common.import_path(test_script_path)
exception = None exception = None
try: try:
test.test(self) test.test(self)

View File

@@ -1,11 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import imp
import os import os
import sys import sys
import common import common
rungdb = imp.load_source('run_gdb', os.path.join(kwargs['root_dir'], 'run-gdb')) rungdb = common.import_path_relative_root('run-gdb')
parser = self.get_argparse(argparse_args={ parser = self.get_argparse(argparse_args={
'description': '''GDB step debug guest userland processes without gdbserver. 'description': '''GDB step debug guest userland processes without gdbserver.

12
test
View File

@@ -28,15 +28,15 @@ Size of the tests to run. Scale:
run_args = self.get_common_args() run_args = self.get_common_args()
test_boot_args = run_args.copy() test_boot_args = run_args.copy()
test_boot_args['size'] = self.env['size'] test_boot_args['size'] = self.env['size']
self.run_test(self.import_path_main('test-boot'), test_boot_args, 'test-boot') self.run_test(common.import_path_main('test-boot'), test_boot_args, 'test-boot')
self.run_test(self.import_path_main('test-userland-full-system'), run_args, 'test-userland') self.run_test(common.import_path_main('test-userland-full-system'), run_args, 'test-userland')
self.run_test(self.import_path_main('test-baremetal'), run_args, 'test-baremetal') self.run_test(common.import_path_main('test-baremetal'), run_args, 'test-baremetal')
self.run_test(self.import_path_main('test-user-mode'), run_args, 'test-user-mode') self.run_test(common.import_path_main('test-user-mode'), run_args, 'test-user-mode')
self.run_test(self.import_path_main('test-gdb'), run_args, 'test-gdb') self.run_test(common.import_path_main('test-gdb'), run_args, 'test-gdb')
if self.env['emulator'] == 'gem5': if self.env['emulator'] == 'gem5':
gem5_unit_test_args = run_args.copy() gem5_unit_test_args = run_args.copy()
gem5_unit_test_args['unit_tests'] = True gem5_unit_test_args['unit_tests'] = True
self.run_test(self.import_path_main('build-gem5'), gem5_unit_test_args, 'gem5-unit-tests') self.run_test(common.import_path_main('build-gem5'), gem5_unit_test_args, 'gem5-unit-tests')
if __name__ == '__main__': if __name__ == '__main__':
Main().cli() Main().cli()

View File

@@ -52,7 +52,7 @@ If given, run only the given tests. Otherwise, run all tests.
test_args = { test_args = {
'expected_exit_status': my_path_properties['exit_status'], 'expected_exit_status': my_path_properties['exit_status'],
'run_args': cur_run_args, 'run_args': cur_run_args,
'run_obj': self.import_path_main('run'), 'run_obj': common.import_path_main('run'),
'test_id': path_relative_root, 'test_id': path_relative_root,
} }
error = thread_pool.submit(test_args) error = thread_pool.submit(test_args)

View File

@@ -45,7 +45,7 @@ See ./test --help for --size.
#) #)
# #
#rm -f "${self.env['test_boot_benchmark_file']}" #rm -f "${self.env['test_boot_benchmark_file']}"
self.run = self.import_path_main('run') self.run = common.import_path_main('run')
self.common_args = self.get_common_args() self.common_args = self.get_common_args()
self.common_args['ctrl_c_host'] = True self.common_args['ctrl_c_host'] = True
self.common_args['quit_after_boot'] = True self.common_args['quit_after_boot'] = True

View File

@@ -22,38 +22,51 @@ found by searching for the Python test files.
) )
def timed_main(self): def timed_main(self):
run = self.import_path_main('run') run = common.import_path_main('run')
run_gdb = self.import_path_main('run-gdb') run_gdb = common.import_path_main('run-gdb')
if self.env['arch'] in self.env['crosstool_ng_supported_archs']: if self.env['arch'] in self.env['crosstool_ng_supported_archs']:
test_sources = []
if self.env['tests'] == []: if self.env['tests'] == []:
test_scripts_noext = [] source_paths = []
for filename in sorted(os.listdir(self.env['baremetal_source_dir'])): for filename in sorted(os.listdir(self.env['baremetal_source_dir'])):
base, ext = os.path.splitext(filename) base, ext = os.path.splitext(filename)
if ext == '.py': if ext in self.env['build_in_exts']:
test_scripts_noext.append(base) test_sources.append(
for root, dirnames, filenames in os.walk(os.path.join(self.env['baremetal_source_dir'], 'arch', self.env['arch'])): os.path.join(
self.env['baremetal_source_dir'],
filename
)
)
for root, dirnames, filenames in os.walk(
os.path.join(
self.env['baremetal_source_dir'],
'arch',
self.env['arch']
)
):
for filename in filenames: for filename in filenames:
base, ext = os.path.splitext(filename) base, ext = os.path.splitext(filename)
if ext == '.py': if ext in self.env['build_in_exts']:
full_path = os.path.join(root, base) test_sources.append(os.path.join(root, filename))
relpath = os.path.relpath(full_path, self.env['baremetal_source_dir'])
test_scripts_noext.append(relpath)
else: else:
test_scripts_noext = self.env['tests'] test_sources = self.env['tests']
for test_script_noext in test_scripts_noext: for test_source_full in test_sources:
common_args = self.get_common_args() base, ext = os.path.splitext(test_source_full)
common_args['baremetal'] = test_script_noext if os.path.exists(base + '.py'):
test_id_string = self.test_setup(test_script_noext) test_source_base = os.path.relpath(base, self.env['root_dir'])
run_args = common_args.copy() common_args = self.get_common_args()
run_args['gdb_wait'] = True common_args['baremetal'] = test_source_base + ext
run_args['background'] = True test_id_string = self.test_setup(test_source_base)
run_thread = threading.Thread(target=lambda: run(**run_args)) run_args = common_args.copy()
run_thread.start() run_args['gdb_wait'] = True
gdb_args = common_args.copy() run_args['background'] = True
gdb_args['test'] = True run_thread = threading.Thread(target=lambda: run(**run_args))
run_gdb(**gdb_args) run_thread.start()
run_thread.join() gdb_args = common_args.copy()
self.test_teardown(run, 0, test_id_string) gdb_args['test'] = True
run_gdb(**gdb_args)
run_thread.join()
self.test_teardown(run, 0, test_id_string)
if __name__ == '__main__': if __name__ == '__main__':
Main().cli() Main().cli()

View File

@@ -50,7 +50,7 @@ If given, run only the given tests. Otherwise, run all tests.
path_abs = os.path.abspath(path) path_abs = os.path.abspath(path)
dirpath_relative_root = path_abs[rootdir_abs_len + 1:] dirpath_relative_root = path_abs[rootdir_abs_len + 1:]
for in_filename in in_filenames: for in_filename in in_filenames:
if os.path.splitext(in_filename)[1] in self.env['userland_in_exts']: if os.path.splitext(in_filename)[1] in self.env['build_in_exts']:
path_relative_root = os.path.join(dirpath_relative_root, in_filename) path_relative_root = os.path.join(dirpath_relative_root, in_filename)
my_path_properties = path_properties.get(path_relative_root) my_path_properties = path_properties.get(path_relative_root)
if my_path_properties.should_be_tested(self.env): if my_path_properties.should_be_tested(self.env):
@@ -62,7 +62,7 @@ If given, run only the given tests. Otherwise, run all tests.
run_test_args = { run_test_args = {
'expected_exit_status': my_path_properties['exit_status'], 'expected_exit_status': my_path_properties['exit_status'],
'run_args': cur_run_args, 'run_args': cur_run_args,
'run_obj': self.import_path_main('run'), 'run_obj': common.import_path_main('run'),
'test_id': path_relative_root, 'test_id': path_relative_root,
} }
if my_path_properties['receives_signal']: if my_path_properties['receives_signal']:

View File

@@ -1,18 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import imp import common
import os
import subprocess
git_root = subprocess.check_output([ test_user_mode = common.import_path_relative_root('test-user-mode')
'git',
'rev-parse',
'--show-toplevel',
]).decode().rstrip()
test_user_mode = imp.load_source(
'test_user_mode',
os.path.join(git_root, 'test-user-mode')
)
class Main(test_user_mode.Main): class Main(test_user_mode.Main):
def __init__(self): def __init__(self):

View File

@@ -13,7 +13,7 @@ https://github.com/cirosantilli/linux-kernel-module-cheat#test-userland-in-full-
''' '''
) )
def timed_main(self): def timed_main(self):
run = self.import_path_main('run') run = common.import_path_main('run')
run_args = self.get_common_args() run_args = self.get_common_args()
run_args['eval_after'] = './test_all.sh;{};'.format(self.env['userland_quit_cmd']) run_args['eval_after'] = './test_all.sh;{};'.format(self.env['userland_quit_cmd'])
self.run_test(run, run_args) self.run_test(run, run_args)

View File

@@ -14,7 +14,7 @@ More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#t
def timed_main(self): def timed_main(self):
args = self.get_common_args() args = self.get_common_args()
run = self.import_path_main('run') run = common.import_path_main('run')
if self.env['emulator'] == 'gem5': if self.env['emulator'] == 'gem5':
args['trace'] = 'Exec,-ExecSymbol,-ExecMicro' args['trace'] = 'Exec,-ExecSymbol,-ExecMicro'
run.main(**args) run.main(**args)
@@ -23,7 +23,7 @@ More information at: https://github.com/cirosantilli/linux-kernel-module-cheat#t
run_args['trace'] = 'exec_tb' run_args['trace'] = 'exec_tb'
run_args['quit_after_boot'] = True run_args['quit_after_boot'] = True
run.main(**run_args) run.main(**run_args)
qemu_trace2txt = self.import_path_main('qemu-trace2txt') qemu_trace2txt = common.import_path_main('qemu-trace2txt')
qemu_trace2txt.main(**args) qemu_trace2txt.main(**args)
# Instruction count. # Instruction count.
# We could put this on a separate script, but it just adds more arch boilerplate to a new script. # We could put this on a separate script, but it just adds more arch boilerplate to a new script.