Skip to content

Commit

Permalink
lmdk: python tools for building and headers pack
Browse files Browse the repository at this point in the history
To build modules using pythons were created several tools making
building easier.
For future deployment there is a tool extracting headers described in
manifest and creating zip file from them.

modules are build now:
	python scripts/lmdk/build_module.py -l <modules_names>

we can build multiple modules by adding them one after another.

Signed-off-by: Dobrowolski, PawelX <[email protected]>
  • Loading branch information
pjdobrowolski committed Feb 15, 2024
1 parent 2ff6925 commit 56d59d7
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 0 deletions.
94 changes: 94 additions & 0 deletions scripts/lmdk/build_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause


import argparse
import pathlib
import platform as py_platform
import sys
import os
import warnings
from tools import cmake_build, header_pack


# https://chrisyeh96.github.io/2017/08/08/definitive-guide-python-imports.html#case-3-importing-from-parent-directory
sys.path.insert(1, os.path.join(sys.path[0], '..'))

MIN_PYTHON_VERSION = 3, 8
assert sys.version_info >= MIN_PYTHON_VERSION, \
f"Python {MIN_PYTHON_VERSION} or above is required."

# Constant value resolves SOF_TOP directory as: "this script directory/.."
SOF_TOP = pathlib.Path(__file__).parents[1].resolve()
west_top = pathlib.Path(SOF_TOP, "../..").resolve()
LMDK_BUILD_DIR = west_top / "sof" / "lmdk"
RIMAGE_BUILD_DIR = west_top / "build-rimage"

if py_platform.system() == "Windows":
xtensa_tools_version_postfix = "-win32"
elif py_platform.system() == "Linux":
xtensa_tools_version_postfix = "-linux"
else:
xtensa_tools_version_postfix = "-unsupportedOS"
warnings.warn(f"Your operating system: {py_platform.system()} is not supported")


class stores_libraries_arguments(argparse.Action):
"""Stores libraries arguments whether provided module name is supported."""
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, "libraries", values)

args = None
def parse_args():
global args
global west_top
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
epilog=("This script supports XtensaTools but only when installed in a specific\n" +
"directory structure, example:\n" +
"myXtensa/\n" +
"└── install/\n" +
" ├── builds/\n" +
" │   ├── RD-2012.5{}/\n".format(xtensa_tools_version_postfix) +
" │   │   └── Intel_HiFiEP/\n" +
" │   └── RG-2017.8{}/\n".format(xtensa_tools_version_postfix) +
" │   ├── LX4_langwell_audio_17_8/\n" +
" │   └── X4H3I16w2D48w3a_2017_8/\n" +
" └── tools/\n" +
" ├── RD-2012.5{}/\n".format(xtensa_tools_version_postfix) +
" │   └── XtensaTools/\n" +
" └── RG-2017.8{}/\n".format(xtensa_tools_version_postfix) +
" └── XtensaTools/\n" +
"$XTENSA_TOOLS_ROOT=/path/to/myXtensa ...\n"), add_help=False)

parser.add_argument("-k", "--key", type=pathlib.Path, required=False,
help="Path to a non-default rimage signing key.")

parser.add_argument("-l", "--libraries", nargs="*", action=stores_libraries_arguments, default=[],
help=""" Function for CMake building modules.
We can build more then one module just by adding more module names.""")

parser.add_argument("-p", "--pack", required=False,
help="Create deployment zip headers pack from headers manifest")

args = parser.parse_args()

# print help message if no arguments provided
if len(sys.argv) == 1: #or args.help:
parser.epilog += "\nTo build module you must provide name and key to sign '"

parser.print_help()
sys.exit(0)


def main():
parse_args()

if args.libraries:
cmake_build.build_libraries(LMDK_BUILD_DIR, RIMAGE_BUILD_DIR, args)
if args.pack:
header_pack.create_headers_pack()


if __name__ == "__main__":
main()

Empty file added scripts/lmdk/tools/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions scripts/lmdk/tools/cmake_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause


import pathlib
import dataclasses
from .utils import rmtree_if_exists, execute_command


SOF_TOP = pathlib.Path(__file__).parents[3].resolve()


@dataclasses.dataclass
# pylint:disable=too-many-instance-attributes
class PlatformConfig:
"Product parameters"
vendor: str
PLAT_CONFIG: str
XTENSA_TOOLS_VERSION: str
XTENSA_CORE: str
DEFAULT_TOOLCHAIN_VARIANT: str = "xt-clang"
RIMAGE_KEY: pathlib.Path = pathlib.Path(SOF_TOP, "keys", "otc_private_key_3k.pem")
aliases: list = dataclasses.field(default_factory=list)
ipc4: bool = False


def build_libraries(LMDK_BUILD_DIR, RIMAGE_BUILD_DIR, args):
library_dir = LMDK_BUILD_DIR / "libraries"
# CMake build rimage module
for lib in args.libraries:
library_cmake = library_dir / lib / "CMakeLists.txt"
if library_cmake.is_file():
print(f"\nBuilding loadable module: " + lib)
lib_path = pathlib.Path(library_dir, lib, "build")
print(f"\nRemoving existing artifacts")
rmtree_if_exists(lib_path)
lib_path.mkdir(parents=True, exist_ok=True)
rimage_bin = RIMAGE_BUILD_DIR / "rimage.exe"
if not rimage_bin.is_file():
rimage_bin = RIMAGE_BUILD_DIR / "rimage"
if args.key:
key = "-DSIGNING_KEY=" + args.key.__str__()
else:
key = "-DSIGNING_KEY=" + PlatformConfig.RIMAGE_KEY.__str__()
execute_command(["cmake", "-B", "build", "-G", "Ninja",
"-DRIMAGE_COMMAND="+str(rimage_bin), key],
cwd=library_dir/lib)
execute_command(["cmake", "--build", "build", "-v"], cwd=library_dir/lib)

45 changes: 45 additions & 0 deletions scripts/lmdk/tools/header_pack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause


import json
import pathlib
import shutil


# Headers for needs of lmdk are defined in
# lmdk/include/headers_list.json


SOF_TOP = pathlib.Path(__file__).parents[3].resolve()
LMDK_HEADERS = SOF_TOP / "lmdk" / "include" / "headers_manifest.json"


def create_separate_headers():
f = open(LMDK_HEADERS)
data = json.load(f)
src = ''

for i in data:
src = ''
for p in i[:-1]:
src += p
src += "/"
pathlib.Path(SOF_TOP / "lmdk" / "include" / "sof" / src).mkdir(parents=True, exist_ok=True)
for p in i[-1:]:
src += p
shutil.copyfile(SOF_TOP / src, SOF_TOP / "lmdk" /"include" / "sof" / src)
f.close()

# -> to do
# def validate_separate_headers():
# return 0


def create_headers_pack():
create_separate_headers()
shutil.make_archive(SOF_TOP / "lmdk" /"include" / "header_pack", "zip", SOF_TOP / "lmdk" /"include" / "sof")
shutil.rmtree(SOF_TOP / "lmdk" /"include" / "sof", ignore_errors=True)
return 0


45 changes: 45 additions & 0 deletions scripts/lmdk/tools/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause


import shlex
import subprocess
import shutil
import os


def rmtree_if_exists(directory):
"This is different from ignore_errors=False because it deletes everything or nothing"
if os.path.exists(directory):
shutil.rmtree(directory)


def execute_command(*run_args, **run_kwargs):
"""[summary] Provides wrapper for subprocess.run that prints
command executed when 'more verbose' verbosity level is set."""
command_args = run_args[0]

# If you really need the shell in some non-portable section then
# invoke subprocess.run() directly.
if run_kwargs.get('shell') or not isinstance(command_args, list):
raise RuntimeError("Do not rely on non-portable shell parsing")

cwd = run_kwargs.get('cwd')
print_cwd = f"In dir: {cwd}" if cwd else f"in current dir: {os.getcwd()}"
print_args = shlex.join(command_args)
output = f"{print_cwd}; running command:\n {print_args}"
env_arg = run_kwargs.get('env')
env_change = set(env_arg.items()) - set(os.environ.items()) if env_arg else None
if env_change and run_kwargs.get('sof_log_env'):
output += "\n... with extra/modified environment:\n"
for k_v in env_change:
output += f"{k_v[0]}={k_v[1]}\n"
print(output, flush=True)

run_kwargs = {k: run_kwargs[k] for k in run_kwargs if not k.startswith("sof_")}

if not 'check' in run_kwargs:
run_kwargs['check'] = True
#pylint:disable=subprocess-run-check

return subprocess.run(*run_args, **run_kwargs)

0 comments on commit 56d59d7

Please sign in to comment.