Monday, May 16, 2016

Bash on Ubuntu on Windows 10 is fast, but Cygwin integrates better with Windows

Up to now, I used Cygwin. Having it was very important, because it allowed me to do some things which would otherwise require booting into Linux or running a Linux VM. Cygwin is quite good in terms of capability. Problems are rare, there are many packages available, and it's often not too hard to compile other Linux software in Cygwin. Its main disadvantage is that some things are a lot slower. Running ./configure shows the biggest slowdown compared to Linux, but even building via make is much slower. I think the main issue is that process creation is slower due to the more heavyweight nature of Windows process plus the tricks Cygwin does to simulate Unix processes. It can be tolerable though, and I used Cygwin for a lot of Rockbox development.

There were faster alternatives available, like MinGW, Unix tools directly compiled for Windows and Microsoft's Subsystem for UNIX-based applications (SUA). However, there were more compatibility issues with those, so although program performance is better, I would spend more more time dealing with compatibility issues.

Bash on Ubuntu on Windows excited me, and motivated me to give Windows 10 another chance. It would allow even better compatibility with Linux applications without requiring a VM, and could offer better performance. After upgrading to the Fast Ring Insider Preview, it was easy to install. It works impressively well, and is very fast. Various things are still unimplemented, but most aren't very important. The most important missing feature is lack of fully working pseudoterminal support, which prevents X terminal apps from working.

Unfortunately, Bash integrates poorly with Windows, and you almost might as well be running a Linux VM. Ubuntu files are in directories under %LOCALAPPDATA%\lxss , with the root directory hidden at %LOCALAPPDATA%\lxss\rootfs and your home folder under %LOCALAPPDATA%\lxss\home . However, if you try to use ordinary Windows apps to access files there, you run into problems. Ubuntu programs don't see what you put there, and files which are newly modified in Ubuntu are inaccessible until you leave Bash. If you want to share files, you need to use one of the Windows drives, via /mnt/c or similar. Unix permissions don't work there. Using that is similar to how a VM can mount folders from the host.

When I was using Cygwin, I would use native Windows editors, and launch them from the Cygwin command line. Whenever I wanted a GUI view of a folder, I would launch Explorer. The difference between Windows and Cygwin paths is a bit of a problem, but I set up aliases to help:

function detach {
    ( nohup "$@" < /dev/null > /dev/null 2>&1 & disown )
}
function detach_c2w()
{
detach "$1" "$(cygpath -aw "$2")"
}
startfunc()
{
/cygdrive/c/Windows/system32/cmd.exe /c start \"Title\" "$(cygpath -aw "$1")"
}
alias edit="detach_c2w /cygdrive/c/Program\ Files/Geany/bin/geany.exe"
alias fc=/cygdrive/c/Windows/system32/fc.exe
alias open=startfunc

explorerfunc()
{
if [ -d "$1" ]; then
  /cygdrive/c/Windows/explorer.exe "$(cygpath -aw "$1")"
else
  /cygdrive/c/Windows/explorer.exe "/select,$(cygpath -aw "$1")"
fi 
}
alias explorer=explorerfunc


All of that is impossible in Bash on Ubuntu on Windows, although it shouldn't be too hard to make a way to launch Windows executables from Bash. It's also impossible to compile things like Python extensions which use Windows features, and I don't see how that could be made possible. To do it you would need another separate Windows or Cygwin installation of Python. One thing you can do already is cross-compile for Windows, because you can cross-compile from Linux.

I'm sure Bash on Ubuntu on Windows is going to improve. This is just a preview release. However, I'm wondering about the extent to which its design will prevent it from integrating smoothly with Windows.

2 comments:

Lester Ingber said...

Using Cygwin, I find it useful to create some small scripts that include cygpath to help with paths both under Cygwin and under Windows:

#!/bin/tcsh -f
set FILE = `cygpath -w -a "$1"`
/usr/local/bin/word "$FILE" &

where I have word as a soft link:
/usr/local/bin/word -> /cygdrive/c/ProgramFilesx86/Microsoft Office/root/Office16/WINWORD.EXE

and where I have soft links set up under c:/
ProgramFiles -> 'Program Files'
ProgramFilesx86 -> 'Program Files (x86)'


Boris Gjenero said...

Here's part of my Cygwin ~/.bash_profile. Comments added now for explanation.

# Normally if you run a Windows GUI EXE, Bash waits until it finishes.
# You don't get console output from those, so it's pointless.
function detach {
( nohup "$@" < /dev/null > /dev/null 2>&1 & disown )
}
# Run an executable detached, translating a Cygwin path
function detach_c2w()
{
detach "$1" "$(cygpath -aw "$2")"
}
# The cmd.exe start command is useful for opening documents using
# Windows file associations, without needing to specify the program.
startfunc()
{
/cygdrive/c/Windows/system32/cmd.exe /c start \"Title\" "$(cygpath -aw "$1")"
}
# Aliases using above functions.
alias npp="detach_c2w /cygdrive/c/Program\ Files/Notepad++/notepad++.exe"
alias edit="detach_c2w /cygdrive/c/Program\ Files/Geany/bin/geany.exe"
alias open=startfunc
# I like fc /b for comparing binary files, so make fc run that
# and not Bash fc builtin.
alias fc=/cygdrive/c/Windows/system32/fc.exe
# This is for opening Explorer in the specified path or with the
# specified file selected.
explorerfunc()
{
if [ -d "$1" ]; then
/cygdrive/c/Windows/explorer.exe "$(cygpath -aw "$1")"
else
/cygdrive/c/Windows/explorer.exe "/select,$(cygpath -aw "$1")"
fi
}
alias explorer=explorerfunc