2021-07-03 18:26:15 +03:00
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
""" generate_rust_analyzer - Generates the `rust-project.json` file for `rust-analyzer`.
"""
import argparse
import json
import logging
2023-04-11 12:17:15 +03:00
import os
2021-07-03 18:26:15 +03:00
import pathlib
import sys
2023-08-04 20:14:39 +03:00
def args_crates_cfgs ( cfgs ) :
crates_cfgs = { }
for cfg in cfgs :
crate , vals = cfg . split ( " = " , 1 )
crates_cfgs [ crate ] = vals . replace ( " --cfg " , " " ) . split ( )
return crates_cfgs
def generate_crates ( srctree , objtree , sysroot_src , external_src , cfgs ) :
2021-07-03 18:26:15 +03:00
# Generate the configuration list.
cfg = [ ]
with open ( objtree / " include " / " generated " / " rustc_cfg " ) as fd :
for line in fd :
line = line . replace ( " --cfg= " , " " )
line = line . replace ( " \n " , " " )
cfg . append ( line )
# Now fill the crates list -- dependencies need to come first.
#
# Avoid O(n^2) iterations by keeping a map of indexes.
crates = [ ]
crates_indexes = { }
2023-08-04 20:14:39 +03:00
crates_cfgs = args_crates_cfgs ( cfgs )
2021-07-03 18:26:15 +03:00
def append_crate ( display_name , root_module , deps , cfg = [ ] , is_workspace_member = True , is_proc_macro = False ) :
crates_indexes [ display_name ] = len ( crates )
crates . append ( {
" display_name " : display_name ,
" root_module " : str ( root_module ) ,
" is_workspace_member " : is_workspace_member ,
" is_proc_macro " : is_proc_macro ,
" deps " : [ { " crate " : crates_indexes [ dep ] , " name " : dep } for dep in deps ] ,
" cfg " : cfg ,
" edition " : " 2021 " ,
" env " : {
" RUST_MODFILE " : " This is only for rust-analyzer "
}
} )
# First, the ones in `rust/` since they are a bit special.
append_crate (
" core " ,
sysroot_src / " core " / " src " / " lib.rs " ,
[ ] ,
2023-08-04 20:14:39 +03:00
cfg = crates_cfgs . get ( " core " , [ ] ) ,
2021-07-03 18:26:15 +03:00
is_workspace_member = False ,
)
append_crate (
" compiler_builtins " ,
srctree / " rust " / " compiler_builtins.rs " ,
[ ] ,
)
append_crate (
" alloc " ,
srctree / " rust " / " alloc " / " lib.rs " ,
[ " core " , " compiler_builtins " ] ,
2023-08-04 20:14:39 +03:00
cfg = crates_cfgs . get ( " alloc " , [ ] ) ,
2021-07-03 18:26:15 +03:00
)
append_crate (
" macros " ,
srctree / " rust " / " macros " / " lib.rs " ,
[ ] ,
is_proc_macro = True ,
)
2023-04-11 12:17:15 +03:00
crates [ - 1 ] [ " proc_macro_dylib_path " ] = f " { objtree } /rust/libmacros.so "
2021-07-03 18:26:15 +03:00
2022-11-10 19:41:37 +03:00
append_crate (
" build_error " ,
srctree / " rust " / " build_error.rs " ,
[ " core " , " compiler_builtins " ] ,
)
2021-07-03 18:26:15 +03:00
append_crate (
" bindings " ,
srctree / " rust " / " bindings " / " lib.rs " ,
[ " core " ] ,
cfg = cfg ,
)
crates [ - 1 ] [ " env " ] [ " OBJTREE " ] = str ( objtree . resolve ( True ) )
append_crate (
" kernel " ,
srctree / " rust " / " kernel " / " lib.rs " ,
2022-11-10 19:41:37 +03:00
[ " core " , " alloc " , " macros " , " build_error " , " bindings " ] ,
2021-07-03 18:26:15 +03:00
cfg = cfg ,
)
crates [ - 1 ] [ " source " ] = {
" include_dirs " : [
str ( srctree / " rust " / " kernel " ) ,
str ( objtree / " rust " )
] ,
" exclude_dirs " : [ ] ,
}
2023-04-11 12:17:15 +03:00
def is_root_crate ( build_file , target ) :
try :
return f " { target } .o " in open ( build_file ) . read ( )
except FileNotFoundError :
return False
2021-07-03 18:26:15 +03:00
# Then, the rest outside of `rust/`.
#
# We explicitly mention the top-level folders we want to cover.
2023-04-11 12:17:15 +03:00
extra_dirs = map ( lambda dir : srctree / dir , ( " samples " , " drivers " ) )
if external_src is not None :
extra_dirs = [ external_src ]
for folder in extra_dirs :
for path in folder . rglob ( " *.rs " ) :
2021-07-03 18:26:15 +03:00
logging . info ( " Checking %s " , path )
name = path . name . replace ( " .rs " , " " )
# Skip those that are not crate roots.
2023-04-11 12:17:15 +03:00
if not is_root_crate ( path . parent / " Makefile " , name ) and \
not is_root_crate ( path . parent / " Kbuild " , name ) :
2021-07-03 18:26:15 +03:00
continue
logging . info ( " Adding %s " , name )
append_crate (
name ,
path ,
[ " core " , " alloc " , " kernel " ] ,
cfg = cfg ,
)
return crates
def main ( ) :
parser = argparse . ArgumentParser ( )
parser . add_argument ( ' --verbose ' , ' -v ' , action = ' store_true ' )
2023-08-04 20:14:39 +03:00
parser . add_argument ( ' --cfgs ' , action = ' append ' , default = [ ] )
2021-07-03 18:26:15 +03:00
parser . add_argument ( " srctree " , type = pathlib . Path )
parser . add_argument ( " objtree " , type = pathlib . Path )
parser . add_argument ( " sysroot_src " , type = pathlib . Path )
2023-04-11 12:17:15 +03:00
parser . add_argument ( " exttree " , type = pathlib . Path , nargs = " ? " )
2021-07-03 18:26:15 +03:00
args = parser . parse_args ( )
logging . basicConfig (
format = " [ %(asctime)s ] [ %(levelname)s ] %(message)s " ,
level = logging . INFO if args . verbose else logging . WARNING
)
rust_project = {
2023-08-04 20:14:39 +03:00
" crates " : generate_crates ( args . srctree , args . objtree , args . sysroot_src , args . exttree , args . cfgs ) ,
2021-07-03 18:26:15 +03:00
" sysroot_src " : str ( args . sysroot_src ) ,
}
json . dump ( rust_project , sys . stdout , sort_keys = True , indent = 4 )
if __name__ == " __main__ " :
main ( )