[Distutils] How to handle launcher script importability?

Steve Dower Steve.Dower at microsoft.com
Mon Aug 12 21:03:00 CEST 2013

Jason R. Coombs wrote:
> My preference is to reject the idea of the side-by-side executable launcher. 
> There are several downsides that I'm trying to avoid by moving away from the 
> executable:
> [SNIP]
> 2. Executables that look like installers. If a launcher executable is used and 
> Windows detects that it "looks like" an installer and it's a 32-bit executable 
> and it doesn't have a manifest to disable the functionality, Windows will 
> execute the file in a separate UAC context (often in a separate Window).

The problematic part of detection is the filename. The "Installer Detection" section of http://msdn.microsoft.com/en-us/library/bb530410.aspx has more details, but isn't 100% precise. I'm sure there's a precise description somewhere, but I don't know where it is.

> 3. Additional files are needed. In particular, due to (2), a manifest must be 
> provided for 32-bit executables.
> 4. Word size accounting. It's not clear to me what word size is needed. 32-bit 
> may be sufficient, though 64-bit seem to have some advantages: a manifest is 
> not needed, and it can match the word size of the installed Python executable 
> (for consistency). Setuptools currently provides both (and installs the one 
> that matches the Python executable).

32-bit is sufficient, and the manifest can be embedded. Since all the executable is doing is looking for a matching/similarly-named file in its directory and launching it, there's no need for a 64-bit version, or for any differences to exist between the executables. They could all be copied from the same source whenever one is needed.

(A 64-bit binary is only required when loading 64-bit DLLs. It is not required to launch a 64-bit process.)

> [SNIP]

> 6. Two to three files to do the job of one. In fact, the "job" isn't much more 
> than to invoke code elsewhere, so it seems ugly to require as many as three 
> files to do the job. Then multiply that by the Python-specific version and you 
> have up to six files for a single script.

While I can understand this from the POV of the implementer/maintainer, I've never heard a single Windows user mention it. And with an embedded manifest, it's no more than one .py and one .exe-per-Python-version.

> [SNIP]
> 8. Unwanted content. Some Unix users have complained about finding Windows 
> executables in their Linux packages, so now Setuptools has special handling to 
> omit the launchers when installed on Unix systems. This is far from beautiful.

Do us Windows users get .sh and .DSStore files filtered out too? :) (More seriously, why isn't the onus on package developers to specify platform-specific files?)

>> Hm, here's a side thought: what if PyLauncher added the ability to serve as 
>> a script wrapper, just like setuptools' existing wrappers?
>> Then setuptools could just copy py.exe or pyw.exe alongside a .pyl or .pyw,
>> and presto!  No PATHEXT compatibility needed, but users could still opt out
>> of using the .exe wrappers if they're sure their shell works right without 
>> it.
>> (The wrapper facility would be implemented by simply checking for an
>> adjacent file of matching filename and extension (.pyl for py.exe, .pyw for
>> pyw.exe), and if found, insert that filename as argv[1] before proceeding
>> with the normal launch process.  For efficiency, the file check could be
>> skipped if the executable has its original name, at the minor cost of it not
>> being possible to name a console script 'py' or a windows app 'pyw'.  But
>> that's an optional tweak.)
> I'm warming up to this idea a bit, especially how it supports the most elegant 
> approach but degrades gracefully. 

py.exe is a great file to use as a launcher, but it would also be easy to make a more specific one.

> Some questions that arise:
> Where would Setuptools expect to find these launchers? Would it expect them to 
> be present on the system?

I don't think that's unreasonable. Perhaps they should always install into Python's path (C:\Python##\py.exe) so they are discoverable? Not everybody can install into C:\Windows\System32 (or SysWOW64)

> Would it symlink or hardlink them or simply copy?

Copying is most reliable and the only way to handle installation onto different drive partitions. Some people will worry about the size, but I don't know that much can be done about that. A smaller executable could be made with no icons and relying on the OS to find "py.exe" wherever it's been installed.

You can hardlink the version-specific executables safely.

> Is py.exe subject to the 'looks like installer' behavior, such that it would need 
> a manifest?

The one that's in Python 3.4 Alpha already has an embedded manifest, but I don't believe it would trigger the installer heuristics anyway.

> I still feel like this approach would require substantial special-casing, but 
> since it provides a transition to the simple, elegant approach, I'm not 
> opposed.

Shouldn't require that much special casing, except that you probably wouldn't be able to use it with an adjacent "py.py" file (that is, you'd special case "py.exe" to have the default behaviour). Expecting the adjacent file to be "name-script.py" or "name.pyl" for "name.exe" seems reasonable to me, and neither of those modules will be importable.


More information about the Distutils-SIG mailing list