diff --git a/.gitignore b/.gitignore
index 6647f99..634cd24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -381,4 +381,6 @@ Makefile
*.o
-*.d
\ No newline at end of file
+*.d
+
+*.ninja*
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/editor.xml b/.idea/editor.xml
new file mode 100644
index 0000000..e54e87a
--- /dev/null
+++ b/.idea/editor.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..53624c9
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build-ninja.sh b/build-ninja.sh
new file mode 100755
index 0000000..3b32607
--- /dev/null
+++ b/build-ninja.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+./vendor/premake5/premake5 ecc
+./vendor/premake5/premake5 ninja
+ninja $1
\ No newline at end of file
diff --git a/build b/build.sh
similarity index 100%
rename from build
rename to build.sh
diff --git a/clean-ninja.sh b/clean-ninja.sh
new file mode 100755
index 0000000..b5e1ed7
--- /dev/null
+++ b/clean-ninja.sh
@@ -0,0 +1,7 @@
+#! /bin/bash
+if [ -z "$1" ] || [ $# -eq 0 ]
+ then
+ ninja debug -t clean && ninja release -t clean
+ else
+ ninja $1 -t clean
+fi
\ No newline at end of file
diff --git a/clean b/clean.sh
similarity index 100%
rename from clean
rename to clean.sh
diff --git a/include/Entities.h b/include/Entities.h
index dc2779e..4a41691 100644
--- a/include/Entities.h
+++ b/include/Entities.h
@@ -5,4 +5,5 @@
#include
#include
#include
-#include
\ No newline at end of file
+#include
+#include
\ No newline at end of file
diff --git a/include/Entities/Components.h b/include/Entities/Components.h
index b9c7241..9067825 100644
--- a/include/Entities/Components.h
+++ b/include/Entities/Components.h
@@ -3,8 +3,6 @@
//#include
#include
-#include
-#include
class Component
{
@@ -15,18 +13,14 @@ public:
class Transform : public Component
{
-//potential optimization - remove angle variable
-//added time for calculations but possible speed increase from cache freindliness
public:
sf::Vector2f position{};
- float speed{};
- sf::Angle facing{};
+ sf::Vector2f speed{};
Transform() = default;
- Transform(sf::Vector2f position_in, float speed_in, sf::Angle facing_in)
+ Transform(sf::Vector2f position_in, sf::Vector2f speed_in)
: position(position_in)
, speed(speed_in)
- , facing(facing_in)
{ }
};
diff --git a/include/Entities/Entity.h b/include/Entities/Entity.h
index 28b81dd..0406579 100644
--- a/include/Entities/Entity.h
+++ b/include/Entities/Entity.h
@@ -1,25 +1,21 @@
#pragma once
-#include
-//#include
-
-using EntityIndex = uint16_t;
-
-enum EntityTag : uint8_t
-{
- none,
-
- tagCount
-};
-
+#include
class EntityManager;
+class EntityViewIterator;
+class EntityViewConstIterator;
class Entity
{
-private:
+//private:
+public:
friend class EntityManager;
- Entity();
+ friend class EntityViewIterator;
+ friend class EntityViewConstIterator;
+
+ Entity() = delete;
+ Entity(EntityIndex);
public:
template
@@ -34,6 +30,8 @@ public:
template
void addComponent(const T&&);
+ EntityIndex id() const;
+
EntityTag tag() const;
bool isAlive() const;
diff --git a/include/Entities/EntityManager.h b/include/Entities/EntityManager.h
index 5fa3905..0697b55 100644
--- a/include/Entities/EntityManager.h
+++ b/include/Entities/EntityManager.h
@@ -1,9 +1,19 @@
#pragma once
+#include "Entities/Entity.h"
+#include "Entities/EntityView.h"
+#include "utility.h"
#include
+#include
class EntityManager
{
private:
-
-};
\ No newline at end of file
+ EntityView getEntiites(EntityTag);
+
+ inline Entity player();
+private:
+ Entity m_player{0};
+ std::array m_numEntitiesByTag{};
+ u16 m_numEntities{};
+};
diff --git a/include/Entities/EntityMemoryPool.h b/include/Entities/EntityMemoryPool.h
index 61ca55a..c61498b 100644
--- a/include/Entities/EntityMemoryPool.h
+++ b/include/Entities/EntityMemoryPool.h
@@ -1,6 +1,5 @@
#pragma once
-#include
#include
#include
@@ -20,8 +19,6 @@ private:
ComponentVectorTuple m_components;
std::vector m_tags;
std::vector m_aliveStates;
- size_t m_entityCount; // for debugging purposes, should not be included in release version
- bool m_holePresent{false};
private:
EntityMemoryPool();
diff --git a/include/Entities/EntityView.h b/include/Entities/EntityView.h
new file mode 100644
index 0000000..71f9e80
--- /dev/null
+++ b/include/Entities/EntityView.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#include "utility.h"
+#include
+
+class EntityView;
+
+class EntityViewIterator
+{
+ friend class EntityView;
+
+ EntityViewIterator(EntityIndex);
+
+ EntityViewIterator& operator++();
+
+ EntityViewIterator operator++(int);
+
+ EntityViewIterator& operator--();
+
+ EntityViewIterator operator--(int);
+
+ Entity operator*();
+
+ Entity operator[](int);
+ Entity* operator->();
+
+ bool operator==(EntityViewIterator);
+ bool operator!=(EntityViewIterator);
+
+private:
+ Entity m_currentEntity;
+};
+
+class EntityViewConstIterator
+{
+ friend class EntityView;
+
+ EntityViewConstIterator(EntityIndex index);
+
+ EntityViewConstIterator& operator++();
+
+ EntityViewConstIterator operator++(int);
+
+ EntityViewConstIterator& operator--();
+
+ EntityViewConstIterator operator--(int);
+
+ const Entity operator*();
+
+ const Entity operator[](int index);
+
+ const Entity* operator->();
+
+
+ bool operator==(EntityViewConstIterator);
+ bool operator!=(EntityViewConstIterator);
+
+private:
+ Entity m_currentEntity;
+};
+
+class EntityView
+{
+public:
+ friend class EntityManager;
+ EntityView() = delete;
+ EntityView(EntityIndex, EntityIndex);
+
+ using iterator = EntityViewIterator;
+ using const_iterator = EntityViewConstIterator;
+
+ iterator begin() { return iterator(m_start); }
+ iterator end() { return iterator(m_start + m_size); }
+
+
+
+ const_iterator cbegin() const { return const_iterator(m_start); }
+ const_iterator cend() const { return const_iterator(m_start + m_size); }
+private:
+ EntityIndex m_start;
+ EntityIndex m_size;
+};
+
diff --git a/include/Globals.h b/include/Globals.h
deleted file mode 100644
index a601224..0000000
--- a/include/Globals.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-#include
-
-namespace Global
-{
- inline constexpr size_t MAX_ENTITIES {10'000u};
-}
\ No newline at end of file
diff --git a/include/SwapBackVector.hpp b/include/SwapBackVector.hpp
deleted file mode 100644
index 0cbcf09..0000000
--- a/include/SwapBackVector.hpp
+++ /dev/null
@@ -1,236 +0,0 @@
-#pragma once
-
-#include "Globals.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-template
-class SwapBackVector
-{
-public:
- //iterator typedefs
- using iterator_category = std::forward_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using data_type = T;
- using iterator = SwapBackVectorIterator>;
- using const_iterator = SwapBackVectorConstIterator>;
-
-public:
- SwapBackVector()
- {
- m_data = new T[capacity_in];
- }
-
- ~SwapBackVector()
- {
- delete[] m_data;
- }
-
- SwapBackVector(const SwapBackVector& other)
- {
- m_nextValidIndex = other.m_nextValidIndex;
- for (int i = 0; i < m_nextValidIndex; i++)
- {
- m_data[i] = other.m_data[i];
- }
- }
-
- SwapBackVector(SwapBackVector&& other)
- {
- m_data = other.m_data;
- other.m_data = nullptr;
- m_nextValidIndex = other.m_nextValidIndex;
- }
-
- SwapBackVector& operator=(const SwapBackVector& rhs)
- {
- if (this == &rhs) return this;
-
- m_nextValidIndex = rhs.m_nextValidIndex;
- for (int i = 0; i < m_nextValidIndex; i++)
- {
- m_data[i] = rhs.m_data[i];
- }
- return *this;
- }
-
- SwapBackVector& operator=(SwapBackVector&& rhs)
- {
- if (this == &rhs) return this;
-
- delete[] m_data;
- m_data = rhs.m_data;
- rhs.m_data = nullptr;
-
- return *this;
- }
-
-public:
- T& operator[](EntityIndex index)
- {
- assert(index < m_nextValidIndex && "ASSERT ERROR -> SwapBackVector.hpp: attempting to index beyond next valid index");
- return m_data[index];
- }
-
- const T& operator[](EntityIndex index) const
- {
- assert(index < m_nextValidIndex && "ASSERT ERROR -> SwapBackVector.hpp: attempting to index beyond next valid index");
- return m_data[index];
- }
-
-public:
- T* data() { return m_data; }
-
- const T* data() const { return m_data; }
-
- void remove(EntityIndex index)
- {
- if (index >= m_nextValidIndex) return;
-
- m_data[index] = m_data[m_nextValidIndex - 1];
- m_nextValidIndex--;
- }
-
- void push()
- {
- assert(capacity_in > m_nextValidIndex);
-
- m_data[m_nextValidIndex] = T();
- m_nextValidIndex++;
- }
-
- void push(const T& data)
- {
- assert(capacity_in > m_nextValidIndex);
-
- m_data[m_nextValidIndex] = data;
- m_nextValidIndex++;
- }
- inline EntityIndex size() const { return m_nextValidIndex; }
-
- inline constexpr EntityIndex capacity() const { return capacity_in; }
-
- iterator begin() { return iterator(m_data); }
-
- iterator end() { return iterator(m_data + m_nextValidIndex); }
-
- const_iterator cbegin() const { return const_iterator(m_data); }
-
- const_iterator cend() const { return const_iterator(m_data + m_nextValidIndex); }
-
-private:
- T* m_data;
- EntityIndex m_nextValidIndex{};
-};
-
-
-//bool specialization
-template
-class SwapBackVector
-{
-public:
- SwapBackVector()
- {
- m_data = new uint8_t[(capacity_in / 8) + 1];
- }
-
- ~SwapBackVector()
- {
- delete[] m_data;
- }
-
- SwapBackVector(const SwapBackVector& other) = delete;
- SwapBackVector(SwapBackVector&& other) = delete;
-
- SwapBackVector& operator=(const SwapBackVector& rhs) = delete;
- SwapBackVector& operator=(SwapBackVector&& rhs) = delete;
-
-public:
- bool operator[](EntityIndex index)
- {
- //assert(index < m_nextValidIndex && "ASSERT ERROR -> SwapBackVector.hpp: attempting to index beyond next valid index");
- EntityIndex clusterIndex = index / 8u;
- EntityIndex stateIndex = index % 8u;
- return m_data[clusterIndex] & (1 << stateIndex);
- }
-
- friend std::ostream& operator<<(std::ostream&, const SwapBackVector&);
-public:
- void remove(EntityIndex index)
- {
- if (index >= m_nextValidIndex) return;
-
- readAt(m_nextValidIndex - 1) ? setTrueAt(index) : setFalseAt(index);
- m_nextValidIndex--;
- }
-
- void push()
- {
- assert(capacity_in > m_nextValidIndex);
-
- setFalseAt(m_nextValidIndex);
- m_nextValidIndex++;
- }
-
- void push(bool state)
- {
- assert(capacity_in > m_nextValidIndex);
-
- state ? setTrueAt(m_nextValidIndex) : setFalseAt(m_nextValidIndex);
- m_nextValidIndex++;
- }
-
- bool readAt(EntityIndex index) const
- {
- EntityIndex clusterIndex = index / 8u;
- EntityIndex stateIndex = index % 8u;
- return m_data[clusterIndex] & 1 << stateIndex;
- }
-
- void setTrueAt(EntityIndex index)
- {
- EntityIndex clusterIndex = index / 8u;
- EntityIndex stateIndex = index % 8u;
- m_data[clusterIndex] |= 1 << stateIndex;
- }
-
- void setFalseAt(EntityIndex index)
- {
- EntityIndex clusterIndex = index / 8u;
- EntityIndex stateIndex = index % 8u;
- m_data[clusterIndex] &= ~(1 << stateIndex);
- }
-
- inline EntityIndex size() const { return m_nextValidIndex; }
-
- inline constexpr EntityIndex capacity() const { return capacity_in; }
-
-private:
- uint8_t* m_data;
- EntityIndex m_nextValidIndex{};
-};
-
-inline std::ostream& operator<<(std::ostream& out, const SwapBackVector& vec)
-{
- for(size_t i = 0; i < (vec.size() / 8) + 1; i++)
- {
- out << std::bitset<8>(vec.m_data[i]) << " ";
- }
- out << "\n";
- return out;
-}
-
-//Entity specialization
-template
-class SwapBackVector
-{
-
-};
-
diff --git a/include/SwapBackVectorIterator.hpp b/include/SwapBackVectorIterator.hpp
deleted file mode 100644
index 9861f16..0000000
--- a/include/SwapBackVectorIterator.hpp
+++ /dev/null
@@ -1,112 +0,0 @@
-#pragma once
-
-//#include "SwapBackVector.hpp"
-#include
-#include
-//#include
-//#include
-//#include
-
-template
-class SwapBackVectorIterator
-{
-public:
- using data_type = typename SwapBackVector::data_type;
- using pointer = data_type*;
- using reference = data_type&;
-
-public:
- SwapBackVectorIterator(pointer ptr)
- : m_ptr(ptr)
- {}
-
- SwapBackVectorIterator& operator++()
- {
- m_ptr++;
- return *this;
- }
-
- SwapBackVectorIterator operator++(int)
- {
- SwapBackVectorIterator it = *this;
- ++(*this);
- return it;
- }
-
- SwapBackVectorIterator& operator--()
- {
- m_ptr--;
- return *this;
- }
-
- SwapBackVectorIterator operator--(int)
- {
- SwapBackVectorIterator it = *this;
- --(*this);
- return it;
- }
-
- reference operator[](int index) { return m_ptr[index]; }
-
- pointer operator->() { return m_ptr; }
-
- reference operator*() { return *m_ptr; }
-
- bool operator==(const SwapBackVectorIterator& rhs) { return m_ptr == rhs.m_ptr; }
- bool operator!=(const SwapBackVectorIterator& rhs) { return !(m_ptr == rhs.m_ptr); }
-private:
- data_type* m_ptr;
-};
-
-
-
-template
-class SwapBackVectorConstIterator
-{
-public:
- using data_type = typename SwapBackVector::data_type;
- using pointer = const data_type*;
- using reference = const data_type&;
-
-public:
- SwapBackVectorConstIterator(pointer ptr)
- : m_ptr(ptr)
- {}
-
- SwapBackVectorConstIterator& operator++()
- {
- m_ptr++;
- return *this;
- }
-
- SwapBackVectorConstIterator operator++(int)
- {
- SwapBackVectorConstIterator it = *this;
- ++(*this);
- return it;
- }
-
- SwapBackVectorConstIterator& operator--()
- {
- m_ptr--;
- return *this;
- }
-
- SwapBackVectorConstIterator operator--(int)
- {
- SwapBackVectorConstIterator it = *this;
- --(*this);
- return it;
- }
-
- reference operator[](int index) { return m_ptr[index]; }
-
- pointer operator->() { return m_ptr; }
-
- reference operator*() { return *m_ptr; }
-
- bool operator==(const SwapBackVectorConstIterator& rhs) { return m_ptr == rhs.m_ptr; }
- bool operator!=(const SwapBackVectorConstIterator& rhs) { return !(m_ptr == rhs.m_ptr); }
-private:
- data_type* m_ptr;
-};
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..941e055
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include
+
+#ifdef LOG_ENABLE
+#define LOG(x) std::cout << x << "\n"
+#else
+#define LOG(x)
+#endif
\ No newline at end of file
diff --git a/include/utility.h b/include/utility.h
index a372240..dbc2c65 100644
--- a/include/utility.h
+++ b/include/utility.h
@@ -1,24 +1,56 @@
#pragma once
-#include
-
#include
-#include
+#include
#include
+using u8 = uint8_t;
+using u16 = uint16_t;
+using u32 = uint32_t;
+using u64 = uint64_t;
+using s8 = int8_t;
+using s16 = int16_t;
+using s32 = int32_t;
+using s64 = int64_t;
+
+using EntityIndex = u16;
+
+enum EntityTag : u8
+{
+ player,
+ tile,
+ enemy,
+ tagCount
+};
+
+
+
namespace util
{
using namespace std::string_view_literals;
+
+ inline constexpr EntityIndex MAX_ENTITIES {60'000u};
+ inline constexpr EntityIndex MAX_TILES {1'000u};
+ inline constexpr EntityIndex MAX_ENEMIES {1'000u};
+
// used for imgui
- inline constexpr std::array tagStringsC =
+ inline constexpr std::array tagStringsC =
{
- "none"
+ "player"
};
- inline constexpr std::array tagStrings =
+ inline constexpr std::array tagStrings =
{
- "none"sv
+ "player"sv
};
-
-}
\ No newline at end of file
+
+ inline constexpr std::array tagStart =
+ {
+ 0,//player
+ 1,//tile start
+ MAX_TILES,//enemy start
+ };
+}
+
+
diff --git a/premake5.lua b/premake5.lua
index 7e87b04..2cd2ad0 100644
--- a/premake5.lua
+++ b/premake5.lua
@@ -1,4 +1,5 @@
require "ecc/ecc"
+require "ninja/ninja"
workspace "fake-mario"
architecture "x64"
@@ -27,8 +28,9 @@ local vs_includedir = "$(SolutionDir)include"
local includedir = "%{wks.location}/include"
project "fake-mario"
- cppdialect "C++17"
language "C++"
+ cppdialect "C++17"
+ systemversion "latest"
files
{
@@ -42,11 +44,11 @@ project "fake-mario"
"vendor/imgui/imgui-SFML.cpp"
}
+
--visual studio--
filter {"action:vs*", "system:windows"}
targetdir (vs_bindir)
objdir (vs_intdir)
- staticruntime "on"
includedirs
{
vs_includedir,
@@ -60,6 +62,7 @@ project "fake-mario"
filter {"action:vs*", "system:windows", "configurations:release"}
libdirs {vs_libreldir}
+
--not visual studio on windows--
filter {"not action:vs*", "system:windows"}
targetdir (bindir)
@@ -77,17 +80,14 @@ project "fake-mario"
libdirs {libreldir}
-
- --platform specific settings--
+ --windows specific settings--
filter{"system:windows"}
- systemversion "latest"
defines "SFML_STATIC"
defines "PLATFORM_WINDOWS"
+ staticruntime "on"
filter {"system:windows", "configurations:debug"}
- kind "ConsoleApp"
defines{"_DEBUG", "_CONSOLE"}
- runtime "Debug"
links
{
"sfml-graphics-s-d",
@@ -108,12 +108,7 @@ project "fake-mario"
}
filter {"system:windows", "configurations:release"}
- kind "WindowedApp"
- optimize "Speed"
- inlining "Auto"
- entrypoint "mainCRTStartup"
defines{"NDEBUG"}
- runtime "Release"
links
{
"sfml-graphics-s",
@@ -133,17 +128,17 @@ project "fake-mario"
"winmm"
}
+
+ --linux specific settings
filter {"system:linux"}
targetdir (bindir)
objdir (intdir)
+ defines "PLATFORM_LINUX"
includedirs
{
includedir,
- sfmldir .. "/include",
imguidir
}
- systemversion "latest"
- defines "PLATFORM_LINUX"
links
{
"sfml-graphics",
@@ -154,15 +149,18 @@ project "fake-mario"
"OpenGL",
}
- filter {"system:linux" , "configurations:debug"}
- kind "ConsoleApp"
+
+ --config settings
+ filter "configurations:debug"
+ defines"LOG_ENABLE"
symbols "on"
runtime "Debug"
-
- filter {"system:linux" , "configurations:release"}
- kind "WindowedApp"
+ kind "ConsoleApp"
+
+ filter "configurations:release"
optimize "Speed"
inlining "Auto"
- entrypoint "mainCRTStartup"
symbols "off"
runtime "Release"
+ kind "WindowedApp"
+ entrypoint "mainCRTStartup"
diff --git a/run b/run.sh
similarity index 100%
rename from run
rename to run.sh
diff --git a/src/Classes/Entity.cpp b/src/Classes/Entity.cpp
index 043afae..dea76b0 100644
--- a/src/Classes/Entity.cpp
+++ b/src/Classes/Entity.cpp
@@ -3,7 +3,12 @@
#include
#include
-//#include
+
+Entity::Entity(EntityIndex id_in)
+ : m_id(id_in)
+{
+
+}
template
bool Entity::hasComponent() const
@@ -31,6 +36,11 @@ void Entity::addComponent(const T&& data)
component.active = true;
}
+EntityIndex Entity::id() const
+{
+ return m_id;
+}
+
EntityTag Entity::tag() const
{
return EntityMemoryPool::instance().getTag(m_id);
diff --git a/src/Classes/EntityManager.cpp b/src/Classes/EntityManager.cpp
index 571c3ef..4a99138 100644
--- a/src/Classes/EntityManager.cpp
+++ b/src/Classes/EntityManager.cpp
@@ -1,4 +1,16 @@
+#include "Entities/EntityView.h"
+#include "utility.h"
#include
#include
+inline constexpr EntityIndex PLAYER_INDEX = 0;
+inline Entity EntityManager::player()
+{
+ return m_player;
+}
+
+EntityView EntityManager::getEntiites(EntityTag tag)
+{
+ return EntityView(util::tagStart[tag], m_numEntitiesByTag[tag]);
+}
\ No newline at end of file
diff --git a/src/Classes/EntityMemoryPool.cpp b/src/Classes/EntityMemoryPool.cpp
index 9e7a471..baec869 100644
--- a/src/Classes/EntityMemoryPool.cpp
+++ b/src/Classes/EntityMemoryPool.cpp
@@ -1,16 +1,14 @@
#include
#include
-#include
-//#include
#include
+#include
EntityMemoryPool::EntityMemoryPool()
{
- std::apply([=](auto&&... args) {((args.reserve(Global::MAX_ENTITIES)), ...); }, m_components);
- m_tags.reserve(Global::MAX_ENTITIES);
- m_aliveStates.reserve(Global::MAX_ENTITIES);
-
+ std::apply([=](auto&&... args) {((args.reserve(util::MAX_ENTITIES)), ...); }, m_components);
+ m_tags.reserve(util::MAX_ENTITIES);
+ m_aliveStates.reserve(util::MAX_ENTITIES);
}
EntityMemoryPool& EntityMemoryPool::instance()
@@ -45,4 +43,10 @@ EntityTag EntityMemoryPool::getTag(EntityIndex id) const
bool EntityMemoryPool::getAlive(EntityIndex id) const
{
return m_aliveStates[id];
+}
+
+void EntityMemoryPool::removeEntity(EntityIndex id)
+{
+ m_aliveStates[id] = false;
+ return;
}
\ No newline at end of file
diff --git a/src/Classes/EntityView.cpp b/src/Classes/EntityView.cpp
new file mode 100644
index 0000000..9375981
--- /dev/null
+++ b/src/Classes/EntityView.cpp
@@ -0,0 +1,123 @@
+
+#include
+#include "utility.h"
+
+EntityView::EntityView(EntityIndex start, EntityIndex size)
+ : m_start(start)
+ , m_size(size)
+{
+
+}
+
+
+//non-const iterator
+EntityViewIterator::EntityViewIterator(EntityIndex index)
+ : m_currentEntity(index)
+{
+
+}
+
+EntityViewIterator& EntityViewIterator::operator++()
+{
+ m_currentEntity.m_id++;
+ return *this;
+}
+
+EntityViewIterator EntityViewIterator::operator++(int)
+{
+ m_currentEntity.m_id++;
+ return m_currentEntity.m_id - 1;
+}
+
+EntityViewIterator& EntityViewIterator::operator--()
+{
+ m_currentEntity.m_id--;
+ return *this;
+}
+
+EntityViewIterator EntityViewIterator::operator--(int)
+{
+ m_currentEntity.m_id--;
+ return m_currentEntity.m_id + 1;
+}
+
+Entity EntityViewIterator::operator*()
+{
+ return m_currentEntity;
+}
+
+Entity EntityViewIterator::operator[](int index)
+{
+ return m_currentEntity.m_id + index;
+}
+
+Entity* EntityViewIterator::operator->()
+{
+ return &m_currentEntity;
+}
+
+bool EntityViewIterator::operator==(EntityViewIterator other)
+{
+ return m_currentEntity.m_id == other->m_id;
+}
+
+bool EntityViewIterator::operator!=(EntityViewIterator other)
+{
+ return m_currentEntity.m_id != other->m_id;
+}
+
+//const iterator
+EntityViewConstIterator::EntityViewConstIterator(EntityIndex index)
+ : m_currentEntity(index)
+{
+
+}
+
+EntityViewConstIterator& EntityViewConstIterator::operator++()
+{
+ m_currentEntity.m_id++;
+ return *this;
+}
+
+EntityViewConstIterator EntityViewConstIterator::operator++(int)
+{
+ m_currentEntity.m_id++;
+ return m_currentEntity.m_id - 1;
+}
+
+EntityViewConstIterator& EntityViewConstIterator::operator--()
+{
+ m_currentEntity.m_id--;
+ return *this;
+}
+
+EntityViewConstIterator EntityViewConstIterator::operator--(int)
+{
+ m_currentEntity.m_id--;
+ return m_currentEntity.m_id + 1;
+}
+
+const Entity EntityViewConstIterator::operator*()
+{
+ return m_currentEntity;
+}
+
+const Entity EntityViewConstIterator::operator[](int index)
+{
+ return m_currentEntity.m_id + index;
+}
+
+const Entity* EntityViewConstIterator::operator->()
+{
+ return &m_currentEntity;
+}
+
+bool EntityViewConstIterator::operator==(EntityViewConstIterator other)
+{
+ return m_currentEntity.m_id == other->m_id;
+}
+
+bool EntityViewConstIterator::operator!=(EntityViewConstIterator other)
+{
+ return m_currentEntity.m_id != other->m_id;
+}
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index d120f8c..d463fa1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,29 +1,15 @@
-#include "Globals.h"
-#include "SwapBackVector.hpp"
+
#include
#include
#include
-//#include
#include
#include
#include
+#include
int main()
{
- SwapBackVector arr;
-
- arr.push(true);
- arr.push(true);
- arr.push();
-
- arr.setTrueAt(0);
-
- std::cout << arr;
- // for (auto x : arr)
- // {
- // std::cout << x << "\n";
- // }
auto window = sf::RenderWindow(sf::VideoMode({ 1920u, 1080u }), "Fake Mario");
window.setFramerateLimit(144);
diff --git a/vendor/premake5/ninja/.github/dependabot.yml b/vendor/premake5/ninja/.github/dependabot.yml
new file mode 100644
index 0000000..d80af56
--- /dev/null
+++ b/vendor/premake5/ninja/.github/dependabot.yml
@@ -0,0 +1,13 @@
+# Keep GitHub Actions up to date with GitHub's Dependabot... dependabot.yml
+# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ groups:
+ github-actions:
+ patterns:
+ - "*" # Group all Actions updates into a single larger pull request
+ schedule:
+ interval: weekly
diff --git a/vendor/premake5/ninja/.github/workflows/macos.yml b/vendor/premake5/ninja/.github/workflows/macos.yml
new file mode 100644
index 0000000..3d768de
--- /dev/null
+++ b/vendor/premake5/ninja/.github/workflows/macos.yml
@@ -0,0 +1,41 @@
+name: macos
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - '.github/workflows/macos.yml'
+ - 'tests/**'
+ - '**/*.lua'
+
+ pull_request:
+ paths:
+ - '.github/workflows/macos.yml'
+ - 'tests/**'
+ - '**/*.lua'
+
+jobs:
+ macos:
+ runs-on: macos-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - uses: mymindstorm/setup-emsdk@v14
+
+ - name: install premake5
+ uses: Jarod42/install-premake5@v6
+
+ - name: install ninja
+ uses: seanmiddleditch/gha-setup-ninja@v6
+
+ - name: Versions
+ run: |
+ python --version
+ premake5 --version
+ ninja --version
+
+ - name: test projects
+ run: cd tests && python run_tests.py
+
diff --git a/vendor/premake5/ninja/.github/workflows/ubuntu.yml b/vendor/premake5/ninja/.github/workflows/ubuntu.yml
new file mode 100644
index 0000000..a658e5c
--- /dev/null
+++ b/vendor/premake5/ninja/.github/workflows/ubuntu.yml
@@ -0,0 +1,45 @@
+name: ubuntu
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - '.github/workflows/ubuntu.yml'
+ - 'tests/**'
+ - '**/*.lua'
+
+ pull_request:
+ paths:
+ - '.github/workflows/ubuntu.yml'
+ - 'tests/**'
+ - '**/*.lua'
+
+jobs:
+ ubuntu:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - uses: mymindstorm/setup-emsdk@v14
+
+ - name: install premake5
+ uses: Jarod42/install-premake5@v6
+
+ - name: apt-get update
+ run: sudo apt-get update -y
+
+ - name: apt-get install ninja-build
+ run: |
+ sudo apt-get install -y ninja-build
+
+ - name: Versions
+ run: |
+ python --version
+ premake5 --version
+ ninja --version
+
+ - name: test projects
+ run: cd tests && python run_tests.py
+
diff --git a/vendor/premake5/ninja/.github/workflows/windows.yml b/vendor/premake5/ninja/.github/workflows/windows.yml
new file mode 100644
index 0000000..7ca4b7a
--- /dev/null
+++ b/vendor/premake5/ninja/.github/workflows/windows.yml
@@ -0,0 +1,44 @@
+name: windows
+
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - '.github/workflows/windows.yml'
+ - 'tests/**'
+ - '**/*.lua'
+
+ pull_request:
+ paths:
+ - '.github/workflows/windows.yml'
+ - 'tests/**'
+ - '**/*.lua'
+
+jobs:
+ windows:
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - uses: mymindstorm/setup-emsdk@v14
+
+ - name: install premake5
+ uses: Jarod42/install-premake5@v6
+
+ - name: install ninja
+ uses: seanmiddleditch/gha-setup-ninja@v6
+
+ - name: Versions
+ run: |
+ python --version
+ premake5 --version
+ ninja --version
+
+ - name: Add cl.exe to PATH
+ uses: ilammy/msvc-dev-cmd@v1
+
+ - name: test projects
+ run: cd tests && python run_tests.py
+ shell: bash
diff --git a/vendor/premake5/ninja/LICENSE b/vendor/premake5/ninja/LICENSE
new file mode 100644
index 0000000..b71e184
--- /dev/null
+++ b/vendor/premake5/ninja/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Dmitry Ivanov
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/premake5/ninja/README.md b/vendor/premake5/ninja/README.md
new file mode 100644
index 0000000..a897467
--- /dev/null
+++ b/vendor/premake5/ninja/README.md
@@ -0,0 +1,43 @@
+# premake-ninja
+
+[Premake](https://github.com/premake/premake-core) module to support [Ninja](https://github.com/martine/ninja), because it's awesome.
+
+## Usage (little reminder)
+1. Put these files in a "premake-ninja" subdirectory of [Premake search paths](https://premake.github.io/docs/Locating-Scripts/).
+
+2. Adapt your premake5.lua script, or better: create/adapt your [premake-system.lua](https://premake.github.io/docs/System-Scripts/)
+
+```lua
+require "premake-ninja/ninja"
+```
+
+3. Generate ninja files
+
+```sh
+premake5 ninja
+```
+On msys2 (mingw)
+```sh
+premake5 ninja --cc=gcc --shell=posix
+```
+
+4. Run ninja
+
+For each project - configuration pair, we create separate .ninja file. For solution we create build.ninja file which imports other .ninja files with subninja command.
+
+Build.ninja file sets phony targets for configuration names so you can build them from command line. And default target is the first configuration name in your project (usually default).
+
+General from:
+```sh
+ninja $(YourProjectName)_$(ConfigName)
+```
+as example:
+```sh
+ninja myapp_Release
+```
+
+### Tested on   
+
+### Extra Tests
+
+Part of integration tests of several generators in https://github.com/Jarod42/premake-sample-projects 
diff --git a/vendor/premake5/ninja/_manifest.lua b/vendor/premake5/ninja/_manifest.lua
new file mode 100644
index 0000000..31fb223
--- /dev/null
+++ b/vendor/premake5/ninja/_manifest.lua
@@ -0,0 +1,4 @@
+return {
+ "_preload.lua",
+ "ninja.lua",
+}
diff --git a/vendor/premake5/ninja/_preload.lua b/vendor/premake5/ninja/_preload.lua
new file mode 100644
index 0000000..aeb1177
--- /dev/null
+++ b/vendor/premake5/ninja/_preload.lua
@@ -0,0 +1,60 @@
+--
+-- Name: premake-ninja/_preload.lua
+-- Purpose: Define the ninja action.
+-- Author: Dmitry Ivanov
+-- Created: 2015/07/04
+-- Copyright: (c) 2015 Dmitry Ivanov
+--
+
+ local p = premake
+
+ newaction
+ {
+ -- Metadata for the command line and help system
+ trigger = "ninja",
+ shortname = "ninja",
+ description = "Ninja is a small build system with a focus on speed",
+
+ -- The capabilities of this action
+ valid_kinds = {"ConsoleApp", "WindowedApp", "SharedLib", "StaticLib", "None"}, -- Not supported: Makefile, Packaging, SharedItems, Utility
+ valid_languages = {"C", "C++"},
+ valid_tools = {cc = { "gcc", "clang", "msc", "emcc" }},
+
+ toolset = iif(os.target() == "windows", "msc-v142", -- Visual Studio 2019
+ iif(os.target() == "macosx", "clang", "gcc")),
+
+ -- Workspace and project generation logic
+ onWorkspace = function(wks)
+ p.eol("\r\n")
+ p.indent(" ")
+ p.generate(wks, "build.ninja", p.modules.ninja.generateWorkspace)
+ end,
+ onProject = function(prj)
+ p.eol("\r\n")
+ p.indent(" ")
+ p.modules.ninja.generateProject(prj)
+ end,
+ onBranch = function(prj)
+ p.eol("\r\n")
+ p.indent(" ")
+ p.modules.ninja.generateProject(prj)
+ end,
+ onCleanSolution = function(sln)
+ -- TODO
+ end,
+ onCleanProject = function(prj)
+ -- TODO
+ end,
+ onCleanTarget = function(prj)
+ -- TODO
+ end,
+ }
+
+
+--
+-- Decide when the full module should be loaded.
+--
+
+ return function(cfg)
+ return (_ACTION == "ninja")
+ end
diff --git a/vendor/premake5/ninja/ninja.lua b/vendor/premake5/ninja/ninja.lua
new file mode 100644
index 0000000..6c6aa55
--- /dev/null
+++ b/vendor/premake5/ninja/ninja.lua
@@ -0,0 +1,845 @@
+--
+-- Name: premake-ninja/ninja.lua
+-- Purpose: Define the ninja action.
+-- Author: Dmitry Ivanov
+-- Created: 2015/07/04
+-- Copyright: (c) 2015 Dmitry Ivanov
+--
+
+local p = premake
+local tree = p.tree
+local project = p.project
+local config = p.config
+local fileconfig = p.fileconfig
+
+-- Some toolset fixes/helper
+p.tools.clang.objectextension = ".o"
+p.tools.gcc.objectextension = ".o"
+p.tools.msc.objectextension = ".obj"
+
+p.tools.clang.tools.rc = p.tools.clang.tools.rc or "windres"
+
+p.tools.msc.gettoolname = function(cfg, name)
+ local map = {cc = "cl", cxx = "cl", ar = "lib", rc = "rc"}
+ return map[name]
+end
+
+-- Ninja module
+premake.modules.ninja = {}
+local ninja = p.modules.ninja
+
+ninja.handlers = {}
+
+function ninja.register_handler(kind, compilation_rules, target_rules)
+ ninja.handlers[kind] = { compilation_rules = compilation_rules, target_rules = target_rules }
+end
+
+local function get_key(cfg, name)
+ local name = name or cfg.project.name
+
+ if cfg.platform then
+ return name .. "_" .. cfg.buildcfg .. "_" .. cfg.platform
+ else
+ return name .. "_" .. cfg.buildcfg
+ end
+end
+
+local build_cache = {}
+
+function ninja.add_build(cfg, out, implicit_outputs, command, inputs, implicit_inputs, dependencies, vars)
+ implicit_outputs = ninja.list(table.translate(implicit_outputs, ninja.esc))
+ if #implicit_outputs > 0 then
+ implicit_outputs = " |" .. implicit_outputs
+ else
+ implicit_outputs = ""
+ end
+
+ inputs = ninja.list(table.translate(inputs, ninja.esc))
+
+ implicit_inputs = ninja.list(table.translate(implicit_inputs, ninja.esc))
+ if #implicit_inputs > 0 then
+ implicit_inputs = " |" .. implicit_inputs
+ else
+ implicit_inputs = ""
+ end
+
+ dependencies = ninja.list(table.translate(dependencies, ninja.esc))
+ if #dependencies > 0 then
+ dependencies = " ||" .. dependencies
+ else
+ dependencies = ""
+ end
+ build_line = "build " .. ninja.esc(out) .. implicit_outputs .. ": " .. command .. inputs .. implicit_inputs .. dependencies
+
+ local cached = build_cache[out]
+ if cached ~= nil then
+ if build_line == cached.build_line
+ and table.equals(vars or {}, cached.vars or {})
+ then
+ -- custom_command/copy rule are identical for each configuration (contrary to other rules)
+ -- So we can compare extra parameter
+ if command == "custom_command" or command == "copy" then
+ p.outln("# INFO: Rule ignored, same as " .. cached.cfg_key)
+ else
+ local cfg_key = get_key(cfg)
+ p.warn(cached.cfg_key .. " and " .. cfg_key .. " both generate (differently?) " .. out .. ". Ignoring " .. cfg_key)
+ p.outln("# WARNING: Rule ignored, using the one from " .. cached.cfg_key)
+ end
+ else
+ local cfg_key = get_key(cfg)
+ p.warn(cached.cfg_key .. " and " .. cfg_key .. " both generate differently " .. out .. ". Ignoring " .. cfg_key)
+ p.outln("# ERROR: Rule ignored, using the one from " .. cached.cfg_key)
+ end
+ p.outln("# " .. build_line)
+ for i, var in ipairs(vars or {}) do
+ p.outln("# " .. var)
+ end
+ return
+ end
+ p.outln(build_line)
+ for i, var in ipairs(vars or {}) do
+ p.outln(" " .. var)
+ end
+ build_cache[out] = {
+ cfg_key = get_key(cfg),
+ build_line = build_line,
+ vars = vars
+ }
+end
+
+function ninja.esc(value)
+ value = value:gsub("%$", "$$") -- TODO maybe there is better way
+ value = value:gsub(":", "$:")
+ value = value:gsub("\n", "$\n")
+ value = value:gsub(" ", "$ ")
+ return value
+end
+
+function ninja.quote(value)
+ value = value:gsub("\\", "\\\\")
+ value = value:gsub("'", "\\'")
+ value = value:gsub("\"", "\\\"")
+
+ return "\"" .. value .. "\""
+end
+
+-- in some cases we write file names in rule commands directly
+-- so we need to propely escape them
+function ninja.shesc(value)
+ if type(value) == "table" then
+ local result = {}
+ local n = #value
+ for i = 1, n do
+ table.insert(result, ninja.shesc(value[i]))
+ end
+ return result
+ end
+
+ if value:find(' ') or value:find('"') or value:find('(', 1, true) or value:find(')') or value:find('|') or value:find('&') then
+ return ninja.quote(value)
+ end
+ return value
+end
+
+function ninja.can_generate(prj)
+ return p.action.supports(prj.kind) and prj.kind ~= p.NONE
+end
+
+-- generate solution that will call ninja for projects
+function ninja.generateWorkspace(wks)
+ local oldGetDefaultSeparator = path.getDefaultSeparator
+ path.getDefaultSeparator = function() return "/" end
+
+ p.outln("# solution build file")
+ p.outln("# generated with premake ninja")
+ p.outln("")
+
+ p.outln("# build projects")
+ local cfgs = {} -- key is concatenated name or variant name, value is string of outputs names
+ local key = ""
+ local cfg_first = nil
+ local cfg_first_lib = nil
+ local subninjas = {}
+
+ for prj in p.workspace.eachproject(wks) do
+ if ninja.can_generate(prj) then
+ for cfg in p.project.eachconfig(prj) do
+ key = get_key(cfg)
+
+ if not cfgs[cfg.buildcfg] then cfgs[cfg.buildcfg] = {} end
+ table.insert(cfgs[cfg.buildcfg], key)
+
+ -- set first configuration name
+ if wks.defaultplatform == nil then
+ if (cfg_first == nil) and (cfg.kind == p.CONSOLEAPP or cfg.kind == p.WINDOWEDAPP) then
+ cfg_first = key
+ end
+ end
+ if (cfg_first_lib == nil) and (cfg.kind == p.STATICLIB or cfg.kind == p.SHAREDLIB) then
+ cfg_first_lib = key
+ end
+ if prj.name == wks.startproject then
+ if wks.defaultplatform == nil then
+ cfg_first = key
+ elseif cfg.platform == wks.defaultplatform then
+ if cfg_first == nil then
+ cfg_first = key
+ end
+ end
+ end
+
+ -- include other ninja file
+ table.insert(subninjas, ninja.esc(ninja.projectCfgFilename(cfg, true)))
+ p.outln("subninja " .. ninja.esc(ninja.projectCfgFilename(cfg, true)))
+ end
+ end
+ end
+
+ if cfg_first == nil then cfg_first = cfg_first_lib end
+
+ p.outln("")
+
+ p.outln("# targets")
+ for cfg, outputs in spairs(cfgs) do
+ p.outln("build " .. ninja.esc(cfg) .. ": phony" .. ninja.list(table.translate(outputs, ninja.esc)))
+ end
+ p.outln("")
+
+ if wks.editorintegration then
+ -- we need to filter out the 'file' argument, since we already output
+ -- the script separately.
+ local args = {}
+ for _, arg in ipairs(_ARGV) do
+ if not (arg:startswith("--file") or arg:startswith("/file")) then
+ table.insert(args, arg);
+ end
+ end
+ table.sort(args)
+
+ p.outln('# Rule')
+ p.outln('rule premake')
+ p.outln(' command = ' .. ninja.shesc(p.workspace.getrelative(wks, _PREMAKE_COMMAND)) .. ' --file=$in ' .. table.concat(ninja.shesc(args), ' '))
+ p.outln(' generator = true')
+ p.outln(' restat = true')
+ p.outln("")
+ p.outln('build build.ninja ' .. table.concat(subninjas, " ") .. ': premake ' .. p.workspace.getrelative(wks, _MAIN_SCRIPT))
+ p.outln("")
+ end
+
+ if cfg_first then
+ p.outln("# default target")
+ p.outln("default " .. ninja.esc(cfg_first))
+ p.outln("")
+ end
+
+ path.getDefaultSeparator = oldGetDefaultSeparator
+end
+
+function ninja.list(value)
+ if #value > 0 then
+ return " " .. table.concat(value, " ")
+ else
+ return ""
+ end
+end
+
+local function shouldcompileasc(filecfg)
+ if filecfg.compileas and filecfg.compileas ~= "Default" then
+ return p.languages.isc(filecfg.compileas)
+ end
+ return path.iscfile(filecfg.abspath)
+end
+
+local function shouldcompileascpp(filecfg)
+ if filecfg.compileas and filecfg.compileas ~= "Default" then
+ return p.languages.iscpp(filecfg.compileas)
+ end
+ return path.iscppfile(filecfg.abspath)
+end
+
+local function getFileDependencies(cfg)
+ local dependencies = {}
+ if #cfg.prebuildcommands > 0 or cfg.prebuildmessage then
+ dependencies = {"prebuild_" .. get_key(cfg)}
+ end
+ for i = 1, #cfg.dependson do
+
+ local dependpostfix = ""
+ if cfg.platform then
+ dependpostfix = "_" .. cfg.platform
+ end
+
+ table.insert(dependencies, cfg.dependson[i] .. "_" .. cfg.buildcfg .. dependpostfix)
+ end
+ return dependencies
+end
+
+local function getcflags(toolset, cfg, filecfg)
+ p.escaper(ninja.shesc)
+ local buildopt = ninja.list(filecfg.buildoptions)
+ local cppflags = ninja.list(toolset.getcppflags(filecfg))
+ local cflags = ninja.list(toolset.getcflags(filecfg))
+ local defines = ninja.list(table.join(toolset.getdefines(filecfg.defines, filecfg), toolset.getundefines(filecfg.undefines)))
+ local includes = ninja.list(toolset.getincludedirs(cfg, filecfg.includedirs, filecfg.externalincludedirs, filecfg.frameworkdirs, filecfg.includedirsafter))
+ local forceincludes = ninja.list(toolset.getforceincludes(cfg))
+ p.escaper(nil)
+
+ return buildopt .. cppflags .. cflags .. defines .. includes .. forceincludes
+end
+
+local function getcxxflags(toolset, cfg, filecfg)
+ p.escaper(ninja.shesc)
+ local buildopt = ninja.list(filecfg.buildoptions)
+ local cppflags = ninja.list(toolset.getcppflags(filecfg))
+ local cxxflags = ninja.list(toolset.getcxxflags(filecfg))
+ local defines = ninja.list(table.join(toolset.getdefines(filecfg.defines, filecfg), toolset.getundefines(filecfg.undefines)))
+ local includes = ninja.list(toolset.getincludedirs(cfg, filecfg.includedirs, filecfg.externalincludedirs, filecfg.frameworkdirs, filecfg.includedirsafter))
+ local forceincludes = ninja.list(toolset.getforceincludes(cfg))
+ p.escaper(nil)
+
+ return buildopt .. cppflags .. cxxflags .. defines .. includes .. forceincludes
+end
+
+local function getldflags(toolset, cfg)
+ local ldflags = ninja.list(table.join(toolset.getLibraryDirectories(cfg),
+ toolset.getrunpathdirs(cfg, table.join(cfg.runpathdirs, config.getsiblingtargetdirs(cfg))),
+ toolset.getldflags(cfg), cfg.linkoptions))
+
+ -- experimental feature, change install_name of shared libs
+ --if (toolset == p.tools.clang) and (cfg.kind == p.SHAREDLIB) and ninja.endsWith(cfg.buildtarget.name, ".dylib") then
+ -- ldflags = ldflags .. " -install_name " .. cfg.buildtarget.name
+ --end
+
+ return ldflags
+end
+
+local function getresflags(toolset, cfg, filecfg)
+ p.escaper(ninja.shesc)
+ local defines = ninja.list(toolset.getdefines(table.join(filecfg.defines, filecfg.resdefines), filecfg))
+ local includes = ninja.list(toolset.getincludedirs(cfg, table.join(filecfg.externalincludedirs, filecfg.includedirsafter, filecfg.includedirs, filecfg.resincludedirs), {}, {}, {}))
+ local options = ninja.list(cfg.resoptions)
+ p.escaper(nil)
+
+ return defines .. includes .. options
+end
+
+local function prebuild_rule(cfg)
+ if #cfg.prebuildcommands > 0 or cfg.prebuildmessage then
+ local commands = {}
+ if cfg.prebuildmessage then
+ commands = {os.translateCommandsAndPaths("{ECHO} " .. cfg.prebuildmessage, cfg.workspace.basedir, cfg.workspace.location)}
+ end
+ commands = table.join(commands, os.translateCommandsAndPaths(cfg.prebuildcommands, cfg.workspace.basedir, cfg.workspace.location))
+ if (#commands > 1) then
+ commands = 'sh -c ' .. ninja.quote(table.implode(commands,"","",";"))
+ else
+ commands = commands[1]
+ end
+ p.outln("rule run_prebuild")
+ p.outln(" command = " .. commands)
+ p.outln(" description = prebuild")
+ p.outln("")
+ end
+end
+
+local function prelink_rule(cfg)
+ if #cfg.prelinkcommands > 0 or cfg.prelinkmessage then
+ local commands = {}
+ if cfg.prelinkmessage then
+ commands = {os.translateCommandsAndPaths("{ECHO} " .. cfg.prelinkmessage, cfg.workspace.basedir, cfg.workspace.location)}
+ end
+ commands = table.join(commands, os.translateCommandsAndPaths(cfg.prelinkcommands, cfg.workspace.basedir, cfg.workspace.location))
+ if (#commands > 1) then
+ commands = 'sh -c ' .. ninja.quote(table.implode(commands,"","",";"))
+ else
+ commands = commands[1]
+ end
+ p.outln("rule run_prelink")
+ p.outln(" command = " .. commands)
+ p.outln(" description = prelink")
+ p.outln("")
+ end
+end
+
+local function postbuild_rule(cfg)
+ if #cfg.postbuildcommands > 0 or cfg.postbuildmessage then
+ local commands = {}
+ if cfg.postbuildmessage then
+ commands = {os.translateCommandsAndPaths("{ECHO} " .. cfg.postbuildmessage, cfg.workspace.basedir, cfg.workspace.location)}
+ end
+ commands = table.join(commands, os.translateCommandsAndPaths(cfg.postbuildcommands, cfg.workspace.basedir, cfg.workspace.location))
+ if (#commands > 1) then
+ commands = 'sh -c ' .. ninja.quote(table.implode(commands,"","",";"))
+ else
+ commands = commands[1]
+ end
+ p.outln("rule run_postbuild")
+ p.outln(" command = " .. commands)
+ p.outln(" description = postbuild")
+ p.outln("")
+ end
+end
+
+local function c_cpp_compilation_rules(cfg, toolset, pch)
+ ---------------------------------------------------- figure out toolset executables
+ local cc = toolset.gettoolname(cfg, "cc")
+ local cxx = toolset.gettoolname(cfg, "cxx")
+ local ar = toolset.gettoolname(cfg, "ar")
+ local link = toolset.gettoolname(cfg, iif(cfg.language == "C", "cc", "cxx"))
+ local rc = toolset.gettoolname(cfg, "rc")
+
+ -- all paths need to be relative to the workspace output location,
+ -- and not relative to the project output location.
+ -- override the toolset getrelative function to achieve this
+
+ local getrelative = p.tools.getrelative
+ p.tools.getrelative = function(cfg, value)
+ return p.workspace.getrelative(cfg.workspace, value)
+ end
+
+ local all_cflags = getcflags(toolset, cfg, cfg)
+ local all_cxxflags = getcxxflags(toolset, cfg, cfg)
+ local all_ldflags = getldflags(toolset, cfg)
+ local all_resflags = getresflags(toolset, cfg, cfg)
+
+ if toolset == p.tools.msc then
+ p.outln("CFLAGS=" .. all_cflags)
+ p.outln("rule cc")
+ p.outln(" command = " .. cc .. " $CFLAGS" .. " /nologo /showIncludes -c /Tc$in /Fo$out")
+ p.outln(" description = cc $out")
+ p.outln(" deps = msvc")
+ p.outln("")
+ p.outln("CXXFLAGS=" .. all_cxxflags)
+ p.outln("rule cxx")
+ p.outln(" command = " .. cxx .. " $CXXFLAGS" .. " /nologo /showIncludes -c /Tp$in /Fo$out")
+ p.outln(" description = cxx $out")
+ p.outln(" deps = msvc")
+ p.outln("")
+ p.outln("CFLAGS=" .. all_cflags)
+ p.outln("rule clangtidy_cc")
+ p.outln(" command = clang-tidy $in -- -x c $CFLAGS &&$")
+ p.outln(" " .. cc .. " $CFLAGS" .. " /nologo /showIncludes -c /Tc$in /Fo$out")
+ p.outln(" description = cc $out")
+ p.outln(" deps = msvc")
+ p.outln("")
+ p.outln("CXXFLAGS=" .. all_cxxflags)
+ p.outln("rule clangtidy_cxx")
+ p.outln(" command = clang-tidy $in -- -x c++ $CFLAGS &&$")
+ p.outln(" " .. cxx .. " $CXXFLAGS" .. " /nologo /showIncludes -c /Tp$in /Fo$out")
+ p.outln(" description = cxx $out")
+ p.outln(" deps = msvc")
+ p.outln("")
+ p.outln("RESFLAGS = " .. all_resflags)
+ p.outln("rule rc")
+ p.outln(" command = " .. rc .. " /nologo /fo$out $in $RESFLAGS")
+ p.outln(" description = rc $out")
+ p.outln("")
+ if cfg.kind == p.STATICLIB then
+ p.outln("rule ar")
+ p.outln(" command = " .. ar .. " $in /nologo -OUT:$out")
+ p.outln(" description = ar $out")
+ p.outln("")
+ else
+ p.outln("rule link")
+ p.outln(" command = " .. link .. " $in" .. ninja.list(ninja.shesc(toolset.getlinks(cfg, true))) .. " /link" .. all_ldflags .. " /nologo /out:$out")
+ p.outln(" description = link $out")
+ p.outln("")
+ end
+ elseif toolset == p.tools.clang or toolset == p.tools.gcc or toolset == p.tools.emcc then
+ local force_include_pch = ""
+ if pch then
+ force_include_pch = " -include " .. ninja.shesc(pch.placeholder)
+ p.outln("rule build_pch")
+ p.outln(" command = " .. iif(cfg.language == "C", cc .. all_cflags .. " -x c-header", cxx .. all_cxxflags .. " -x c++-header") .. " -H -MF $out.d -c -o $out $in")
+ p.outln(" description = build_pch $out")
+ p.outln(" depfile = $out.d")
+ p.outln(" deps = gcc")
+ end
+ p.outln("CFLAGS=" .. all_cflags)
+ p.outln("rule cc")
+ p.outln(" command = " .. cc .. " $CFLAGS" .. force_include_pch .. " -x c -MF $out.d -c -o $out $in")
+ p.outln(" description = cc $out")
+ p.outln(" depfile = $out.d")
+ p.outln(" deps = gcc")
+ p.outln("")
+ p.outln("CXXFLAGS=" .. all_cxxflags)
+ p.outln("rule cxx")
+ p.outln(" command = " .. cxx .. " $CXXFLAGS" .. force_include_pch .. " -x c++ -MF $out.d -c -o $out $in")
+ p.outln(" description = cxx $out")
+ p.outln(" depfile = $out.d")
+ p.outln(" deps = gcc")
+ p.outln("")
+ p.outln("CFLAGS=" .. all_cflags)
+ p.outln("rule clangtidy_cc")
+ p.outln(" command = clang-tidy $in -- -x c $CFLAGS" .. force_include_pch .. " &&$")
+ p.outln(" " .. cc .. " $CFLAGS" .. force_include_pch .. " -x c -MF $out.d -c -o $out $in")
+ p.outln(" description = cc $out")
+ p.outln(" depfile = $out.d")
+ p.outln(" deps = gcc")
+ p.outln("")
+ p.outln("CXXFLAGS=" .. all_cxxflags)
+ p.outln("rule clangtidy_cxx")
+ p.outln(" command = clang-tidy $in -- -x c++ $CFLAGS" .. force_include_pch .. " &&$")
+ p.outln(" " .. cxx .. " $CXXFLAGS" .. force_include_pch .. " -x c++ -MF $out.d -c -o $out $in")
+ p.outln(" description = cxx $out")
+ p.outln(" depfile = $out.d")
+ p.outln(" deps = gcc")
+ p.outln("")
+ p.outln("RESFLAGS = " .. all_resflags)
+
+ if rc then
+ p.outln("rule rc")
+ p.outln(" command = " .. rc .. " -i $in -o $out $RESFLAGS")
+ p.outln(" description = rc $out")
+ p.outln("")
+ end
+
+ if ar and cfg.kind == p.STATICLIB then
+ p.outln("rule ar")
+ p.outln(" command = " .. ar .. " rcs $out $in")
+ p.outln(" description = ar $out")
+ p.outln("")
+ else
+ local groups = iif(cfg.linkgroups == premake.ON, {"-Wl,--start-group ", " -Wl,--end-group"}, {"", ""})
+ p.outln("rule link")
+ p.outln(" command = " .. link .. " -o $out " .. groups[1] .. "$in" .. ninja.list(ninja.shesc(toolset.getlinks(cfg, true, true))) .. all_ldflags .. groups[2])
+ p.outln(" description = link $out")
+ p.outln("")
+ end
+ end
+
+ p.tools.getrelative = getrelative
+end
+
+local function custom_command_rule()
+ p.outln("rule custom_command")
+ p.outln(" command = $CUSTOM_COMMAND")
+ p.outln(" description = $CUSTOM_DESCRIPTION")
+ p.outln("")
+end
+
+local function copy_rule()
+ p.outln("rule copy")
+ p.outln(" command = " .. os.translateCommands("{COPYFILE} $in $out"))
+ p.outln(" description = copy $in $out")
+ p.outln("")
+end
+
+local function collect_generated_files(prj, cfg)
+ local generated_files = {}
+ tree.traverse(project.getsourcetree(prj), {
+ onleaf = function(node, depth)
+ function append_to_generated_files(filecfg)
+ local outputs = project.getrelative(prj.workspace, filecfg.buildoutputs)
+ generated_files = table.join(generated_files, outputs)
+ end
+ local filecfg = fileconfig.getconfig(node, cfg)
+ if not filecfg or filecfg.flags.ExcludeFromBuild then
+ return
+ end
+ local rule = p.global.getRuleForFile(node.name, prj.rules)
+ if fileconfig.hasCustomBuildRule(filecfg) then
+ append_to_generated_files(filecfg)
+ elseif rule then
+ local environ = table.shallowcopy(filecfg.environ)
+
+ if rule.propertydefinition then
+ p.rule.prepareEnvironment(rule, environ, cfg)
+ p.rule.prepareEnvironment(rule, environ, filecfg)
+ end
+ local rulecfg = p.context.extent(rule, environ)
+ append_to_generated_files(rulecfg)
+ end
+ end,
+ }, false, 1)
+ return generated_files
+end
+
+local function pch_build(cfg, pch)
+ local pch_dependency = {}
+ if pch then
+ pch_dependency = { pch.gch }
+ ninja.add_build(cfg, pch.gch, {}, "build_pch", {pch.input}, {}, {}, {})
+ end
+ return pch_dependency
+end
+
+local function custom_command_build(prj, cfg, filecfg, filename, file_dependencies)
+ local outputs = project.getrelative(prj.workspace, filecfg.buildoutputs)
+ local output = outputs[1]
+ table.remove(outputs, 1)
+ local commands = {}
+ if filecfg.buildmessage then
+ commands = {os.translateCommandsAndPaths("{ECHO} " .. filecfg.buildmessage, prj.workspace.basedir, prj.workspace.location)}
+ end
+ commands = table.join(commands, os.translateCommandsAndPaths(filecfg.buildcommands, prj.workspace.basedir, prj.workspace.location))
+ if (#commands > 1) then
+ commands = 'sh -c ' .. ninja.quote(table.implode(commands,"","",";"))
+ else
+ commands = commands[1]
+ end
+
+ ninja.add_build(cfg, output, outputs, "custom_command", {filename}, project.getrelative(prj.workspace, filecfg.buildinputs), file_dependencies,
+ {"CUSTOM_COMMAND = " .. commands, "CUSTOM_DESCRIPTION = custom build " .. ninja.shesc(output)})
+end
+
+local function compile_file_build(cfg, filecfg, toolset, pch_dependency, regular_file_dependencies, objfiles, extrafiles)
+ local obj_dir = project.getrelative(cfg.workspace, cfg.objdir)
+ local filepath = project.getrelative(cfg.workspace, filecfg.abspath)
+ local has_custom_settings = fileconfig.hasFileSettings(filecfg)
+ local use_clangtidy = filecfg.clangtidy or (filecfg.clangtidy == nil and cfg.clangtidy)
+
+ if filecfg.buildaction == "None" then
+ return
+ elseif filecfg.buildaction == "Copy" then
+ local target = project.getrelative(cfg.workspace, path.join(cfg.targetdir, filecfg.name))
+ ninja.add_build(cfg, target, {}, "copy", {filepath}, {}, {}, {})
+ extrafiles[#extrafiles + 1] = target
+ elseif shouldcompileasc(filecfg) then
+ local objfilename = obj_dir .. "/" .. filecfg.objname .. (toolset.objectextension or ".o")
+ objfiles[#objfiles + 1] = objfilename
+ local cflags = {}
+ if has_custom_settings then
+ cflags = {"CFLAGS = $CFLAGS " .. getcflags(toolset, cfg, filecfg)}
+ end
+ ninja.add_build(cfg, objfilename, {}, iif(use_clangtidy, "clangtidy_cc", "cc"), {filepath}, pch_dependency, regular_file_dependencies, cflags)
+ elseif shouldcompileascpp(filecfg) then
+ local objfilename = obj_dir .. "/" .. filecfg.objname .. (toolset.objectextension or ".o")
+ objfiles[#objfiles + 1] = objfilename
+ local cxxflags = {}
+ if has_custom_settings then
+ cxxflags = {"CXXFLAGS = $CXXFLAGS " .. getcxxflags(toolset, cfg, filecfg)}
+ end
+ ninja.add_build(cfg, objfilename, {}, iif(use_clangtidy, "clangtidy_cxx", "cxx"), {filepath}, pch_dependency, regular_file_dependencies, cxxflags)
+ elseif path.isresourcefile(filecfg.abspath) then
+ local objfilename = obj_dir .. "/" .. filecfg.basename .. ".res"
+ objfiles[#objfiles + 1] = objfilename
+ local resflags = {}
+ if has_custom_settings then
+ resflags = {"RESFLAGS = $RESFLAGS " .. getresflags(toolset, cfg, filecfg)}
+ end
+ local rc = toolset.gettoolname(cfg, "rc")
+ if rc then
+ ninja.add_build(cfg, objfilename, {}, "rc", {filepath}, {}, {}, resflags)
+ else
+ p.warnOnce(filepath, string.format("Ignored resource: '%s'", filepath))
+ end
+ end
+end
+
+local function files_build(prj, cfg, toolset, pch_dependency, regular_file_dependencies, file_dependencies)
+ local objfiles = {}
+ local extrafiles = {}
+ tree.traverse(project.getsourcetree(prj), {
+ onleaf = function(node, depth)
+ local filecfg = fileconfig.getconfig(node, cfg)
+ if not filecfg or filecfg.flags.ExcludeFromBuild then
+ return
+ end
+ local rule = p.global.getRuleForFile(node.name, prj.rules)
+ local filepath = project.getrelative(cfg.workspace, node.abspath)
+
+ if fileconfig.hasCustomBuildRule(filecfg) then
+ custom_command_build(prj, cfg, filecfg, filepath, file_dependencies)
+ elseif rule then
+ local environ = table.shallowcopy(filecfg.environ)
+
+ if rule.propertydefinition then
+ p.rule.prepareEnvironment(rule, environ, cfg)
+ p.rule.prepareEnvironment(rule, environ, filecfg)
+ end
+ local rulecfg = p.context.extent(rule, environ)
+ custom_command_build(prj, cfg, rulecfg, filepath, file_dependencies)
+ else
+ compile_file_build(cfg, filecfg, toolset, pch_dependency, regular_file_dependencies, objfiles, extrafiles)
+ end
+ end,
+ }, false, 1)
+ p.outln("")
+
+ return objfiles, extrafiles
+end
+
+local function generated_files_build(cfg, generated_files, key)
+ local final_dependency = {}
+ if #generated_files > 0 then
+ p.outln("# generated files")
+ ninja.add_build(cfg, "generated_files_" .. key, {}, "phony", generated_files, {}, {}, {})
+ final_dependency = {"generated_files_" .. key}
+ end
+ return final_dependency
+end
+
+-- generate project + config build file
+function ninja.generateProjectCfg(cfg)
+ local oldGetDefaultSeparator = path.getDefaultSeparator
+ path.getDefaultSeparator = function() return "/" end
+
+ local prj = cfg.project
+ local key = get_key(cfg)
+ local toolset, toolset_version = p.tools.canonical(cfg.toolset)
+
+ if not toolset then
+ p.error("Unknown toolset " .. cfg.toolset)
+ end
+
+ -- Some toolset fixes
+ cfg.gccprefix = cfg.gccprefix or ""
+
+ p.outln("# project build file")
+ p.outln("# generated with premake ninja")
+ p.outln("")
+
+ -- premake-ninja relies on scoped rules
+ -- and they were added in ninja v1.6
+ p.outln("ninja_required_version = 1.6")
+ p.outln("")
+
+ local is_c_or_cpp = cfg.language == p.C or cfg.language == p.CPP;
+
+ ---------------------------------------------------- figure out settings
+ local pch = nil
+ if is_c_or_cpp then
+ if toolset ~= p.tools.msc then
+ pch = p.tools.gcc.getpch(cfg)
+ if pch then
+ pch = {
+ input = pch,
+ placeholder = project.getrelative(cfg.workspace, path.join(cfg.objdir, path.getname(pch))),
+ gch = project.getrelative(cfg.workspace, path.join(cfg.objdir, path.getname(pch) .. ".gch"))
+ }
+ end
+ end
+ end
+
+ ---------------------------------------------------- write rules
+ p.outln("# core rules for " .. cfg.name)
+ prebuild_rule(cfg)
+ prelink_rule(cfg)
+ postbuild_rule(cfg)
+
+ if is_c_or_cpp then
+ c_cpp_compilation_rules(cfg, toolset, pch)
+ else
+ local handler = ninja.handlers[cfg.language]
+ if not handler then
+ p.error("expected registered ninja handler action for target " .. cfg.language)
+ end
+ handler.compilation_rules(cfg, toolset)
+ end
+
+ copy_rule()
+ custom_command_rule()
+
+ ---------------------------------------------------- build all files
+ p.outln("# build files")
+
+ local pch_dependency = is_c_or_cpp and pch_build(cfg, pch) or {}
+
+ local generated_files = collect_generated_files(prj, cfg)
+
+ local file_dependencies = getFileDependencies(cfg)
+ local regular_file_dependencies = table.join(iif(#generated_files > 0, {"generated_files_" .. key}, {}), file_dependencies)
+
+ local obj_dir = project.getrelative(cfg.workspace, cfg.objdir)
+ local objfiles, extrafiles = files_build(prj, cfg, toolset, pch_dependency, regular_file_dependencies, file_dependencies)
+ local final_dependency = generated_files_build(cfg, generated_files, key)
+
+ ---------------------------------------------------- build final target
+ if #cfg.prebuildcommands > 0 or cfg.prebuildmessage then
+ p.outln("# prebuild")
+ ninja.add_build(cfg, "prebuild_" .. get_key(cfg), {}, "run_prebuild", {}, {}, {}, {})
+ end
+ local prelink_dependency = {}
+ if #cfg.prelinkcommands > 0 or cfg.prelinkmessage then
+ p.outln("# prelink")
+ ninja.add_build(cfg, "prelink_" .. get_key(cfg), {}, "run_prelink", {}, objfiles, final_dependency, {})
+ prelink_dependency = { "prelink_" .. get_key(cfg) }
+ end
+ if #cfg.postbuildcommands > 0 or cfg.postbuildmessage then
+ p.outln("# postbuild")
+ ninja.add_build(cfg, "postbuild_" .. get_key(cfg), {}, "run_postbuild", {}, {ninja.outputFilename(cfg)}, {}, {})
+ end
+
+ if is_c_or_cpp then
+ -- we don't pass getlinks(cfg) through dependencies
+ -- because system libraries are often not in PATH so ninja can't find them
+ local libs = table.translate(config.getlinks(cfg, "siblings", "fullpath"),
+ function (p) return project.getrelative(cfg.workspace, path.join(cfg.project.location, p)) end)
+ local cfg_output = ninja.outputFilename(cfg)
+ local extra_outputs = {}
+ local command_rule = ""
+ if cfg.kind == p.STATICLIB then
+ p.outln("# link static lib")
+ command_rule = "ar"
+ elseif cfg.kind == p.SHAREDLIB then
+ p.outln("# link shared lib")
+ command_rule = "link"
+ extra_outputs = iif(os.target() == "windows", {path.replaceextension(cfg_output, ".lib"), path.replaceextension(cfg_output, ".exp")}, {})
+ elseif (cfg.kind == p.CONSOLEAPP) or (cfg.kind == p.WINDOWEDAPP) then
+ p.outln("# link executable")
+ command_rule = "link"
+ else
+ p.error("ninja action doesn't support this kind of target " .. cfg.kind)
+ end
+
+ local deps = table.join(final_dependency, extrafiles, prelink_dependency)
+ ninja.add_build(cfg, cfg_output, extra_outputs, command_rule, table.join(objfiles, libs), {}, deps, {})
+ outputs = {cfg_output}
+ else
+ local handler = ninja.handlers[cfg.language]
+ if not handler then
+ p.error("expected registered ninja handler action for target " .. cfg.language)
+ end
+ outputs = handler.target_rules(cfg, toolset)
+ end
+
+ p.outln("")
+ if #cfg.postbuildcommands > 0 or cfg.postbuildmessage then
+ ninja.add_build(cfg, key, {}, "phony", {"postbuild_" .. get_key(cfg)}, {}, {}, {})
+ else
+ ninja.add_build(cfg, key, {}, "phony", outputs, {}, {}, {})
+ end
+ p.outln("")
+
+ path.getDefaultSeparator = oldGetDefaultSeparator
+end
+
+-- return name of output binary relative to build folder
+function ninja.outputFilename(cfg)
+ return project.getrelative(cfg.workspace, cfg.buildtarget.directory) .. "/" .. cfg.buildtarget.name
+end
+
+-- return name of build file for configuration
+function ninja.projectCfgFilename(cfg, relative)
+ if relative ~= nil then
+ relative = project.getrelative(cfg.workspace, cfg.location) .. "/"
+ else
+ relative = ""
+ end
+ return relative .. get_key(cfg, cfg.project.filename) .. ".ninja"
+end
+
+-- check if string starts with string
+function ninja.startsWith(str, starts)
+ return str:sub(0, starts:len()) == starts
+end
+
+-- check if string ends with string
+function ninja.endsWith(str, ends)
+ return str:sub(-ends:len()) == ends
+end
+
+-- generate all build files for every project configuration
+function ninja.generateProject(prj)
+ if not ninja.can_generate(prj) then
+ return
+ end
+ for cfg in project.eachconfig(prj) do
+ p.generate(cfg, ninja.projectCfgFilename(cfg), ninja.generateProjectCfg)
+ end
+end
+
+include("_preload.lua")
+
+return ninja
diff --git a/vendor/premake5/ninja/tests/console_app/includepath/main.cpp b/vendor/premake5/ninja/tests/console_app/includepath/main.cpp
new file mode 100644
index 0000000..7e050fa
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/includepath/main.cpp
@@ -0,0 +1,11 @@
+#include
+#include "test1.h"
+#include "test2.h"
+
+int main()
+{
+ printf("hello world !\n");
+ test1();
+ test2();
+ return 0;
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/includepath/premake5.lua b/vendor/premake5/ninja/tests/console_app/includepath/premake5.lua
new file mode 100644
index 0000000..da58659
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/includepath/premake5.lua
@@ -0,0 +1,22 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj"
+ kind "ConsoleApp"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"**.cpp", "**.c", "**.h"}
+ includedirs {"test1", "test2"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/console_app/includepath/test1/test1.c b/vendor/premake5/ninja/tests/console_app/includepath/test1/test1.c
new file mode 100644
index 0000000..cb8dc1b
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/includepath/test1/test1.c
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/includepath/test1/test1.h b/vendor/premake5/ninja/tests/console_app/includepath/test1/test1.h
new file mode 100644
index 0000000..8e3f361
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/includepath/test1/test1.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test1();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/premake5/ninja/tests/console_app/includepath/test2/test2.cpp b/vendor/premake5/ninja/tests/console_app/includepath/test2/test2.cpp
new file mode 100644
index 0000000..56ba9c9
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/includepath/test2/test2.cpp
@@ -0,0 +1,7 @@
+#include "test2.h"
+#include
+
+void test2()
+{
+ printf("hello from test2 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/includepath/test2/test2.h b/vendor/premake5/ninja/tests/console_app/includepath/test2/test2.h
new file mode 100644
index 0000000..f43be8f
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/includepath/test2/test2.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void test2();
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/simple/main.cpp b/vendor/premake5/ninja/tests/console_app/simple/main.cpp
new file mode 100644
index 0000000..8664e36
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/main.cpp
@@ -0,0 +1,13 @@
+#include
+#include "test1.h"
+#include "test2.h"
+#include "test 3.h"
+
+int main()
+{
+ printf("hello world !\n");
+ test1();
+ test2();
+ test3();
+ return 0;
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/simple/premake5.lua b/vendor/premake5/ninja/tests/console_app/simple/premake5.lua
new file mode 100644
index 0000000..f2c6edb
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/premake5.lua
@@ -0,0 +1,21 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj"
+ kind "ConsoleApp"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"**.cpp", "**.c", "**.h"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/console_app/simple/test 3.c b/vendor/premake5/ninja/tests/console_app/simple/test 3.c
new file mode 100644
index 0000000..f59b780
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/test 3.c
@@ -0,0 +1,7 @@
+#include "test 3.h"
+#include
+
+void test3()
+{
+ printf("hello from test3 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/simple/test 3.h b/vendor/premake5/ninja/tests/console_app/simple/test 3.h
new file mode 100644
index 0000000..65794a7
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/test 3.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test3();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/premake5/ninja/tests/console_app/simple/test1.c b/vendor/premake5/ninja/tests/console_app/simple/test1.c
new file mode 100644
index 0000000..cb8dc1b
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/test1.c
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/simple/test1.h b/vendor/premake5/ninja/tests/console_app/simple/test1.h
new file mode 100644
index 0000000..8e3f361
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/test1.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test1();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/premake5/ninja/tests/console_app/simple/test2.cpp b/vendor/premake5/ninja/tests/console_app/simple/test2.cpp
new file mode 100644
index 0000000..56ba9c9
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/test2.cpp
@@ -0,0 +1,7 @@
+#include "test2.h"
+#include
+
+void test2()
+{
+ printf("hello from test2 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/console_app/simple/test2.h b/vendor/premake5/ninja/tests/console_app/simple/test2.h
new file mode 100644
index 0000000..f43be8f
--- /dev/null
+++ b/vendor/premake5/ninja/tests/console_app/simple/test2.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void test2();
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/run_tests.py b/vendor/premake5/ninja/tests/run_tests.py
new file mode 100644
index 0000000..47ef726
--- /dev/null
+++ b/vendor/premake5/ninja/tests/run_tests.py
@@ -0,0 +1,270 @@
+# unittests for premake-ninja
+
+import os
+import sys
+import time
+import shutil
+import platform
+import unittest
+import subprocess
+
+# we are changing working directory often in this tests, so let's save current one
+current_cwd = os.getcwd()
+
+# if set, will override compiler name when premake is executed
+override_compiler = None
+
+# finds the file in path
+def which(cmd, mode = os.F_OK | os.X_OK, path = None):
+ if sys.version_info[0:2] >= (3, 3):
+ return shutil.which(cmd, mode, path)
+ else:
+ def _access_check(fn, mode):
+ return (os.path.exists(fn) and os.access(fn, mode)
+ and not os.path.isdir(fn))
+
+ if os.path.dirname(cmd):
+ if _access_check(cmd, mode):
+ return cmd
+ return None
+
+ if path is None:
+ path = os.environ.get("PATH", os.defpath)
+ if not path:
+ return None
+ path = path.split(os.pathsep)
+
+ if sys.platform == "win32":
+ if not os.curdir in path:
+ path.insert(0, os.curdir)
+ pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
+ if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
+ files = [cmd]
+ else:
+ files = [cmd + ext for ext in pathext]
+ else:
+ files = [cmd]
+
+ seen = set()
+ for dir in path:
+ normdir = os.path.normcase(dir)
+ if not normdir in seen:
+ seen.add(normdir)
+ for thefile in files:
+ name = os.path.join(dir, thefile)
+ if _access_check(name, mode):
+ return name
+ return None
+
+# ----------------------------------------------------- helper class
+class Helper(unittest.TestCase):
+ # removes build directory in test folder
+ def clear(self, build_dir):
+ if os.path.exists(build_dir):
+ shutil.rmtree(build_dir)
+
+ # enters test, and clears it
+ def enter_test(self, test, build_dir = "build"):
+ self.build_dir = build_dir
+ os.chdir(current_cwd) # if previous test failed then we need to restore cwd
+ os.chdir(test)
+ self.clear(build_dir)
+
+ # clears test and exit from it
+ def exit_test(self, build_dir = "build"):
+ # for some reason call/check_call are not waiting for executable to completely finish
+ # so let's wait a bit so we can remove folder safely
+ time.sleep(0.3)
+ self.clear(build_dir)
+ os.chdir(current_cwd)
+
+ # call premake in the test
+ def premake(self):
+ if override_compiler:
+ args = ["premake5", "--scripts=../../..", "--cc=" + override_compiler, "ninja"]
+ if override_compiler == "emcc":
+ args += ["--os=emscripten"]
+ self.assertEqual(subprocess.call(args), 0, "looks like premake failed")
+ else:
+ self.assertEqual(subprocess.call(["premake5", "--scripts=../../..", "ninja"]), 0, "looks like premake failed")
+
+ # call ninja in the test
+ def ninja(self, target = None):
+ args = ["ninja", "-C", "build"]
+ if target is not None:
+ args.append(target)
+ self.assertEqual(subprocess.call(args), 0, "looks like ninja failed")
+
+ # get out name with ext and prefix
+ def out_name(self, path, ext = None, prefix = None):
+ if (ext == None) and (prefix == None):
+ return path
+ base_path = os.path.dirname(path)
+ base_name_and_ext = os.path.splitext(os.path.basename(path))
+ if prefix == None:
+ prefix = ""
+ if ext == None:
+ ext = base_name_and_ext[1]
+ return base_path + "/" + prefix + base_name_and_ext[0] + ext
+
+ # check if executable exist
+ def out_exist(self, path):
+ print(f"Looking for {path} in {os.listdir(os.path.dirname(path))}")
+ sys.stdout.flush()
+ self.assertTrue(
+ os.path.exists(path) or
+ os.path.exists(self.out_name(path, ".exe")) or
+ os.path.exists(self.out_name(path, ".app")) or
+ os.path.exists(self.out_name(path, ".lib")) or
+ os.path.exists(self.out_name(path, ".a", "lib")) or
+ os.path.exists(self.out_name(path, ".dll")) or
+ os.path.exists(self.out_name(path, ".so", "lib")) or
+ os.path.exists(self.out_name(path, ".dylib", "lib")) or
+ os.path.exists(self.out_name(path, ".wasm"))
+ )
+ print(f"Found {path}")
+ sys.stdout.flush()
+ # check if executable doesn't exist
+ def out_not_exist(self, path):
+ self.assertFalse(
+ os.path.exists(path) or
+ os.path.exists(self.out_name(path, ".exe")) or
+ os.path.exists(self.out_name(path, ".app")) or
+ os.path.exists(self.out_name(path, ".lib")) or
+ os.path.exists(self.out_name(path, ".a", "lib")) or
+ os.path.exists(self.out_name(path, ".dll")) or
+ os.path.exists(self.out_name(path, ".so", "lib")) or
+ os.path.exists(self.out_name(path, ".dylib", "lib")) or
+ os.path.exists(self.out_name(path, ".wasm"))
+ )
+
+ # check if executable exist
+ def exe(self, path):
+ if os.path.exists(path):
+ current_cwd = os.getcwd()
+ os.chdir(self.build_dir)
+ executable = os.path.relpath(path, self.build_dir)
+ subprocess.check_call([executable], env={'LD_LIBRARY_PATH': os.path.dirname(executable), 'DYLD_LIBRARY_PATH': os.path.dirname(executable)})
+ os.chdir(current_cwd)
+ elif os.path.exists(path + ".exe"):
+ subprocess.check_call([path + ".exe"])
+ elif os.path.exists(path + ".app"):
+ subprocess.check_call([path + ".app"])
+ elif os.path.exists(self.out_name(path, ".lib")) or os.path.exists(self.out_name(path, ".a", "lib")) or os.path.exists(self.out_name(path, ".dll")) or os.path.exists(self.out_name(path, ".so", "lib")) or os.path.exists(self.out_name(path, ".dylib", "lib")):
+ pass
+ else:
+ self.assertTrue(False, "executable '" + path + "' doesn't exist")
+
+ # check basic flow, run debug and release executables
+ def check_basics(self, out_debug, out_release, build_dir = "build"):
+ # build dir should not exist before premake is called
+ self.assertFalse(os.path.exists(build_dir))
+
+ # call premake
+ # build dir should exist afterwards, but executables shouldn't
+ self.premake()
+ self.assertTrue(os.path.exists(build_dir))
+ self.out_not_exist(out_debug)
+ self.out_not_exist(out_release)
+
+ # call ninja, by default ninja should build debug target
+ # so debug executable should exist, and release shouldn't
+ self.ninja()
+ self.out_exist(out_debug)
+ self.out_not_exist(out_release)
+
+ # let's build debug target explicitly, and still release executable shouldn't exist
+ self.ninja("debug")
+ self.out_exist(out_debug)
+ self.out_not_exist(out_release)
+
+ # let's build release target explicitly, all basic executables should exist now
+ self.ninja("release")
+ self.out_exist(out_debug)
+ self.out_exist(out_release)
+
+ # run executables to check if they are valid
+ if override_compiler != "emcc":
+ self.exe(out_debug)
+ self.exe(out_release)
+
+# ----------------------------------------------------- console app tests
+class TestConsoleApp(Helper):
+ # test simple app
+ def test_simple(self):
+ self.enter_test("console_app/simple")
+ self.check_basics("build/bin_debug/ninjatestprj", "build/bin_release/ninjatestprj")
+ self.exit_test()
+
+ # test include path app
+ def test_include_path(self):
+ self.enter_test("console_app/includepath")
+ self.check_basics("build/bin_debug/ninjatestprj", "build/bin_release/ninjatestprj")
+ self.exit_test()
+
+# ----------------------------------------------------- static lib tests
+class TestStaticLib(Helper):
+ # test simple app
+ def test_simple(self):
+ self.enter_test("static_lib/simple")
+ self.check_basics("build/bin_debug/ninjatestprj", "build/bin_release/ninjatestprj")
+ self.exit_test()
+
+ # test static lib with app
+ def test_withapp(self):
+ self.enter_test("static_lib/withapp")
+ self.check_basics("build/bin_debug/ninjatestprj_app", "build/bin_release/ninjatestprj_app")
+ self.out_exist("build/bin_debug/ninjatestprj_lib test1")
+ self.out_exist("build/bin_release/ninjatestprj_lib test1")
+ self.out_exist("build/bin_debug/ninjatestprj_lib_test2")
+ self.out_exist("build/bin_release/ninjatestprj_lib_test2")
+ self.exit_test()
+
+# ----------------------------------------------------- shared lib tests
+class TestSharedLib(Helper):
+ # test simple app
+ def test_simple(self):
+ # Skip shared library tests on Emscripten since this is an advanced feature not supported by Premake yet.
+ if override_compiler == "emcc":
+ return
+ self.enter_test("shared_lib/simple")
+ self.check_basics("build/bin_debug/ninjatestprj", "build/bin_release/ninjatestprj")
+ self.exit_test()
+
+ # test shared lib with app
+ def test_withapp(self):
+ # Skip shared library tests on Emscripten since this is an advanced feature not supported by Premake yet.
+ if override_compiler == "emcc":
+ return
+ self.enter_test("shared_lib/withapp")
+ self.check_basics("build/bin_debug/ninjatestprj_app", "build/bin_release/ninjatestprj_app")
+ self.out_exist("build/bin_debug/ninjatestprj_lib_test1")
+ self.out_exist("build/bin_release/ninjatestprj_lib_test1")
+ self.out_exist("build/bin_debug/ninjatestprj_lib_test2")
+ self.out_exist("build/bin_release/ninjatestprj_lib_test2")
+ self.exit_test()
+
+# ----------------------------------------------------- windowed app tests
+class TestWindowedApp(Helper):
+ # test simple app
+ def test_simple(self):
+ self.enter_test("windowed_app/simple")
+ self.check_basics("build/bin_debug/ninjatestprj", "build/bin_release/ninjatestprj")
+ self.exit_test()
+
+# ----------------------------------------------------- entry point
+if __name__ == "__main__":
+ print("-------------------------- test default setup")
+ r = unittest.main(exit = False)
+ if not r.result.wasSuccessful():
+ sys.exit(1)
+
+ if platform.system() == "Windows" and which("gcc"):
+ print("-------------------------- found gcc on windows")
+ override_compiler = "gcc"
+ unittest.main()
+
+ if which("emcc"):
+ print("-------------------------- found emcc")
+ override_compiler = "emcc"
+ unittest.main()
diff --git a/vendor/premake5/ninja/tests/shared_lib/simple/premake5.lua b/vendor/premake5/ninja/tests/shared_lib/simple/premake5.lua
new file mode 100644
index 0000000..e4e91c6
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/simple/premake5.lua
@@ -0,0 +1,22 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj"
+ kind "SharedLib"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"**.cpp", "**.c", "**.h"}
+ defines {"DLL_EXPORT"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/shared_lib/simple/test1.cpp b/vendor/premake5/ninja/tests/shared_lib/simple/test1.cpp
new file mode 100644
index 0000000..69c0200
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/simple/test1.cpp
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+TESTLIB void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/shared_lib/simple/test1.h b/vendor/premake5/ninja/tests/shared_lib/simple/test1.h
new file mode 100644
index 0000000..913e032
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/simple/test1.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef _WIN32
+ #ifdef DLL_EXPORT
+ #define TESTLIB __declspec(dllexport)
+ #else
+ #define TESTLIB __declspec(dllimport)
+ #endif
+#else
+ #define TESTLIB
+#endif
+
+TESTLIB void test1();
diff --git a/vendor/premake5/ninja/tests/shared_lib/withapp/main.cpp b/vendor/premake5/ninja/tests/shared_lib/withapp/main.cpp
new file mode 100644
index 0000000..7e050fa
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/withapp/main.cpp
@@ -0,0 +1,11 @@
+#include
+#include "test1.h"
+#include "test2.h"
+
+int main()
+{
+ printf("hello world !\n");
+ test1();
+ test2();
+ return 0;
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/shared_lib/withapp/premake5.lua b/vendor/premake5/ninja/tests/shared_lib/withapp/premake5.lua
new file mode 100644
index 0000000..507802c
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/withapp/premake5.lua
@@ -0,0 +1,59 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj_app"
+ kind "ConsoleApp"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"main.cpp"}
+ includedirs {"test1", "test2"}
+ links {"ninjatestprj_lib_test1", "ninjatestprj_lib_test2"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
+
+project "ninjatestprj_lib_test1"
+ kind "SharedLib"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"test1/**.cpp", "test1/**.c", "test1/**.h"}
+ includedirs {"test1"}
+ defines {"DLL_EXPORT"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
+
+project "ninjatestprj_lib_test2"
+ kind "SharedLib"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"test2/**.cpp", "test2/**.c", "test2/**.h"}
+ includedirs {"test2"}
+ defines {"DLL_EXPORT2"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/shared_lib/withapp/test1/test1.cpp b/vendor/premake5/ninja/tests/shared_lib/withapp/test1/test1.cpp
new file mode 100644
index 0000000..69c0200
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/withapp/test1/test1.cpp
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+TESTLIB void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/shared_lib/withapp/test1/test1.h b/vendor/premake5/ninja/tests/shared_lib/withapp/test1/test1.h
new file mode 100644
index 0000000..913e032
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/withapp/test1/test1.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef _WIN32
+ #ifdef DLL_EXPORT
+ #define TESTLIB __declspec(dllexport)
+ #else
+ #define TESTLIB __declspec(dllimport)
+ #endif
+#else
+ #define TESTLIB
+#endif
+
+TESTLIB void test1();
diff --git a/vendor/premake5/ninja/tests/shared_lib/withapp/test2/test2.cpp b/vendor/premake5/ninja/tests/shared_lib/withapp/test2/test2.cpp
new file mode 100644
index 0000000..edb7a6c
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/withapp/test2/test2.cpp
@@ -0,0 +1,7 @@
+#include "test2.h"
+#include
+
+TESTLIB2 void test2()
+{
+ printf("hello from test2 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/shared_lib/withapp/test2/test2.h b/vendor/premake5/ninja/tests/shared_lib/withapp/test2/test2.h
new file mode 100644
index 0000000..af7340f
--- /dev/null
+++ b/vendor/premake5/ninja/tests/shared_lib/withapp/test2/test2.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef _WIN32
+ #ifdef DLL_EXPORT2
+ #define TESTLIB2 __declspec(dllexport)
+ #else
+ #define TESTLIB2 __declspec(dllimport)
+ #endif
+#else
+ #define TESTLIB2
+#endif
+
+TESTLIB2 void test2();
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/static_lib/simple/premake5.lua b/vendor/premake5/ninja/tests/static_lib/simple/premake5.lua
new file mode 100644
index 0000000..32d66d2
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/simple/premake5.lua
@@ -0,0 +1,21 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj"
+ kind "StaticLib"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"**.cpp", "**.c", "**.h"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/static_lib/simple/test1.c b/vendor/premake5/ninja/tests/static_lib/simple/test1.c
new file mode 100644
index 0000000..cb8dc1b
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/simple/test1.c
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/static_lib/simple/test1.h b/vendor/premake5/ninja/tests/static_lib/simple/test1.h
new file mode 100644
index 0000000..8e3f361
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/simple/test1.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test1();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/premake5/ninja/tests/static_lib/withapp/main.cpp b/vendor/premake5/ninja/tests/static_lib/withapp/main.cpp
new file mode 100644
index 0000000..7e050fa
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/withapp/main.cpp
@@ -0,0 +1,11 @@
+#include
+#include "test1.h"
+#include "test2.h"
+
+int main()
+{
+ printf("hello world !\n");
+ test1();
+ test2();
+ return 0;
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/static_lib/withapp/premake5.lua b/vendor/premake5/ninja/tests/static_lib/withapp/premake5.lua
new file mode 100644
index 0000000..df4fe4a
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/withapp/premake5.lua
@@ -0,0 +1,64 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj_app"
+ kind "ConsoleApp"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"main.cpp"}
+ includedirs {"test1", "test2"}
+ links {"ninjatestprj_lib test1", "ninjatestprj_lib_test2"}
+
+ filter {"system:windows"}
+ links { "user32", "gdi32" }
+
+ filter {"system:linux"}
+ links { "pthread" }
+ -- todo add system libs for os x and linux
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
+
+project "ninjatestprj_lib test1"
+ kind "StaticLib"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"test1/**.cpp", "test1/**.c", "test1/**.h"}
+ includedirs {"test1"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
+
+project "ninjatestprj_lib_test2"
+ kind "StaticLib"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"test2/**.cpp", "test2/**.c", "test2/**.h"}
+ includedirs {"test2"}
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/static_lib/withapp/test1/test1.c b/vendor/premake5/ninja/tests/static_lib/withapp/test1/test1.c
new file mode 100644
index 0000000..cb8dc1b
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/withapp/test1/test1.c
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/static_lib/withapp/test1/test1.h b/vendor/premake5/ninja/tests/static_lib/withapp/test1/test1.h
new file mode 100644
index 0000000..8e3f361
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/withapp/test1/test1.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test1();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/premake5/ninja/tests/static_lib/withapp/test2/test2.cpp b/vendor/premake5/ninja/tests/static_lib/withapp/test2/test2.cpp
new file mode 100644
index 0000000..56ba9c9
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/withapp/test2/test2.cpp
@@ -0,0 +1,7 @@
+#include "test2.h"
+#include
+
+void test2()
+{
+ printf("hello from test2 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/static_lib/withapp/test2/test2.h b/vendor/premake5/ninja/tests/static_lib/withapp/test2/test2.h
new file mode 100644
index 0000000..f43be8f
--- /dev/null
+++ b/vendor/premake5/ninja/tests/static_lib/withapp/test2/test2.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void test2();
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/windowed_app/simple/main.cpp b/vendor/premake5/ninja/tests/windowed_app/simple/main.cpp
new file mode 100644
index 0000000..ddcfdcf
--- /dev/null
+++ b/vendor/premake5/ninja/tests/windowed_app/simple/main.cpp
@@ -0,0 +1,16 @@
+#include
+#include "test1.h"
+#include "test2.h"
+
+#ifdef _WIN32
+#include
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
+#else
+int main()
+#endif
+{
+ printf("hello world !\n");
+ test1();
+ test2();
+ return 0;
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/windowed_app/simple/premake5.lua b/vendor/premake5/ninja/tests/windowed_app/simple/premake5.lua
new file mode 100644
index 0000000..7af6497
--- /dev/null
+++ b/vendor/premake5/ninja/tests/windowed_app/simple/premake5.lua
@@ -0,0 +1,24 @@
+require "ninja"
+
+solution "ninjatestsln"
+ location "build"
+ configurations {"debug", "release"}
+
+project "ninjatestprj"
+ kind "WindowedApp"
+ location "build"
+ language "C++"
+ targetdir "build/bin_%{cfg.buildcfg}"
+
+ files {"**.cpp", "**.c", "**.h"}
+
+ filter "system:windows"
+ entrypoint "WinMainCRTStartup"
+
+ filter "configurations:debug"
+ defines {"DEBUG"}
+ symbols "On"
+
+ filter "configurations:release"
+ defines {"NDEBUG"}
+ optimize "On"
diff --git a/vendor/premake5/ninja/tests/windowed_app/simple/test1.c b/vendor/premake5/ninja/tests/windowed_app/simple/test1.c
new file mode 100644
index 0000000..cb8dc1b
--- /dev/null
+++ b/vendor/premake5/ninja/tests/windowed_app/simple/test1.c
@@ -0,0 +1,7 @@
+#include "test1.h"
+#include
+
+void test1()
+{
+ printf("hello from test1 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/windowed_app/simple/test1.h b/vendor/premake5/ninja/tests/windowed_app/simple/test1.h
new file mode 100644
index 0000000..8e3f361
--- /dev/null
+++ b/vendor/premake5/ninja/tests/windowed_app/simple/test1.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test1();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/vendor/premake5/ninja/tests/windowed_app/simple/test2.cpp b/vendor/premake5/ninja/tests/windowed_app/simple/test2.cpp
new file mode 100644
index 0000000..56ba9c9
--- /dev/null
+++ b/vendor/premake5/ninja/tests/windowed_app/simple/test2.cpp
@@ -0,0 +1,7 @@
+#include "test2.h"
+#include
+
+void test2()
+{
+ printf("hello from test2 !\n");
+}
\ No newline at end of file
diff --git a/vendor/premake5/ninja/tests/windowed_app/simple/test2.h b/vendor/premake5/ninja/tests/windowed_app/simple/test2.h
new file mode 100644
index 0000000..f43be8f
--- /dev/null
+++ b/vendor/premake5/ninja/tests/windowed_app/simple/test2.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void test2();
\ No newline at end of file