Skip to content

Commit 8a96eeb

Browse files
committed
Correct Windows path for preferences.txt
Added portable path for preferences.txt Expanded file timestamp granularity Improved error message printing for Arduino IDE 2.0 RC4
1 parent dc3d37c commit 8a96eeb

File tree

1 file changed

+72
-42
lines changed

1 file changed

+72
-42
lines changed

tools/mkbuildoptglobals.py

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@
173173
in ~/.arduino15/preferences.txt, to disable the aggressive caching feature:
174174
https://forum.arduino.cc/t/no-aggressively-cache-compiled-core-in-ide-1-8-15/878954/2
175175
176+
Added workaround for `compiler.cache_core=true` case.
177+
See `if use_aggressive_caching_workaround:` in main().
178+
176179
7) Suspected but not confirmed. A quick edit and rebuild don't always work well.
177180
Build does not work as expected. This does not fail often. Maybe PIC NIC.
178181
"""
@@ -191,11 +194,19 @@
191194
docs_url = "https://arduino-esp8266.readthedocs.io/en/latest/faq/a06-global-build-options.html"
192195

193196
def print_msg(*args, **kwargs):
194-
print(*args, flush=True, **kwargs)
197+
print(*args, **kwargs)
195198

196199

200+
# I prefer error messages to stand out; however, using stderr for a different
201+
# color does not work on the new Arduino IDE 2.0 RC4. Also, separate pipes,
202+
# buffering, and multiple threads with output can create mixed-up messages.
203+
# Bring attention to errors with a blank line and lines starting with "*** ".
204+
# Let multiple prints buffer to aid them in staying together.
197205
def print_err(*args, **kwargs):
198-
print(*args, flush=True, file=sys.stderr, **kwargs) # file=sys.stderr,
206+
if (args[0])[0] != ' ':
207+
print("")
208+
print("*** ", end='')
209+
print(*args, **kwargs)
199210

200211

201212
def copy_create_build_file(source_fqfn, build_target_fqfn):
@@ -221,18 +232,19 @@ def copy_create_build_file(source_fqfn, build_target_fqfn):
221232
else:
222233
# Place holder - Must have an empty file to satisfy parameter list
223234
# specifications in platform.txt.
224-
open(build_target_fqfn, 'w').close()
235+
with open(build_target_fqfn, 'w'):
236+
pass
225237
return True # file changed
226238

227239

228240
def add_include_line(build_opt_fqfn, include_fqfn):
229241
if not os.path.exists(include_fqfn):
230242
# If file is missing, we need an place holder
231-
open(include_fqfn, 'w').close()
243+
with open(include_fqfn, 'w'):
244+
pass
232245
print("add_include_line: Created " + include_fqfn)
233-
build_opt = open(build_opt_fqfn, 'a')
234-
build_opt.write('-include "' + include_fqfn.replace('\\', '\\\\') + '"\n')
235-
build_opt.close()
246+
with open(build_opt_fqfn, 'a') as build_opt:
247+
build_opt.write('-include "' + include_fqfn.replace('\\', '\\\\') + '"\n')
236248

237249

238250
def extract_create_build_opt_file(globals_h_fqfn, file_name, build_opt_fqfn):
@@ -261,7 +273,7 @@ def extract_create_build_opt_file(globals_h_fqfn, file_name, build_opt_fqfn):
261273
if line == build_opt_signature:
262274
if complete_comment:
263275
build_opt_error = True
264-
print_err("Multiple embedded build.opt blocks in " + file_name + ":" + str(line_no))
276+
print_err(" Multiple embedded build.opt blocks in " + file_name + ":" + str(line_no))
265277
continue
266278
print_msg("Extracting embedded compiler command-line options from " + file_name + ":" + str(line_no))
267279
for line in src:
@@ -280,27 +292,26 @@ def extract_create_build_opt_file(globals_h_fqfn, file_name, build_opt_fqfn):
280292
continue
281293
# some consistency checking before writing - give some hints about what is wrong
282294
elif line == build_opt_signature:
283-
print_err("Double begin before end for embedded build.opt block in " + file_name + ":" + str(line_no))
295+
print_err(" Double begin before end for embedded build.opt block in " + file_name + ":" + str(line_no))
284296
build_opt_error = True
285297
elif line.startswith(build_opt_signature):
286-
print_err("build.opt signature block ignored, trailing character for embedded build.opt block in " + file_name + ":" + str(line_no))
298+
print_err(" build.opt signature block ignored, trailing character for embedded build.opt block in " + file_name + ":" + str(line_no))
287299
build_opt_error = True
288300
elif "/*" in line or "*/" in line :
289-
print_err("Nesting issue for embedded build.opt block in " + file_name + ":" + str(line_no))
301+
print_err(" Nesting issue for embedded build.opt block in " + file_name + ":" + str(line_no))
290302
build_opt_error = True
291303
else:
292304
build_opt.write(line + "\n")
293305
elif line.startswith(build_opt_signature):
294-
print_err("build.opt signature block ignored, trailing character for embedded build.opt block in " + file_name + ":" + str(line_no))
306+
print_err(" build.opt signature block ignored, trailing character for embedded build.opt block in " + file_name + ":" + str(line_no))
295307
build_opt_error = True
296-
src.close()
297308
if not complete_comment or build_opt_error:
298309
build_opt.truncate(0)
299310
build_opt.close()
300311
if build_opt_error:
301312
# this will help the script start over when the issue is fixed
302313
os.remove(globals_h_fqfn)
303-
print_err("Extraction failed")
314+
print_err(" Extraction failed")
304315
# Don't let the failure get hidden by a spew of nonsensical error
305316
# messages that will follow. Bring things to a halt.
306317
sys.exit(1)
@@ -312,54 +323,66 @@ def extract_create_build_opt_file(globals_h_fqfn, file_name, build_opt_fqfn):
312323

313324

314325
def enable_override(enable, commonhfile_fqfn):
315-
file=open(commonhfile_fqfn, 'w')
316-
if enable:
317-
file.write("//Override aggressive caching\n")
318-
file.close()
326+
with open(commonhfile_fqfn, 'w') as file:
327+
if enable:
328+
file.write("//Override aggressive caching\n")
319329
# enabled when getsize(commonhfile_fqfn) is non-zero, disabled when zero
320330

331+
321332
def find_preferences_txt():
322333
platform_name = platform.system()
323334
# OS Path list from:
324335
# https://www.arduino.cc/en/hacking/preferences
325-
if "Windows" == platform_name:
326-
fqfn = os.path.expanduser("\Arduino15\preferences.txt") # Windows
336+
if "Linux" == platform_name:
337+
# Test for portable 1ST
338+
# <Arduino IDE installation folder>/portable/preferences.txt (when used in portable mode)
339+
# For more on portable mode see https://docs.arduino.cc/software/ide-v1/tutorials/PortableIDE
340+
# Working directory must be set to the location of the Arduino IDE executable.
341+
fqfn = "./portable/preferences.txt" # Linux portable - verified
327342
if os.path.exists(fqfn):
328343
return fqfn
329-
fqfn = os.path.expanduser("\Documents\ArduinoData\preferences.txt") # Windows app version
344+
fqfn = os.path.expanduser("~/.arduino15/preferences.txt") # Linux - verified
330345
if os.path.exists(fqfn):
331346
return fqfn
332-
elif "Darwin" == platform_name:
333-
fqfn = os.path.expanduser("~/Library/Arduino15/preferences.txt") # Max OS X
347+
elif "Windows" == platform_name:
348+
fqfn = ".\portable\preferences.txt"
349+
if os.path.exists(fqfn):
350+
return fqfn
351+
fqfn = os.path.expanduser("~\Documents\ArduinoData\preferences.txt") # Windows app version - verified
334352
if os.path.exists(fqfn):
335353
return fqfn
336-
elif "Linux" == platform_name:
337-
fqfn = os.path.expanduser("~/.arduino15/preferences.txt") # Linux - works
354+
fqfn = os.path.expanduser("~\Arduino15\preferences.txt") # Windows
338355
if os.path.exists(fqfn):
339356
return fqfn
340-
# Where and how would I find this?
341-
# <Arduino IDE installation folder>/portable/preferences.txt (when used in portable mode)
357+
elif "Darwin" == platform_name:
358+
# Skip portable on Macs. Portable is not compatable with Macs
359+
# see https://docs.arduino.cc/software/ide-v1/tutorials/PortableIDE
360+
fqfn = os.path.expanduser("~/Library/Arduino15/preferences.txt") # Max OS X
361+
if os.path.exists(fqfn):
362+
return fqfn
363+
364+
print_err("File preferences.txt not found on " + platform_name)
342365
return ""
343366

344367

345368
def get_preferences_txt(file_fqfn, key):
346-
with open(file_fqfn) as fd:
347-
for line in fd:
369+
with open(file_fqfn) as file:
370+
for line in file:
348371
name, value = line.partition("=")[::2]
349372
if name.strip().lower() == key:
350373
if value.strip().lower() == 'true':
351-
print_msg("found compiler.cache_core " + value.strip()) #D debug
352374
return True
353375
else:
354376
return False
377+
print_err("Key " + key + " not found in preferences.txt. Default to true.")
355378
return True # If we don't find it just assume it is set True
356379

357380

358381
def check_preferences_txt():
359382
file_fqfn = find_preferences_txt()
360383
if file_fqfn == "":
361384
return True # cannot find file assume enabled
362-
print_msg("\nfound preferences " + file_fqfn) #D debug
385+
print_msg("Using preferences from " + file_fqfn)
363386
return get_preferences_txt(file_fqfn, "compiler.cache_core")
364387

365388

@@ -368,25 +391,27 @@ def touch(fname, times=None):
368391
os.utime(fname, times)
369392

370393

371-
def time_sync(globals_h_fqfn, commonhfile_fqfn):
372-
ts = time.time()
373-
touch(globals_h_fqfn, (ts, ts))
374-
touch(commonhfile_fqfn, (ts, ts))
394+
def synchronous_touch(globals_h_fqfn, commonhfile_fqfn):
395+
with open(globals_h_fqfn, 'a'):
396+
os.utime(globals_h_fqfn)
397+
ts = os.stat(globals_h_fqfn)
398+
with open(commonhfile_fqfn, 'a'):
399+
os.utime(commonhfile_fqfn, ns=(ts.st_atime_ns, ts.st_mtime_ns))
375400

376401

377402
def main():
378403
global build_opt_signature
379404
global docs_url
380405
num_include_lines = 1
381-
use_aggressive_caching_workaround = check_preferences_txt() #? preliminary
406+
use_aggressive_caching_workaround = check_preferences_txt()
382407

383408
if len(sys.argv) >= 5:
384409
source_globals_h_fqfn = os.path.normpath(sys.argv[1])
385410
globals_name = os.path.basename(source_globals_h_fqfn)
386411
globals_h_fqfn = os.path.normpath(sys.argv[2])
387412
build_path = os.path.dirname(globals_h_fqfn)
388-
build_opt_fqfn = os.path.normpath(sys.argv[3])
389413
# Assumption: globals_h_fqfn and build_opt_fqfn have the same dirname
414+
build_opt_fqfn = os.path.normpath(sys.argv[3])
390415
commonhfile_fqfn = os.path.normpath(sys.argv[4])
391416

392417
if os.path.exists(commonhfile_fqfn):
@@ -425,21 +450,26 @@ def main():
425450
copy_create_build_file(source_globals_h_fqfn, globals_h_fqfn)
426451

427452
# globals_h_fqfn timestamp was only updated if the source changed. This
428-
# controls the rebuild on change. We can always extact a new build.opt
453+
# controls the rebuild on change. We can always extract a new build.opt
429454
# w/o triggering a needless rebuild.
430455
embedded_options = extract_create_build_opt_file(globals_h_fqfn, globals_name, build_opt_fqfn)
431456

432457
if use_aggressive_caching_workaround:
458+
# When a Sketch owns a "Sketch.ino.globals.h" file in the build tree
459+
# that exactly matches the timestamp of "CommonHFile.h" in the
460+
# platform source tree, it owns the core cache. If not, or
461+
# "Sketch.ino.globals.h" has changed, rebuild core.
433462
if os.path.getsize(commonhfile_fqfn):
434-
print("os.path.getmtime(globals_h_fqfn) " + str(os.path.getmtime(globals_h_fqfn)))
435-
print("os.path.getmtime(commonhfile_fqfn) " + str(os.path.getmtime(commonhfile_fqfn)))
436463
if (os.path.getmtime(globals_h_fqfn) != os.path.getmtime(commonhfile_fqfn)):
437464
# Need to rebuild core.a
438465
# touching commonhfile_fqfn in the source core tree will cause rebuild.
439-
time_sync(globals_h_fqfn, commonhfile_fqfn)
466+
# Looks like touching or writing unrelated files in the source core tree will cause rebuild.
467+
synchronous_touch(globals_h_fqfn, commonhfile_fqfn)
468+
print_msg("Using 'aggressive caching' workaround.")
440469
elif os.path.getsize(globals_h_fqfn):
441470
enable_override(True, commonhfile_fqfn)
442-
time_sync(globals_h_fqfn, commonhfile_fqfn)
471+
synchronous_touch(globals_h_fqfn, commonhfile_fqfn)
472+
print_msg("Using 'aggressive caching' workaround.")
443473

444474
add_include_line(build_opt_fqfn, commonhfile_fqfn)
445475
add_include_line(build_opt_fqfn, globals_h_fqfn)

0 commit comments

Comments
 (0)