Zen and the art of...

2010-04-18

Cygwin Tip #1

Calling Java Under Cygwin

Cygwin is a fantastic piece of software for those who, like me, can't live without a Linux-like command line and environment. But for any person who have tried to blend two completely different cultures, we know it's not always easy to make them play well together. In this post I'll explain how to make Java's Windows version feel more like a Cygwin application.

The main problem comes from the way a file path differs between Windows and the POSIX standard. The most obvious difference is the path separator issue, in Windows world it's \ while for the rest of the planet it's /. Another one is the way the root path(s) are being represented, in Windows each drive/partition have it's own letters with its own root path. Cygwin being POSIX-based has a single root path (/) and maps the Windows letters in a directory called /cygdrive. Those problems are easily circumvented using a the cygpath command:

$ cygpath -aw '/cygdrive/c/Program Files/Java/jdk1.6.0_18/bin/java'
C:\Program Files\Java\jdk1.6.0_18\bin\java

That's Not Enough

It wouldn't be hard to call this command on the classpath argument when calling java from cygwin, but there's another hindrance. The classpath usually contains more than one path, these paths being separated by a colon (:) in POSIX systems or by a semicolon (;) under Windows. It would be also quite tiresome edit java calls manually so I came up with a little Ruby script that can do the job for us.

#!/bin/ruby
# Slightly obfuscated cygwin + windows java wrapper, automate cygpath

cpi = ARGV.index("-cp") + 1
cp = ARGV[cpi] if cpi

XBCP = "-Xbootclasspath/a:"

xbcpi = ARGV.index{|i|i=~/^#{XBCP}.*/}
xbcp = ARGV[xbcpi] if xbcpi

if cp or xbcpi
  def convert_paths(paths)
    paths = paths.gsub(':', ';').split(';')
    paths.map{|p|`cygpath -aw #{p}`.strip}.join ';'
  end
  ARGV[cpi] = convert_paths(cp) if cp
  ARGV[xbcpi] = XBCP + convert_paths(xbcp.sub(XBCP, '')) if xbcp
end

java = '/cygdrive/c/Program Files/Java/jdk1.6.0_18/bin/java'
cmd = [java].concat ARGV

def e(s); "\"#{s.strip.gsub('"','\"')}\""; end

exec(cmd.map{|a|e a}.join(' '))

This is more of a hack than a solid solution, but it's enough for my current usage and hopefully yours. Now the Windows java command can take POSIX paths without complaining under Windows, isn't that marvellous!

No comments:

Post a Comment

About Me

My photo
Quebec, Canada
Your humble servant.