Here's a brief summary of some of the major changes in this release, with more detailed information in the following sections:
The inout
and borrowed
argument conventions have been renamed to mut
and read
, respectively. A new out
convention has been added for the self
argument in constructors and for named results. See Language changes for details.
Lifetime
and related types in the standard library have been renamed to Origin
to better clarify that parameters of this type indicate where a reference is derived from, not the more complicated notion of where a variable is initialized and destroyed. As a consequence the __lifetime_of()
operator is now named __origin_of()
.
There are also a number of other origin-related improvements in this release, including being able to specify a union of origins by listing multiple values in the __origin_of()
operator or inside the ref
origin specifier (ref [a, b]
). For details, see Language changes.
For background information and rationale on the name change see the proposal. For more information on origins, see Lifetimes, origins and references in the Mojo Manual.
Implicit conversions are now opt-in using the @implicit
decorator. See Language changes for details.
The standard library has added several new types, including Deque
(a double-ended queue) and OwnedPointer
(safe, single-owner, non-nullable smart pointer). See Standard library changes for details.
The VS Code extension now supports setting data breakpoints and function breakpoints, and the Mojo LLDB debugger supports symbol breakpoints, such as b main
or b my_module::main
.
We've made a number of improvement to how information is displayed in error messages, LSP, and generated API documentation. For details, see Tooling changes.
And we've added a number of new docs, including a brand new Mojo tutorial, new pages on operators and expressions, error handling, and pointers, and many smaller additions and improvements.
Argument convention changes:
The inout
and borrowed
argument conventions have been renamed to mut
(for "mutate") and read
, respectively. These verbs reflect what the callee can do to the argument value passed in by the caller, without requiring the programmer to know about advanced features like references.
For information on Mojo's argument conventions, see Argument conventions in the Mojo Manual.
The argument convention for the self
argument in the __init__()
, __copyinit__()
, and __moveinit__()
methods has been changed from inout
to out
, reflecting that a constructor method initializes its self
value without reading from it. This also enables spelling the type of an initializer correctly, which was not supported before:
struct Foo: fn __init__(out self): passfn test(): # This works now var fnPtr : fn(out x: Foo)->None = Foo.__init__ var someFoo : Foo fnPtr(someFoo) # initializes someFoo.
struct Foo: fn __init__(out self): passfn test(): # This works now var fnPtr : fn(out x: Foo)->None = Foo.__init__ var someFoo : Foo fnPtr(someFoo) # initializes someFoo.
The previous fn __init__(inout self)
syntax is still supported in this release of Mojo, but will be removed in the future. Please migrate to the new syntax.
Similarly, the spelling of named results has switched to use out
syntax instead of -> T as name
. Functions may have at most one named result or return type specified with the usual ->
syntax. out
arguments may occur anywhere in the argument list, but are typically last (except for __init__
methods, where they are typically first).
# This function has type "fn() -> String"fn example(out result: String): result = "foo"
# This function has type "fn() -> String"fn example(out result: String): result = "foo"
The parser still accepts the old syntax as a synonym for this, but that will eventually be deprecated and removed.
This was discussed extensively in a public proposal. For more information, see Named results in the Mojo Manual.
Single argument constructors now require the @implicit
decorator to allow for implicit conversions. Previously you could define an __init__
that takes a single argument:
struct Foo: var value: Int fn __init__(out self, value: Int): self.value = value
struct Foo: var value: Int fn __init__(out self, value: Int): self.value = value
And this would allow you to pass an Int
in the position of a Foo
:
fn func(foo: Foo): print("implicitly converted Int to Foo:", foo.value)fn main(): func(Int(42))
fn func(foo: Foo): print("implicitly converted Int to Foo:", foo.value)fn main(): func(Int(42))
This can result in complicated errors that are difficult to debug. By default this implicit behavior is now turned off, so you have to explicitly construct Foo
:
fn main(): func(Foo(42))
fn main(): func(Foo(42))
You can still opt into implicit conversions by adding the @implicit
decorator. For example, to enable implicit conversions from Int
to Foo
:
struct Foo: var value: Int @implicit fn __init__(out self, value: Int): self.value = value
struct Foo: var value: Int @implicit fn __init__(out self, value: Int): self.value = value
For more information see Constructors and implicit conversion in the Mojo Manual.
Origin-related changes:
The AnyLifetime
type (useful for declaring origin types as parameters) has has been renamed to Origin
and the __lifetime_of()
operator renamed to __origin_of()
.
Origin
is now a complete wrapper around the MLIR origin type.
The Origin.type
alias has been renamed to _mlir_origin
. In parameter lists, you can now write just Origin[..]
, instead of Origin[..].type
.
ImmutableOrigin
and MutableOrigin
are now, respectively, just aliases for Origin[False]
and Origin[True]
.
Origin
struct values are now supported in the origin specifier of a ref [..]
argument.
Added Origin.cast_from
for casting the mutability of an origin value.
ref
arguments and results now allow for providing a memory value directly in the origin specifier, rather than requiring the use of __origin_of()
. It is still fine to use __origin_of()
explicitly though, and this is required when specifying origins for parameters (e.g. to the Pointer
type). For example, this is now valid without __origin_of()
:
fn return_ref(a: String) -> ref [a] String: return a
fn return_ref(a: String) -> ref [a] String: return a
Various improvements to origin handling and syntax have landed, including support for the ternary operator and allowing multiple arguments in a ref
specifier (which are implicitly unions). This enables expression of simple algorithms cleanly:
fn my_min[T: Comparable](ref a: T, ref b: T) -> ref [a, b] T: return a if a < b else b
fn my_min[T: Comparable](ref a: T, ref b: T) -> ref [a, b] T: return a if a < b else b
It is also nice that my_min
automatically and implicitly propagates the mutability of its arguments, so things like my_min(str1, str2) += "foo"
is valid.
ref
function arguments without an origin clause are now treated as ref [_]
, which is more syntactically convenient and consistent:
fn takes_and_return_ref(ref a: String) -> ref [a] String: return a
fn takes_and_return_ref(ref a: String) -> ref [a] String: return a
The __type_of(x)
and __origin_of(x)
operators are much more general now: they allow arbitrary expressions inside of them, allow referring to dynamic values in parameter contexts, and even allow referring to raising functions in non-raising contexts. These operations never evaluate their expression, so any side effects that occur in the expression are never evaluated at runtime, eliminating concerns about __type_of(expensive())
being a problem.
The destructor insertion logic in Mojo is now aware that types that take an MutableAnyOrigin
or ImmutableAnyOrigin
as part of their signature could potentially access any live value that destructor insertion is tracking, eliminating a significant usability issue with unsafe APIs like UnsafePointer
. Consider a typical example working with strings before this change:
var str = String(...)var ptr = str.unsafe_ptr()some_low_level_api(ptr)_ = str^ # OLD HACK: Explicitly keep string alive until here!
var str = String(...)var ptr = str.unsafe_ptr()some_low_level_api(ptr)_ = str^ # OLD HACK: Explicitly keep string alive until here!
The _ = str^
pattern was formerly required because the Mojo compiler has no idea what "ptr" might reference. As a consequence, it had no idea that some_low_level_api()
might access str
and therefore thought it was ok to destroy the String
before the call - this is why the explicit lifetime extension was required.
Mojo now knows that UnsafePointer
may access the MutableAnyOrigin
origin, and now assumes that any API that uses that origin could use live values. In this case, it assumes that some_low_level_api()
might access str
and because it might be using it, it cannot destroy str
until after the call. The consequence of this is that the old hack is no longer needed for these cases!
Function types now accept an origin set parameter. This parameter represents the origins of values captured by a parameter closure. The compiler automatically tags parameter closures with the right set of origins. This enables lifetimes and parameter closures to correctly compose.
fn call_it[f: fn() capturing [_] -> None](): f()fn test(): var msg = String("hello world") @parameter fn say_hi(): print(msg) call_it[say_hi]() # no longer need to write `_ = msg^`!!
fn call_it[f: fn() capturing [_] -> None](): f()fn test(): var msg = String("hello world") @parameter fn say_hi(): print(msg) call_it[say_hi]() # no longer need to write `_ = msg^`!!
Note that this only works for higher-order functions which have explicitly added [_]
as the capture origins. By default, the compiler still assumes a capturing
closure does not reference any origins. This will soon change.
Infer-only parameters may now be explicitly bound with keywords, enabling some important patterns in the standard library:
struct StringSlice[is_mutable: Bool, //, origin: Origin[is_mutable]]: ...alias ImmStringSlice = StringSlice[is_mutable=False]# This auto-parameterizes on the origin, but constrains it to being an# immutable slice instead of a potentially mutable one.fn take_imm_slice(a: ImmStringSlice): ...
struct StringSlice[is_mutable: Bool, //, origin: Origin[is_mutable]]: ...alias ImmStringSlice = StringSlice[is_mutable=False]# This auto-parameterizes on the origin, but constrains it to being an# immutable slice instead of a potentially mutable one.fn take_imm_slice(a: ImmStringSlice): ...
The flag for turning on asserts has changed, e.g. to enable all checks:
mojo -D ASSERT=all main.mojo
mojo -D ASSERT=all main.mojo
The levels are:
none
: all assertions off
warn
: print assertion errors e.g. for multithreaded tests (previously -D ASSERT_WARNING
)
safe
: the default mode for standard CPU safety assertions
all
: turn on all assertions (previously -D MOJO_ENABLE_ASSERTIONS
)
You can now also pass Stringable
args to format a message, which will have no runtime penalty or IR bloat cost when assertions are off. Previously you had to:
x = -1debug_assert( x > 0, String.format_sequence(“expected x to be more than 0 but got: ”, x))
x = -1debug_assert( x > 0, String.format_sequence(“expected x to be more than 0 but got: ”, x))
Which can't be optimized away by the compiler in release builds, you can now pass multiple args for a formatted message at no runtime cost:
debug_assert(x > 0, “expected x to be more than 0 but got: ”, x)
debug_assert(x > 0, “expected x to be more than 0 but got: ”, x)
Automatic parameterization of parameters is now supported. Specifying a parameterized type with unbound parameters causes them to be implicitly added to the function signature as infer-only parameters.
fn foo[value: SIMD[DType.int32, _]](): pass# Equivalent tofn foo[size: Int, //, value: SIMD[DType.int32, size]](): pass
fn foo[value: SIMD[DType.int32, _]](): pass# Equivalent tofn foo[size: Int, //, value: SIMD[DType.int32, size]](): pass
Mojo can now interpret simple LLVM intrinsics in parameter expressions, enabling things like count_leading_zeros
to work at compile time: Issue #933.
Introduced the @explicit_destroy
annotation, the __disable_del
keyword, the UnknownDestructibility
trait, and the ImplicitlyDestructible
keyword, for the experimental explicitly destroyed types feature.
Added associated types; we can now have aliases like alias T: AnyType
, alias N: Int
, etc. in a trait, and then specify them in structs that conform to that trait. For more information, see Associated aliases for generics.
Introduced a new Deque
(double-ended queue) collection type, based on a dynamically resizing circular buffer for efficient O(1) additions and removals at both ends as well as O(1) direct access to all elements.
The Deque
supports the full Python collections.deque
API, ensuring that all expected deque operations perform as in Python.
Enhancements to the standard Python API include peek()
and peekleft()
methods for non-destructive access to the last and first elements, and advanced constructor options (capacity
, min_capacity
, and shrink
) for customizing memory allocation and performance. These options allow for optimized memory usage and reduced buffer reallocations, providing flexibility based on application requirements.
The Formatter
struct has been replaced with a Writer
trait to enable buffered IO, increasing print and file writing perf to the same speed as C. It's now more general purpose and can write any Span[Byte]
. To align with this the Formattable
trait is now named Writable
, and the String.format_sequence()
static method to initialize a new String
has been renamed to String.write()
. Here's an example of using all of the changes:
from memory import Span@valuestruct NewString(Writer, Writable): var s: String # Writer requirement to write a Span of Bytes fn write_bytes(inout self, bytes: Span[Byte, _]): self.s._iadd[False](bytes) # Writer requirement to take multiple args fn write[*Ts: Writable](inout self, *args: *Ts): @parameter fn write_arg[T: Writable](arg: T): arg.write_to(self) args.each[write_arg]() # Also make it Writable to allow `print` to write the inner String fn write_to[W: Writer](self, inout writer: W): writer.write(self.s)@valuestruct Point(Writable): var x: Int var y: Int # Pass multiple args to the Writer. The Int and StringLiteral types call # `writer.write_bytes` in their own `write_to` implementations. fn write_to[W: Writer](self, inout writer: W): writer.write("Point(", self.x, ", ", self.y, ")") # Enable conversion to a String using `str(point)` fn __str__(self) -> String: return String.write(self)fn main(): var point = Point(1, 2) var new_string = NewString(str(point)) new_string.write("\n", Point(3, 4)) print(new_string)
from memory import Span@valuestruct NewString(Writer, Writable): var s: String # Writer requirement to write a Span of Bytes fn write_bytes(inout self, bytes: Span[Byte, _]): self.s._iadd[False](bytes) # Writer requirement to take multiple args fn write[*Ts: Writable](inout self, *args: *Ts): @parameter fn write_arg[T: Writable](arg: T): arg.write_to(self) args.each[write_arg]() # Also make it Writable to allow `print` to write the inner String fn write_to[W: Writer](self, inout writer: W): writer.write(self.s)@valuestruct Point(Writable): var x: Int var y: Int # Pass multiple args to the Writer. The Int and StringLiteral types call # `writer.write_bytes` in their own `write_to` implementations. fn write_to[W: Writer](self, inout writer: W): writer.write("Point(", self.x, ", ", self.y, ")") # Enable conversion to a String using `str(point)` fn __str__(self) -> String: return String.write(self)fn main(): var point = Point(1, 2) var new_string = NewString(str(point)) new_string.write("\n", Point(3, 4)) print(new_string)
Point(1, 2)Point(3, 4)
Point(1, 2)Point(3, 4)
Python interop changes:
Introduced TypedPythonObject
as a light-weight way to annotate PythonObject
values with static type information. This design will likely evolve and change significantly.
Added Python.add_object()
, to add a named PythonObject
value to a Python 'module' object instance.
Added Python.unsafe_get_python_exception()
, as an efficient low-level utility to get the Mojo Error
equivalent of the current CPython error state.
Add PythonObject.from_borrowed_ptr()
, to simplify the construction of PythonObject
values from CPython 'borrowed reference' pointers.
The existing PythonObject.__init__(PyObjectPtr)
should continue to be used for the more common case of constructing a PythonObject
from a 'strong reference' pointer.
Support for multi-dimensional indexing and slicing for PythonObject
(PR #3549, PR #3583).
var np = Python.import_module("numpy")var a = np.array(PythonObject([1,2,3,4,5,6])).reshape(2,3)print((a[0, 1])) # 2print((a[1][::-1])) # [6 5 4]
var np = Python.import_module("numpy")var a = np.array(PythonObject([1,2,3,4,5,6])).reshape(2,3)print((a[0, 1])) # 2print((a[1][::-1])) # [6 5 4]
Note that the syntax, a[1, ::-1]
, is currently not supported.
Added PythonObject.__contains__()
. (PR #3101)
Example usage:
x = PythonObject([1,2,3])if 1 in x: print("1 in x")
x = PythonObject([1,2,3])if 1 in x: print("1 in x")
Pointer related changes:
The UnsafePointer
type now has an origin
parameter that can be used when the UnsafePointer
points to a value with a known origin. This origin is propagated through the ptr[]
indirection operation. This parameter and other UnsafePointer
parameters (other than the type) are now keyword-only.
You can now index into UnsafePointer
using SIMD
scalar integral types:
p = UnsafePointer[Int].alloc(1)i = UInt8(1)p[i] = 42print(p[i])
p = UnsafePointer[Int].alloc(1)i = UInt8(1)p[i] = 42print(p[i])
Added a new OwnedPointer
type as a safe, single-owner, non-nullable smart pointer with similar semantics to Rust's Box<>
and C++'s std::unique_ptr
. (PR #3524)
Arc
has been renamed to ArcPointer
, for consistency with OwnedPointer
.
ArcPointer
now implements Identifiable
, and can be compared for pointer equivalence using a is b
.
The Reference
type has been renamed to Pointer
: a memory safe complement to UnsafePointer
. This change is motivated by the fact that Pointer
is assignable and requires an explicit dereference with ptr[]
. Renaming to Pointer
clarifies that "references" means ref
arguments and results, and gives us a model that is more similar to what the C++ community would expect.
For an overview of Mojo's pointer types, see the new Intro to pointers page in the Mojo Manual.
A new as_noalias_ptr()
method as been added to UnsafePointer
. This method specifies to the compiler that the resultant pointer is a distinct identifiable object that does not alias any other memory in the local scope.
Added the Floatable
and FloatableRaising
traits to denote types that can be converted to a Float64
value using the builtin float
function. Made SIMD
and FloatLiteral
conform to the Floatable
trait. (PR #3163)
fn foo[F: Floatable](v: F): ...var f = float(Int32(45))
fn foo[F: Floatable](v: F): ...var f = float(Int32(45))
The rebind()
standard library function now works with memory-only types in addition to @register_passable("trivial")
ones, without requiring a copy. For more information, see The rebind()
builtin in the Mojo Manual.
Introduced the random.shuffle()
function for randomizing the elements of a List
. (PR #3327)
Example:
from random import shufflevar l = List[Int](1, 2, 3, 4, 5)shuffle(l)
from random import shufflevar l = List[Int](1, 2, 3, 4, 5)shuffle(l)
The Dict.__getitem__()
method now returns a reference instead of a copy of the value (or raises). This improves the performance of common code that uses Dict
by allowing borrows from the Dict
elements.
Slice.step
is now an Optional[Int]
, matching the optionality of slice.step
in Python. (PR #3160)
There is now a Byte
alias to better express intent when working with a pack of bits. (PR #3670).
Expanded os.path
with new functions:
os.path.expandvars()
: Expands environment variables in a path (PR #3735).
os.path.splitroot()
: Split a path into drive, root and tail. (PR #3780).
Added a reserve()
method and new constructor to the String
struct to allocate additional capacity. (PR #3755).
A new StringLiteral.get[some_stringable]()
method is available. It allows forming a runtime-constant StringLiteral
from a compile-time-dynamic Stringable
value.
Span
has moved from the utils
module to the memory
module.
Span
now implements __reversed__()
. This means that one can get a reverse iterator over a Span
using reversed(my_span)
. Users should currently prefer this method over my_span[::-1]
.
A new AsBytes
trait has been added to enable taking a Span[Byte]
from any type that implements as_bytes()
. String.as_bytes()
and String.as_bytes_slice()
have been consolidated under String.as_bytes()
to return a Span[Byte]
. If you require a copy, you can convert the Span
to a List
with List(my_string.as_bytes())
.
StringSlice
now implements strip()
, rstrip()
, and lstrip()
.
StringRef
now implements split()
which can be used to split a StringRef
into a List[StringRef]
by a delimiter. (PR #2705)
StringRef
is now representable so repr(StringRef("hello"))
will return StringRef('hello')
.
More things have been removed from the auto-exported set of entities in the prelude
module from the Mojo standard library:
Restored implicit copyability of Tuple
and ListLiteral
.
The aliases for C foreign function interface (FFI) have been renamed: C_int
-> c_int
, C_long
-> c_long
and so on.
Float32
and Float64
are now printed and converted to strings with roundtrip guarantee and shortest representation:
Value Old NewFloat64(0.3) 0.29999999999999999 0.3Float32(0.3) 0.30000001192092896 0.3Float64(0.0001) 0.0001 0.0001Float32(0.0001) 9.9999997473787516e-05 0.0001Float64(-0.00001) -1.0000000000000001e-05 -1e-05Float32(-0.00001) -9.9999997473787516e-06 -1e-05Float32(0.00001234) 1.2339999557298142e-05 1.234e-05Float32(-0.00000123456) -1.2345600453045336e-06 -1.23456e-06Float64(1.1234567e-320) 1.1235052786429946e-320 1.1235e-320Float64(1.234 * 10**16) 12340000000000000.0 1.234e+16
Value Old NewFloat64(0.3) 0.29999999999999999 0.3Float32(0.3) 0.30000001192092896 0.3Float64(0.0001) 0.0001 0.0001Float32(0.0001) 9.9999997473787516e-05 0.0001Float64(-0.00001) -1.0000000000000001e-05 -1e-05Float32(-0.00001) -9.9999997473787516e-06 -1e-05Float32(0.00001234) 1.2339999557298142e-05 1.234e-05Float32(-0.00000123456) -1.2345600453045336e-06 -1.23456e-06Float64(1.1234567e-320) 1.1235052786429946e-320 1.1235e-320Float64(1.234 * 10**16) 12340000000000000.0 1.234e+16
The StaticIntTuple
data structure in the utils
package has been renamed to IndexList
. The data structure now allows one to specify the index bitwidth of the elements along with whether the underlying indices are signed or unsigned.
Added DLHandle.get_symbol()
, for getting a pointer to a symbol in a dynamic library. This is more general purpose than the existing methods for getting function pointers.
The VS Code Mojo Debugger now has a buildArgs
JSON debug configuration setting that can be used in conjunction with mojoFile
to define the build arguments when compiling the Mojo file.
The VS Code extension now supports a Configure Build and Run Args
command that helps set the build and run args for actions file Run Mojo File
and Debug Mojo File
. A corresponding button appears in Run and Debug
selector in the top right corner of a Mojo File.
The VS Code extension now has the mojo.run.focusOnTerminalAfterLaunch
setting, which controls whether to focus on the terminal used by the Mojo: Run Mojo File
command or on the editor after launch. Issue #3532.
The VS Code extension now has the mojo.SDK.additionalSDKs
setting, which allows the user to provide a list of MAX SDKs that the extension can use when determining a default SDK to use. The user can select the default SDK to use with the Mojo: Select the default MAX SDK
command.
The VS Code extension now supports setting data breakpoints as well as function breakpoints.
The Mojo LLDB debugger now supports symbol breakpoints, for example, b main
or b my_module::main
.
Error messages that include type names no longer include inferred or defaulted parameters when they aren't needed. For example, previously Mojo complained about things like:
... cannot be converted from 'UnsafePointer[UInt, 0, _default_alignment::AnyType](), MutableAnyOrigin]' to 'UnsafePointer[Int, 0, _default_alignment[::AnyType](), MutableAnyOrigin]'
... cannot be converted from 'UnsafePointer[UInt, 0, _default_alignment::AnyType](), MutableAnyOrigin]' to 'UnsafePointer[Int, 0, _default_alignment[::AnyType](), MutableAnyOrigin]'
it now complains more helpfully that:
... cannot be converted from 'UnsafePointer[UInt]' to 'UnsafePointer[Int]'
... cannot be converted from 'UnsafePointer[UInt]' to 'UnsafePointer[Int]'
Tooling now prints the origins of ref
arguments and results correctly, and prints self
instead of self: Self
in methods.
The Mojo Language Server and generated documentation now print parametric result types correctly, e.g. showing SIMD[type, simd_width]
instead of SIMD[$0, $1]
.
Generated API documentation now shows the signatures for structs, and identifies @register_passable
and @register_passable("trivial")
types.
The VS Code extension now allows cancelling the installation of its private MAX SDK.
The VS Code extension now opens the Run and Debug tab automatically whenever a debug session starts.
The mojo debug --vscode
command now support the --init-command
and --stop-on-entry
flags. Execute mojo debug --help
for more information.
The Mojo LLDB debugger on VS Code now supports inspecting the raw attributes of variables that are handled as synthetic types, e.g. List
from Mojo or std::vector
from C++.
The VS Code extension now allows selecting a default SDK when multiple are available.
Lifetime tracking is now fully field sensitive, which makes the uninitialized variable checker more precise.
Issue #1310 - Mojo permits the use of any constructor for implicit conversions
Issue #1632 - Mojo produces weird error when inout function is used in non mutating function
Issue #3444 - Raising init causing use of uninitialized variable
Issue #3544 - Known mutable ref
argument are not optimized as noalias
by LLVM.
Issue #3559 - VariadicPack doesn't extend the lifetimes of the values it references.
Issue #3627 - Compiler overlooked exclusivity violation caused by ref [MutableAnyOrigin] T
Issue #3710 - Mojo frees memory while reference to it is still in use.
Issue #3805 - Crash When Initializing !llvm.ptr.
Issue #3816 - Ternary if-operator doesn't propagate origin information.
Issue #3815 - [BUG] Mutability not preserved when taking the union of two origins.
Issue #3829 - Poor error message when invoking a function pointer upon an argument of the wrong origin
Issue #3830 - Failures emitting register RValues to ref arguments.
The VS Code extension now auto-updates its private copy of the MAX SDK.
The variadic initializer for SIMD
now works in parameter expressions.
The VS Code extension now downloads its private copy of the MAX SDK in a way that prevents ETXTBSY
errors on Linux.
The VS Code extension now allows invoking a mojo formatter from SDK installations that contain white spaces in their path.