diff --git a/CMakeLists.txt b/CMakeLists.txt
index b5f0ab3a20a80f05f1b8c3064a18390e20756b45..934802709e84bfda69154d4ca65385429f3d0dda 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
 set(LIB_TARGET dusklib)
 set(PROJECT_VERSION 1.0.0)
 project(
-    ${LIB_TARGET}
+    "dusk-lang"
     VERSION ${PROJECT_VERSION}
     DESCRIPTION "Dusk programming language"
 )
@@ -21,7 +21,7 @@ message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
 # link LLVM
 add_definitions(${LLVM_DEFINITIONS})
 include_directories(${LLVM_INCLUDE_DIRS})
-llvm_map_components_to_libnames(llvm_libs support core irreader tablegen)
+llvm_map_components_to_libnames(llvm_libs all)
 
 # add dusklib target
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
diff --git a/examples/funcDecl.dusk b/examples/funcDecl.dusk
index bc8e437aed0beb445da2a77076a8aac20f7edd4c..de1eeace293c4614b880aec750ca0d2489d601df 100644
--- a/examples/funcDecl.dusk
+++ b/examples/funcDecl.dusk
@@ -1,3 +1,5 @@
+extern func test();
+
 func inc(i) -> Int {
     return i + 1;
 }
diff --git a/grammar.txt b/grammar.txt
index 4fdd1aa538ac45a6d1d5dd85d0e36aacae1816cf..7d1e51a403233d69954602db1813c58e61e98626 100644
--- a/grammar.txt
+++ b/grammar.txt
@@ -6,14 +6,13 @@ Program -> Stmt Program                      // 'for', 'while', 'if'
 
 Decl -> 'var' identifier DeclVal ';'         // 'var'
 Decl -> 'let' identifier DeclVal ';'         // 'let'
+Decl -> 'extern' FuncDecl                    // 'extern'
 DeclVal -> '=' Expr                          // '='
 
-// Decl_ -> '[' DeclArray                       // '['
-// DeclArray -> Expr                            // '(', identifier, number_literal, '-'
-// DeclArray -> ']' '=' ArrayLiteral            // ']'
+Func -> FuncDelc Block                       // 'func'
+FuncDecl -> 'func' identifier '(' Args ')' RetType // 'func'
 
-Func -> 'func' identifier '(' Args ')' RetType Block // 'func'
-RetType -> epsilon                           // _ | '{'
+RetType -> epsilon                           // _ | '{', ';'
 RetType -> '->' RetType_                     // '->'
 RetType_ -> 'void'                           // 'Void'
 RetType_ -> 'Int'                            // 'Int'
diff --git a/include/dusk/AST/ASTVisitor.h b/include/dusk/AST/ASTVisitor.h
index 5e84b6ac90cb4e586955201f18cc3ac5b0dbe6e2..af8db936d18d61ead248cfdcfb647039635e82ee 100644
--- a/include/dusk/AST/ASTVisitor.h
+++ b/include/dusk/AST/ASTVisitor.h
@@ -102,6 +102,8 @@ public:
       return getDerived().visit(static_cast<SubscriptStmt *>(S));
     case StmtKind::Block:
       return getDerived().visit(static_cast<BlockStmt *>(S));
+    case StmtKind::Extern:
+      return getDerived().visit(static_cast<ExternStmt *>(S));
     case StmtKind::For:
       return getDerived().visit(static_cast<ForStmt *>(S));
     case StmtKind::Func:
diff --git a/include/dusk/AST/DiagnosticsParse.h b/include/dusk/AST/DiagnosticsParse.h
index ff44661840af99d7fb254f7e61390fd873d68c10..6260c397ee8cd6ee9757e1e541b444cce677e978 100644
--- a/include/dusk/AST/DiagnosticsParse.h
+++ b/include/dusk/AST/DiagnosticsParse.h
@@ -38,7 +38,8 @@ enum struct DiagID : unsigned {
   expected_r_bracket,
   expected_r_brace,
   expected_return_type,
-  expected_type_specifier
+  expected_type_specifier,
+  expected_func_kw
 };
 
 static StringRef getTextForID(DiagID ID) {
@@ -80,6 +81,8 @@ static StringRef getTextForID(DiagID ID) {
       return "Expected '->' return type decalration";
   case DiagID::expected_type_specifier:
       return "Expected type specifier";
+  case DiagID::expected_func_kw:
+    return "Expected 'func' keyword to at start of function delaration";
   }
 }
 
diff --git a/include/dusk/AST/Stmt.h b/include/dusk/AST/Stmt.h
index 6cdc2fc8aa5dca3f62fd6a852c4a510c009fe38f..ac10dca241be6565efd8190d6dee28ce00b7c31b 100644
--- a/include/dusk/AST/Stmt.h
+++ b/include/dusk/AST/Stmt.h
@@ -30,6 +30,7 @@ enum struct StmtKind {
   Break,
   Return,
   Range,
+  Extern,
   Block,
   Func,
   For,
@@ -139,6 +140,22 @@ public:
   virtual SMRange getSourceRange() const override;
 };
 
+class ExternStmt : public Stmt {
+  /// Location of extern keyword
+  SMLoc ExternLoc;
+
+  /// Function prototype
+  Decl *Prototype;
+
+public:
+  ExternStmt(SMLoc EL, Decl *P);
+
+  SMLoc getExternLoc() const { return ExternLoc; }
+  Decl *getPrototype() const { return Prototype; }
+
+  virtual SMRange getSourceRange() const override;
+};
+
 /// Represents a Function statement a.k.a declaration and definition.
 class FuncStmt : public Stmt {
   Decl *Prototype;
diff --git a/include/dusk/Basic/TokenDefinition.h b/include/dusk/Basic/TokenDefinition.h
index 7750360be620e7841fc90357ca341396b423a3bb..52639936844c6fa28198ee8309ae022f0003ccc0 100644
--- a/include/dusk/Basic/TokenDefinition.h
+++ b/include/dusk/Basic/TokenDefinition.h
@@ -27,8 +27,9 @@ enum struct tok {
   kwFor,
   kwIn,
   kwFunc,
-  kwWriteln,
+  kwPrintln,
   kwReadln,
+  kwExtern,
   
   // Types
   kwVoid,
@@ -112,10 +113,12 @@ inline raw_ostream &operator<<(raw_ostream &OS, const dusk::tok &T) {
     return OS << "in";
   case dusk::tok::kwFunc:
     return OS << "func";
-  case dusk::tok::kwWriteln:
+  case dusk::tok::kwPrintln:
     return OS << "writeln";
   case dusk::tok::kwReadln:
     return OS << "readln";
+  case dusk::tok::kwExtern:
+    return OS << "extern";
       
   // Types
   case dusk::tok::kwVoid:
diff --git a/include/dusk/Frontend/Compiler.h b/include/dusk/Frontend/Compiler.h
index ed230f491431aeb86cf4d96fd64d5714144d4a07..57d4cadbd4932c68940034e7c695f04b5a29e9d1 100644
--- a/include/dusk/Frontend/Compiler.h
+++ b/include/dusk/Frontend/Compiler.h
@@ -20,6 +20,10 @@
 #include <vector>
 #include <memory>
 
+namespace llvm {
+class Module;
+}
+
 namespace dusk {
 class ParserResult;
 
diff --git a/include/dusk/IRGen/IRGenerator.h b/include/dusk/IRGen/IRGenerator.h
index cd561a86dc7abf518cd921e2138517775139c152..50e15ec981926110561d6e48fd18f652b39b865a 100644
--- a/include/dusk/IRGen/IRGenerator.h
+++ b/include/dusk/IRGen/IRGenerator.h
@@ -51,7 +51,7 @@ public:
   IRGenerator(DiagnosticEngine &Diag);
   ~IRGenerator();
   
-  bool gen(ModuleDecl *M);
+  llvm::Module *gen(ModuleDecl *M);
   
 private:
     bool prepareGlobals(Context &Ctx, ModuleDecl *M);
diff --git a/include/dusk/Parse/Parser.h b/include/dusk/Parse/Parser.h
index 3c3873d254fc1a471f310d22c5131cd1f9d2a667..8428099c35dcd9be945d82d5240e3a7a97f53e92 100644
--- a/include/dusk/Parse/Parser.h
+++ b/include/dusk/Parse/Parser.h
@@ -147,6 +147,7 @@ private:
   
   Stmt *parseSubscriptStmt();
 
+  Stmt *parseExterStmt();
   Stmt *parseFuncStmt();
 
   Stmt *parseForStmt();
diff --git a/include/dusk/Parse/Token.h b/include/dusk/Parse/Token.h
index 7689faa2a2afcb06a3c21a8df210f82b1dc2057c..1dbb0fcf44817dd6c39ab6afc2a2d0fda8b2771e 100644
--- a/include/dusk/Parse/Token.h
+++ b/include/dusk/Parse/Token.h
@@ -114,6 +114,7 @@ public:
     switch (Kind) {
     case tok::kwVar:
     case tok::kwLet:
+        
     case tok::kwBreak:
     case tok::kwReturn:
     case tok::kwIf:
@@ -122,10 +123,13 @@ public:
     case tok::kwFor:
     case tok::kwIn:
     case tok::kwFunc:
-    case tok::kwWriteln:
+    case tok::kwPrintln:
     case tok::kwReadln:
+    case tok::kwExtern:
+        
     case tok::kwVoid:
     case tok::kwInt:
+        
       return true;
     default:
       return false;
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index ee7a3abff041dc9e6e34cadfee18ed85a0864cc1..2bf63462e0f127f56ac17e13524c1a31a6c1ae63 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -199,6 +199,23 @@ public:
     return true;
   }
 
+  bool visit(ExternStmt *S) {
+    Printer.printStmtPre(S);
+    Printer << tok::kwExtern << " ";
+    super::visit(S->getPrototype());
+    Printer.printStmtPost(S);
+    return true;
+  }
+  
+  bool visit(FuncStmt *S) {
+    Printer.printStmtPre(S);
+    super::visit(S->getPrototype());
+    Printer << " ";
+    super::visit(S->getBody());
+    Printer.printStmtPost(S);
+    return true;
+  }
+  
   bool visit(ForStmt *S) {
     Printer.printStmtPre(S);
 
@@ -213,15 +230,6 @@ public:
     return true;
   }
 
-  bool visit(FuncStmt *S) {
-    Printer.printStmtPre(S);
-    super::visit(S->getPrototype());
-    Printer << " ";
-    super::visit(S->getBody());
-    Printer.printStmtPost(S);
-    return true;
-  }
-
   bool visit(IfStmt *S) {
     Printer.printStmtPre(S);
     Printer << tok::kwIf << " ";
@@ -286,21 +294,21 @@ public:
     tok KW;
     switch (D->getKind()) {
     case DeclKind::Let:
+      if (!isAtStartOfLine())
+        printNewline();
       KW = tok::kwLet;
       break;
     case DeclKind::Var:
+      if (!isAtStartOfLine())
+        printNewline();
       KW = tok::kwVar;
       break;
     case DeclKind::Func:
       KW = tok::kwFunc;
-      printNewline();
       break;
     default:
       return;
     }
-
-    if (!isAtStartOfLine())
-      printNewline();
     *this << KW << " ";
   }
 
@@ -320,8 +328,13 @@ public:
       *this << tok::l_brace;
       ++(*this);
       break;
-    case StmtKind::For:
+    case StmtKind::Extern:
     case StmtKind::Func:
+      if (!isAtStartOfLine())
+        printNewline();
+      printNewline();
+      break;
+    case StmtKind::For:
     case StmtKind::If:
     case StmtKind::While:
       if (!isAtStartOfLine())
@@ -343,6 +356,7 @@ public:
       break;
     case StmtKind::Break:
     case StmtKind::Return:
+    case StmtKind::Extern:
       *this << ";";
       break;
     case StmtKind::Subscript:
diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp
index 4d4cd412992ebfb052c1a392900d4a140e0692d5..90a1b812f273dcab3c316117cbde5e2b8db6a6ea 100644
--- a/lib/AST/ASTWalker.cpp
+++ b/lib/AST/ASTWalker.cpp
@@ -230,24 +230,34 @@ public:
     return Walker.postWalk(S);
   }
 
-  bool visit(ForStmt *S) {
+  bool visit(ExternStmt *S) {
     // Skip subtree
     if (!Walker.preWalk(S))
+      return true;
+    
+    if (!super::visit(S->getPrototype()))
       return false;
-
-    if (!super::visit(S->getRange()))
+    return Walker.postWalk(S);
+  }
+  
+  bool visit(FuncStmt *S) {
+    // Skip subtree
+    if (!Walker.preWalk(S))
+      return true;
+    
+    if (!super::visit(S->getPrototype()))
       return false;
     if (!super::visit(S->getBody()))
       return false;
     return !Walker.postWalk(S);
   }
-
-  bool visit(FuncStmt *S) {
+  
+  bool visit(ForStmt *S) {
     // Skip subtree
     if (!Walker.preWalk(S))
-      return true;
+      return false;
 
-    if (!super::visit(S->getPrototype()))
+    if (!super::visit(S->getRange()))
       return false;
     if (!super::visit(S->getBody()))
       return false;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 522922d2ce924014bf4ffe42e70b3c6bac4c9878..d8c988379fe01a0cdedea57c26b313d858418839 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -53,6 +53,15 @@ BlockStmt::BlockStmt(SMLoc S, SMLoc E, std::vector<ASTNode *> &&N)
 
 SMRange BlockStmt::getSourceRange() const { return {BlockStart, BlockEnd}; }
 
+// MARK: - Extern statement
+
+ExternStmt::ExternStmt(SMLoc EL, Decl *P)
+    : Stmt(StmtKind::Extern), ExternLoc(EL), Prototype(P) {}
+
+SMRange ExternStmt::getSourceRange() const {
+  return { ExternLoc, Prototype->getSourceRange().End };
+}
+
 // MARK: - Funcion statement
 
 FuncStmt::FuncStmt(Decl *FP, Stmt *B)
diff --git a/lib/Frontend/Compiler.cpp b/lib/Frontend/Compiler.cpp
index cf51e042303d668b0ec53bdc84d21d2487181bf4..18b7851df1bb2cc18b1deea108a4be74df29e37f 100644
--- a/lib/Frontend/Compiler.cpp
+++ b/lib/Frontend/Compiler.cpp
@@ -6,6 +6,21 @@
 #include "dusk/IRGen/IRGenerator.h"
 #include "llvm/Support/raw_os_ostream.h"
 
+#include "llvm/Analysis/Passes.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
+#include "llvm/ExecutionEngine/Interpreter.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
+
 #include <iostream>
 #include <vector>
 
@@ -33,11 +48,16 @@ void Compiler::Compile() {
       return;
     Results.push_back(std::move(R));
   }
-//
+
 //  for (auto &&R : Results)
 //    F.format(R.getRoot(), OS);
   irgen::IRGenerator IRGen(Engine);
-  IRGen.gen(Results.front().getRoot());
+  auto Module = IRGen.gen(Results.front().getRoot());
+  if (!Module)
+    return;
+  
+  Module->print(llvm::errs(), nullptr);
+  llvm::verifyModule(*Module);
   std::cout << std::endl;
 }
 
diff --git a/lib/IRGen/GenStmt.cpp b/lib/IRGen/GenStmt.cpp
index 864cfac9921499bedc9e4217a92d934d7d7d1ee6..7f229ea0297a405b319ad2a342a7928c296c442e 100644
--- a/lib/IRGen/GenStmt.cpp
+++ b/lib/IRGen/GenStmt.cpp
@@ -148,6 +148,8 @@ bool irgen::codegenStmt(Context &Ctx, Scope &Scp, Stmt *S) {
       return codegenStmt(Ctx, Scp, static_cast<WhileStmt *>(S));
     case StmtKind::If:
       return codegenStmt(Ctx, Scp, static_cast<IfStmt *>(S));
+    case StmtKind::Extern:
+      return true;
     case StmtKind::Subscript:
       llvm_unreachable("Not implemented yet");
   }
diff --git a/lib/IRGen/IRGenerator.cpp b/lib/IRGen/IRGenerator.cpp
index 3f5971714f49373b21482b2e5a4de207dedf5833..55bb3ddcedc1e3236226cb26a5bf1b1e2ca40701 100644
--- a/lib/IRGen/IRGenerator.cpp
+++ b/lib/IRGen/IRGenerator.cpp
@@ -27,7 +27,7 @@ IRGenerator::~IRGenerator() {}
 
 
 
-bool IRGenerator::gen(ModuleDecl *M) {
+llvm::Module *IRGenerator::gen(ModuleDecl *M) {
   Module = std::make_unique<llvm::Module>(M->getName(), Ctx);
   Context Ctx(this->Ctx, Module.get(), Builder);
   Scope Scp;
@@ -44,10 +44,9 @@ bool IRGenerator::gen(ModuleDecl *M) {
       llvm_unreachable("Unexpected node");
     
     if (!R)
-      return false;
+      return nullptr;
   }
-  Module->print(llvm::errs(), nullptr);
-  return true;
+  return Module.release();
 }
 
 bool IRGenerator::prepareGlobals(Context &Ctx, ModuleDecl *M) {
@@ -58,6 +57,9 @@ bool IRGenerator::prepareGlobals(Context &Ctx, ModuleDecl *M) {
     if (auto Fn = dynamic_cast<FuncStmt *>(N))
       if (!codegenDecl(Ctx, Fn->getPrototype()))
         return false;
+    if (auto Fn = dynamic_cast<ExternStmt *>(N))
+      if (!codegenDecl(Ctx, Fn->getPrototype()))
+        return false;
   }
   return true;
 }
diff --git a/lib/Parser/Lexer.cpp b/lib/Parser/Lexer.cpp
index 219f9cb83cb22c64d9a43c78dfe953b178444f09..3041ff5aad6ab827f9fb491df14b05d0ad1274bb 100644
--- a/lib/Parser/Lexer.cpp
+++ b/lib/Parser/Lexer.cpp
@@ -286,8 +286,9 @@ tok Lexer::kindOfIdentifier(StringRef Str) {
       .Case("for", tok::kwFor)
       .Case("in", tok::kwIn)
       .Case("func", tok::kwFunc)
-      .Case("writeln", tok::kwWriteln)
+      .Case("println", tok::kwPrintln)
       .Case("readln", tok::kwReadln)
+      .Case("extern", tok::kwExtern)
       .Case("Void", tok::kwVoid)
       .Case("Int", tok::kwInt)
       .Default(tok::identifier);
diff --git a/lib/Parser/ParseDecl.cpp b/lib/Parser/ParseDecl.cpp
index 3fc8f854795899791b2a2f7c7c94167a44cce9c3..807d8144671545eb4c0ee4077fc2d2c37f7ad726 100644
--- a/lib/Parser/ParseDecl.cpp
+++ b/lib/Parser/ParseDecl.cpp
@@ -92,7 +92,7 @@ Decl *Parser::parseFuncDecl() {
 ///     '->' 'Int' | 'Void'
 FuncRetType *Parser::parseFuncDeclType() {
   // Implicit return type is `Void`
-  if (Tok.is(tok::l_brace))
+  if (Tok.isAny(tok::l_brace, tok::semicolon))
     return nullptr;
   
   if (!consumeIf(tok::arrow)) {
diff --git a/lib/Parser/ParseStmt.cpp b/lib/Parser/ParseStmt.cpp
index c89eac58fa119d61b092a048a4702ba7464424aa..b1349512ab05df261ca5d8a223864dfcf3747c76 100644
--- a/lib/Parser/ParseStmt.cpp
+++ b/lib/Parser/ParseStmt.cpp
@@ -159,15 +159,38 @@ ASTNode *Parser::parseBlockBody() {
   }
 }
 
+/// ExternStmt ::=
+///     'extern' 'func' indentifier
+Stmt *Parser::parseExterStmt() {
+  // Validate `exter` keyword
+  assert(Tok.is(tok::kwExtern) && "Invalid parse method");
+  auto EL = consumeToken();
+  if (Tok.isNot(tok::kwFunc)) {
+    diagnose(Tok.getLoc(), diag::DiagID::expected_func_kw)
+    .fixItBefore("func", Tok.getLoc());
+    return nullptr;
+  }
+  
+  auto D = make<ExternStmt>(EL, parseFuncDecl());
+  if (consumeIf(tok::semicolon))
+    return D;
+
+  diagnose(Tok.getLoc(), diag::DiagID::expected_semicolon)
+    .fixItBefore(";", Tok.getLoc());
+  return nullptr;
+}
+
+/// FuncStmt ::=
+///     'func' identifier '(' Args ')' RetType Block
 Stmt *Parser::parseFuncStmt() {
   // Validate `func` keyword
   assert(Tok.is(tok::kwFunc) && "Invalid parse method");
   auto D = parseFuncDecl();
   if (Tok.is(tok::l_brace))
     return make<FuncStmt>(D, parseBlock());
+  
   diagnose(Tok.getLoc(), diag::DiagID::expected_l_brace)
     .fixIt("{", Tok.getLoc());
-  
   return nullptr;
 }
 
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index 05a273fa1cc0c289b0c04074bee0ff2835402d72..42e6bd07db7c7d0a90ca27a237699f8f485482ea 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -69,6 +69,8 @@ ASTNode *Parser::parseGlobal() {
     return parseVarDecl();
   case tok::kwLet:
     return parseConstDecl();
+  case tok::kwExtern:
+    return parseExterStmt();
   case tok::kwFunc:
     return parseFuncStmt();
   case tok::kwFor: