@@ -64,11 +64,10 @@ def create(self, env_dir):
6464 self .system_site_packages = False
6565 self .create_configuration (context )
6666 self .setup_python (context )
67- if not self .upgrade :
68- self .setup_scripts (context )
6967 if self .with_pip :
7068 self ._setup_pip (context )
7169 if not self .upgrade :
70+ self .setup_scripts (context )
7271 self .post_setup (context )
7372 if true_system_site_packages :
7473 # We had set it to False before, now
@@ -176,6 +175,23 @@ def symlink_or_copy(self, src, dst, relative_symlinks_ok=False):
176175 logger .warning ('Unable to symlink %r to %r' , src , dst )
177176 force_copy = True
178177 if force_copy :
178+ if os .name == 'nt' :
179+ # On Windows, we rewrite symlinks to our base python.exe into
180+ # copies of venvlauncher.exe
181+ basename , ext = os .path .splitext (os .path .basename (src ))
182+ if basename .endswith ('_d' ):
183+ ext = '_d' + ext
184+ basename = basename [:- 2 ]
185+ if sysconfig .is_python_build (True ):
186+ if basename == 'python' :
187+ basename = 'venvlauncher'
188+ elif basename == 'pythonw' :
189+ basename = 'venvwlauncher'
190+ scripts = os .path .dirname (src )
191+ else :
192+ scripts = os .path .join (os .path .dirname (__file__ ), "scripts" , "nt" )
193+ src = os .path .join (scripts , basename + ext )
194+
179195 shutil .copyfile (src , dst )
180196
181197 def setup_python (self , context ):
@@ -202,23 +218,31 @@ def setup_python(self, context):
202218 if not os .path .islink (path ):
203219 os .chmod (path , 0o755 )
204220 else :
205- # For normal cases, the venvlauncher will be copied from
206- # our scripts folder. For builds, we need to copy it
207- # manually.
208- if sysconfig .is_python_build (True ):
209- suffix = '.exe'
210- if context .python_exe .lower ().endswith ('_d.exe' ):
211- suffix = '_d.exe'
212-
213- src = os .path .join (dirname , "venvlauncher" + suffix )
214- dst = os .path .join (binpath , context .python_exe )
215- copier (src , dst )
221+ if self .symlinks :
222+ # For symlinking, we need a complete copy of the root directory
223+ # If symlinks fail, you'll get unnecessary copies of files, but
224+ # we assume that if you've opted into symlinks on Windows then
225+ # you know what you're doing.
226+ suffixes = [
227+ f for f in os .listdir (dirname ) if
228+ os .path .normcase (os .path .splitext (f )[1 ]) in ('.exe' , '.dll' )
229+ ]
230+ if sysconfig .is_python_build (True ):
231+ suffixes = [
232+ f for f in suffixes if
233+ os .path .normcase (f ).startswith (('python' , 'vcruntime' ))
234+ ]
235+ else :
236+ suffixes = ['python.exe' , 'python_d.exe' , 'pythonw.exe' ,
237+ 'pythonw_d.exe' ]
216238
217- src = os .path .join (dirname , "venvwlauncher" + suffix )
218- dst = os .path .join (binpath , "pythonw" + suffix )
219- copier (src , dst )
239+ for suffix in suffixes :
240+ src = os .path .join (dirname , suffix )
241+ if os .path .exists (src ):
242+ copier (src , os .path .join (binpath , suffix ))
220243
221- # copy init.tcl over
244+ if sysconfig .is_python_build (True ):
245+ # copy init.tcl
222246 for root , dirs , files in os .walk (context .python_dir ):
223247 if 'init.tcl' in files :
224248 tcldir = os .path .basename (root )
@@ -304,6 +328,9 @@ def install_scripts(self, context, path):
304328 dirs .remove (d )
305329 continue # ignore files in top level
306330 for f in files :
331+ if (os .name == 'nt' and f .startswith ('python' )
332+ and f .endswith (('.exe' , '.pdb' ))):
333+ continue
307334 srcfile = os .path .join (root , f )
308335 suffix = root [plen :].split (os .sep )[2 :]
309336 if not suffix :
0 commit comments