Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#432 Proposed solution for cross building against multiple Scala versions #462

Merged
merged 4 commits into from
Mar 11, 2013

Conversation

skipoleschris
Copy link
Contributor

The main scala build has been modified to generate an artifact named cucumber-scala_2.10
A new sub-directory of the scala build has been created. This uses the same source files as its parent but builds a cucumber-scala_2.9.2 artifact using the Scala 2.9.2 compiler and library
To get this to work correctly the README.java and package.html files were moved into the scala source tree
The scala-calculator example was modified to use the cucumber-scala_2.10 artifact
The root pom.xml file no longer directly references Scala library dependencies as there are now different versions between the 2.10 and 2.9.2 build. (Is the a solution to this?)

@aslakhellesoy
Copy link
Contributor

Builds fine here, thanks!

Is the overall goal of this PR and #432 to build Cucumber-Scala against the latest minor version (currently 2.10) and the previous minor version (currently 2.9.2)? If that's it, is the motivation behind this to allow Scala users some time to upgrade to a new scala version while still enjoying the latest cucumber-scala?

I'm asking, because when the latest minor version is, say, 2.11, should we then build agains 2.10.x as well and no longer build for 2.9.x?

What if we renamed scala/scala_2.9.2 to scala/previous_minor_release? That would make it easier to keep following this release pattern.

@skipoleschris
Copy link
Contributor Author

The Scala versioning system is enough to make even a hardened Scala veteran curl up in a ball on the floor and cry! I'll try to explain what a nightmare it is and hopefully at the same time it will make sense of the versioning numbers and build proposal.

Okay, so Scala is not generally binary or api compatible between different major or minor versions. So, code built using/against 2.9.x generally won't work in an application being built using 2.10.x and visa-versa. As someone building applications it's not too much of a problem as you just have to find the right versions of libraries for the Scala version you are using. As a library author it's a right pain as you have to cross build for every Scala version that you want to support.

Previously on the 2.9.x releases you had to cross build for each patch release as well (e.g. 2.9.0, 2.9.1, 2.9.2 etc.). The authors of Scala and the SBT (Simple Build Tool) realised that this was a real pain, so starting from 2.10 onwards you can just build for the major/minor version (e.g. 2.10) as patch 2.10 releases will be fully compatible with each other. Therefore it is likely that 2.9.2 is likely to be the last version that we need patch point release builds for. Going forward it should be possible to just build 2.10, 2.11 and so on and have it work with all patch releases (prays they manage to deliver on this!).

Anyway, we currently need to build against 2.9.2 as that's the current stable release of 2.9 and there are still a large amount of projects being built against this version (including a number of Scala projects I work on) and they deserve the latest cucumber-jvm version I think. The newest Scala version is 2.10.0 but this has only been released about 6 weeks, so most projects haven't switched to it yet, but we still need to build this version (2.10) as well. There's also a 2.11 in development, and this is possibly expected around the end of the year. So, in the worst case we might need different builds for 2.9.2, 2.10 and 2.11 (yuk, hope not!)

Anyway, the SBT build tool for Scala has created some defacto conventions for numbering Scala project artifacts based around the artifact name, an underscore and the Scala version. So, from an SBT project you can reference a library by version directly:

"my.package" % "mylib_2.10" % "1.0.0" % "compile"

However, there is also a special syntax in SBT that allows the version Scala to be ommitted. SBT will then look at the version of Scala being used to build the project and select the appropriate artifact name:

"my.package" %% "mylib" % "1.0.0" % "compile"

So, if building with Scala 2.9.2 it will select mylib_2.9.2 and if building under Scala 2.10.x it will select mylib_2.10. Note that since 2.10.0 (and sbt 0.12.2) for 2.10.x it defaults to not including the patch version number.

Fortunately, SBT makes life a little easier for library developers in that you can specify cross-build versions of Scala, so I can say build my library with Scala 2.9.2, 2.10 and so on. It will then compile and test my library using each Scala version and then produce artifacts for each with the appropriate Scala version numbers appended to the name.

To cut a long (and painful) story short, if we want to create artifacts compatible with the SBT versioning system then they should have the Scala version number as part of the artifact name. For 2.9.2 we need the patch version included. Going forward we shouldn't need the patch number.

Hope that makes sense (from an understanding point of view anyway, it makes little sense from a sanity perspective). Sorry for the essay!

(Relates to #432)

@aslakhellesoy
Copy link
Contributor

Thanks!

To avoid confusion: When I referred to minor version, it was in the major.minor.patch sense (aka semver, which I, apparently mistakenly, thought was the versioning scheme used by Scala).
I think what you call minor is what semver refers to as patch. And what you call major is what semver calls minor. Not sure what you call what semver calls patch ;-)

@skipoleschris
Copy link
Contributor Author

Ahh, okay, makes sense. Prior to Scala 2.10 I don't think there was such a thing as a patch release. Any change had the potential to break forward/backward compatibility even if it changed only the patch version number. Hopefully from 2.10 going forwards this won't be the case and Scala releases will follow semver more correctly.

I'll edit my post above to use the correct major.minor.patch terminology.

@aslakhellesoy
Copy link
Contributor

I tried to merge this PR after merging #455. After resolving a minor merge conflict in the top level pom.xml the build failed with this exception:

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; nested exception is java.lang.reflect.InvocationTargetException: null
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:113)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.lang.NoClassDefFoundError: scala/collection/convert/DecorateAsJava
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2442)
    at java.lang.Class.getMethod0(Class.java:2685)
    at java.lang.Class.getMethod(Class.java:1620)
    at org.apache.maven.surefire.util.ReflectionUtils.tryGetMethod(ReflectionUtils.java:57)
    at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.isSuiteOnly(JUnit3TestChecker.java:64)
    at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.isValidJUnit3Test(JUnit3TestChecker.java:59)
    at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.accept(JUnit3TestChecker.java:54)
    at org.apache.maven.surefire.common.junit4.JUnit4TestChecker.accept(JUnit4TestChecker.java:51)
    at org.apache.maven.surefire.util.DefaultScanResult.applyFilter(DefaultScanResult.java:97)
    at org.apache.maven.surefire.junit4.JUnit4Provider.scanClassPath(JUnit4Provider.java:194)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:92)
    ... 9 more
Caused by: java.lang.ClassNotFoundException: scala.collection.convert.DecorateAsJava
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 21 more

Results :

I'm not sure what this means or how to fix this.

@skipoleschris could you try to rebase this PR with master and see if you can get it to work? /cc @lucas1000001

The main scala build has been modified to generate an artifact named cucumber-scala_2.10
A new sub-directory of the scala build has been created. This uses the same source files as its parent but builds a cucumber-scala_2.9.2 artifact using the Scala 2.9.2 compiler and library
To get this to work correctly the README.java and package.html files were moved into the scala source tree
The scala-calculator example was modified to use the cucumber-scala_2.10 artifact
The root pom.xml file no longer directly references Scala library dependencies as there are now different versions between the 2.10 and 2.9.2 build. (Is the a solution to this?)
The main scala build has been modified to generate an artifact named cucumber-scala_2.10
A new sub-directory of the scala build has been created. This uses the same source files as its parent but builds a cucumber-scala_2.9.2 artifact using the Scala 2.9.2 compiler and library
To get this to work correctly the README.java and package.html files were moved into the scala source tree
The scala-calculator example was modified to use the cucumber-scala_2.10 artifact
The root pom.xml file no longer directly references Scala library dependencies as there are now different versions between the 2.10 and 2.9.2 build. (Is the a solution to this?)
@skipoleschris
Copy link
Contributor Author

There was one recent change that made the scala code only compile against 2.10.0. Fortunately it was just using a method that was renamed between 2.9.2 and 2.10.0. I swapped it to use the name that is compatible between both versions. This builds locally for me now.

@aslakhellesoy aslakhellesoy merged commit f9ce1cf into cucumber:master Mar 11, 2013
aslakhellesoy added a commit that referenced this pull request Apr 12, 2013
@lock
Copy link

lock bot commented Oct 25, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants