ldgen: Improve error output when linker input is invalid, don't create output file until end of process

This commit is contained in:
Angus Gratton 2018-11-29 11:46:54 +11:00 committed by Angus Gratton
parent 2c7fc07aae
commit d4a5682e7d
5 changed files with 47 additions and 17 deletions

23
tools/ldgen/common.py Normal file
View file

@ -0,0 +1,23 @@
#
# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
class LdGenFailure(RuntimeError):
"""
Parent class for any ldgen runtime failure which is due to input data
"""
def __init__(self, message):
super(LdGenFailure, self).__init__(message)

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python
# #
# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD # Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
# #
@ -22,6 +21,7 @@ import os
from sdkconfig import SDKConfig from sdkconfig import SDKConfig
from pyparsing import * from pyparsing import *
from common import LdGenFailure
""" """
Fragment file internal representation. Parses and stores instances of the fragment definitions Fragment file internal representation. Parses and stores instances of the fragment definitions
@ -43,7 +43,13 @@ class FragmentFileModel():
# Set any text beginnning with # as comment # Set any text beginnning with # as comment
parser.ignore("#" + restOfLine) parser.ignore("#" + restOfLine)
self.fragments = parser.parseFile(fragment_file, parseAll=True) try:
self.fragments = parser.parseFile(fragment_file, parseAll=True)
except ParseBaseException as e:
# the actual parse error is kind of useless for normal users, so just point to the location of
# the error
raise LdGenFailure("Parse error in linker fragment %s: error at line %d col %d (char %d)" % (
fragment_file.name, e.lineno, e.column, e.loc))
for fragment in self.fragments: for fragment in self.fragments:
fragment.path = path fragment.path = path

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python
# #
# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD # Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
# #
@ -25,6 +24,7 @@ import fnmatch
from sdkconfig import SDKConfig from sdkconfig import SDKConfig
from fragments import FragmentFileModel, Sections, Scheme, Mapping, Fragment from fragments import FragmentFileModel, Sections, Scheme, Mapping, Fragment
from pyparsing import * from pyparsing import *
from common import LdGenFailure
""" """
Encapsulates a generated placement rule placed under a target Encapsulates a generated placement rule placed under a target
@ -561,7 +561,7 @@ class TemplateModel:
Exception for linker script generation failures such as undefined references/ failure to Exception for linker script generation failures such as undefined references/ failure to
evaluate conditions, duplicate mappings, etc. evaluate conditions, duplicate mappings, etc.
""" """
class GenerationException(Exception): class GenerationException(LdGenFailure):
UNDEFINED_REFERENCE = "Undefined reference" UNDEFINED_REFERENCE = "Undefined reference"

View file

@ -19,10 +19,12 @@ import argparse
import os import os
import traceback import traceback
import sys import sys
import tempfile
from fragments import FragmentFileModel from fragments import FragmentFileModel
from sdkconfig import SDKConfig from sdkconfig import SDKConfig
from generation import GenerationModel, TemplateModel, SectionsInfo from generation import GenerationModel, TemplateModel, SectionsInfo
from common import LdGenFailure
def main(): def main():
@ -48,7 +50,7 @@ def main():
argparser.add_argument( argparser.add_argument(
"--output", "-o", "--output", "-o",
help = "Output linker script", help = "Output linker script",
type = argparse.FileType("w")) type = str)
argparser.add_argument( argparser.add_argument(
"--config", "-c", "--config", "-c",
@ -70,10 +72,10 @@ def main():
input_file = args.input input_file = args.input
fragment_files = [] if not args.fragments else args.fragments fragment_files = [] if not args.fragments else args.fragments
config_file = args.config config_file = args.config
output_file = args.output output_path = args.output
sections_info_files = [] if not args.sections else args.sections sections_info_files = [] if not args.sections else args.sections
kconfig_file = args.kconfig kconfig_file = args.kconfig
try: try:
sections_infos = SectionsInfo() sections_infos = SectionsInfo()
@ -92,14 +94,14 @@ def main():
script_model = TemplateModel(input_file) script_model = TemplateModel(input_file)
script_model.fill(mapping_rules, sdkconfig) script_model.fill(mapping_rules, sdkconfig)
script_model.write(output_file) with tempfile.TemporaryFile("w+") as output:
except Exception as e: script_model.write(output)
print("linker script generation failed for %s\nERROR: %s" % (input_file.name, e.message)) output.seek(0)
# Delete the file so the entire build will fail; and not use an outdated script. with open(output_path, "w") as f: # only create output file after generation has suceeded
os.remove(output_file.name) f.write(output.read())
# Print traceback and exit except LdGenFailure as e:
traceback.print_exc() print("linker script generation failed for %s\nERROR: %s" % (input_file.name, e))
sys.exit(1) sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -1,4 +1,3 @@
#!/usr/bin/env python
# #
# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD # Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
# #
@ -84,4 +83,4 @@ class SDKConfig:
("&&", 2, opAssoc.LEFT), ("&&", 2, opAssoc.LEFT),
("||", 2, opAssoc.LEFT)]) ("||", 2, opAssoc.LEFT)])
return grammar return grammar