diff --git a/tools/win32spawn.py b/tools/win32spawn.py index 961e08ddfea..223d060fa73 100644 --- a/tools/win32spawn.py +++ b/tools/win32spawn.py @@ -24,6 +24,7 @@ import os import subprocess +import tempfile class Win32Spawn: def spawn(self, sh, escape, cmd, args, env): @@ -51,7 +52,38 @@ def spawn(self, sh, escape, cmd, args, env): os.environ['PATH'] = _e['PATH'] try: - proc = subprocess.Popen(cmdline, env=_e, shell=False) + # On Windows, CreateProcess has a ~32K command line limit. + # When the link command gets very long (many object files), + # use a GCC @response file to shorten the command line. + if len(cmdline) > 25000 and (cmd.find('gcc') != -1 or cmd.find('g++') != -1): + # Split args: object files go into response file; + # flags stay on command line. Libraries (-l*, -L*) must + # come after object files for proper symbol resolution. + pre_obj_flags = [] + post_obj_flags = [] + obj_args = [] + seen_obj = False + for arg in args[1:]: + stripped = arg.strip('"') + if stripped.endswith('.o') or stripped.endswith('.a'): + obj_args.append(stripped) + seen_obj = True + elif not seen_obj: + pre_obj_flags.append(stripped) + else: + post_obj_flags.append(stripped) + + # Create response file for object files + fd, rsp_path = tempfile.mkstemp(suffix='.rsp', prefix='scons_link_') + with os.fdopen(fd, 'w') as f: + for obj in obj_args: + # GCC @file treats backslash as escape char; + # use forward slashes for Windows paths + f.write(obj.replace('\\', '/') + '\n') + rsp_args = [cmd] + pre_obj_flags + ['@' + rsp_path] + post_obj_flags + proc = subprocess.Popen(rsp_args, env=_e, shell=False) + else: + proc = subprocess.Popen(cmdline, env=_e, shell=False) except Exception as e: print('Error in calling command:' + cmdline.split(' ')[0]) print('Exception: ' + os.strerror(e.errno)) @@ -62,4 +94,13 @@ def spawn(self, sh, escape, cmd, args, env): finally: os.environ['PATH'] = old_path - return proc.wait() + ret = proc.wait() + + # Clean up response file if used + if len(cmdline) > 25000 and (cmd.find('gcc') != -1 or cmd.find('g++') != -1): + try: + os.unlink(rsp_path) + except: + pass + + return ret