187187import glob
188188import os
189189import platform
190+ import traceback
190191import sys
191192import textwrap
192193import time
193194
195+ import locale
196+
194197# Need to work on signature line used for match to avoid conflicts with
195198# existing embedded documentation methods.
196199build_opt_signature = "/*@create-file:build.opt@"
201204err_print_flag = False
202205msg_print_buf = ""
203206debug_enabled = False
207+ default_encoding = None
204208
205209# Issues trying to address through buffered printing
206210# 1. Arduino IDE 2.0 RC5 does not show stderr text in color. Text printed does
@@ -295,16 +299,16 @@ def copy_create_build_file(source_fqfn, build_target_fqfn):
295299 pass
296300 return True # file changed
297301
298-
299302def add_include_line(build_opt_fqfn, include_fqfn):
303+ global default_encoding
300304 if not os.path.exists(include_fqfn):
301305 # If file is missing, we need an place holder
302- with open(include_fqfn, 'w', encoding="utf-8" ):
306+ with open(include_fqfn, 'w', encoding=default_encoding ):
303307 pass
304- print("add_include_line: Created " + include_fqfn)
305- with open(build_opt_fqfn, 'a', encoding="utf-8") as build_opt:
306- build_opt.write('-include "' + include_fqfn.replace('\\', '\\\\') + '"\n')
308+ print_msg("add_include_line: Created " + include_fqfn)
307309
310+ with open(build_opt_fqfn, 'a', encoding=default_encoding) as build_opt:
311+ build_opt.write('-include "' + include_fqfn.replace('\\', '\\\\') + '"\n')
308312
309313def extract_create_build_opt_file(globals_h_fqfn, file_name, build_opt_fqfn):
310314 """
@@ -313,8 +317,9 @@ def extract_create_build_opt_file(globals_h_fqfn, file_name, build_opt_fqfn):
313317 copy of Sketch.ino.globals.h.
314318 """
315319 global build_opt_signature
320+ global default_encoding
316321
317- build_opt = open(build_opt_fqfn, 'w', encoding="utf-8" )
322+ build_opt = open(build_opt_fqfn, 'w', encoding=default_encoding )
318323 if not os.path.exists(globals_h_fqfn) or (0 == os.path.getsize(globals_h_fqfn)):
319324 build_opt.close()
320325 return False
@@ -605,12 +610,63 @@ def parse_args():
605610 # ref nargs='*'', https://stackoverflow.com/a/4480202
606611 # ref no '--n' parameter, https://stackoverflow.com/a/21998252
607612
613+
614+ # retrieve *system* encoding, not the one used by python internally
615+ if sys.version_info >= (3, 11):
616+ def get_encoding():
617+ return locale.getencoding()
618+ else:
619+ def get_encoding():
620+ return locale.getdefaultlocale()[1]
621+
622+
623+ def show_value(desc, value):
624+ print_dbg(f'{desc:<40} {value}')
625+ return
626+
627+ def locale_dbg():
628+ show_value("get_encoding()", get_encoding())
629+ show_value("locale.getdefaultlocale()", locale.getdefaultlocale())
630+ show_value('sys.getfilesystemencoding()', sys.getfilesystemencoding())
631+ show_value("sys.getdefaultencoding()", sys.getdefaultencoding())
632+ show_value("locale.getpreferredencoding(False)", locale.getpreferredencoding(False))
633+ try:
634+ show_value("locale.getpreferredencoding()", locale.getpreferredencoding())
635+ except:
636+ pass
637+ show_value("sys.stdout.encoding", sys.stdout.encoding)
638+
639+ # use current setting
640+ show_value("locale.setlocale(locale.LC_ALL, None)", locale.setlocale(locale.LC_ALL, None))
641+ try:
642+ show_value("locale.getencoding()", locale.getencoding())
643+ except:
644+ pass
645+ show_value("locale.getlocale()", locale.getlocale())
646+
647+ # use user setting
648+ show_value("locale.setlocale(locale.LC_ALL, '')", locale.setlocale(locale.LC_ALL, ''))
649+ # show_value("locale.getencoding()", locale.getencoding())
650+ show_value("locale.getlocale()", locale.getlocale())
651+ return
652+
653+
608654def main():
609655 global build_opt_signature
610656 global docs_url
611657 global debug_enabled
658+ global default_encoding
612659 num_include_lines = 1
613660
661+ # Given that GCC will handle lines from an @file as if they were on
662+ # the command line. I assume that the contents of @file need to be encoded
663+ # to match that of the shell running GCC runs. I am not 100% sure this API
664+ # gives me that, but it appears to work.
665+ #
666+ # However, elsewhere when dealing with source code we continue to use 'utf-8',
667+ # ref. https://gcc.gnu.org/onlinedocs/cpp/Character-sets.html
668+ default_encoding = get_encoding()
669+
614670 args = parse_args()
615671 debug_enabled = args.debug
616672 runtime_ide_path = os.path.normpath(args.runtime_ide_path)
@@ -623,6 +679,13 @@ def main():
623679 build_path_core, build_opt_name = os.path.split(build_opt_fqfn)
624680 globals_h_fqfn = os.path.join(build_path_core, globals_name)
625681
682+ if debug_enabled:
683+ locale_dbg()
684+
685+ default_locale = locale.getdefaultlocale()
686+ print_msg(f'default locale: {default_locale}')
687+ print_msg(f'default_encoding: {default_encoding}')
688+
626689 print_dbg(f"runtime_ide_path: {runtime_ide_path}")
627690 print_dbg(f"runtime_ide_version: {args.runtime_ide_version}")
628691 print_dbg(f"build_path: {build_path}")
@@ -655,6 +718,10 @@ def main():
655718 print_dbg(f"first_time: {first_time}")
656719 print_dbg(f"use_aggressive_caching_workaround: {use_aggressive_caching_workaround}")
657720
721+ if not os.path.exists(build_path_core):
722+ os.makedirs(build_path_core)
723+ print_msg("Clean build, created dir " + build_path_core)
724+
658725 if first_time or \
659726 not use_aggressive_caching_workaround or \
660727 not os.path.exists(commonhfile_fqfn):
@@ -667,10 +734,6 @@ def main():
667734 touch(commonhfile_fqfn)
668735 print_err(f"Neutralized future timestamp on build file: {commonhfile_fqfn}")
669736
670- if not os.path.exists(build_path_core):
671- os.makedirs(build_path_core)
672- print_msg("Clean build, created dir " + build_path_core)
673-
674737 if os.path.exists(source_globals_h_fqfn):
675738 print_msg("Using global include from " + source_globals_h_fqfn)
676739
@@ -750,4 +813,10 @@ def main():
750813 handle_error(0) # commit print buffer
751814
752815if __name__ == '__main__':
753- sys.exit(main())
816+ rc = 1
817+ try:
818+ rc = main()
819+ except:
820+ print_err(traceback.format_exc())
821+ handle_error(0)
822+ sys.exit(rc)
0 commit comments