diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3e8e86c2f81530097ea840db51d5df9eb2b62fe
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResult.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.interop.base;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.r.runtime.data.RTruffleObject;
+
+public final class ESoftVersionResult implements RTruffleObject {
+    private final Map<String, String> paths = new HashMap<>();
+
+    public void putVersion(String libName, String version) {
+        paths.put(libName, version);
+    }
+
+    public Map<String, String> getVersions() {
+        return paths;
+    }
+
+    @Override
+    public ForeignAccess getForeignAccess() {
+        return ESoftVersionResultMRForeign.ACCESS;
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc958b7b30ff2f235e3ff12999bb024c86b95d03
--- /dev/null
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/interop/base/ESoftVersionResultMR.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.ffi.impl.interop.base;
+
+import com.oracle.truffle.api.interop.CanResolve;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.Resolve;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+
+@MessageResolution(receiverType = ESoftVersionResult.class)
+public class ESoftVersionResultMR {
+    @CanResolve
+    public abstract static class ESoftVersionResultCallbackCheck extends Node {
+
+        protected static boolean test(TruffleObject receiver) {
+            return receiver instanceof ESoftVersionResult;
+        }
+    }
+
+    @Resolve(message = "IS_EXECUTABLE")
+    public abstract static class ESoftVersionResultIsExecutable extends Node {
+        protected Object access(@SuppressWarnings("unused") ESoftVersionResult receiver) {
+            return true;
+        }
+    }
+
+    @Resolve(message = "EXECUTE")
+    public abstract static class ESoftVersionResultCallbackExecute extends Node {
+        protected Object access(ESoftVersionResult receiver, Object[] arguments) {
+            if (arguments.length == 2) {
+                receiver.putVersion("zlib", arguments[0].toString());
+                receiver.putVersion("PCRE", arguments[1].toString());
+            }
+            return receiver;
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
index bfe843a1f8b43ddc6a4aa65973d4976189fe8bfd..0f61b48a678c82be4291124847ffa9a88b9879e0 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_Base.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,10 @@ package com.oracle.truffle.r.ffi.impl.llvm;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Map;
 
 import com.oracle.truffle.r.ffi.impl.interop.NativeCharArray;
+import com.oracle.truffle.r.ffi.impl.interop.base.ESoftVersionResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult;
@@ -224,6 +226,22 @@ public class TruffleLLVM_Base implements BaseRFFI {
         }
     }
 
+    private static class TruffleLLVM_ESoftVersionNode extends TruffleLLVM_DownCallNode implements ESoftVersionNode {
+
+        @Override
+        protected NativeFunction getFunction() {
+            return NativeFunction.eSoftVersion;
+        }
+
+        @Override
+        public Map<String, String> eSoftVersion() {
+            ESoftVersionResult result = new ESoftVersionResult();
+            call(result);
+            return result.getVersions();
+        }
+
+    }
+
     @Override
     public GetpidNode createGetpidNode() {
         return new TruffleLLVM_GetpidNode();
@@ -273,4 +291,9 @@ public class TruffleLLVM_Base implements BaseRFFI {
     public GlobNode createGlobNode() {
         return new TruffleLLVM_GlobNode();
     }
+
+    @Override
+    public ESoftVersionNode createESoftVersionNode() {
+        return new TruffleLLVM_ESoftVersionNode();
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
index 185cf45f55a9247a410794dc1681ff6132ccc3a0..a1280ebd9b70b973f6ccb6d4c1d772b1de1350d6 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/managed/Managed_Base.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -200,4 +200,9 @@ public class Managed_Base implements BaseRFFI {
     public GlobNode createGlobNode() {
         return null;
     }
+
+    @Override
+    public ESoftVersionNode createESoftVersionNode() {
+        return null;
+    }
 }
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
index 7628b86c76a65db335336d11c6a3e2e1022c5506..7d8f8a9a8a5300fe18ec2e0fd0fbff81a0c044bc 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nfi/TruffleNFI_Base.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,9 +24,11 @@ package com.oracle.truffle.r.ffi.impl.nfi;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Map;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.r.ffi.impl.interop.base.ESoftVersionResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.GlobResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.ReadlinkResult;
 import com.oracle.truffle.r.ffi.impl.interop.base.StrtolResult;
@@ -214,6 +216,22 @@ public class TruffleNFI_Base implements BaseRFFI {
         }
     }
 
+    private static class TruffleNFI_ESoftVersionNode extends TruffleNFI_DownCallNode implements ESoftVersionNode {
+
+        @Override
+        protected NativeFunction getFunction() {
+            return NativeFunction.eSoftVersion;
+        }
+
+        @Override
+        public Map<String, String> eSoftVersion() {
+            ESoftVersionResult result = new ESoftVersionResult();
+            call(result);
+            return result.getVersions();
+        }
+
+    }
+
     @Override
     public GetpidNode createGetpidNode() {
         return new TruffleNFI_GetpidNode();
@@ -263,4 +281,10 @@ public class TruffleNFI_Base implements BaseRFFI {
     public GlobNode createGlobNode() {
         return new TruffleNFI_GlobNode();
     }
+
+    @Override
+    public ESoftVersionNode createESoftVersionNode() {
+        return new TruffleNFI_ESoftVersionNode();
+    }
+
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
index 25215c77f151d7cdeefe188bee891b245ff1d96a..17c0363e6cc98c9bee698420babe26fc6d70f154 100644
--- a/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
+++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/base_rffi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -107,3 +107,18 @@ void call_base_strtol(void (*call_setresult)(long result, int cerrno), char *s,
     long rc = strtol(s, NULL, base);
 	call_setresult(rc, errno);
 }
+
+#include <zlib.h>
+#include <bzlib.h>
+#ifdef HAVE_PCRE_PCRE_H
+# include <pcre/pcre.h>
+#else
+# include <pcre.h>
+#endif
+void call_base_eSoftVersion(void (*call_eSoftVersion_setfields)(char *zlibVersion, char *pcreVersion)) {
+
+    char sZlibVersion[256], sPcreVersion[256];
+    snprintf(sZlibVersion, 256, "%s", zlibVersion());
+    snprintf(sPcreVersion, 256, "%s", pcre_version());
+    call_eSoftVersion_setfields(sZlibVersion, sPcreVersion);
+}
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 0a3cf0343b971211a7bca1d18d0ce6dcb06e4715..a2bd261a010db0f0de92690e60863f29b8e8df5a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -40,6 +40,7 @@ import com.oracle.truffle.r.nodes.builtin.base.ConnectionFunctions.SockSelect;
 import com.oracle.truffle.r.nodes.builtin.base.ConnectionFunctionsFactory.SockSelectNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.DebugFunctions.FastRSetBreakpoint;
 import com.oracle.truffle.r.nodes.builtin.base.DebugFunctionsFactory.FastRSetBreakpointNodeGen;
+import com.oracle.truffle.r.nodes.builtin.base.VersionFunctions.RVersion;
 import com.oracle.truffle.r.nodes.builtin.base.fastpaths.AssignFastPathNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.fastpaths.ExistsFastPathNodeGen;
 import com.oracle.truffle.r.nodes.builtin.base.fastpaths.GetFastPathNodeGen;
@@ -395,6 +396,7 @@ public class BasePackage extends RBuiltinPackage {
         add(DynLoadFunctions.GetLoadedDLLs.class, DynLoadFunctionsFactory.GetLoadedDLLsNodeGen::create);
         add(DynLoadFunctions.GetSymbolInfo.class, DynLoadFunctionsFactory.GetSymbolInfoNodeGen::create);
         add(DynLoadFunctions.IsLoaded.class, DynLoadFunctionsFactory.IsLoadedNodeGen::create);
+        add(VersionFunctions.ExtSoftVersion.class, VersionFunctionsFactory.ExtSoftVersionNodeGen::create);
         add(EncodeString.class, EncodeStringNodeGen::create);
         add(EncodingFunctions.Encoding.class, EncodingFunctionsFactory.EncodingNodeGen::create);
         add(EncodingFunctions.SetEncoding.class, EncodingFunctionsFactory.SetEncodingNodeGen::create);
@@ -599,6 +601,7 @@ public class BasePackage extends RBuiltinPackage {
         add(LaFunctions.Version.class, LaFunctionsFactory.VersionNodeGen::create);
         add(LaFunctions.LaSolve.class, LaFunctionsFactory.LaSolveNodeGen::create);
         add(LaFunctions.Svd.class, LaFunctionsFactory.SvdNodeGen::create);
+        add(LaFunctions.LaLibrary.class, LaFunctionsFactory.LaLibraryNodeGen::create);
         add(Lapply.class, LapplyNodeGen::create);
         add(Length.class, LengthNodeGen::create);
         add(Lengths.class, LengthsNodeGen::create);
@@ -667,7 +670,7 @@ public class BasePackage extends RBuiltinPackage {
         add(RNGFunctions.RNGkind.class, RNGFunctionsFactory.RNGkindNodeGen::create);
         add(RNGFunctions.SetSeed.class, RNGFunctionsFactory.SetSeedNodeGen::create);
         add(RNGFunctions.FastRSetSeed.class, RNGFunctionsFactory.FastRSetSeedNodeGen::create);
-        add(RVersion.class, RVersionNodeGen::create);
+        add(RVersion.class, VersionFunctionsFactory.RVersionNodeGen::create);
         add(RawFunctions.CharToRaw.class, RawFunctionsFactory.CharToRawNodeGen::create);
         add(RawFunctions.RawToChar.class, RawFunctionsFactory.RawToCharNodeGen::create);
         add(RawFunctions.RawShift.class, RawFunctionsFactory.RawShiftNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
index b872653b289458c180eeea4bf635342526498a23..05c9f4f3e4473716fbc0ddd35fec26b398cf8dda 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DynLoadFunctions.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.nodes.builtin.base;
 
-import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asStringVector;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue;
 import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notEmpty;
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
index a75d886e0ad27c539f783b7f8d61249b6298e49c..49f5c90d3a70bf8a9266ea29ab7554649a6b447c 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java
@@ -41,6 +41,7 @@ import com.oracle.truffle.api.dsl.Cached;
 import com.oracle.truffle.api.dsl.Specialization;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.profiles.ConditionProfile;
+import com.oracle.truffle.r.ffi.impl.common.LibPaths;
 import com.oracle.truffle.r.nodes.access.vector.ExtractListElement;
 import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode;
 import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
@@ -63,7 +64,6 @@ import com.oracle.truffle.r.runtime.data.RComplexVector;
 import com.oracle.truffle.r.runtime.data.RDataFactory;
 import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory;
 import com.oracle.truffle.r.runtime.data.RDoubleVector;
-import com.oracle.truffle.r.runtime.data.RFunction;
 import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RStringVector;
@@ -866,4 +866,17 @@ public class LaFunctions {
             return RDataFactory.createList(val, nm);
         }
     }
+
+    @RBuiltin(name = "La_library", kind = INTERNAL, parameterNames = {}, behavior = PURE)
+    public abstract static class LaLibrary extends RBuiltinNode.Arg0 {
+
+        static {
+            Casts.noCasts(LaLibrary.class);
+        }
+
+        @Specialization
+        protected Object doLibrary() {
+            return RDataFactory.createStringVector(LibPaths.getBuiltinLibPath("Rlapack"));
+        }
+    }
 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VersionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VersionFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..a012fdfa939be6db14f894b61d71d91d4cf3643d
--- /dev/null
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/VersionFunctions.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.nodes.builtin.base;
+
+import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
+import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.Specialization;
+import com.oracle.truffle.r.ffi.impl.common.LibPaths;
+import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
+import com.oracle.truffle.r.runtime.RCompression;
+import com.oracle.truffle.r.runtime.RVersionInfo;
+import com.oracle.truffle.r.runtime.builtins.RBuiltin;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RStringVector;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI;
+import com.oracle.truffle.r.runtime.ffi.BaseRFFI.ESoftVersionNode;
+
+public abstract class VersionFunctions {
+
+    @RBuiltin(name = "Version", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
+    public abstract static class RVersion extends RBuiltinNode.Arg0 {
+
+        @Specialization
+        @TruffleBoundary
+        protected Object doRVersion() {
+            return RDataFactory.createList(RVersionInfo.listValues(), RDataFactory.createStringVector(RVersionInfo.listNames(), RDataFactory.COMPLETE_VECTOR));
+        }
+    }
+
+    @RBuiltin(name = "eSoftVersion", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
+    public abstract static class ExtSoftVersion extends RBuiltinNode.Arg0 {
+        @Child private ESoftVersionNode eSoftVersionNode = BaseRFFI.ESoftVersionNode.create();
+
+        static {
+            Casts.noCasts(ExtSoftVersion.class);
+        }
+
+        @Specialization
+        @TruffleBoundary
+        protected RStringVector getSymbolInfo() {
+
+            Map<String, String> eSoftVersion = eSoftVersionNode.eSoftVersion();
+
+            List<String> libNames = new ArrayList<>();
+            List<String> versions = new ArrayList<>();
+
+            for (Map.Entry<String, String> versionEntry : eSoftVersion.entrySet()) {
+                libNames.add(versionEntry.getKey());
+                versions.add(versionEntry.getValue());
+            }
+
+            // BZIP2
+            try {
+                versions.add(RCompression.getBz2Version());
+                libNames.add("bzip2");
+            } catch (IOException e) {
+                // ignore
+            }
+
+            // BLAS
+            libNames.add("BLAS");
+            versions.add(LibPaths.getBuiltinLibPath("Rblas"));
+
+            RStringVector names = RDataFactory.createStringVector(libNames.toArray(new String[0]), true);
+            return RDataFactory.createStringVector(versions.toArray(new String[0]), true, names);
+
+        }
+    }
+}
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java
index d95a86df371ee0199a5f05c546dd74ad20c2b43b..92868ceba0918ea765bb21c11bfb4412b5f1c061 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCompression.java
@@ -250,4 +250,39 @@ public class RCompression {
         }
         throw new IOException();
     }
+
+    public static String getBz2Version() throws IOException {
+        // assumes: "bzip2, a block-sorting file compressor. Version 1.0.6, 6-Sept-2010."
+        String[] command = {"bzip2", "-V"};
+        int rc;
+        ProcessBuilder pb = new ProcessBuilder(command);
+        Process p = pb.start();
+        // version is written to the error output stream
+        InputStream is = p.getErrorStream();
+        OutputStream os = p.getOutputStream();
+        ProcessOutputManager.OutputThreadVariable readThread = new ProcessOutputManager.OutputThreadVariable(command[0], is);
+        readThread.start();
+        os.close();
+        try {
+            rc = p.waitFor();
+            if (rc == 0) {
+                readThread.join();
+                String output = new String(readThread.getData(), 0, readThread.getTotalRead());
+                String version = "Version ";
+                String firstLine = output.split("\\n")[0];
+                int versionIdx = firstLine.indexOf(version);
+                if (versionIdx >= 0) {
+                    int commaIdx = firstLine.lastIndexOf('.');
+                    if (commaIdx > versionIdx) {
+                        return firstLine.substring(versionIdx + version.length(), commaIdx);
+                    }
+                }
+            } else {
+                throw new IOException("bzip2 error code: " + rc);
+            }
+        } catch (InterruptedException ex) {
+            // fall through
+        }
+        throw new IOException();
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
index ed2fdc7b53a9229f96a2e584e76ca7274a009de7..4dd512a84a0a8283b8ecb4afed0dfb7e8d053656 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.ffi;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Map;
 
 import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.nodes.NodeInterface;
@@ -163,6 +164,14 @@ public interface BaseRFFI {
         }
     }
 
+    interface ESoftVersionNode extends NodeInterface {
+        Map<String, String> eSoftVersion();
+
+        static ESoftVersionNode create() {
+            return RFFIFactory.getBaseRFFI().createESoftVersionNode();
+        }
+    }
+
     /*
      * The RFFI implementation influences exactly what subclass of the above nodes is created. Each
      * implementation must therefore, implement these methods that are called by the associated
@@ -189,6 +198,8 @@ public interface BaseRFFI {
 
     GlobNode createGlobNode();
 
+    ESoftVersionNode createESoftVersionNode();
+
     /*
      * Some functions are called from non-Truffle contexts, which requires a RootNode
      */
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
index 77e64b651b6fc773256b0342f1bd56ea5ada3f35..7ea60974f127f4e77b12c0d1c6148cb07b8404ff 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/NativeFunction.java
@@ -43,6 +43,7 @@ public enum NativeFunction {
     strtol("((sint64, sint32): void, string, sint32): void", "call_base_"),
     uname("((string, string, string, string, string): void): void", "call_base_"),
     glob("((string): void, string): void", "call_base_"),
+    eSoftVersion("((string, string): void): void", "call_base_"),
     // PCRE
     maketables("(): sint64", "call_pcre_"),
     compile("((uint64, string, sint32): void, string, sint32, uint64): void", "call_pcre_"),
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index cd370d6523e88dfacbdd0f04daf20995a2ed5a4b..56a64a29f0b4ef9de71ecb392cfc6496c22cb9a9 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -23592,6 +23592,10 @@ logical(0)
 #argv <- list(structure('lattice', .Names = ''), FALSE, FALSE, NA); .Internal(duplicated(argv[[1]], argv[[2]], argv[[3]], argv[[4]]))
 [1] FALSE
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_eSoftVersion.testESoftVersion#
+#{ v <- .Internal(eSoftVersion()); !is.null(v) && length(v) > 0 }
+[1] TRUE
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_enc2native.testInvalidArguments#Output.IgnoreErrorMessage#
 #enc2native(42);
 Error in enc2native(42) : argument is not a character vector
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eSoftVersion.java
similarity index 50%
rename from com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.java
rename to com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eSoftVersion.java
index 5deeb4662eddf0329a88478afd547eee3a3fcdbf..36108046e543c72d7303be8478bc336cd4f8e118 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RVersion.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eSoftVersion.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -20,24 +20,16 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package com.oracle.truffle.r.nodes.builtin.base;
+package com.oracle.truffle.r.test.builtins;
 
-import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE;
-import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL;
+import org.junit.Test;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
-import com.oracle.truffle.r.runtime.RVersionInfo;
-import com.oracle.truffle.r.runtime.builtins.RBuiltin;
-import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.test.TestBase;
 
-@RBuiltin(name = "Version", kind = INTERNAL, parameterNames = {}, behavior = READS_STATE)
-public abstract class RVersion extends RBuiltinNode.Arg0 {
+public class TestBuiltin_eSoftVersion extends TestBase {
 
-    @Specialization
-    @TruffleBoundary
-    protected Object doRVersion() {
-        return RDataFactory.createList(RVersionInfo.listValues(), RDataFactory.createStringVector(RVersionInfo.listNames(), RDataFactory.COMPLETE_VECTOR));
+    @Test
+    public void testESoftVersion() {
+        assertEval("{ v <- .Internal(eSoftVersion()); !is.null(v) && length(v) > 0 }");
     }
 }
diff --git a/mx.fastr/mx_fastr_pkgs.py b/mx.fastr/mx_fastr_pkgs.py
index 01c06cdd18d173999e700a5a4b2560a662021911..0a4c5df475c90b454ea09fabc17f230aef3eac10 100644
--- a/mx.fastr/mx_fastr_pkgs.py
+++ b/mx.fastr/mx_fastr_pkgs.py
@@ -617,6 +617,10 @@ def _replace_engine_references(output):
             output[idx] = val.replace('fastr', '<engine>').replace('gnur', '<engine>')
 
 
+def _is_ignored_function(fun_name, gnur_content, gnur_stmt, fastr_content, fastr_stmt):
+    return gnur_stmt != -1 and fun_name in gnur_content[gnur_stmt] and fastr_stmt != -1 and fun_name in fastr_content[fastr_stmt]
+
+
 def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, verbose=False):
     """
     Compares the test output of GnuR and FastR by ignoring implementation-specific differences like header, error,
@@ -647,12 +651,12 @@ def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, v
     gnur_prompt = _capture_prompt(gnur_content, gnur_i)
     fastr_prompt = _capture_prompt(fastr_content, fastr_i)
 
-    gnur_cur_statement_start = -1
-    fastr_cur_statement_start = -1
-    while True:
-        gnur_line, gnur_i = _get_next_line(gnur_prompt, gnur_content, gnur_end, gnur_i)
-        fastr_line, fastr_i = _get_next_line(fastr_prompt, fastr_content, fastr_len, fastr_i)
+    gnur_line, gnur_i = _get_next_line(gnur_prompt, gnur_content, gnur_end, gnur_i)
+    fastr_line, fastr_i = _get_next_line(fastr_prompt, fastr_content, fastr_len, fastr_i)
+    gnur_cur_statement_start = gnur_i
+    fastr_cur_statement_start = fastr_i
 
+    while True:
         if gnur_line is None or fastr_line is None:
             # fail if FastR's output is shorter than GnuR's
             if gnur_line is not None and fastr_line is None:
@@ -661,14 +665,6 @@ def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, v
                 overall_result = 1
             break
 
-        # check if the current line starts a statement
-        if _is_statement_begin(gnur_prompt, gnur_line) and gnur_cur_statement_start != gnur_i:
-            gnur_cur_statement_start = gnur_i
-
-        # if we find a new statement begin
-        if _is_statement_begin(fastr_prompt, fastr_line) and fastr_cur_statement_start != fastr_i:
-            fastr_cur_statement_start = fastr_i
-
         # flag indicating that we want to synchronize
         sync = False
         if gnur_line != fastr_line:
@@ -678,30 +674,41 @@ def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, v
                 if fastr_content[fastr_i].startswith('NULL') and not gnur_line.startswith('NULL'):
                     # ignore additional visible NULL
                     fastr_i = fastr_i + 1
-                continue
-            if gnur_line.startswith('Warning') and gnur_i + 1 < gnur_end and 'closing unused connection' in gnur_content[gnur_i + 1]:
+                sync = True
+            elif gnur_line.startswith('Warning') and gnur_i + 1 < gnur_end and 'closing unused connection' in gnur_content[gnur_i + 1]:
                 # ignore message about closed connection
                 gnur_i = gnur_i + 2
-                continue
-            if gnur_i > 0 and gnur_content[gnur_i - 1].startswith('   user  system elapsed'):
+                sync = True
+            elif gnur_i > 0 and gnur_content[gnur_i - 1].startswith('   user  system elapsed'):
                 # ignore differences in timing
                 gnur_i = gnur_i + 1
                 fastr_i = fastr_i + 1
-                continue
+                sync = True
             # we are fuzzy on Error/Warning as FastR often differs
             # in the context/format of the error/warning message AND GnuR is sometimes
             # inconsistent over which error message it uses. Unlike the unit test environment,
             # we cannot tag tests in any way, so we simply check that FastR does report
             # an error. We then scan forward to try to get the files back in sync, as the
             # the number of error/warning lines may differ.
-            if 'Error' in gnur_line or 'Warning' in gnur_line:
+            elif 'Error' in gnur_line or 'Warning' in gnur_line:
                 to_match = 'Error' if 'Error' in gnur_line else 'Warning'
                 if to_match not in fastr_line:
                     result = 1
                 else:
                     # accept differences in the error/warning messages but we need to synchronize
+                    gnur_i = gnur_i + 1
+                    fastr_i = fastr_i + 1
                     sync = True
-
+            elif _is_ignored_function("sessionInfo", gnur_content, gnur_cur_statement_start, fastr_content, fastr_cur_statement_start):
+                # ignore differences in 'sessionInfo' output
+                gnur_i = gnur_i + 1
+                fastr_i = fastr_i + 1
+                sync = True
+            elif _is_ignored_function("extSoftVersion", gnur_content, gnur_cur_statement_start, fastr_content, fastr_cur_statement_start):
+                # ignore differences in 'extSoftVersion' output
+                gnur_i = gnur_i + 1
+                fastr_i = fastr_i + 1
+                sync = True
             else:
                 # genuine difference (modulo whitespace)
                 if not _ignore_whitespace(gnur_line, fastr_line):
@@ -716,6 +723,8 @@ def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, v
                 print fastr_line.strip()
 
             # we need to synchronize the indices such that we can continue
+            gnur_i = gnur_i + 1
+            fastr_i = fastr_i + 1
             sync = True
             # report the last statement to produce different output
             assert fastr_cur_statement_start != -1
@@ -733,8 +742,6 @@ def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, v
 
         # synchronize: skip until lines match (or file end reached)
         if sync:
-            gnur_i = gnur_i + 1
-            fastr_i = fastr_i + 1
             if gnur_i == gnur_end - 1:
                 # at end (there is always a blank line)
                 break
@@ -754,6 +761,17 @@ def _fuzzy_compare(gnur_content, fastr_content, gnur_filename, fastr_filename, v
             gnur_i = gnur_i + 1
             fastr_i = fastr_i + 1
 
+        gnur_line, gnur_i = _get_next_line(gnur_prompt, gnur_content, gnur_end, gnur_i)
+        fastr_line, fastr_i = _get_next_line(fastr_prompt, fastr_content, fastr_len, fastr_i)
+
+        # check if the current line starts a statement
+        if _is_statement_begin(gnur_prompt, gnur_line) and gnur_cur_statement_start != gnur_i:
+            gnur_cur_statement_start = gnur_i
+
+        # if we find a new statement begin
+        if _is_statement_begin(fastr_prompt, fastr_line) and fastr_cur_statement_start != fastr_i:
+            fastr_cur_statement_start = fastr_i
+
     return overall_result, len(statements_passed), len(statements_failed)
 
 
@@ -781,8 +799,10 @@ def _capture_prompt(lines, idx):
 
 
 def _is_statement_begin(captured_prompt, line):
-    line_wo_prompt = line.replace(captured_prompt, "").strip()
-    return line.startswith(captured_prompt) and line_wo_prompt is not "" and not line_wo_prompt.startswith("#")
+    if not line is None:
+        line_wo_prompt = line.replace(captured_prompt, "").strip()
+        return line.startswith(captured_prompt) and line_wo_prompt is not "" and not line_wo_prompt.startswith("#")
+    return False
 
 
 def pkgtest_cmp(args):