@ -12,18 +12,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import typing as T
from . import ExtensionModule , ModuleReturnValue
from . . import mlog
from . . build import BuildTarget , Executable , InvalidArguments
from . . build import BuildTarget , CustomTargetIndex , Executable , GeneratedList , InvalidArguments , IncludeDirs , CustomTarget
from . . dependencies import Dependency , ExternalLibrary
from . . interpreter import ExecutableHolder , BuildTargetHolder , permitted_kwargs
from . . interpreter import ExecutableHolder , BuildTargetHolder , CustomTargetHolder , permitted_kwargs , noPos args
from . . interpreterbase import InterpreterException , permittedKwargs , FeatureNew , typed_pos_args
from . . mesonlib import stringlistify , unholder , listify
from . . mesonlib import stringlistify , unholder , listify , typeslistify , File
if T . TYPE_CHECKING :
from . . interpreter import ModuleState , Interpreter
from . . dependencies import ExternalProgram
class RustModule ( ExtensionModule ) :
@ -33,6 +35,7 @@ class RustModule(ExtensionModule):
@FeatureNew ( ' rust module ' , ' 0.57.0 ' )
def __init__ ( self , interpreter : ' Interpreter ' ) - > None :
super ( ) . __init__ ( interpreter )
self . _bindgen_bin : T . Optional [ ' ExternalProgram ' ] = None
@permittedKwargs ( permitted_kwargs [ ' test ' ] | { ' dependencies ' } ^ { ' protocol ' } )
@typed_pos_args ( ' rust.test ' , str , BuildTargetHolder )
@ -127,6 +130,77 @@ class RustModule(ExtensionModule):
return ModuleReturnValue ( [ ] , [ e , test ] )
@noPosargs
@permittedKwargs ( { ' input ' , ' output ' , ' include_directories ' , ' c_args ' , ' args ' } )
def bindgen ( self , state : ' ModuleState ' , args : T . List , kwargs : T . Dict [ str , T . Any ] ) - > ModuleReturnValue :
""" Wrapper around bindgen to simplify it ' s use.
The main thing this simplifies is the use of ` include_directory `
objects , instead of having to pass a plethora of ` - I ` arguments .
"""
header : T . Union [ File , CustomTarget , GeneratedList , CustomTargetIndex ]
_deps : T . Sequence [ T . Union [ File , CustomTarget , GeneratedList , CustomTargetIndex ] ]
try :
header , * _deps = unholder ( self . interpreter . source_strings_to_files ( listify ( kwargs [ ' input ' ] ) ) )
except KeyError :
raise InvalidArguments ( ' rustmod.bindgen() `input` argument must have at least one element. ' )
try :
output : str = kwargs [ ' output ' ]
except KeyError :
raise InvalidArguments ( ' rustmod.bindgen() `output` must be provided ' )
if not isinstance ( output , str ) :
raise InvalidArguments ( ' rustmod.bindgen() `output` argument must be a string. ' )
include_dirs : T . List [ IncludeDirs ] = typeslistify ( unholder ( listify ( kwargs . get ( ' include_directories ' , [ ] ) ) ) , IncludeDirs )
c_args : T . List [ str ] = stringlistify ( listify ( kwargs . get ( ' c_args ' , [ ] ) ) )
bind_args : T . List [ str ] = stringlistify ( listify ( kwargs . get ( ' args ' , [ ] ) ) )
# Split File and Target dependencies to add pass to CustomTarget
depends : T . List [ BuildTarget ] = [ ]
depend_files : T . List [ File ] = [ ]
for d in _deps :
if isinstance ( d , File ) :
depend_files . append ( d )
else :
depends . append ( d )
inc_strs : T . List [ str ] = [ ]
for i in include_dirs :
# bindgen always uses clang, so it's safe to hardcode -I here
inc_strs . extend ( [ f ' -I { x } ' for x in i . to_string_list ( state . environment . get_source_dir ( ) ) ] )
if self . _bindgen_bin is None :
# there's some bugs in the interpreter typeing.
self . _bindgen_bin = T . cast ( ' ExternalProgram ' , self . interpreter . find_program_impl ( [ ' bindgen ' ] ) . held_object )
name : str
if isinstance ( header , File ) :
name = header . fname
else :
name = header . get_outputs ( ) [ 0 ]
target = CustomTarget (
f ' rustmod-bindgen- { name } ' . replace ( ' / ' , ' _ ' ) ,
state . subdir ,
state . subproject ,
{
' input ' : header ,
' output ' : output ,
' command ' : self . _bindgen_bin . get_command ( ) + [
' @INPUT@ ' , ' --output ' ,
os . path . join ( state . environment . build_dir , ' @OUTPUT@ ' ) ] +
bind_args + [ ' -- ' ] + c_args + inc_strs +
[ ' -MD ' , ' -MQ ' , ' @INPUT@ ' , ' -MF ' , ' @DEPFILE@ ' ] ,
' depfile ' : ' @PLAINNAME@.d ' ,
' depends ' : depends ,
' depend_files ' : depend_files ,
} ,
backend = state . backend ,
)
return ModuleReturnValue ( [ target ] , [ CustomTargetHolder ( target , self . interpreter ) ] )
def initialize ( * args : T . List , * * kwargs : T . Dict ) - > RustModule :
return RustModule ( * args , * * kwargs ) # type: ignore