Stale /etc/portage/package.unmask

As a recommendation to people who use /etc/portage/package.unmask regularly: You really ought to keep tabs on the thing that you’re unmasking… and once it has been unmasked, you should remove the entries from package.unmask.

Here’s a scenario: You heard about the new Java system being in package.mask, so you decided to try it. Cool. It has since come out of package.mask… but you still have it unmasked via /etc/portage/package.unmask. Now, we release a new revision of java-config that we put in package.mask for testing… and now you get the version that we are heavily tested, and it doesn’t quite work 100%…

So, please, be mindful of your package.unmasks.

JAVA_HOME pointing to generation-1 system vm

So, one of the issues that has come up on occaision is that JAVA_HOME ends up pointing at, for instance, /opt/blackdown-jdk-1.4.2.03, instead of the shiny, recently unmasked Java 1.5 you installed and set as your VM of choice.

The reason for this has is legacy support. java-config-1 isn’t so smart. It determines what the current VM is based on JAVA_HOME in the environment. It expects it to be living under /opt/${P}, where ${P} is the name and version of the VM.

The workaround we found is described in the upgrade guide. However, the problem is, that java-config-1 would then no longer be able to know what VM is currently being used, which is a bit problematic.

Thanks to the hax0ring skills, we now have a patched java-config-1 that uses VMHANDLE instead of JAVA_HOME. VMHANDLE is the token by which a VM is identified with the new Java system, and happens to be in the environment.

We have added a new entry for /etc/profile.d, which uses the prescribed way of setting JAVA_HOME from the upgrade guide. This means that JAVA_HOME would be set correctly most of the time. The only time it wouldn’t be accurate would be if you did not have a user vm set (JAVA_HOME points at /etc/java-config-2/current-system-vm), and then you set a user vm, JAVA_HOME would point at current-system-vm, instead of ~/.gentoo/java-config-2/current-user-vm. Running ‘source /etc/profile’ though, remedies the problem.

Perhaps java-config-2 can be updated to give notice that you need to source /etc/profile ? Or perhaps it can directly update JAVA_HOME… The only problem with the the latter point ist hat it would probably only fix JAVA_HOME in the current terminal, and not in all the other open terminals.

I’ve added revision bumps of java-config to the tree that work as described here. Because of the changes though, I’ve put them in package.mask while we finish testing the new way of handling JAVA_HOME. The package.mask entry is below, for those interested in testing and providing feedback:

# Joshua Nichols <nichoj@gentoo.org> (02 Aug 2006)
# Testing new versions of java-config, which will let us remove
# JAVA_HOME from env, which points to generation-1 system vm
=dev-java/java-config-1.3.0-r3
=dev-java/java-config-2.0.26-r6

Assuming there aren’t any issues while testing, I expect to unmask it in a day or two. At that point, I’ll also update all the env.d files for the VMs, so they no longer export JAVA_HOME (note: this is different from the profile.d, which is actually overwriting the JAVA_HOME originally being set by the env.d file).

Java 1.4: Do we still need it?

The answer, as of this moment, is most definitely. There are two reasons for this at the moment.

  1. there are still packages which don’t compile when built with Java 1.5. In these cases, the new Java build system switches to a 1.4 JDK for building.
  2. it is needed for packages that haven’t been migrated to use the new Java system. This is necessary, otherwise we encounter the same exact problems that prompted the initial package.mask of Java 1.5.

Just to recap why Java 1.5 was package was package.mask’d…. It really comes down to backwards compatibility, and that Java 1.5 isn’t 100% backwards compatible with Java 1.4. Things that ran with Java 1.4 should still run with Java 1.5… but some things that once built with Java 1.4 no longer compile with Java 1.5. Specifically:

  1. There’s a new reserved keyword with Java 1.5, enum. So where you used to be able to use enum as a variable name, you no longer can in 1.5.
  2. A number of new methods have been introduced to some abstract classes and interfaces. If a particular implementation doesn’t implement the new methods, then it won’t compile against Java 1.5

Now, say you’re using Java 1.5 to build all your packages, and then you come up to a package that can’t compile for one of these reasons? It’d fail for one. But then you may try with Java 1.4… and all is well until you see a compile error: UnsupportedClassVersionError. What does this mean though?

Well, each major release of Java has it’s own version of bytecode. Bytecode is forward compatible, ie run 1.4 bytecode in 1.5, but not backwards compatible. If you try to use 1.5 bytecode in 1.4, you will see the infernal UnsupportedClassVersionError. This happens because, since you were using Java 1.5, the dependencies of the package you were just trying to compile with 1.4 were built with 1.5, and the default behavior is to build the highest possible bytecode.

So, these are the reasons Java 1.5 was package.mask’d, and why we need to use Java 1.4 for building unmigrated packages.

But how does the new Java system help?

  • We get around the problem of enum by specifically telling the compiler to use source=”1.4″, where enum is a valid variable name.
  • We get around the changes in API by switching to a version where it can be compiled, until such time as the package can be properly patched.
  • Additionally, we make javac compile the lowest possible bytecode, so it can be used by as many other packages as possible.