major update

-added support for building with ninja and added corresponding shell scripts
-added EntityView class to iterate over entities of the same tag
-entities are now grouped together in memory by tag rather than all together
-moved globals.h into utility.h
-moved EntityTag and EntityIndex into utility.h
This commit is contained in:
Joseph Aquino 2025-07-02 15:34:14 -04:00
parent abf26355dd
commit 260d2ad84d
75 changed files with 2377 additions and 437 deletions

2
.gitignore vendored
View File

@ -382,3 +382,5 @@ Makefile
*.o *.o
*.d *.d
*.ninja*

8
.idea/.gitignore vendored Normal file
View File

@ -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

102
.idea/editor.xml Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BackendCodeEditorSettings">
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
</component>
</project>

18
.idea/misc.xml Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MakefileSettings">
<option name="linkedExternalProjectsSettings">
<MakefileProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="version" value="2" />
</MakefileProjectSettings>
</option>
</component>
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

5
build-ninja.sh Executable file
View File

@ -0,0 +1,5 @@
#! /bin/bash
./vendor/premake5/premake5 ecc
./vendor/premake5/premake5 ninja
ninja $1

View File

7
clean-ninja.sh Executable file
View File

@ -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

View File

View File

@ -6,3 +6,4 @@
#include <Entities/Entity.h> #include <Entities/Entity.h>
#include <Entities/EntityManager.h> #include <Entities/EntityManager.h>
#include <Entities/EntityMemoryPool.h> #include <Entities/EntityMemoryPool.h>
#include <Entities/EntityView.h>

View File

@ -3,8 +3,6 @@
//#include <tuple> //#include <tuple>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <SFML/System/Angle.hpp>
#include <SFML/System/Vector2.hpp>
class Component class Component
{ {
@ -15,18 +13,14 @@ public:
class Transform : public Component class Transform : public Component
{ {
//potential optimization - remove angle variable
//added time for calculations but possible speed increase from cache freindliness
public: public:
sf::Vector2f position{}; sf::Vector2f position{};
float speed{}; sf::Vector2f speed{};
sf::Angle facing{};
Transform() = default; 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) : position(position_in)
, speed(speed_in) , speed(speed_in)
, facing(facing_in)
{ } { }
}; };

View File

@ -1,25 +1,21 @@
#pragma once #pragma once
#include <cstdint> #include <utility.h>
//#include <utility.h>
using EntityIndex = uint16_t;
enum EntityTag : uint8_t
{
none,
tagCount
};
class EntityManager; class EntityManager;
class EntityViewIterator;
class EntityViewConstIterator;
class Entity class Entity
{ {
private: //private:
public:
friend class EntityManager; friend class EntityManager;
Entity(); friend class EntityViewIterator;
friend class EntityViewConstIterator;
Entity() = delete;
Entity(EntityIndex);
public: public:
template<typename T> template<typename T>
@ -34,6 +30,8 @@ public:
template<typename T> template<typename T>
void addComponent(const T&&); void addComponent(const T&&);
EntityIndex id() const;
EntityTag tag() const; EntityTag tag() const;
bool isAlive() const; bool isAlive() const;

View File

@ -1,9 +1,19 @@
#pragma once #pragma once
#include "Entities/Entity.h"
#include "Entities/EntityView.h"
#include "utility.h"
#include <Entities/EntityMemoryPool.h> #include <Entities/EntityMemoryPool.h>
#include <array>
class EntityManager class EntityManager
{ {
private: private:
EntityView getEntiites(EntityTag);
inline Entity player();
private:
Entity m_player{0};
std::array<u16, tagCount> m_numEntitiesByTag{};
u16 m_numEntities{};
}; };

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cstddef>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@ -20,8 +19,6 @@ private:
ComponentVectorTuple m_components; ComponentVectorTuple m_components;
std::vector<EntityTag> m_tags; std::vector<EntityTag> m_tags;
std::vector<bool> m_aliveStates; std::vector<bool> m_aliveStates;
size_t m_entityCount; // for debugging purposes, should not be included in release version
bool m_holePresent{false};
private: private:
EntityMemoryPool(); EntityMemoryPool();

View File

@ -0,0 +1,83 @@
#pragma once
#include "utility.h"
#include <Entities/Entity.h>
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;
};

View File

@ -1,7 +0,0 @@
#pragma once
#include <cstddef>
namespace Global
{
inline constexpr size_t MAX_ENTITIES {10'000u};
}

View File

@ -1,236 +0,0 @@
#pragma once
#include "Globals.h"
#include <Entities/Entity.h>
#include <SwapBackVectorIterator.hpp>
#include <bitset>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <ostream>
template<typename T, EntityIndex capacity_in = Global::MAX_ENTITIES>
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<SwapBackVector<T, capacity_in>>;
using const_iterator = SwapBackVectorConstIterator<SwapBackVector<T, capacity_in>>;
public:
SwapBackVector()
{
m_data = new T[capacity_in];
}
~SwapBackVector()
{
delete[] m_data;
}
SwapBackVector(const SwapBackVector<T>& other)
{
m_nextValidIndex = other.m_nextValidIndex;
for (int i = 0; i < m_nextValidIndex; i++)
{
m_data[i] = other.m_data[i];
}
}
SwapBackVector(SwapBackVector<T>&& other)
{
m_data = other.m_data;
other.m_data = nullptr;
m_nextValidIndex = other.m_nextValidIndex;
}
SwapBackVector<T>& operator=(const SwapBackVector<T>& 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<T>& operator=(SwapBackVector<T>&& 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<EntityIndex capacity_in>
class SwapBackVector<bool, capacity_in>
{
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<bool>&);
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<bool>& 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<EntityIndex capacity_in>
class SwapBackVector<Entity, capacity_in>
{
};

View File

@ -1,112 +0,0 @@
#pragma once
//#include "SwapBackVector.hpp"
#include <Entities/Entity.h>
#include <cassert>
//#include <cstdint>
//#include <cstddef>
//#include <iterator>
template<typename SwapBackVector>
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<typename SwapBackVector>
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;
};

9
include/log.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <iostream>
#ifdef LOG_ENABLE
#define LOG(x) std::cout << x << "\n"
#else
#define LOG(x)
#endif

View File

@ -1,24 +1,56 @@
#pragma once #pragma once
#include<Entities.h>
#include <array> #include <array>
#include <string> #include <cstdint>
#include <string_view> #include <string_view>
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 namespace util
{ {
using namespace std::string_view_literals; 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 // used for imgui
inline constexpr std::array<const char*, 1> tagStringsC = inline constexpr std::array<const char*, tagCount> tagStringsC =
{ {
"none" "player"
}; };
inline constexpr std::array<std::string_view, 1> tagStrings = inline constexpr std::array<std::string_view, tagCount> tagStrings =
{ {
"none"sv "player"sv
}; };
inline constexpr std::array<EntityIndex, tagCount> tagStart =
{
0,//player
1,//tile start
MAX_TILES,//enemy start
};
} }

View File

@ -1,4 +1,5 @@
require "ecc/ecc" require "ecc/ecc"
require "ninja/ninja"
workspace "fake-mario" workspace "fake-mario"
architecture "x64" architecture "x64"
@ -27,8 +28,9 @@ local vs_includedir = "$(SolutionDir)include"
local includedir = "%{wks.location}/include" local includedir = "%{wks.location}/include"
project "fake-mario" project "fake-mario"
cppdialect "C++17"
language "C++" language "C++"
cppdialect "C++17"
systemversion "latest"
files files
{ {
@ -42,11 +44,11 @@ project "fake-mario"
"vendor/imgui/imgui-SFML.cpp" "vendor/imgui/imgui-SFML.cpp"
} }
--visual studio-- --visual studio--
filter {"action:vs*", "system:windows"} filter {"action:vs*", "system:windows"}
targetdir (vs_bindir) targetdir (vs_bindir)
objdir (vs_intdir) objdir (vs_intdir)
staticruntime "on"
includedirs includedirs
{ {
vs_includedir, vs_includedir,
@ -60,6 +62,7 @@ project "fake-mario"
filter {"action:vs*", "system:windows", "configurations:release"} filter {"action:vs*", "system:windows", "configurations:release"}
libdirs {vs_libreldir} libdirs {vs_libreldir}
--not visual studio on windows-- --not visual studio on windows--
filter {"not action:vs*", "system:windows"} filter {"not action:vs*", "system:windows"}
targetdir (bindir) targetdir (bindir)
@ -77,17 +80,14 @@ project "fake-mario"
libdirs {libreldir} libdirs {libreldir}
--windows specific settings--
--platform specific settings--
filter{"system:windows"} filter{"system:windows"}
systemversion "latest"
defines "SFML_STATIC" defines "SFML_STATIC"
defines "PLATFORM_WINDOWS" defines "PLATFORM_WINDOWS"
staticruntime "on"
filter {"system:windows", "configurations:debug"} filter {"system:windows", "configurations:debug"}
kind "ConsoleApp"
defines{"_DEBUG", "_CONSOLE"} defines{"_DEBUG", "_CONSOLE"}
runtime "Debug"
links links
{ {
"sfml-graphics-s-d", "sfml-graphics-s-d",
@ -108,12 +108,7 @@ project "fake-mario"
} }
filter {"system:windows", "configurations:release"} filter {"system:windows", "configurations:release"}
kind "WindowedApp"
optimize "Speed"
inlining "Auto"
entrypoint "mainCRTStartup"
defines{"NDEBUG"} defines{"NDEBUG"}
runtime "Release"
links links
{ {
"sfml-graphics-s", "sfml-graphics-s",
@ -133,17 +128,17 @@ project "fake-mario"
"winmm" "winmm"
} }
--linux specific settings
filter {"system:linux"} filter {"system:linux"}
targetdir (bindir) targetdir (bindir)
objdir (intdir) objdir (intdir)
defines "PLATFORM_LINUX"
includedirs includedirs
{ {
includedir, includedir,
sfmldir .. "/include",
imguidir imguidir
} }
systemversion "latest"
defines "PLATFORM_LINUX"
links links
{ {
"sfml-graphics", "sfml-graphics",
@ -154,15 +149,18 @@ project "fake-mario"
"OpenGL", "OpenGL",
} }
filter {"system:linux" , "configurations:debug"}
kind "ConsoleApp" --config settings
filter "configurations:debug"
defines"LOG_ENABLE"
symbols "on" symbols "on"
runtime "Debug" runtime "Debug"
kind "ConsoleApp"
filter {"system:linux" , "configurations:release"} filter "configurations:release"
kind "WindowedApp"
optimize "Speed" optimize "Speed"
inlining "Auto" inlining "Auto"
entrypoint "mainCRTStartup"
symbols "off" symbols "off"
runtime "Release" runtime "Release"
kind "WindowedApp"
entrypoint "mainCRTStartup"

View File

View File

@ -3,7 +3,12 @@
#include <Entities/EntityMemoryPool.h> #include <Entities/EntityMemoryPool.h>
#include <utility.h> #include <utility.h>
//#include <utility>
Entity::Entity(EntityIndex id_in)
: m_id(id_in)
{
}
template<typename T> template<typename T>
bool Entity::hasComponent() const bool Entity::hasComponent() const
@ -31,6 +36,11 @@ void Entity::addComponent(const T&& data)
component.active = true; component.active = true;
} }
EntityIndex Entity::id() const
{
return m_id;
}
EntityTag Entity::tag() const EntityTag Entity::tag() const
{ {
return EntityMemoryPool::instance().getTag(m_id); return EntityMemoryPool::instance().getTag(m_id);

View File

@ -1,4 +1,16 @@
#include "Entities/EntityView.h"
#include "utility.h"
#include <Entities/EntityManager.h> #include <Entities/EntityManager.h>
#include <Entities/Entity.h> #include <Entities/Entity.h>
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]);
}

View File

@ -1,16 +1,14 @@
#include <Entities/EntityMemoryPool.h> #include <Entities/EntityMemoryPool.h>
#include <Entities/Entity.h> #include <Entities/Entity.h>
#include <Globals.h>
//#include <cstddef>
#include <vector> #include <vector>
#include <utility.h>
EntityMemoryPool::EntityMemoryPool() EntityMemoryPool::EntityMemoryPool()
{ {
std::apply([=](auto&&... args) {((args.reserve(Global::MAX_ENTITIES)), ...); }, m_components); std::apply([=](auto&&... args) {((args.reserve(util::MAX_ENTITIES)), ...); }, m_components);
m_tags.reserve(Global::MAX_ENTITIES); m_tags.reserve(util::MAX_ENTITIES);
m_aliveStates.reserve(Global::MAX_ENTITIES); m_aliveStates.reserve(util::MAX_ENTITIES);
} }
EntityMemoryPool& EntityMemoryPool::instance() EntityMemoryPool& EntityMemoryPool::instance()
@ -46,3 +44,9 @@ bool EntityMemoryPool::getAlive(EntityIndex id) const
{ {
return m_aliveStates[id]; return m_aliveStates[id];
} }
void EntityMemoryPool::removeEntity(EntityIndex id)
{
m_aliveStates[id] = false;
return;
}

123
src/Classes/EntityView.cpp Normal file
View File

@ -0,0 +1,123 @@
#include <Entities/EntityView.h>
#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;
}

View File

@ -1,29 +1,15 @@
#include "Globals.h"
#include "SwapBackVector.hpp"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <imgui-SFML.h> #include <imgui-SFML.h>
#include <imgui.h> #include <imgui.h>
//#include <iostream>
#include <Entities.h> #include <Entities.h>
#include <iostream> #include <iostream>
#include <utility.h> #include <utility.h>
#include <vector>
int main() int main()
{ {
SwapBackVector<bool> 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"); auto window = sf::RenderWindow(sf::VideoMode({ 1920u, 1080u }), "Fake Mario");
window.setFramerateLimit(144); window.setFramerateLimit(144);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

22
vendor/premake5/ninja/LICENSE vendored Normal file
View File

@ -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.

43
vendor/premake5/ninja/README.md vendored Normal file
View File

@ -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/).<br>
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 ![ubuntu-badge](https://github.com/jimon/premake-ninja/actions/workflows/ubuntu.yml/badge.svg) ![windows-badge](https://github.com/jimon/premake-ninja/actions/workflows/windows.yml/badge.svg) ![macos-badge](https://github.com/jimon/premake-ninja/actions/workflows/macos.yml/badge.svg)
### Extra Tests
Part of integration tests of several generators in https://github.com/Jarod42/premake-sample-projects ![Premake5 ubuntu ninja badge](https://github.com/Jarod42/premake-sample-projects/actions/workflows/premake5-ubuntu-ninja.yml/badge.svg)![Premake5 window ninja badge](https://github.com/Jarod42/premake-sample-projects/actions/workflows/premake5-windows-ninja.yml/badge.svg)

4
vendor/premake5/ninja/_manifest.lua vendored Normal file
View File

@ -0,0 +1,4 @@
return {
"_preload.lua",
"ninja.lua",
}

60
vendor/premake5/ninja/_preload.lua vendored Normal file
View File

@ -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

845
vendor/premake5/ninja/ninja.lua vendored Normal file
View File

@ -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

View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include "test1.h"
#include "test2.h"
int main()
{
printf("hello world !\n");
test1();
test2();
return 0;
}

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
void test1()
{
printf("hello from test1 !\n");
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test1();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
#include "test2.h"
#include <stdio.h>
void test2()
{
printf("hello from test2 !\n");
}

View File

@ -0,0 +1,3 @@
#pragma once
void test2();

View File

@ -0,0 +1,13 @@
#include <stdio.h>
#include "test1.h"
#include "test2.h"
#include "test 3.h"
int main()
{
printf("hello world !\n");
test1();
test2();
test3();
return 0;
}

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test 3.h"
#include <stdio.h>
void test3()
{
printf("hello from test3 !\n");
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test3();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
void test1()
{
printf("hello from test1 !\n");
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test1();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
#include "test2.h"
#include <stdio.h>
void test2()
{
printf("hello from test2 !\n");
}

View File

@ -0,0 +1,3 @@
#pragma once
void test2();

270
vendor/premake5/ninja/tests/run_tests.py vendored Normal file
View File

@ -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()

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
TESTLIB void test1()
{
printf("hello from test1 !\n");
}

View File

@ -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();

View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include "test1.h"
#include "test2.h"
int main()
{
printf("hello world !\n");
test1();
test2();
return 0;
}

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
TESTLIB void test1()
{
printf("hello from test1 !\n");
}

View File

@ -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();

View File

@ -0,0 +1,7 @@
#include "test2.h"
#include <stdio.h>
TESTLIB2 void test2()
{
printf("hello from test2 !\n");
}

View File

@ -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();

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
void test1()
{
printf("hello from test1 !\n");
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test1();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include "test1.h"
#include "test2.h"
int main()
{
printf("hello world !\n");
test1();
test2();
return 0;
}

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
void test1()
{
printf("hello from test1 !\n");
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test1();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
#include "test2.h"
#include <stdio.h>
void test2()
{
printf("hello from test2 !\n");
}

View File

@ -0,0 +1,3 @@
#pragma once
void test2();

View File

@ -0,0 +1,16 @@
#include <stdio.h>
#include "test1.h"
#include "test2.h"
#ifdef _WIN32
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
#else
int main()
#endif
{
printf("hello world !\n");
test1();
test2();
return 0;
}

View File

@ -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"

View File

@ -0,0 +1,7 @@
#include "test1.h"
#include <stdio.h>
void test1()
{
printf("hello from test1 !\n");
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void test1();
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
#include "test2.h"
#include <stdio.h>
void test2()
{
printf("hello from test2 !\n");
}

View File

@ -0,0 +1,3 @@
#pragma once
void test2();