Search code examples
pythonlinuxwindowsmacosplatform

Cross-Platform Installer paths


I'm writing an installer for a Python app I'm making, and needed to have paths for different file locations. These are what I have so far, and so wondered if these were correct of if I should change any of them (particularly the Linux/macOS ones)

I have a path for:

  • the actual binary
  • for the config file
  • the README
  • the start menu, should the user want to add a shortcut (this will create the .desktop file on Linux/macOS, a shortcut on Windows)
  • the desktop, should the user want to add a shortcut

Can anyone let me know if there should be changes to these to make them work on all devices etc

Windows

binary = '%ProgramFiles%'
configs = '%AppData%'
README = '%ProgramFiles%'
start menu = '%AppData%\Microsoft\Windows\Start Menu'
desktop = os.path.expanduser('~\Desktop')

Linux

binary = '/usr/local/bin'
config = os.path.expanduser('~/.config')
README = '/usr/local/share/doc/packages'
start menu = os.path.expanduser('~/.local/share/applications')
desktop = os.path.expanduser('~/Desktop')

macOS

binary = '/usr/local/bin'
config = os.path.expanduser('~/.config')
README = '/usr/local/share/doc/packages'
start menu = os.path.expanduser('~/.local/share/applications')
desktop = os.path.expanduser('~/Desktop')

Thanks in advance

EDIT: I have added the option for the user to change the paths anyway so it doesn't have to be perfect but I would like the best 'normal' paths


Solution

  • My recommendation is to use sysconfig as much as possible. For example on a POSIX system get_paths() returns:

    In [5]: sysconfig.get_paths()
    Out[5]: 
    {'stdlib': '/usr/local/lib/python3.9',
     'platstdlib': '/usr/local/lib/python3.9',
     'purelib': '/usr/local/lib/python3.9/site-packages',
     'platlib': '/usr/local/lib/python3.9/site-packages',
     'include': '/usr/local/include/python3.9',
     'platinclude': '/usr/local/include/python3.9',
     'scripts': '/usr/local/bin',
     'data': '/usr/local'}
    

    Note that sysconfig supports different schemes:

    In [6]: sysconfig.get_scheme_names()
    Out[6]: 
    ('nt',
     'nt_user',
     'osx_framework_user',
     'posix_home',
     'posix_prefix',
     'posix_user')
    

    The home or user schemes are handy when the installer doesn't have root or administrator privileges.