|
|
@ -4,21 +4,21 @@ |
|
|
|
import os,subprocess,re,json,hashlib |
|
|
|
|
|
|
|
# |
|
|
|
# The dumbest preprocessor in the world |
|
|
|
# Extract macro name from an header file and store them in an array |
|
|
|
# No processing is done here, so they are raw values here and it does not match what actually enabled |
|
|
|
# in the file (since you can have #if SOMETHING_UNDEFINED / #define BOB / #endif) |
|
|
|
# But it's useful to filter the useful macro spit out by the preprocessor from noise from the system |
|
|
|
# headers. |
|
|
|
# Return all macro names in a header as an array, so we can take |
|
|
|
# the intersection with the preprocessor output, giving a decent |
|
|
|
# reflection of all enabled options that (probably) came from the |
|
|
|
# configuration files. We end up with the actual configured state, |
|
|
|
# better than what the config files say. You can then use the |
|
|
|
# resulting config.ini to produce more exact configuration files. |
|
|
|
# |
|
|
|
def extract_defines(filepath): |
|
|
|
f = open(filepath, encoding="utf8").read().split("\n") |
|
|
|
a = [] |
|
|
|
for line in f: |
|
|
|
sline = line.strip(" \t\n\r") |
|
|
|
sline = line.strip() |
|
|
|
if sline[:7] == "#define": |
|
|
|
# Extract the key here (we don't care about the value) |
|
|
|
kv = sline[8:].strip().split(' ') |
|
|
|
kv = sline[8:].strip().split() |
|
|
|
a.append(kv[0]) |
|
|
|
return a |
|
|
|
|
|
|
@ -51,7 +51,7 @@ def compute_build_signature(env): |
|
|
|
# Definitions from these files will be kept |
|
|
|
files_to_keep = [ 'Marlin/Configuration.h', 'Marlin/Configuration_adv.h' ] |
|
|
|
|
|
|
|
build_dir=os.path.join(env['PROJECT_BUILD_DIR'], env['PIOENV']) |
|
|
|
build_dir = os.path.join(env['PROJECT_BUILD_DIR'], env['PIOENV']) |
|
|
|
|
|
|
|
# Check if we can skip processing |
|
|
|
hashes = '' |
|
|
@ -77,14 +77,14 @@ def compute_build_signature(env): |
|
|
|
complete_cfg = run_preprocessor(env) |
|
|
|
|
|
|
|
# Dumb #define extraction from the configuration files |
|
|
|
real_defines = {} |
|
|
|
conf_defines = {} |
|
|
|
all_defines = [] |
|
|
|
for header in files_to_keep: |
|
|
|
defines = extract_defines(header) |
|
|
|
# To filter only the define we want |
|
|
|
all_defines = all_defines + defines |
|
|
|
all_defines += defines |
|
|
|
# To remember from which file it cames from |
|
|
|
real_defines[header.split('/')[-1]] = defines |
|
|
|
conf_defines[header.split('/')[-1]] = defines |
|
|
|
|
|
|
|
r = re.compile(r"\(+(\s*-*\s*_.*)\)+") |
|
|
|
|
|
|
@ -116,16 +116,16 @@ def compute_build_signature(env): |
|
|
|
resolved_defines = {} |
|
|
|
for key in defines: |
|
|
|
# Remove all boards now |
|
|
|
if key[0:6] == "BOARD_" and key != "BOARD_INFO_NAME": |
|
|
|
if key.startswith("BOARD_") and key != "BOARD_INFO_NAME": |
|
|
|
continue |
|
|
|
# Remove all keys ending by "_NAME" as it does not make a difference to the configuration |
|
|
|
if key[-5:] == "_NAME" and key != "CUSTOM_MACHINE_NAME": |
|
|
|
if key.endswith("_NAME") and key != "CUSTOM_MACHINE_NAME": |
|
|
|
continue |
|
|
|
# Remove all keys ending by "_T_DECLARED" as it's a copy of not important system stuff |
|
|
|
if key[-11:] == "_T_DECLARED": |
|
|
|
# Remove all keys ending by "_T_DECLARED" as it's a copy of extraneous system stuff |
|
|
|
if key.endswith("_T_DECLARED"): |
|
|
|
continue |
|
|
|
# Remove keys that are not in the #define list in the Configuration list |
|
|
|
if not (key in all_defines) and key != "DETAILED_BUILD_VERSION" and key != "STRING_DISTRIBUTION_DATE": |
|
|
|
if key not in all_defines + [ 'DETAILED_BUILD_VERSION', 'STRING_DISTRIBUTION_DATE' ]: |
|
|
|
continue |
|
|
|
|
|
|
|
# Don't be that smart guy here |
|
|
@ -136,13 +136,13 @@ def compute_build_signature(env): |
|
|
|
data = {} |
|
|
|
data['__INITIAL_HASH'] = hashes |
|
|
|
# First create a key for each header here |
|
|
|
for header in real_defines: |
|
|
|
for header in conf_defines: |
|
|
|
data[header] = {} |
|
|
|
|
|
|
|
# Then populate the object where each key is going to (that's a O(N^2) algorithm here...) |
|
|
|
for key in resolved_defines: |
|
|
|
for header in real_defines: |
|
|
|
if key in real_defines[header]: |
|
|
|
for header in conf_defines: |
|
|
|
if key in conf_defines[header]: |
|
|
|
data[header][key] = resolved_defines[key] |
|
|
|
|
|
|
|
# Append the source code version and date |
|
|
@ -155,6 +155,9 @@ def compute_build_signature(env): |
|
|
|
except: |
|
|
|
pass |
|
|
|
|
|
|
|
# |
|
|
|
# Produce a JSON file for CONFIGURATION_EMBEDDING or CONFIG_DUMP > 0 |
|
|
|
# |
|
|
|
with open(marlin_json, 'w') as outfile: |
|
|
|
json.dump(data, outfile, separators=(',', ':')) |
|
|
|
|
|
|
@ -163,10 +166,12 @@ def compute_build_signature(env): |
|
|
|
|
|
|
|
# Generate a C source file for storing this array |
|
|
|
with open('Marlin/src/mczip.h','wb') as result_file: |
|
|
|
result_file.write(b'#ifndef NO_CONFIGURATION_EMBEDDING_WARNING\n') |
|
|
|
result_file.write(b' #warning "Generated file \'mc.zip\' is embedded (Define NO_CONFIGURATION_EMBEDDING_WARNING to suppress this warning.)"\n') |
|
|
|
result_file.write(b'#endif\n') |
|
|
|
result_file.write(b'const unsigned char mc_zip[] PROGMEM = {\n ') |
|
|
|
result_file.write( |
|
|
|
b'#ifndef NO_CONFIGURATION_EMBEDDING_WARNING\n' |
|
|
|
+ b' #warning "Generated file \'mc.zip\' is embedded (Define NO_CONFIGURATION_EMBEDDING_WARNING to suppress this warning.)"\n' |
|
|
|
+ b'#endif\n' |
|
|
|
+ b'const unsigned char mc_zip[] PROGMEM = {\n ' |
|
|
|
) |
|
|
|
count = 0 |
|
|
|
for b in open(os.path.join(build_dir, 'mc.zip'), 'rb').read(): |
|
|
|
result_file.write(b' 0x%02X,' % b) |
|
|
|