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):
295299pass
296300return True # file changed
297301
298-
299302def add_include_line (build_opt_fqfn ,include_fqfn ):
303+ global default_encoding
300304if 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 ):
303307pass
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 """
315319global 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 )
318323if not os .path .exists (globals_h_fqfn )or (0 == os .path .getsize (globals_h_fqfn )):
319324build_opt .close ()
320325return 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 ():
609655global build_opt_signature
610656global docs_url
611657global debug_enabled
658+ global default_encoding
612659num_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+
614670args = parse_args ()
615671debug_enabled = args .debug
616672runtime_ide_path = os .path .normpath (args .runtime_ide_path )
@@ -623,6 +679,13 @@ def main():
623679build_path_core ,build_opt_name = os .path .split (build_opt_fqfn )
624680globals_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+
626689print_dbg (f"runtime_ide_path:{ runtime_ide_path } " )
627690print_dbg (f"runtime_ide_version:{ args .runtime_ide_version } " )
628691print_dbg (f"build_path:{ build_path } " )
@@ -655,6 +718,10 @@ def main():
655718print_dbg (f"first_time:{ first_time } " )
656719print_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+
658725if first_time or \
659726not use_aggressive_caching_workaround or \
660727not os .path .exists (commonhfile_fqfn ):
@@ -667,10 +734,6 @@ def main():
667734touch (commonhfile_fqfn )
668735print_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-
674737if os .path .exists (source_globals_h_fqfn ):
675738print_msg ("Using global include from " + source_globals_h_fqfn )
676739
@@ -750,4 +813,10 @@ def main():
750813handle_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 )