diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab4c44a2b556aa013c3f41c39783f89a94643246..1e812a7cb4c03a6cb43d45b66689b17c6379149b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,14 +16,13 @@ add_compile_definitions(
         RUNTIME_LOG_LEVEL=spdlog::level::${LOG_LEVEL_LOWER}
 )
 
-
 add_executable(CTUApex
         src/main.cpp
         src/CTUApexAction.cpp
         src/CTUApexConsumer.cpp
         src/CTUApexVisitor.cpp
         src/Util.cpp
-        src/IncludeFinder.cpp
+        src/PreprocessorExtract.cpp
         src/GlobalsMarker.cpp
         )
 
diff --git a/include/CTUApexAction.h b/include/CTUApexAction.h
index 3a024865b79be978f818aebbdb36860d5ba12d89..990878f81ae8c05e8b61d329444195f783bd8b58 100644
--- a/include/CTUApexAction.h
+++ b/include/CTUApexAction.h
@@ -7,6 +7,7 @@
 
 #include <clang/Frontend/FrontendAction.h>
 #include <Callgraph.h>
+#include "PreprocessorExtract.h"
 
 class CTUApexAction : public clang::ASTFrontendAction {
 public:
@@ -18,6 +19,9 @@ public:
     CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile);
 
 private:
+    std::vector<ExtractionBlock> includes;
+    std::vector<ExtractionBlock> macros;
+    std::vector<ExtractionBlock> pragmas;
     metacg::Callgraph *call_graph;
     std::string output_text;
 };
diff --git a/include/CTUApexConsumer.h b/include/CTUApexConsumer.h
index 0f2fd629bc4c02974ce14d2104a2083823529bad..cd41f28a9b4b88662c4541a08b3d6ff8a5e76f04 100644
--- a/include/CTUApexConsumer.h
+++ b/include/CTUApexConsumer.h
@@ -13,24 +13,39 @@
 #include "clang/Lex/Lexer.h"
 #include "GlobalsMarker.h"
 #include "CTUApexAction.h"
-#include "IncludeFinder.h"
+#include "ExtractionBlock.h"
+
 
 class CTUApexConsumer : public clang::ASTConsumer {
 public:
-    explicit CTUApexConsumer(IncludeFinder* includes,metacg::Callgraph *call_graph)
-            : completedIncludeFinder(includes), call_graph(call_graph) {}
+    explicit CTUApexConsumer(metacg::Callgraph *call_graph, std::vector<ExtractionBlock> &includes,
+                             std::vector<ExtractionBlock> &macros, std::vector<ExtractionBlock>& pragmas)
+            : call_graph(call_graph), includes(includes), macros(macros), pragmas(pragmas) {
+    }
+
+
+    void outlineFunctions();
+    void outlineGlobals();
 
-    std::string outline(metacg::Callgraph &cg);
+    std::string mergeSorted();
 
     virtual void HandleTranslationUnit(clang::ASTContext &Context);
 
 private:
-    void addCalleesToSet(std::unordered_set<clang::Decl *> &set, size_t nodeID, const metacg::Callgraph &cg);
 
-    std::unordered_set<clang::Decl *> getCutout(metacg::Callgraph &cg);
+    std::vector<ExtractionBlock> funcs;
+    std::vector<ExtractionBlock> globals;
 
-    IncludeFinder* completedIncludeFinder; //not owned
     std::vector<clang::CallExpr *> calls;
-    metacg::Callgraph *call_graph;  // not owned
+    // not owned
+    metacg::Callgraph *call_graph;
+    std::vector<ExtractionBlock>& includes;
+    std::vector<ExtractionBlock>& macros;
+    std::vector<ExtractionBlock>& pragmas;
+
+    ExtractionBlock getNextExtractionBlock();
+
+    void getAvailableFunctions(metacg::Callgraph callgraph);
 };
+
 #endif //CTUAPEX_CTUAPEXCONSUMER_H
diff --git a/include/ExtractionBlock.h b/include/ExtractionBlock.h
new file mode 100644
index 0000000000000000000000000000000000000000..64d235140222bbae9eeff56de348457ed2ddbab4
--- /dev/null
+++ b/include/ExtractionBlock.h
@@ -0,0 +1,20 @@
+//
+// Created by tim on 02.01.24.
+//
+
+#ifndef CTUAPEX_EXTRACTIONBLOCK_H
+#define CTUAPEX_EXTRACTIONBLOCK_H
+struct ExtractionBlock {
+    ExtractionBlock()=default;
+
+    ExtractionBlock(clang::SourceLocation b, clang::SourceLocation e, std::string c) {
+        begin = b;
+        end = e;
+        contents = c;
+    }
+
+    clang::SourceLocation begin;
+    clang::SourceLocation end;
+    std::string contents;
+};
+#endif //CTUAPEX_EXTRACTIONBLOCK_H
diff --git a/include/ExtractionMetadata.h b/include/ExtractionMetadata.h
index 6e0d32b4ecca1ec14643ffdfed806da45bbf7dc0..ad733425316c25fe8bd765b65598c3a2a7143fa4 100644
--- a/include/ExtractionMetadata.h
+++ b/include/ExtractionMetadata.h
@@ -32,6 +32,7 @@ public:
     clang::FunctionDecl *get_decl_node() const {return mappedDecl;};
 
     bool isMarkedToExtract(){return extract;};
+    void setMarkedToExtract(bool shouldExtract){extract=shouldExtract;}
 private:
     clang::FunctionDecl* mappedDecl= nullptr;
     bool extract=false;
diff --git a/include/IncludeFinder.h b/include/IncludeFinder.h
deleted file mode 100644
index fa4c854e439cf38d722da953e5fc46d03c91b7f3..0000000000000000000000000000000000000000
--- a/include/IncludeFinder.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// Created by tim on 21.12.23.
-//
-
-#ifndef CTUAPEX_INCLUDEFINDER_H
-#define CTUAPEX_INCLUDEFINDER_H
-
-#include <clang/Lex/PPCallbacks.h>
-#include <clang/Lex/Lexer.h>
-#include <spdlog/spdlog.h>
-
-class IncludeFinder : public clang::PPCallbacks {
-public:
-    IncludeFinder(clang::SourceManager &sm) : sourceManager(sm) {}
-
-    inline std::unique_ptr<clang::PPCallbacks> createPreprocessorCallbacks() {
-        SPDLOG_INFO("Collecting include statements");
-        return std::make_unique<IncludeFinder>(*this);
-    }
-
-    inline void InclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
-                                   clang::StringRef FileName, bool IsAngled,
-                                   clang::CharSourceRange FilenameRange,
-                                   clang::Optional<clang::FileEntryRef> File,
-                                   clang::StringRef SearchPath, clang::StringRef RelativePath,
-                                   const clang::Module *Imported,
-                                   clang::SrcMgr::CharacteristicKind FileType) override {
-        //Note: we currently exclude headers only by name, we could also compare them according to their sourcerange
-        if (sourceManager.isInMainFile(HashLoc)) {
-            includes.emplace_back(HashLoc, FilenameRange.getEnd(), FileName.str());
-        }
-    };
-
-
-    void Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override;
-
-    inline void PragmaDirective(clang::SourceLocation Loc,
-                                clang::PragmaIntroducerKind Introducer) override;
-
-    struct PreprocessorExtract {
-        PreprocessorExtract(clang::SourceLocation b, clang::SourceLocation e, std::string c) : begin(b), end(e),
-                                                                                               contents(std::move(c)) {}
-
-        clang::SourceLocation begin;
-        clang::SourceLocation end;
-        std::string contents;
-    };
-
-    std::string name;
-    std::vector<PreprocessorExtract> includes;
-    std::vector<PreprocessorExtract> macros;
-    clang::SourceManager &sourceManager;
-};
-
-#endif //CTUAPEX_INCLUDEFINDER_H
diff --git a/include/PreprocessorExtract.h b/include/PreprocessorExtract.h
new file mode 100644
index 0000000000000000000000000000000000000000..01fab77ae84ce7b062bde18f1b610bc05a4001a8
--- /dev/null
+++ b/include/PreprocessorExtract.h
@@ -0,0 +1,56 @@
+//
+// Created by tim on 21.12.23.
+//
+
+#ifndef CTUAPEX_PREPROCESSOREXTRACT_H
+#define CTUAPEX_PREPROCESSOREXTRACT_H
+
+#include <clang/Lex/PPCallbacks.h>
+#include <clang/Lex/Lexer.h>
+#include <spdlog/spdlog.h>
+
+#include <utility>
+
+#include "iostream"
+
+#include "ExtractionBlock.h"
+
+class PreprocessorExtract : public clang::PPCallbacks {
+public:
+    PreprocessorExtract(clang::SourceManager &sm, std::vector<ExtractionBlock> &includes,
+                        std::vector<ExtractionBlock> &macros, std::vector<ExtractionBlock> &pragmas) : sourceManager(
+            sm), includes(includes), macros(macros), pragmas(pragmas) {}
+
+    inline void InclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
+                                   clang::StringRef FileName, bool IsAngled,
+                                   clang::CharSourceRange FilenameRange,
+                                   clang::Optional<clang::FileEntryRef> File,
+                                   clang::StringRef SearchPath, clang::StringRef RelativePath,
+                                   const clang::Module *Imported,
+                                   clang::SrcMgr::CharacteristicKind FileType) override;
+
+    void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
+            ConditionValueKind ConditionValue) override;
+
+    void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+               const clang::MacroDefinition &MD) override;
+
+    void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+               const clang::MacroDefinition &MD) override;
+
+    void Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override;
+
+    inline void PragmaDirective(clang::SourceLocation Loc,
+                                clang::PragmaIntroducerKind Introducer) override;
+
+private:
+    std::vector<ExtractionBlock> &includes;
+    std::vector<ExtractionBlock> &macros;
+    std::vector<ExtractionBlock> &pragmas;
+    //FixMe: make macroBeginStack with beginSourceLoc to save space
+    std::stack<ExtractionBlock> macroNestingStack;
+    clang::SourceManager &sourceManager;
+
+};
+
+#endif //CTUAPEX_PREPROCESSOREXTRACT_H
diff --git a/include/Util.h b/include/Util.h
index 5210552c2745c7cef7bda6686957b0d8ff616a2a..db77ae161e92e404204787ff0822274d83e19423 100644
--- a/include/Util.h
+++ b/include/Util.h
@@ -44,6 +44,7 @@ inline bool contains(const C &c, const T &val) {
     return std::find(c.begin(), c.end(), val) != c.end();
 }
 
+/*
 template <typename T>
 std::string col2str(const T &col, const std::string &prefix = "", const std::string &split = ",",
                     const std::string &suffix = ""){
@@ -56,28 +57,21 @@ std::string col2str(const T &col, const std::string &prefix = "", const std::str
     ret += suffix;
     return ret;
 }
+*/
+template<typename T>
+std::string col2str(const T &col, const std::string &prefix = "", const std::string &split = ",",
+                    const std::string &suffix = "", std::string (*transformer)(
+        typename std::remove_reference<decltype(*std::declval<T>().begin())>::type) = [](
+        typename std::remove_reference<decltype(*std::declval<T>().begin())>::type t) -> std::string { return t; }) {
+    std::string ret = prefix;
 
-template <typename T>
-std::string col2str(const T &col, std::string (*transformer)(typename std::remove_reference< decltype( *std::declval<T>().begin() ) >::type), const std::string &prefix = "", const std::string &split = ",",
-                    const std::string &suffix = ""){
-    std::cout<<__LINE__<<"\n";
-    std::string ret=prefix;
-    auto begin=col.begin();
-    std::cout<<__LINE__<<"\n";
-    auto end=std::prev(col.end());
-    std::cout<<__LINE__<<"\n";
-    for (; begin != end; begin++) {
-        std::cout<<__LINE__<<"\n";
+    for (auto begin = col.begin(), end = std::prev(col.end()); begin != end; begin++) {
         ret += transformer(*begin);
-        std::cout<<__LINE__<<"\n";
         ret += split;
-        std::cout<<__LINE__<<"\n";
     }
-    std::cout<<__LINE__<<"\n";
-    ret += transformer(*col.end());
-    std::cout<<__LINE__<<"\n";
+    ret += transformer(col.back());
+
     ret += suffix;
-    std::cout<<__LINE__<<"\n";
     return ret;
 }
 
diff --git a/src/CTUApexAction.cpp b/src/CTUApexAction.cpp
index e449c0681122ba2c11bc61785cbf2352b581af25..8c4b9261065c634de84f92950dd1622be117ffe4 100644
--- a/src/CTUApexAction.cpp
+++ b/src/CTUApexAction.cpp
@@ -4,11 +4,10 @@
 
 #include "CTUApexConsumer.h"
 #include <clang/Frontend/CompilerInstance.h>
-#include "IncludeFinder.h"
 
 std::unique_ptr<clang::ASTConsumer>
 CTUApexAction::CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
-    IncludeFinder includeFinder(Compiler.getSourceManager());
-    Compiler.getPreprocessor().addPPCallbacks(includeFinder.createPreprocessorCallbacks());
-    return std::make_unique<CTUApexConsumer>(&includeFinder, call_graph);
+    std::unique_ptr<PreprocessorExtract> includeFinder = std::make_unique<PreprocessorExtract>(Compiler.getSourceManager(), includes, macros, pragmas);
+    Compiler.getPreprocessor().addPPCallbacks(std::move(includeFinder));
+    return std::make_unique<CTUApexConsumer>(call_graph,includes,macros,pragmas);
 }
\ No newline at end of file
diff --git a/src/CTUApexConsumer.cpp b/src/CTUApexConsumer.cpp
index c19d7fe846b3a2cb3e5c3705b8b0d00fb9c558c2..6c979368cb07b5db4525943b9aec5c19719972c5 100644
--- a/src/CTUApexConsumer.cpp
+++ b/src/CTUApexConsumer.cpp
@@ -8,122 +8,148 @@
 #include "llvm/Demangle/Demangle.h"
 #include "FunctionFinderVisitor.h"
 
-std::unordered_set<clang::Decl *> CTUApexConsumer::getCutout(metacg::Callgraph &cg) {
-    std::unordered_set<clang::Decl *> retSet;
-    std::unordered_set<size_t> entryNodes;
-    for (const auto &node: cg.getNodes()) {
-        if (node.second->has<ExtractionMetadata>() && node.second->get<ExtractionMetadata>()->isMarkedToExtract())
-            entryNodes.insert(node.first);
-    }
-
-    for (auto id: entryNodes) {
-        addCalleesToSet(retSet, id, cg);
-    }
-
-    std::cout << "Cutout for this TU is:\n";
-    for (auto &elem: retSet) {
-        std::cout << clang::cast<clang::FunctionDecl>(elem)->getNameAsString() << "\n";
-    }
-    std::cout << std::flush;
-    return retSet;
-
-
-}
-
-std::string CTUApexConsumer::outline(metacg::Callgraph &cg) {
-    //TODO: Move this so its only computed once for each run, not once for each file
-    SPDLOG_INFO("Compute set of functions to be extracted");
-
-    std::unordered_set<clang::Decl *> availableFunctionDecls;
-    for (const auto &node: cg.getNodes()) {
-        if (node.second->has<ExtractionMetadata>() && node.second->get<ExtractionMetadata>()->isMarkedToExtract()) {
-            if (node.second->get<ExtractionMetadata>()->get_decl_node() == nullptr) {
-                std::cout << "node " << node.second->getFunctionName()
-                          << " was marked to extract but is not part of this TU\n";
-            } else {
-                auto functionDecl = node.second->get<ExtractionMetadata>()->get_decl_node();
-                availableFunctionDecls.insert(functionDecl);
+void CTUApexConsumer::outlineFunctions() {
+    for (const auto &node: call_graph->getNodes()) {
+        if (auto md = node.second->checkAndGet<ExtractionMetadata>(); md.first && md.second->get_decl_node()) {
+            ExtractionBlock eb;
+            clang::SourceRange sourceRange = md.second->get_decl_node()->getSourceRange();
+            eb.begin = sourceRange.getBegin();
+            eb.end = sourceRange.getEnd();
+            if(md.second->isMarkedToExtract()){
+                //std::cout<<"Need to extract: "<<md.second->get_decl_node()->getNameAsString()<<"\n";
+                eb.contents = clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(sourceRange),
+                                                          md.second->get_decl_node()->getASTContext().getSourceManager(),
+                                                          clang::LangOptions(),
+                                                          nullptr).str();
+            }else{
+                //std::cout<<"Not extracting: "<<md.second->get_decl_node()->getNameAsString()<<"\n";
+                eb.contents="";
             }
-            addCalleesToSet(availableFunctionDecls, node.first, cg);
+            funcs.push_back(eb);
         }
     }
 
-    std::cout << "Function marked to be extracted from this TU:\n";
-    for (auto &elem: availableFunctionDecls) {
-        std::cout << clang::cast<clang::FunctionDecl>(elem)->getNameAsString() << "\n";
-    }
+    //the callgraph nodes are unsorted, we need to sort the extraction blocks afterward
+    std::sort(funcs.begin(),funcs.end(),[](const ExtractionBlock& a, const ExtractionBlock& b){return a.begin<b.begin;});
+}
 
+void CTUApexConsumer::outlineGlobals() {
     //Fixme: does this need to extract cross TU as well?
     SPDLOG_INFO("Compute set of used globals");
     std::unordered_set<clang::Decl *> availableGlobals;
-    for (const auto &node: availableFunctionDecls) {
-        assert(clang::isa<clang::FunctionDecl>(node) &&
-               "Extractionset should only contain function decls at this point");
-        GlobalsMarker gMarker;
-        auto func_set = gMarker.get_nodes_to_outline(clang::cast<clang::FunctionDecl>(node));
-        availableGlobals.insert(func_set.begin(), func_set.end());
+    std::vector<ExtractionBlock> returnBlocks;
+    for (const auto &node: call_graph->getNodes()) {
+        if (auto md = node.second->checkAndGet<ExtractionMetadata>(); md.first && md.second->get_decl_node()) {
+            assert(clang::isa<clang::FunctionDecl>(md.second->get_decl_node()) &&
+                   "Extractionset should only contain function decls at this point");
+            GlobalsMarker gMarker;
+            auto globalsSet = gMarker.get_nodes_to_outline(clang::cast<clang::FunctionDecl>(md.second->get_decl_node()));
+            for (const auto &func: globalsSet) {
+                ExtractionBlock eb;
+                eb.begin = func->getBeginLoc();
+                eb.end = func->getEndLoc();
+                clang::SourceRange range(eb.begin, eb.end);
+                clang::CharSourceRange charSourceRange(range, true);
+                eb.contents = clang::Lexer::getSourceText(charSourceRange, func->getASTContext().getSourceManager(),
+                                                          clang::LangOptions(),
+                                                          nullptr).str();
+                globals.push_back(eb);
+            }
+        }
     }
+}
 
-    std::string returnString;
-
-    for (const auto &decl: availableGlobals) {
-        clang::SourceRange sourceRange = decl->getSourceRange();
-        returnString += clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(sourceRange),
-                                                    decl->getASTContext().getSourceManager(), clang::LangOptions(),
-                                                    nullptr).str();
-        returnString += "\n";
+ExtractionBlock CTUApexConsumer::getNextExtractionBlock() {
+    //find the earliest block by starting source location
+    ExtractionBlock min;
+    if (!includes.empty()) {
+        SPDLOG_TRACE("Setting include as assumed min");
+        min = includes.front();
+    } else if (!funcs.empty()) {
+        SPDLOG_TRACE("Setting funcs as assumed min");
+        min = funcs.front();
+    } else if (!globals.empty()) {
+        SPDLOG_TRACE("Setting globals as assumed min");
+        min = globals.front();
+    } else if (!macros.empty()) {
+        SPDLOG_TRACE("Setting macros as assumed min");
+        min = macros.front();
+    } else if (!pragmas.empty()) {
+        SPDLOG_TRACE("Setting pragmas as assumed min");
+        min = pragmas.front();
     }
 
-    std::vector<clang::Decl *> sortedFunctionDecls = {};
-
 
-
-    sortedFunctionDecls.reserve(availableFunctionDecls.size());
-    for (const auto &decl: availableFunctionDecls) {
-        sortedFunctionDecls.push_back(decl);
+    while (!funcs.empty() && min.begin > funcs.front().begin) {
+        SPDLOG_TRACE("Overwriting with funcs as min");
+        min = funcs.front();
+    }
+    while (!globals.empty() && min.begin > globals.front().begin) {
+        SPDLOG_TRACE("Overwriting with globals as min");
+        min = globals.front();
+    }
+    while (!macros.empty() && min.begin > macros.front().begin) {
+        SPDLOG_TRACE("Overwriting with macros as min");
+        min = macros.front();
+    }
+    while (!pragmas.empty() && min.begin > pragmas.front().begin) {
+        SPDLOG_TRACE("Overwriting with pragmas as min");
+        min = pragmas.front();
     }
 
-    std::sort(sortedFunctionDecls.begin(),sortedFunctionDecls.end(),[](clang::Decl* a, clang::Decl* b){return a->getBeginLoc()<b->getLocation();});
-
-    for (const auto &decl: sortedFunctionDecls) {
-        clang::SourceRange sourceRange = decl->getSourceRange();
-        returnString += clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(sourceRange),
-                                                    decl->getASTContext().getSourceManager(), clang::LangOptions(),
-                                                    nullptr).str();
-        returnString += "\n";
+    //if the earliest blocks end is after another block, we fully contain the other block
+    //we don't need to merge that block anymore
+    while (!includes.empty() && min.end >= includes.front().end) {
+        SPDLOG_TRACE("Erasing include entry");
+        includes.erase(includes.begin());
+    }
+    while (!funcs.empty() && min.end >= funcs.front().end) {
+        SPDLOG_TRACE("Erasing funcs entry");
+        funcs.erase(funcs.begin());
+    }
+    while (!globals.empty() && min.end >= globals.front().end) {
+        SPDLOG_TRACE("Erasing globals entry");
+        globals.erase(globals.begin());
+    }
+    while (!macros.empty() && min.end >= macros.front().end) {
+        SPDLOG_TRACE("Erasing macros entry");
+        macros.erase(macros.begin());
+    }
+    while (!pragmas.empty() && min.end >= pragmas.front().end) {
+        SPDLOG_TRACE("Erasing pragmas entry");
+        pragmas.erase(pragmas.begin());
     }
 
-    return returnString;
+    return min;
 }
 
-
 void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) {
     const auto &translation_unit = Context.getTranslationUnitDecl();
+
     SPDLOG_INFO("Mapping functions to the call graph");
     FunctionFinderVisitor functionFinderVisitor(call_graph);
     functionFinderVisitor.TraverseTranslationUnitDecl(translation_unit);
 
-    for (auto &node: call_graph->getNodes()) {
-        if (node.second->has<ExtractionMetadata>() &&
-            node.second->get<ExtractionMetadata>()->get_decl_node() != nullptr) {
-            std::cout << "Found " << node.second->getFunctionName() << " in TU\n";
-        }
-    }
-
-    SPDLOG_INFO("Generate code skeleton");
+    SPDLOG_INFO("Outlining Functions");
+    outlineFunctions();
 
-    auto t = outline(*call_graph);
+    SPDLOG_INFO("Outlining Globals");
+    outlineGlobals();
 
+    SPDLOG_INFO("Generate code skeleton");
     const auto &sm = Context.getSourceManager();
     std::string filename = sm.getFileEntryForID(sm.getMainFileID())->getName().str();
     filename.insert(filename.find_last_of('.') + 1, "mini.");
     std::ofstream outFile;
     outFile.open(filename);
     assert(outFile.is_open());
-    outFile /*<< col2str(completedIncludeFinder.includes, "#include \"", "\"\n#include \"", "\"\n") */<< t << "\n";
-    outFile.close();
+    while (!(includes.empty() && funcs.empty() && globals.empty() && macros.empty() && pragmas.empty())) {
+        outFile << getNextExtractionBlock().contents << "\n";
+    }
 
+    outFile.close();
     SPDLOG_INFO("Generate wrapper calls");
+    SPDLOG_CRITICAL("WRAPPER CALLS CAN NOT YET BE IMPLEMENTED");
 
     // Outline the code we want
     //SPDLOG_DEBUG("Generating outline");
@@ -147,15 +173,4 @@ void CTUApexConsumer::HandleTranslationUnit(clang::ASTContext &Context) {
 }
 
 
-void CTUApexConsumer::addCalleesToSet(std::unordered_set<clang::Decl *> &set, const size_t nodeID, const metacg::Callgraph &cg) {
-    for (const auto &call: cg.getCallees(nodeID)) {
-        if (call->has<ExtractionMetadata>() && call->get<ExtractionMetadata>()->get_decl_node() != nullptr) {
-            set.insert(call->get<ExtractionMetadata>()->get_decl_node());
-            SPDLOG_DEBUG("{} attached AST node",call->getFunctionName());
-        } else {
-            //SPDLOG_DEBUG("{} has no attached AST node",call->getFunctionName());
-        }
-        addCalleesToSet(set, call->getId(), cg);
-    }
-}
 
diff --git a/src/CTUApexVisitor.cpp b/src/CTUApexVisitor.cpp
index 8b458de4baa6039ac6a3b53625ec4454de740c67..fb17c50c43212fd454aeda30cf73491267b67677 100644
--- a/src/CTUApexVisitor.cpp
+++ b/src/CTUApexVisitor.cpp
@@ -27,8 +27,13 @@ std::vector<std::string> getMangledName(clang::NamedDecl const *const nd) {
 }
 
 bool FunctionFinderVisitor::VisitFunctionDecl(clang::FunctionDecl *functionDecl) {
+    //If the function is not from main file (e.g a header defined function, don't mark
+    if(!functionDecl->getASTContext().getSourceManager().isInMainFile(functionDecl->getSourceRange().getBegin())){
+        return true;
+    }
+
     if(functionDecl->isDependentContext()){
-        //SPDLOG_TRACE("Function {} is context dependend\n",functionDecl->getNameAsString());
+        SPDLOG_DEBUG("Function {} is context dependent",functionDecl->getNameAsString());
         return true;
     }
 
@@ -37,20 +42,13 @@ bool FunctionFinderVisitor::VisitFunctionDecl(clang::FunctionDecl *functionDecl)
     //std::cout<<functionDecl->getNameAsString()<<col2str(possibleNames," All possible manglings are:(",",",")")<<"\n";
 
     for(const auto& name : possibleNames){
-        // We should only override if we have a body or if it is null
-        if(functionDecl->getASTContext().getSourceManager().isInMainFile(functionDecl->getSourceRange().getBegin())){
-            //SPDLOG_DEBUG("Function is part of main file\n");
-        }else{
-            //SPDLOG_DEBUG("Function is from header\n");
+        // we should find every node in the whole program callgraph
+        if(!callgraph->hasNode(name)){
+            SPDLOG_WARN("Node {} is not in the call-graph. Graph might be wrong or incomplete!",name);
             continue;
         }
 
-        if(!callgraph->hasNode(name)){ // if we do not have the node, it is not used in the program and can be ignored
-            //std::cout<<"Node "<<name <<" is not in the graph\n";
-            continue;
-        }
-
-        //SPDLOG_TRACE("Attaching AST node: {}, to the call graph",possibleNames.at(0));
+        // We should only override if we have a body or if it is null
         if (functionDecl->hasBody() || callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->get_decl_node()==
                                        nullptr) {
             callgraph->getNode(name)->getOrCreateMD<ExtractionMetadata>()->set_decl_node(functionDecl);
diff --git a/src/GlobalsMarker.cpp b/src/GlobalsMarker.cpp
index 22fae1e528eed3fbd92ab5dabd6cbe35afd90222..c1b901610a4b293c39e22f1862f7f5c7d3e27b55 100644
--- a/src/GlobalsMarker.cpp
+++ b/src/GlobalsMarker.cpp
@@ -11,7 +11,7 @@ bool GlobalsMarker::VisitDeclRefExpr(clang::DeclRefExpr *decl_ref){
     auto *decl = decl_ref->getDecl();
 
     if(!decl_ref->getDecl()->getASTContext().getSourceManager().isInMainFile(decl_ref->getDecl()->getSourceRange().getBegin())){
-        std::cout<<"We reference a declaration that is part of a header, we dont need to extract it\n";
+        //std::cout<<"We reference a declaration that is part of a header, we don't need to extract it\n";
         return true;
     }
 
diff --git a/src/IncludeFinder.cpp b/src/IncludeFinder.cpp
deleted file mode 100644
index 330ba6bc2e7d2e60fbf7c5385050f8d86780aef8..0000000000000000000000000000000000000000
--- a/src/IncludeFinder.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// Created by tim on 21.12.23.
-//
-#include "IncludeFinder.h"
-
-#include <iostream>
-
-void IncludeFinder::Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) {
-    clang::LangOptions langOptions;
-    std::cout << "Preprocessor found #if #endif: \n" << clang::Lexer::getSourceText(
-            clang::Lexer::getAsCharRange(clang::SourceRange(IfLoc, Loc), sourceManager, clang::LangOptions()),
-            sourceManager, clang::LangOptions()).str() << "\n";
-    std::cout << "------------------------------------\n";
-}
-
-inline void IncludeFinder::PragmaDirective(clang::SourceLocation Loc,
-                                           clang::PragmaIntroducerKind Introducer) {
-    if (!sourceManager.isInMainFile(Loc)) {
-        return;
-    }
-    std::cout << "Preprocessor found pragma: " << Loc.printToString(sourceManager) << "\n";
-    Loc.dump(sourceManager);
-}
\ No newline at end of file
diff --git a/src/PreprocessorExtract.cpp b/src/PreprocessorExtract.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b5dd4f3bed1654a27cfa11e4043a776f3230ebc
--- /dev/null
+++ b/src/PreprocessorExtract.cpp
@@ -0,0 +1,71 @@
+//
+// Created by tim on 21.12.23.
+//
+#include "PreprocessorExtract.h"
+
+
+void PreprocessorExtract::If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
+                             ConditionValueKind ConditionValue) {
+    if (!sourceManager.isInMainFile(Loc)) {
+        return;
+    }
+    assert(Loc.isValid());
+    macroNestingStack.emplace(Loc, Loc, "");
+}
+void PreprocessorExtract::Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+                                const clang::MacroDefinition &MD) {
+    if (!sourceManager.isInMainFile(Loc)) {
+        return;
+    }
+    assert(Loc.isValid());
+    macroNestingStack.emplace(Loc, Loc, "");
+}
+void PreprocessorExtract::Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
+                                 const clang::MacroDefinition &MD) { Ifdef(Loc, MacroNameTok, MD); };
+
+void PreprocessorExtract::Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) {
+    if (!sourceManager.isInMainFile(Loc)) {
+        return;
+    }
+    assert(macroNestingStack.top().begin.isValid());
+    assert(macroNestingStack.top().end.isValid());
+    assert(IfLoc.isValid());
+    assert("If these are not equal, we overwrote the last found macro end location allready" &&
+           macroNestingStack.top().begin == macroNestingStack.top().end);
+    assert("The last found macros start should be the if loc we found" && macroNestingStack.top().begin == IfLoc);
+    ExtractionBlock macro = macroNestingStack.top();
+    macroNestingStack.pop();
+    macro.end = Loc;
+    clang::SourceRange sourceRange(macro.begin,macro.end);
+    clang::CharSourceRange charSourceRange(sourceRange,true);
+    macro.contents = "#"+clang::Lexer::getSourceText(charSourceRange,sourceManager,clang::LangOptions()).str();
+    macros.push_back(macro);
+}
+
+inline void PreprocessorExtract::PragmaDirective(clang::SourceLocation Loc,
+                                                 clang::PragmaIntroducerKind Introducer) {
+    if (!sourceManager.isInMainFile(Loc)) {
+        return;
+    }
+    clang::SourceRange sourceRange(Loc,Loc);
+    clang::CharSourceRange charSourceRange(sourceRange,true);
+    ExtractionBlock res;
+    res.begin=Loc;
+    res.end=charSourceRange.getEnd();
+    res.contents=clang::Lexer::getSourceText(charSourceRange,sourceManager,clang::LangOptions());
+    std::cout<<res.contents;
+    pragmas.push_back(res);
+}
+
+void PreprocessorExtract::InclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
+                                             clang::StringRef FileName, bool IsAngled,
+                                             clang::CharSourceRange FilenameRange,
+                                             clang::Optional<clang::FileEntryRef> File,
+                                             clang::StringRef SearchPath, clang::StringRef RelativePath,
+                                             const clang::Module *Imported,
+                                             clang::SrcMgr::CharacteristicKind FileType) {
+//Note: we currently exclude headers only by name, we could also compare them according to their sourcerange
+    if (sourceManager.isInMainFile(HashLoc)) {
+        includes.emplace_back(HashLoc, FilenameRange.getEnd(), "#include \""+FileName.str()+"\"");
+    }
+}
diff --git a/src/main.cpp b/src/main.cpp
index f050d5fba574a4b9ae82fb0e04f17e0a8595ca32..9c40d69553d250867ccfc1060eea2a5b207a69da 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,7 +22,9 @@
 class FilePropertiesMetaData : public metacg::MetaData::Registrar<FilePropertiesMetaData> {
 public:
     static constexpr const char *key = "fileProperties";
+
     FilePropertiesMetaData() : origin("INVALID"), fromSystemInclude(false), lineNumber(0) {}
+
     explicit FilePropertiesMetaData(const nlohmann::json &j) {
         if (j.is_null()) {
             metacg::MCGLogger::instance().getConsole()->trace("Could not retrieve meta data for {}", key);
@@ -48,10 +50,13 @@ public:
     bool fromSystemInclude;
     int lineNumber;
 };
+
 class PiraOneData : public metacg::MetaData::Registrar<PiraOneData> {
 public:
     static constexpr const char *key = "numStatements";
+
     PiraOneData() = default;
+
     explicit PiraOneData(const nlohmann::json &j) {
         metacg::MCGLogger::instance().getConsole()->trace("Running PiraOneMetaDataRetriever::read from json");
         if (j.is_null()) {
@@ -72,13 +77,21 @@ public:
     virtual const char *getKey() const final { return key; }
 
     void setNumberOfStatements(int numStmts) { this->numStmts = numStmts; }
+
     int getNumberOfStatements() const { return this->numStmts; }
+
     void setHasBody(bool hasBody = true) { this->hasBody = hasBody; }
+
     bool getHasBody() const { return this->hasBody; }
+
     void setDominantRuntime(bool dominantRuntime = true) { this->dominantRuntime = dominantRuntime; }
+
     bool isDominantRuntime() const { return this->dominantRuntime; }
+
     void setComesFromCube(bool fromCube = true) { this->wasInPreviousProfile = fromCube; }
+
     bool comesFromCube() const { return this->wasInPreviousProfile; }
+
     bool inPreviousProfile() const { return wasInPreviousProfile; }
 
 private:
@@ -122,7 +135,6 @@ static cl::opt<bool> DumpAnalysisResult("dump-analysis-result",
                                         cl::desc("Dump the dependence analysis result to stdout"), cl::cat(CTUApex));
 
 
-
 template<typename T, class... Args>
 std::unique_ptr<clang::tooling::FrontendActionFactory> argumentParsingFrontendActionFactory(Args... args) {
 
@@ -143,10 +155,24 @@ std::unique_ptr<clang::tooling::FrontendActionFactory> argumentParsingFrontendAc
     return std::unique_ptr<FrontendActionFactory>(new SimpleFrontendActionFactory(args...));
 }
 
-//Der einsprungspunt in das programm
+
+void markCalleesToExtract(const size_t nodeID, const metacg::Callgraph &cg) {
+    for (const auto &call: cg.getCallees(nodeID)) {
+        call->getOrCreateMD<ExtractionMetadata>()->setMarkedToExtract(true);
+        markCalleesToExtract(call->getId(), cg);
+    }
+}
+void markFunctionsAlongCallpaths(metacg::Callgraph &cg) {
+    SPDLOG_INFO("Compute set of functions to be extracted");
+    for (const auto &node: cg.getNodes()) {
+        if (auto md = node.second->checkAndGet<ExtractionMetadata>();
+                md.first && md.second->isMarkedToExtract()) {
+            markCalleesToExtract(node.first, cg);
+        }
+    }
+}
+
 int main(int argc, const char **argv) {
-    //Wir wollen commandozeilen parameter verarbeiten können, also nehmen wir einen option parser
-    //Da beim parsen etwas schief gehen kann, machen wir den extra schritt mit expectation
 
     auto ExpectedParser = CommonOptionsParser::create(argc, argv, CTUApex);
 
@@ -156,7 +182,6 @@ int main(int argc, const char **argv) {
         return 1;
     }
 
-
     switch (LoggingLevel) {
         case LogLevel::Trace:
             spdlog::set_level(spdlog::level::trace);
@@ -178,19 +203,18 @@ int main(int argc, const char **argv) {
             break;
     }
 
-    //Das ist der eigentliche option parser
     CommonOptionsParser &OptionsParser = ExpectedParser.get();
-    //Wir erstellen ein clang tool objekt
     ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
-    std::string error="error";
-    auto fcd = FixedCompilationDatabase::loadFromDirectory("",error);
+    std::string error = "error";
+    auto fcd = FixedCompilationDatabase::loadFromDirectory("", error);
     metacg::io::FileSource fs(cg_file.getValue());
     metacg::io::VersionTwoMetaCGReader mcgReader(fs);
-    auto& mcgManager=metacg::graph::MCGManager::get();
-    mcgManager.addToManagedGraphs("emptyGraph",std::make_unique<metacg::Callgraph>());
+    auto &mcgManager = metacg::graph::MCGManager::get();
+    mcgManager.addToManagedGraphs("emptyGraph", std::make_unique<metacg::Callgraph>());
     mcgReader.read(mcgManager);
 
-    //Wir führen die frontend action mit unserem tool aus
+    markFunctionsAlongCallpaths(*mcgManager.getCallgraph());
+
     Tool.run(argumentParsingFrontendActionFactory<CTUApexAction>(mcgManager.getCallgraph()).get());
     return 0;
 }