222 lines
6.7 KiB
Python
222 lines
6.7 KiB
Python
#---Imports---------------------------------------------------------------------
|
|
|
|
import os
|
|
import xml.etree.ElementTree as ETree
|
|
import argparse
|
|
import json
|
|
|
|
|
|
#---definitions-----------------------------------------------------------------
|
|
|
|
|
|
#---ewp parsing-----------------------------------------------------------------
|
|
|
|
def parse_ewp(ewp_file, arg_file=None):
|
|
"""
|
|
Parse an ewp file, returning a list of defines, includes and files to compile.
|
|
The first valid configuration in the file is used. An additionnal argvars file
|
|
can be used to directly expand the variables present in the various fields
|
|
|
|
:param ewp_file: the ewp file to parse
|
|
:param arg_file: additionnal argvars file
|
|
:returns: tuple of defines, includes and files to compile
|
|
"""
|
|
|
|
#parse ewp file for defines and include paths
|
|
ewp_base_path = os.path.dirname(os.path.abspath(ewp_file))
|
|
ewp_tree = ETree.parse(ewp_file)
|
|
|
|
for config in ewp_tree.findall(".//configuration"):
|
|
raw_defines = list_option_values(config, "CCDefines")
|
|
raw_includes = list_option_values(config, "CCIncludePath2")
|
|
|
|
if 0 != len(raw_defines) and 0 != len(raw_includes):
|
|
break
|
|
|
|
raw_files = list_project_files(ewp_tree)
|
|
|
|
#parse argvars, if any, for global values
|
|
if None != arg_file:
|
|
arg_tree = ETree.parse(arg_file)
|
|
|
|
variables = list_variables(arg_tree)
|
|
else:
|
|
variables = {}
|
|
|
|
variables["PROJ_DIR"] = ewp_base_path
|
|
|
|
#expand variables in the defines and include paths
|
|
defines = expand_variables(raw_defines, variables)
|
|
includes = expand_variables(raw_includes, variables)
|
|
files = expand_variables(raw_files, variables)
|
|
norm_files = [os.path.normpath(file) for file in files]
|
|
|
|
return (defines, includes, norm_files)
|
|
|
|
|
|
def list_option_values(config, option_name):
|
|
"""
|
|
Tool function to list the compilation options with the given name defined in
|
|
an ewp file's configuration
|
|
|
|
:param config: xml tree representing an ewp configuration
|
|
:param option_name: the name of the options to list
|
|
:returns: a list of the compilations options
|
|
"""
|
|
found = False
|
|
values = []
|
|
|
|
for option in config.findall('settings/data/option'):
|
|
for child in option:
|
|
if (child.text == option_name):
|
|
found = True
|
|
|
|
if found and (child.tag == "state") and (None != child.text):
|
|
values.append(normalize_path(child.text))
|
|
|
|
if found:
|
|
break
|
|
|
|
return values
|
|
|
|
|
|
def list_variables(arg_tree):
|
|
"""
|
|
Tool function to list the variables defined in an argvars file
|
|
|
|
:param argvars: xml tree representing an argvars file
|
|
:returns: a list of the defined variables
|
|
"""
|
|
variables = {}
|
|
|
|
for variable in arg_tree.findall(".//variable"):
|
|
name = variable.find("name")
|
|
value = variable.find("value")
|
|
if None != name:
|
|
variables[name.text] = value.text
|
|
|
|
return variables
|
|
|
|
|
|
def list_project_files(ewp_tree):
|
|
"""
|
|
Tool function to generate a list of the file to compile from a ewp file
|
|
|
|
:param ewp_tree: xml tree representing a ewp file
|
|
:returns: a list of the file to compile
|
|
"""
|
|
raw_files = [file.find("name").text for file in ewp_tree.findall(".//file")]
|
|
return [os.path.abspath(normalize_path(file)) for file in raw_files]
|
|
|
|
|
|
def expand_variables(raw_values, variables):
|
|
"""
|
|
Tool function to expand the given values (paths, defines, ...) using the
|
|
global project variables. These variables are usually stored in the
|
|
custom_argvars file. Unknown variables will be left as-is
|
|
|
|
:param raw_values: list of non-expanded values
|
|
:param variables: dictionnay of the variables and their associated values
|
|
:returns: the list of values with the variables expanded
|
|
"""
|
|
values = []
|
|
|
|
for raw_value in raw_values:
|
|
value = raw_value
|
|
for (key, var) in variables.items():
|
|
value = value.replace("$" + key + "$", var)
|
|
values.append(value)
|
|
|
|
return values
|
|
|
|
|
|
#---compile_commands generation-------------------------------------------------
|
|
|
|
def generate_compile_commands(output_file, root_path, options, files):
|
|
"""
|
|
Generates a json compilation database according to this standard:
|
|
https://clang.llvm.org/docs/JSONCompilationDatabase.html, using the given
|
|
options and list of files. The options must be full, valid, compiler options
|
|
|
|
:param output_file: the name of the file to generate
|
|
:param options: a list of the compilation options
|
|
:param files: a list of files
|
|
"""
|
|
with open(output_file, "w") as output:
|
|
commands = []
|
|
for file in files:
|
|
commands.append(
|
|
{"directory": root_path, "arguments": options, "file": file})
|
|
|
|
json.dump(commands, output, indent=True)
|
|
|
|
|
|
def normalize_path(path):
|
|
"""
|
|
Normalizes the given path. Handles mixed-convention paths (dos/unix), which
|
|
the standard library functions don't
|
|
|
|
:param path: the path to normalize
|
|
:returns: the normalized path
|
|
"""
|
|
return os.path.normpath(path.replace("\\", "/"))
|
|
|
|
|
|
#---main function---------------------------------------------------------------
|
|
|
|
if "__main__" == __name__:
|
|
|
|
#setup command line
|
|
parser = argparse.ArgumentParser(
|
|
prog="Ewp2CompileCommands",
|
|
description="Parse the .ewp file of an IAR project and generates the "
|
|
"corresponding compile_commands.json")
|
|
|
|
parser.add_argument("ewp_file", type=str,
|
|
help="path to the project's ewp file")
|
|
parser.add_argument("-a", "--argvars", type=str,
|
|
help="path to the project's argvars file")
|
|
parser.add_argument("-f", "--files", type=str,
|
|
help="list of files to use instead of the ones in the "
|
|
"ewp file")
|
|
parser.add_argument("-o", "--options", type=str,
|
|
help="list of options to add to project options")
|
|
parser.add_argument("-r", "--root", type=str,
|
|
help="path to project root. current path is used if not "
|
|
"specified")
|
|
|
|
#get command line parameters
|
|
args = parser.parse_args()
|
|
|
|
ewp_file = args.ewp_file
|
|
arg_file = args.argvars
|
|
file_list = args.files
|
|
opt_list = args.options
|
|
root_path = args.root
|
|
|
|
#parse ewp and argvars files
|
|
(defs, incs, files) = parse_ewp(ewp_file, arg_file)
|
|
|
|
#replace files if necessary
|
|
if None != file_list:
|
|
with open(file_list, "r") as f:
|
|
raw_files = [line.strip() for line in f.readlines()]
|
|
files = [os.path.abspath(normalize_path(file)) for file in raw_files]
|
|
|
|
#parse additionnal options
|
|
opts = []
|
|
if None != opt_list:
|
|
with open(opt_list, "r") as f:
|
|
opts = [line.strip() for line in f.readlines()]
|
|
|
|
#set default root path if necessary
|
|
if None == root_path:
|
|
root_path = os.getcwd()
|
|
|
|
#generate compile_commands
|
|
defs = ["-D" + define for define in defs]
|
|
incs = ["-I" + inc for inc in incs]
|
|
generate_compile_commands("compile_commands.json", root_path,
|
|
defs + incs + opts, files)
|
|
|