Enable heap only on demand
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dd09bf1..26f3490 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -35,7 +35,7 @@
 
 - connect your device to your computer
 - open a console, e.g. `tockloader listen`
-- run the tests: `PLATFORM=nrf52 cargo rtv7em hardware_test`
+- run the tests: `PLATFORM=nrf52 cargo rtv7em hardware_test --features=alloc`
 
 The expected output on the UART console will be as follows.
 
diff --git a/Cargo.toml b/Cargo.toml
index 53da413..2122490 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,10 +5,13 @@
 license = "MIT/Apache-2.0"
 edition = "2018"
 
+[features]
+alloc = [ "linked_list_allocator" ]
+
 [dependencies]
 core = { package = "async-support", path = "async-support" }
-linked_list_allocator = { version = "=0.6.5", default-features = false }
 libtock_codegen = { path = "codegen" }
+linked_list_allocator = { optional = true, version = "=0.6.5", default-features = false }
 
 [dev-dependencies]
 corepack = { version = "0.4.0", default-features = false, features = ["alloc"] }
@@ -17,6 +20,26 @@
 serde = { version = "=1.0.84", default-features = false, features = ["derive"] }
 futures = { version = "0.3.1", default-features = false, features = ["unstable", "cfg-target-has-atomic"] }
 
+[[example]]
+name = "alloc_error"
+path = "examples-alloc/alloc_error.rs"
+required-features = ["alloc"]
+
+[[example]]
+name = "ble_scanning"
+path = "examples-alloc/ble_scanning.rs"
+required-features = ["alloc"]
+
+[[example]]
+name = "hardware_test"
+path = "examples-alloc/hardware_test.rs"
+required-features = ["alloc"]
+
+[[example]]
+name = "simple_ble"
+path = "examples-alloc/simple_ble.rs"
+required-features = ["alloc"]
+
 [profile.dev]
 panic = "abort"
 lto = true
diff --git a/build_examples.sh b/build_examples.sh
index c094db9..fd67b75 100755
--- a/build_examples.sh
+++ b/build_examples.sh
@@ -3,4 +3,5 @@
 set -eux
 
 PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples
+PLATFORM=nrf52 cargo build --release --target=thumbv7em-none-eabi --examples --features=alloc
 PLATFORM=riscv32 cargo build --release --target=riscv32imc-unknown-none-elf --examples # Important for testing: This target does not support atomics
diff --git a/examples/alloc_error.rs b/examples-alloc/alloc_error.rs
similarity index 100%
rename from examples/alloc_error.rs
rename to examples-alloc/alloc_error.rs
diff --git a/examples/ble_scanning.rs b/examples-alloc/ble_scanning.rs
similarity index 100%
rename from examples/ble_scanning.rs
rename to examples-alloc/ble_scanning.rs
diff --git a/examples/hardware_test.rs b/examples-alloc/hardware_test.rs
similarity index 100%
rename from examples/hardware_test.rs
rename to examples-alloc/hardware_test.rs
diff --git a/examples/simple_ble.rs b/examples-alloc/simple_ble.rs
similarity index 100%
rename from examples/simple_ble.rs
rename to examples-alloc/simple_ble.rs
diff --git a/src/alloc.rs b/src/alloc.rs
new file mode 100644
index 0000000..ee3de18
--- /dev/null
+++ b/src/alloc.rs
@@ -0,0 +1,59 @@
+use crate::drivers;
+use crate::leds::LedsDriver;
+use crate::result::TockResult;
+use crate::timer::Duration;
+use crate::timer::ParallelSleepDriver;
+use core::alloc::GlobalAlloc;
+use core::alloc::Layout;
+use core::executor;
+use core::ptr;
+use core::ptr::NonNull;
+use linked_list_allocator::Heap;
+
+pub static mut HEAP: Heap = Heap::empty();
+
+struct TockAllocator;
+
+unsafe impl GlobalAlloc for TockAllocator {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        HEAP.allocate_first_fit(layout)
+            .ok()
+            .map_or(ptr::null_mut(), NonNull::as_ptr)
+    }
+
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
+    }
+}
+
+#[global_allocator]
+static ALLOCATOR: TockAllocator = TockAllocator;
+
+#[alloc_error_handler]
+unsafe fn alloc_error_handler(_: Layout) -> ! {
+    executor::block_on(async {
+        let mut drivers = drivers::retrieve_drivers_unsafe();
+
+        let leds_driver = drivers.leds.init_driver();
+        let mut timer_driver = drivers.timer.create_timer_driver();
+        let timer_driver = timer_driver.activate();
+
+        if let (Ok(leds_driver), Ok(timer_driver)) = (leds_driver, timer_driver) {
+            let _ = cycle_all_leds(&leds_driver, &timer_driver).await;
+        }
+        loop {}
+    })
+}
+
+async fn cycle_all_leds(
+    leds_driver: &LedsDriver<'_>,
+    timer_driver: &ParallelSleepDriver<'_>,
+) -> TockResult<()> {
+    loop {
+        for led in leds_driver.leds() {
+            led.on()?;
+            timer_driver.sleep(Duration::from_ms(100)).await?;
+            led.off()?;
+        }
+    }
+}
diff --git a/src/entry_point/mod.rs b/src/entry_point/mod.rs
index cc5f402..ae43a19 100644
--- a/src/entry_point/mod.rs
+++ b/src/entry_point/mod.rs
@@ -127,12 +127,13 @@
 
     // we could have also bss_end for app_heap_start
     let app_heap_start = app_heap_break;
-    let app_heap_end = app_heap_break + HEAP_SIZE;
+    let app_heap_end = app_heap_start + HEAP_SIZE;
 
     // Tell the kernel the new app heap break.
     memop::set_brk(app_heap_end as *const u8);
 
-    HEAP.init(app_heap_start, HEAP_SIZE);
+    #[cfg(feature = "alloc")]
+    crate::alloc::HEAP.init(app_heap_start, HEAP_SIZE);
 
     main(0, ptr::null());
 
@@ -140,24 +141,3 @@
         syscalls::raw::yieldk();
     }
 }
-
-use core::alloc::GlobalAlloc;
-use core::alloc::Layout;
-use core::ptr::NonNull;
-use linked_list_allocator::Heap;
-
-static mut HEAP: Heap = Heap::empty();
-
-pub struct TockAllocator;
-
-unsafe impl GlobalAlloc for TockAllocator {
-    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        HEAP.allocate_first_fit(layout)
-            .ok()
-            .map_or(ptr::null_mut(), NonNull::as_ptr)
-    }
-
-    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        HEAP.deallocate(NonNull::new_unchecked(ptr), layout)
-    }
-}
diff --git a/src/lang_items.rs b/src/lang_items.rs
index 69ddf85..bb4bd77 100644
--- a/src/lang_items.rs
+++ b/src/lang_items.rs
@@ -19,12 +19,10 @@
 //! crate.
 
 use crate::drivers;
-use crate::entry_point::TockAllocator;
 use crate::leds::LedsDriver;
 use crate::result::TockResult;
 use crate::timer::Duration;
 use crate::timer::ParallelSleepDriver;
-use core::alloc::Layout;
 use core::executor;
 use core::panic::PanicInfo;
 
@@ -78,35 +76,3 @@
         timer_driver.sleep(Duration::from_ms(100)).await?;
     }
 }
-
-#[global_allocator]
-static ALLOCATOR: TockAllocator = TockAllocator;
-
-#[alloc_error_handler]
-unsafe fn alloc_error_handler(_: Layout) -> ! {
-    executor::block_on(async {
-        let mut drivers = drivers::retrieve_drivers_unsafe();
-
-        let leds_driver = drivers.leds.init_driver();
-        let mut timer_driver = drivers.timer.create_timer_driver();
-        let timer_driver = timer_driver.activate();
-
-        if let (Ok(leds_driver), Ok(timer_driver)) = (leds_driver, timer_driver) {
-            let _ = cycle_all_leds(&leds_driver, &timer_driver).await;
-        }
-        loop {}
-    })
-}
-
-async fn cycle_all_leds(
-    leds_driver: &LedsDriver<'_>,
-    timer_driver: &ParallelSleepDriver<'_>,
-) -> TockResult<()> {
-    loop {
-        for led in leds_driver.leds() {
-            led.on()?;
-            timer_driver.sleep(Duration::from_ms(100)).await?;
-            led.off()?;
-        }
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index e7d9d63..0744a53 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,9 @@
-#![feature(asm, alloc_error_handler, lang_items, naked_functions)]
+#![feature(asm, lang_items, naked_functions)]
+#![cfg_attr(feature = "alloc", feature(alloc_error_handler))]
 #![cfg_attr(any(target_arch = "arm", target_arch = "riscv32"), no_std)]
 
+#[cfg(feature = "alloc")]
+mod alloc;
 mod entry_point;
 #[cfg(any(target_arch = "arm", target_arch = "riscv32"))]
 mod lang_items;