11# SPDX-License-Identifier: MIT
2- # Copyright (c) 2019-2022 The Pybricks Authors
2+ # Copyright (c) 2019-2023 The Pybricks Authors
33
44import asyncio
55import logging
66import os
77from modulefinder import ModuleFinder
8- from typing import List , Optional
8+ from typing import List , Optional , Tuple , Union
99
1010import mpy_cross_v5
1111import mpy_cross_v6
@@ -76,7 +76,7 @@ async def compile_file(path: str, abi: int, compile_args: Optional[List[str]] =
7676 return mpy
7777
7878
79- async def compile_multi_file (path : str , abi : int ):
79+ async def compile_multi_file (path : str , abi : Union [ int , Tuple [ int , int ]] ):
8080 """Compiles a Python file and its dependencies with ``mpy-cross``.
8181
8282 On the hub, all dependencies behave as independent modules. Any (leading)
@@ -101,7 +101,8 @@ async def compile_multi_file(path: str, abi: int):
101101 path:
102102 Path to script that is to be compiled.
103103 abi:
104- Expected MPY ABI version.
104+ Expected MPY ABI version. Can be major version (int) if no native
105+ .mpy modules or tuple of major, minor version.
105106
106107 Returns:
107108 Concatenation of all compiled files in the format given above.
@@ -123,10 +124,12 @@ async def compile_multi_file(path: str, abi: int):
123124 # Get a data blob with all scripts.
124125 parts : List [bytes ] = []
125126
127+ abi_major , abi_minor = (abi , None ) if isinstance (abi , int ) else abi
128+
126129 for name , module in finder .modules .items ():
127130 if not module .__file__ :
128131 continue
129- mpy = await compile_file (module .__file__ , abi )
132+ mpy = await compile_file (module .__file__ , abi_major )
130133
131134 parts .append (len (mpy ).to_bytes (4 , "little" ))
132135 parts .append (name .encode () + b"\x00 " )
@@ -138,9 +141,19 @@ async def compile_multi_file(path: str, abi: int):
138141 try :
139142 with open (os .path .join (spath , f"{ name } .mpy" ), "rb" ) as f :
140143 mpy = f .read ()
141- if mpy [1 ] != abi :
144+ if mpy [1 ] != abi_major :
145+ raise ValueError (
146+ f"{ name } .mpy has abi major version { mpy [1 ]} while { abi_major } is required"
147+ )
148+ if (
149+ abi_minor is not None # hub indicated a minor version
150+ and (mpy [2 ] >> 2 ) # mpy has native arch
151+ # TODO: How to validate native arch? For now just gets runtime error on hub.
152+ and (mpy [2 ] & 0x3 )
153+ != abi_minor # mpy minor version does not match hub minor version
154+ ):
142155 raise ValueError (
143- f"{ name } .mpy has abi version { mpy [1 ] } while { abi } is required"
156+ f"{ name } .mpy has abi minor version { mpy [2 ] & 0x3 } while { abi_minor } is required"
144157 )
145158 parts .append (len (mpy ).to_bytes (4 , "little" ))
146159 parts .append (name .encode () + b"\x00 " )
0 commit comments