Components & Versioning in .NET Core

This post covers the versions and components in .NET Core 1.x.

Components

.NET Core consists of multiple components that are each versioned
independently and can often be mixed and matched.

  • The Shared Framework contains the APIs and the Virtual Machine and other runtime services needed for running .NET Core applications.
    • The current .NET Core Virtual Machine is called CoreCLR. This executes the .NET bytecode by compiling it JIT and provides various runtime services including a garbage collector. The complete source code for CoreCLR is available at https://github.com/dotnet/coreclr.
    • The .NET Core standard APIs are implemented in CoreFX. This provides implementations of all your favourite APIs such as System.Runtime, System.Theading and so on. The source code for CoreFX is available at https://github.com/dotnet/corefx.
  • The Host is also sometimes called the muxer or driver. This components represents the dotnet command and is responsible for deciding what happens next. The source for this is available at https://github.com/dotnet/core-setup.
  • The SDK consists of the various tools (dotnet subcommands) and their implementations that deal with building code. This includes handling the restoring of dependencies, compiling code, building binaries, producing packages and publishing standalone or framework dependent packages. The SDK itself consists of the CLI, which handles command line operations (at https://github.com/dotnet/cli) and various subprojects that implement the various operations the CLI needs to do.

Versions

Each of the components listed above are versioned separately. You can find out the version of each of those components.

  • For the SDK, you can use the --version option to dotnet to see the version. For example:
    $ ~/dotnet-1.1.1/dotnet --version
    1.0.0-preview2-1-003176
    
  • For the Host you can run dotnet by itself without any arguments or options to see the version.
    $ ~/dotnet-1.1.1/dotnet
    
    Microsoft .NET Core Shared Framework Host
    
    Version : 1.1.0
    Build : 362e48a95c86b40cd1f2ef3d08741f7fed897956
    
    Usage: dotnet [common-options] [[options] path-to-application]
    ...
    
  • For the Shared Framework there no command currently to display the version(s). I use ls /path/to/where/you/installed/dotnet/shared/Microsoft.NETCore.App which relies on internal implementation details. For example:
    $ ls ~/dotnet-1.1.1/shared/Microsoft.NETCore.App/
    1.1.1
    

Components in .NET Core Installations

Various official and unoffical packages, tarballs, zips and installers for .NET Core (including those available on https://dot.net/core) provide .NET Core in many variants. Two common ones are .NET Core SDK and .NET Core Runtimes. Each .NET Core SDK or .NET Core Runtime distribution contains a number (possibly 0) of hosts, sdk and shared framework components described above.

  • .NET Core Runtime contains
    • 1 version of the Host
    • 1 version of the Shared Framework
  • .NET Core SDK contains
    • 1 or more versions of the Shared Framework (varies depending on the version of the version of the .NET Core SDK)
    • 1 version of the Host
    • 1 version of the SDK

Selecting Versions

It’s possible to have multiple .NET Core SDKs and .NET Core Runtimes available on disk. You can select the versions easily.

To select the version of the SDK to use, use global.json.

To select the version of the shared framework to use, use the .csproj file (or project.json if you are still using that).

-Wmisleading-indentation in OpenJDK

Inspired by this post by Mark Wielaard I started wondering how OpenJDK 9 would fare in a -Wmisleading-indentation test. So I built OpenJDK 9 using -Wall to find out.

First, though, a big heads up: the OpenJDK 9 build selectively enables and disables warnings and turns on -Werorr. There doesn’t seem to be a straight-forward way of enabling all compiler warnings everywhere. I ended up patching various makefiles to comment out various DISABLED_WARNINGS* flags. Hotspot needed a separate patch to initialize WARNING_FLAGS with -Wall in hotspot/make/linux/makefiles/gcc.make. Then I built OpenJDK 9 using:

mkdir build
cd build
bash ../configure --with-extra-cflags="-Wall -Wextra" --with-extra-cxxflags="-Wall -Wextra -fpermissive" --disable-warnings-as-errors

A grep misleading-indentation build.log was surprising:

jdk9-dev/jdk/src/java.base/share/native/libfdlibm/e_asin.c:103:17: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.base/share/native/libfdlibm/k_rem_pio2.c:201:61: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmscgats.c:613:13: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmscgats.c:690:13: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c:959:29: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmsintrp.c:1023:29: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmsio1.c:717:9: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmsopt.c:557:13: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmsopt.c:1021:29: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmsps2.c:1015:9: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmstypes.c:2398:9: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmstypes.c:2679:9: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/liblcms/cmswtpnt.c:109:9: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/libfontmanager/layout/SunLayoutEngine.cpp:154:25: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c:3880:16: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
jdk9-dev/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngread.c:3997:10: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]

libfdlibm, liblcms and libpng are all external libraries that are bundled with OpenJDK. In the case of Linux distributions, they are often replaced with dynamically linked system libraries. That only code that’s actually part of OpenJDK itself is libfontmanager.

Let’s take a look at that. The warning itself is:

/home/omajid/jdk9-dev/jdk/src/java.desktop/share/native/libfontmanager/layout/SunLayoutEngine.cpp:154:25: warning: statement is indented as if it were guarded by... [-Wmisleading-indentation]
   if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
                         ^~
/home/omajid/jdk9-dev/jdk/src/java.desktop/share/native/libfontmanager/layout/SunLayoutEngine.cpp:154:3: note: ...this 'if' clause, but it is not
   if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
   ^~

So gcc thinks the programmer meant to guard the second if statement with the first but failed to do so. But a quick look at the code suggests that these are indeed two independent checks – one checks and fixes min and the other fixes max. The developer just tried to save whitespace and write them in one line. Definitely a false postive.

Anyway, I am impressed with OpenJDK’s code quality: gcc doesn’t find any actual misleading indentation issues in OpenJDK.

SharedSecrets in OpenJDK

I have always been impressed by the effort OpenJDK folks go to maintain API compatibility. I recently came across a nifty little trick that is used in the OpenJDK codebase to help achieve this goal. Behold the SharedSecrets class! The name of the class is a little misleading since it doesn’t have anything to do with the cryptographic concepts of shared secrets. The javadocs do a (slightly) better job describing its purpose:

/** A repository of "shared secrets", which are a mechanism for
    calling implementation-private methods in another package without
    using reflection. A package-private class implements a public
    interface and provides the ability to call package-private methods
    within that package; the object implementing that interface is
    provided through a third package to which access is restricted.
    This framework avoids the primary disadvantage of using reflection
    for this purpose, namely the loss of compile-time checking. */

In other words, it is used to make private methods public, without using reflection! AND it works under a security manager! At first, I thought this was too good to be true but it turns out that the concept behind it is pretty simple. Here’s how it works. Suppose we have a class with a fixed public api and we wish to add a new method to it that we would like to be able to use internally within the project but not provide as an api:

public class FixedPublicApi {
  private static doFoo() { /* do something */ }
}

We could choose to add the doFoo method to another class (in fact, it will primarily be accessed through another class) and make it public, but let’s assume that the only way to avoid duplicating lots of code is to keep doFoo in FixedPublicApi. First we create an interface that exposes the method we want to be invoked:

public interface FooHandler {
  public void doFoo();
}

Then we modify the SharedSecrets class (or it’s equivalent in our codebase), to set the implementation for FooHandler

public class SharedSecrets {
  private static FooHandler fooHandler;
  public static void setFoo(FooHandler handler) {
    fooHandler = handler;
  }
  public static void foo() {
    fooHandler.doFoo();
  }
}

Finally we modify the FixedPublicApi class to install a handler:

public class FixedPublicApi {
  static {
     SharedSecrets.setFoo(new FooHandler() {
       public void doFoo() {
         FixedPublicApi.doFoo();
       }
     }
  }

  private static doFoo() { /* do something */ }
}

And that’s it! Now we can use SharedSecrets to call the private method:

  SharedSecrets.doFoo();

Hats off to whoever came up with this great technique.

What IcedTea-Web 1.1 means for you

A number of changes occurred between IcedTea-Web 1.0 and IcedTea-Web 1.1. If you are a packager or a developer here are some things you need to know.

Are you a packager?
IcedTea-Web 1.1 can be installed into a regular prefix (/usr/ or /usr/local/ or anything else). Unlike IcedTea-Web 1.0, you do not need to install IcedTea-Web into a JDK or JRE directory. IcedTea-Web uses a JDK to build itself (specified using --with-jdk-home). IcedTea-Web will use the JDK it was compiled against to run. The launchers (javaws and itweb-settings) are now shell scripts and can be customized as needed.

Are you a developer using applets or java web start?
IcedTea-Web 1.1 provides netscape.javascript.* and javax.jnlp.* classes that applets and web start applications use. However, unlike icedtea-web < 1.1 (or older releases of icedtea6) the jars that provide these classes will not be automatically be picked up by the JDK. netscape.javascript.* classes are included in IcedTea-Web’s plugin.jar. javax.jnlp.* classes are included in IcedTea-Web’s netx.jar. Please add these classes to your classpath when building.