Developing on windows

This is a sketch of the steps that I (MB) went through setting up a semi-standard development environment for python packaging on windows.

My system(s)

I’ve got several Windows 7 instances running mainly as buildbot machines, a Windows 8 machine kindly donated by Chris Holdgraf of the UC Berkeley Knight lab, and some virtual machines, also running Windows 7. I used to have some XP machines, but UC Berkeley doesn’t allow them on the network any more.

Basic setup

  • Shell: in the old days, we had to use the awful Windows cmd shell. It’s still useful sometimes, but the newer powershell is vastly better. It comes installed with Windows 7 and later. If you are using Vista or XP (really?), you will have to install it (see links from powershell page). Compared to cmd, Powershell has better command and filename completion, ls for directory listing, a less idiosyncratic cd, and a less painful scripting language. I believe I’ve used version 1 and version 2. $Host.version at the powershell prompt gave me 1 0 0 0 on my old XP installation. Don’t forget to enable quickedit mode for much nicer right-click copy and paste.
  • Install msysgit. In the installation, set git to be on the command path, but not the git bash utilities. I set the repo to have LF endings, but the checked out files to have system endings. You’ll see this setting offered in the installation GUI - it sets core.autocrlf=input in your global git config.

SSH setup

msysgit has ssh, but for various reasons I wanted to be able to use powershell with git. In order to do this I need to get git SSH authentication working via the windows tools:

  • Install putty. Well, in fact, install all the putty utilities via the windows installer - including plink and pageant. These are utilities we need for handling ssh authentication for git and other tools.

  • You might consider putting the Putty directory on the path. Something like:

    $my_path = [Environment]::GetEnvironmentVariable("PATH","User")
    $my_path += ";C:\Program files (x86)\Putty" # (x86) on my windows 7 system
    [Environment]::SetEnvironmentVariable("PATH", $my_path, "User")
  • I have ssh keys I use on unix and mac. I got the necessary ssh keys via sftp (installed by Putty installer). These went into $HOME/.ssh. I then ran PUTTYgen (installed by the Putty installer) to import the Unix ssh key into putty .ppk format. Save .ppk in $HOME/.ssh.

  • Start pageant (installed by putty installer). Add .ppk key file.

  • If you’ve got the putty utilities on the path, check you can get authenticated e.g. into github with plink If you don’t have putty etc on the path, you’ll need the full path to plink, as in: "c:\Program files (x86)\Putty\plink".

  • Set a couple of environment variables from powershell - see powershell environment variables. First set $GIT_SSH to pick up plink as the ssh executable:

    [Environment]::SetEnvironmentVariable("GIT_SSH", "C:\Program files\Putty\plink.exe", "User")

    Next we make sure that $HOME is set for safety. For example, setuptools appears to need it set correctly - see the example pypi page for the assertion at least:

    [Environment]::SetEnvironmentVariable("HOME", $env:USERPROFILE, "User")

    Restart powershell after doing this to pick up the GIT_SSH environment variable in particular. We should now be able to do something like git clone without being asked our password (pageant handles this). The first time you use this combination with a particular host you may get an error like this:

    The server's host key is not cached in the registry. You
    have no guarantee that the server is the computer you
    think it is.

    If so, run plink manually to cache the key:

    & 'C:\Program Files (x86)\PuTTY\plink.exe'

    and press y when asked.

  • I run pageant at startup. I first set up a desktop shortcut with the following command:

    "C:\Program Files (x86)\PuTTY\pageant.exe" c:\Users\mb312\.ssh\id_dsa.ppk

    I move this shortcut into my startup folder to start at login. On windows 7 my startup folder is:

    C:\Users\mb312\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

    where mb312 is my username.

  • For using ssh inside the msysgit bash shell, I like to add the keychain-like script, by including this in my ~/.bashrc file:

    # Source personal definitions
    if [ -f "$HOME/.bash_keychain_lite" ]; then
        . "$HOME/.bash_keychain_lite"

    where the .bash_keychain_lite file arises from the dotfiles command above.


  • I got used to the mac keyboard way of using the command key for things like making new tabs in the browser (command-t), copy, paste (command-c, command-v) and so on. I can’t replicate all of this on windows, but as a first pass, I use an autohotkey script. Putting this remap.ahk script file into my Windows start menu startup folder caused it to be loaded at login:

    ; From:
    ; See also :
    ; # usually means Windows key.
    #SingleInstance force ; but sometimes # introduces a command
    #r::Send ^r ;reload
    #z::Send ^z ; undo
    #y::Send ^y ; redo
    #f::Send ^f ; find inside apps
    #g::Send ^g ; repeat find inside apps
    #c::Send ^c ; copy
    #x::Send ^x ; cut
    #v::Send ^v ; paste
    #a::Send ^a ; select all
    #t::Send ^t ; new tab in browser (IE, Safari, Firefox, etc)
    #s::Send ^s ; save inside apps
    LWin & Tab::AltTab ; the motherlode, alt-tab!
    #Up::Send {PgUp} ; PgUp
    #Down::Send {PgDn} ; PgDown
    #Left::Send {home} ; Home
    #Right::Send {end} ; End
  • I depend heavily on knowing which branch I am on when using git. This is the what the git-completion bash routines do; posh-git does the equivalent for powershell.

Other programs

  • Install editor. I use vim. With a 64 bit python (below), I needed a 64 bit vim

  • Install python - the current version. I need this for the scripts installing the personal configuration below. For the convenience of using python at the command line you could do something like:

    $my_path = [Environment]::GetEnvironmentVariable("PATH","User")
    $my_path += ";C:\Python27;C:\Python27\Scripts"
    [Environment]::SetEnvironmentVariable("PATH", $my_path, "User")
  • Set up personal configuration. For me this is:

    cd c:\
    mkdir code
    cd code
    mkdir dev_trees
    cd dev_trees
    git clone
    git clone
    cd myconfig
    python dotfiles
    cd ..\myvim
    python vimfiles
  • I am trying out virtualenvwrapper-powershell . Install with the standard python install. You then need import-module virtualenvwrapper from the powershell prompt. Maybe it goes better in a powershell profile.

  • As for any other environment, the nose-ipdb ipython debugger for nose makes debugging easier for nose tests. Easiest route is easy_install ipdbplugin.

Windows compiler and build tools

  • Download and install the mingw windows compiler. I used the mingw-get-inst automated installation route. Select the options giving you c++, fortran, and the msys build environment. I didn’t directly add these to the path, but made a script c:\Mingw\mingwvars.ps1:

    # convenience script to add mingw to path
    echo "Adding mingw to PATH..."
    $mingw = [System.IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Definition)
    $env:path = "$mingw\bin;$mingw\msys\1.0\bin;$env:path"

    Then in powershell - . c:\Mingw\mingwvars.ps1 to add the msys and mingw tools to the path.

  • Using mingw, you might get this kind of error:

    error: Setup script exited with error: Unable to find vcvarsall.bat

    Of course you’ve already tried the standard solution to this, of the form:

    python build --compiler=mingw32

    If that doesn’t work, you might have hit a mingw distutils bug. One suggested fix is to make a distutils.cfg file in your Python distutils directory (e.g. C:\Python26\Lib\distutils) with the following content:



Download the swig version for windows, swigwin, from swig downloads, unpack into, say, C:\, then:

$my_path = [Environment]::GetEnvironmentVariable("PATH","User")
$my_path += ";C:\swigwin-2.0.10"
[Environment]::SetEnvironmentVariable("PATH", $my_path, "User")
[Environment]::SetEnvironmentVariable("PYTHON_INCLUDE", "C:\Python27\include", "User")
[Environment]::SetEnvironmentVariable("PYTHON_LIB", "C:\Python27\libs\python27.lib", "User")