mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-07-15 02:37:48 -06:00
🔨 Build script improvements
This commit is contained in:
parent
b94c75bcda
commit
3b33f7ec03
4 changed files with 68 additions and 39 deletions
|
@ -110,7 +110,7 @@ def disable_all_options():
|
||||||
match = regex.match(line)
|
match = regex.match(line)
|
||||||
if match:
|
if match:
|
||||||
name = match[3].upper()
|
name = match[3].upper()
|
||||||
if name in ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION'): continue
|
if name in ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXAMPLES_DIR'): continue
|
||||||
if name.startswith('_'): continue
|
if name.startswith('_'): continue
|
||||||
found = True
|
found = True
|
||||||
# Comment out the define
|
# Comment out the define
|
||||||
|
|
|
@ -80,7 +80,7 @@ def load_boards():
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
#
|
#
|
||||||
# Extract the current configuration files in the form of a structured schema.
|
# Extract the specified configuration files in the form of a structured schema.
|
||||||
# Contains the full schema for the configuration files, not just the enabled options,
|
# Contains the full schema for the configuration files, not just the enabled options,
|
||||||
# Contains the current values of the options, not just data structure, so "schema" is a slight misnomer.
|
# Contains the current values of the options, not just data structure, so "schema" is a slight misnomer.
|
||||||
#
|
#
|
||||||
|
@ -99,9 +99,9 @@ def load_boards():
|
||||||
# - requires = The conditions that must be met for the define to be enabled
|
# - requires = The conditions that must be met for the define to be enabled
|
||||||
# - comment = The comment for the define, if it has one
|
# - comment = The comment for the define, if it has one
|
||||||
# - units = The units for the define, if it has one
|
# - units = The units for the define, if it has one
|
||||||
# - options = The options for the define, if it has one
|
# - options = The options for the define, if it has any
|
||||||
#
|
#
|
||||||
def extract():
|
def extract_files(filekey):
|
||||||
# Load board names from boards.h
|
# Load board names from boards.h
|
||||||
boards = load_boards()
|
boards = load_boards()
|
||||||
|
|
||||||
|
@ -114,10 +114,8 @@ def extract():
|
||||||
GET_SENSORS = 4 # Gathering temperature sensor options
|
GET_SENSORS = 4 # Gathering temperature sensor options
|
||||||
ERROR = 9 # Syntax error
|
ERROR = 9 # Syntax error
|
||||||
|
|
||||||
# List of files to process, with shorthand
|
|
||||||
filekey = { 'Configuration.h':'basic', 'Configuration_adv.h':'advanced' }
|
|
||||||
# A JSON object to store the data
|
# A JSON object to store the data
|
||||||
sch_out = { 'basic':{}, 'advanced':{} }
|
sch_out = { key:{} for key in filekey.values() }
|
||||||
# Regex for #define NAME [VALUE] [COMMENT] with sanitized line
|
# Regex for #define NAME [VALUE] [COMMENT] with sanitized line
|
||||||
defgrep = re.compile(r'^(//)?\s*(#define)\s+([A-Za-z0-9_]+)\s*(.*?)\s*(//.+)?$')
|
defgrep = re.compile(r'^(//)?\s*(#define)\s+([A-Za-z0-9_]+)\s*(.*?)\s*(//.+)?$')
|
||||||
# Pattern to match a float value
|
# Pattern to match a float value
|
||||||
|
@ -180,6 +178,12 @@ def extract():
|
||||||
cfield = 'notes' if 'comment' in last_added_ref else 'comment'
|
cfield = 'notes' if 'comment' in last_added_ref else 'comment'
|
||||||
last_added_ref[cfield] = cline
|
last_added_ref[cfield] = cline
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add the given comment line to the comment buffer, unless:
|
||||||
|
# - The line starts with ':' and JSON values to assign to 'opt'.
|
||||||
|
# - The line starts with '@section' so a new section needs to be returned.
|
||||||
|
# - The line starts with '======' so just skip it.
|
||||||
|
#
|
||||||
def use_comment(c, opt, sec, bufref):
|
def use_comment(c, opt, sec, bufref):
|
||||||
if c.startswith(':'): # If the comment starts with : then it has magic JSON
|
if c.startswith(':'): # If the comment starts with : then it has magic JSON
|
||||||
d = c[1:].strip() # Strip the leading :
|
d = c[1:].strip() # Strip the leading :
|
||||||
|
@ -199,7 +203,7 @@ def extract():
|
||||||
# The comment will be applied to the next #define.
|
# The comment will be applied to the next #define.
|
||||||
if state == Parse.SLASH_COMMENT:
|
if state == Parse.SLASH_COMMENT:
|
||||||
if not defmatch and the_line.startswith('//'):
|
if not defmatch and the_line.startswith('//'):
|
||||||
use_comment(the_line[2:].strip(), options_json, section, comment_buff)
|
options_json, section = use_comment(the_line[2:].strip(), options_json, section, comment_buff)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
state = Parse.NORMAL
|
state = Parse.NORMAL
|
||||||
|
@ -219,7 +223,7 @@ def extract():
|
||||||
|
|
||||||
state = Parse.NORMAL
|
state = Parse.NORMAL
|
||||||
|
|
||||||
# Strip the leading '*' from block comments
|
# Strip the leading '* ' from block comments
|
||||||
cline = re.sub(r'^\* ?', '', cline)
|
cline = re.sub(r'^\* ?', '', cline)
|
||||||
|
|
||||||
# Collect temperature sensors
|
# Collect temperature sensors
|
||||||
|
@ -412,6 +416,13 @@ def extract():
|
||||||
|
|
||||||
return sch_out
|
return sch_out
|
||||||
|
|
||||||
|
#
|
||||||
|
# Extract the current configuration files in the form of a structured schema.
|
||||||
|
#
|
||||||
|
def extract():
|
||||||
|
# List of files to process, with shorthand
|
||||||
|
return extract_files({ 'Configuration.h':'basic', 'Configuration_adv.h':'advanced' })
|
||||||
|
|
||||||
def dump_json(schema:dict, jpath:Path):
|
def dump_json(schema:dict, jpath:Path):
|
||||||
with jpath.open('w') as jfile:
|
with jpath.open('w') as jfile:
|
||||||
json.dump(schema, jfile, ensure_ascii=False, indent=2)
|
json.dump(schema, jfile, ensure_ascii=False, indent=2)
|
||||||
|
|
|
@ -35,18 +35,27 @@ def enabled_defines(filepath):
|
||||||
'''
|
'''
|
||||||
outdict = {}
|
outdict = {}
|
||||||
section = "user"
|
section = "user"
|
||||||
spatt = re.compile(r".*@section +([-a-zA-Z0-9_\s]+)$") # must match @section ...
|
spatt = re.compile(r".*@section +([-a-zA-Z0-9_\s]+)$") # @section ...
|
||||||
|
|
||||||
f = open(filepath, encoding="utf8").read().split("\n")
|
f = open(filepath, encoding="utf8").read().split("\n")
|
||||||
|
|
||||||
# Get the full contents of the file and remove all block comments.
|
incomment = False
|
||||||
# This will avoid false positives from #defines in comments
|
|
||||||
f = re.sub(r'/\*.*?\*/', '', '\n'.join(f), flags=re.DOTALL).split("\n")
|
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
sline = line.strip()
|
sline = line.strip()
|
||||||
|
|
||||||
m = re.match(spatt, sline) # @section ...
|
m = re.match(spatt, sline) # @section ...
|
||||||
if m: section = m.group(1).strip() ; continue
|
if m: section = m.group(1).strip() ; continue
|
||||||
|
|
||||||
|
if incomment:
|
||||||
|
if '*/' in sline:
|
||||||
|
incomment = False
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
mpos, spos = sline.find('/*'), sline.find('//')
|
||||||
|
if mpos >= 0 and (spos < 0 or spos > mpos):
|
||||||
|
incomment = True
|
||||||
|
continue
|
||||||
|
|
||||||
if sline[:7] == "#define":
|
if sline[:7] == "#define":
|
||||||
# Extract the key here (we don't care about the value)
|
# Extract the key here (we don't care about the value)
|
||||||
kv = sline[8:].strip().split()
|
kv = sline[8:].strip().split()
|
||||||
|
@ -70,6 +79,11 @@ def compress_file(filepath, storedname, outpath):
|
||||||
with zipfile.ZipFile(outpath, 'w', compression=zipfile.ZIP_BZIP2, compresslevel=9) as zipf:
|
with zipfile.ZipFile(outpath, 'w', compression=zipfile.ZIP_BZIP2, compresslevel=9) as zipf:
|
||||||
zipf.write(filepath, arcname=storedname, compress_type=zipfile.ZIP_BZIP2, compresslevel=9)
|
zipf.write(filepath, arcname=storedname, compress_type=zipfile.ZIP_BZIP2, compresslevel=9)
|
||||||
|
|
||||||
|
ignore = ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXAMPLES_DIR', 'CONFIG_EXPORT')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Compute a build signature and/or export the configuration
|
||||||
|
#
|
||||||
def compute_build_signature(env):
|
def compute_build_signature(env):
|
||||||
'''
|
'''
|
||||||
Compute the build signature by extracting all configuration settings and
|
Compute the build signature by extracting all configuration settings and
|
||||||
|
@ -81,11 +95,17 @@ def compute_build_signature(env):
|
||||||
env.Append(BUILD_SIGNATURE=1)
|
env.Append(BUILD_SIGNATURE=1)
|
||||||
|
|
||||||
build_path = Path(env['PROJECT_BUILD_DIR'], env['PIOENV'])
|
build_path = Path(env['PROJECT_BUILD_DIR'], env['PIOENV'])
|
||||||
marlin_json = build_path / 'marlin_config.json'
|
json_name = 'marlin_config.json'
|
||||||
|
marlin_json = build_path / json_name
|
||||||
marlin_zip = build_path / 'mc.zip'
|
marlin_zip = build_path / 'mc.zip'
|
||||||
|
|
||||||
|
# ANSI colors
|
||||||
|
green = "\u001b[32m"
|
||||||
|
yellow = "\u001b[33m"
|
||||||
|
red = "\u001b[31m"
|
||||||
|
|
||||||
# Definitions from these files will be kept
|
# Definitions from these files will be kept
|
||||||
header_paths = [ 'Marlin/Configuration.h', 'Marlin/Configuration_adv.h' ]
|
header_paths = ('Marlin/Configuration.h', 'Marlin/Configuration_adv.h')
|
||||||
|
|
||||||
# Check if we can skip processing
|
# Check if we can skip processing
|
||||||
hashes = ''
|
hashes = ''
|
||||||
|
@ -100,7 +120,7 @@ def compute_build_signature(env):
|
||||||
conf = json.load(infile)
|
conf = json.load(infile)
|
||||||
same_hash = conf['__INITIAL_HASH'] == hashes
|
same_hash = conf['__INITIAL_HASH'] == hashes
|
||||||
if same_hash:
|
if same_hash:
|
||||||
compress_file(marlin_json, 'marlin_config.json', marlin_zip)
|
compress_file(marlin_json, json_name, marlin_zip)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -179,25 +199,28 @@ def compute_build_signature(env):
|
||||||
extended_dump = config_dump > 100
|
extended_dump = config_dump > 100
|
||||||
if extended_dump: config_dump -= 100
|
if extended_dump: config_dump -= 100
|
||||||
|
|
||||||
|
# Get the schema class for exports that require it
|
||||||
|
if config_dump in (3, 4) or (extended_dump and config_dump in (2, 5)):
|
||||||
|
try:
|
||||||
|
conf_schema = schema.extract()
|
||||||
|
except Exception as exc:
|
||||||
|
print(red + "Error: " + str(exc))
|
||||||
|
conf_schema = None
|
||||||
|
|
||||||
#
|
#
|
||||||
# Produce an INI file if CONFIG_EXPORT == 2
|
# Produce an INI file if CONFIG_EXPORT == 2
|
||||||
#
|
#
|
||||||
if config_dump == 2:
|
if config_dump == 2:
|
||||||
print("Generating config.ini ...")
|
print(yellow + "Generating config.ini ...")
|
||||||
|
|
||||||
ini_fmt = '{0:40} = {1}'
|
ini_fmt = '{0:40} = {1}'
|
||||||
ext_fmt = '{0:40} {1}'
|
ext_fmt = '{0:40} {1}'
|
||||||
ignore = ('CONFIGURATION_H_VERSION', 'CONFIGURATION_ADV_H_VERSION', 'CONFIG_EXAMPLES_DIR', 'CONFIG_EXPORT')
|
|
||||||
|
|
||||||
if extended_dump:
|
if extended_dump:
|
||||||
# Extended export will dump config options by section
|
# Extended export will dump config options by section
|
||||||
|
|
||||||
# We'll use Schema class to get the sections
|
# We'll use Schema class to get the sections
|
||||||
try:
|
if not conf_schema: exit(1)
|
||||||
conf_schema = schema.extract()
|
|
||||||
except Exception as exc:
|
|
||||||
print("Error: " + str(exc))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Then group options by schema @section
|
# Then group options by schema @section
|
||||||
sections = {}
|
sections = {}
|
||||||
|
@ -305,27 +328,22 @@ f'''#
|
||||||
for header in real_config:
|
for header in real_config:
|
||||||
outfile.write(f'\n[{filegrp[header]}]\n')
|
outfile.write(f'\n[{filegrp[header]}]\n')
|
||||||
for name in sorted(real_config[header]):
|
for name in sorted(real_config[header]):
|
||||||
if name not in ignore:
|
if name in ignore: continue
|
||||||
val = real_config[header][name]['value']
|
val = real_config[header][name]['value']
|
||||||
if val == '': val = 'on'
|
if val == '': val = 'on'
|
||||||
outfile.write(ini_fmt.format(name.lower(), val) + '\n')
|
outfile.write(ini_fmt.format(name.lower(), val) + '\n')
|
||||||
|
|
||||||
#
|
#
|
||||||
# CONFIG_EXPORT 3 = schema.json, 4 = schema.yml
|
# CONFIG_EXPORT 3 = schema.json, 4 = schema.yml
|
||||||
#
|
#
|
||||||
if config_dump >= 3:
|
if config_dump in (3, 4):
|
||||||
try:
|
|
||||||
conf_schema = schema.extract()
|
|
||||||
except Exception as exc:
|
|
||||||
print("Error: " + str(exc))
|
|
||||||
conf_schema = None
|
|
||||||
|
|
||||||
if conf_schema:
|
if conf_schema:
|
||||||
#
|
#
|
||||||
# 3 = schema.json
|
# 3 = schema.json
|
||||||
#
|
#
|
||||||
if config_dump in (3, 13):
|
if config_dump in (3, 13):
|
||||||
print("Generating schema.json ...")
|
print(yellow + "Generating schema.json ...")
|
||||||
schema.dump_json(conf_schema, build_path / 'schema.json')
|
schema.dump_json(conf_schema, build_path / 'schema.json')
|
||||||
if config_dump == 13:
|
if config_dump == 13:
|
||||||
schema.group_options(conf_schema)
|
schema.group_options(conf_schema)
|
||||||
|
@ -335,7 +353,7 @@ f'''#
|
||||||
# 4 = schema.yml
|
# 4 = schema.yml
|
||||||
#
|
#
|
||||||
elif config_dump == 4:
|
elif config_dump == 4:
|
||||||
print("Generating schema.yml ...")
|
print(yellow + "Generating schema.yml ...")
|
||||||
try:
|
try:
|
||||||
import yaml
|
import yaml
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -355,7 +373,7 @@ f'''#
|
||||||
|
|
||||||
json_data = {}
|
json_data = {}
|
||||||
if extended_dump:
|
if extended_dump:
|
||||||
print("Extended dump ...")
|
print(yellow + "Extended dump ...")
|
||||||
for header in real_config:
|
for header in real_config:
|
||||||
confs = real_config[header]
|
confs = real_config[header]
|
||||||
json_data[header] = {}
|
json_data[header] = {}
|
||||||
|
@ -395,7 +413,7 @@ f'''#
|
||||||
|
|
||||||
# Compress the JSON file as much as we can
|
# Compress the JSON file as much as we can
|
||||||
if not same_hash:
|
if not same_hash:
|
||||||
compress_file(marlin_json, 'marlin_config.json', marlin_zip)
|
compress_file(marlin_json, json_name, marlin_zip)
|
||||||
|
|
||||||
# Generate a C source file containing the entire ZIP file as an array
|
# Generate a C source file containing the entire ZIP file as an array
|
||||||
with open('Marlin/src/mczip.h','wb') as result_file:
|
with open('Marlin/src/mczip.h','wb') as result_file:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* Marlin 3D Printer Firmware
|
* Marlin 3D Printer Firmware
|
||||||
* Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
* Copyright (c) 2024 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||||
*
|
*
|
||||||
* Based on Sprinter and grbl.
|
* Based on Sprinter and grbl.
|
||||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue