mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-03-06 21:13:02 +00:00
Merge pull request #700 from Laupetin/chore/templating-iterative-compilation
chore: do not write templated output if up to date
This commit is contained in:
@@ -225,50 +225,50 @@ bool LinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldContin
|
|||||||
// --asset-search-path
|
// --asset-search-path
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_ASSET_SEARCH_PATH))
|
if (m_argument_parser.IsOptionSpecified(OPTION_ASSET_SEARCH_PATH))
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_ASSET_SEARCH_PATH), m_asset_search_paths))
|
if (!utils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_ASSET_SEARCH_PATH), m_asset_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(DEFAULT_ASSET_SEARCH_PATH, m_asset_search_paths))
|
if (!utils::ParsePathsString(DEFAULT_ASSET_SEARCH_PATH, m_asset_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --add-assets-search-path
|
// --add-assets-search-path
|
||||||
for (const auto& specifiedValue : m_argument_parser.GetParametersForOption(OPTION_ADD_ASSET_SEARCH_PATH))
|
for (const auto& specifiedValue : m_argument_parser.GetParametersForOption(OPTION_ADD_ASSET_SEARCH_PATH))
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(specifiedValue, m_asset_search_paths))
|
if (!utils::ParsePathsString(specifiedValue, m_asset_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --gdt-search-path
|
// --gdt-search-path
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_GDT_SEARCH_PATH))
|
if (m_argument_parser.IsOptionSpecified(OPTION_GDT_SEARCH_PATH))
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_GDT_SEARCH_PATH), m_gdt_search_paths))
|
if (!utils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_GDT_SEARCH_PATH), m_gdt_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(DEFAULT_GDT_SEARCH_PATH, m_gdt_search_paths))
|
if (!utils::ParsePathsString(DEFAULT_GDT_SEARCH_PATH, m_gdt_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --source-search-path
|
// --source-search-path
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_SOURCE_SEARCH_PATH))
|
if (m_argument_parser.IsOptionSpecified(OPTION_SOURCE_SEARCH_PATH))
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_SOURCE_SEARCH_PATH), m_source_search_paths))
|
if (!utils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_SOURCE_SEARCH_PATH), m_source_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(DEFAULT_SOURCE_SEARCH_PATH, m_source_search_paths))
|
if (!utils::ParsePathsString(DEFAULT_SOURCE_SEARCH_PATH, m_source_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --add-source-search-path
|
// --add-source-search-path
|
||||||
for (const auto& specifiedValue : m_argument_parser.GetParametersForOption(OPTION_ADD_SOURCE_SEARCH_PATH))
|
for (const auto& specifiedValue : m_argument_parser.GetParametersForOption(OPTION_ADD_SOURCE_SEARCH_PATH))
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(specifiedValue, m_source_search_paths))
|
if (!utils::ParsePathsString(specifiedValue, m_source_search_paths))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
namespace ipak_consts
|
namespace ipak_consts
|
||||||
{
|
{
|
||||||
static constexpr uint32_t IPAK_MAGIC = FileUtils::MakeMagic32('K', 'A', 'P', 'I');
|
static constexpr uint32_t IPAK_MAGIC = utils::MakeMagic32('K', 'A', 'P', 'I');
|
||||||
static constexpr uint32_t IPAK_VERSION = 0x50000;
|
static constexpr uint32_t IPAK_VERSION = 0x50000;
|
||||||
|
|
||||||
static constexpr uint32_t IPAK_INDEX_SECTION = 1;
|
static constexpr uint32_t IPAK_INDEX_SECTION = 1;
|
||||||
static constexpr uint32_t IPAK_DATA_SECTION = 2;
|
static constexpr uint32_t IPAK_DATA_SECTION = 2;
|
||||||
static constexpr uint32_t IPAK_BRANDING_SECTION = FileUtils::MakeMagic32('M', 'E', 'T', 'A');
|
static constexpr uint32_t IPAK_BRANDING_SECTION = utils::MakeMagic32('M', 'E', 'T', 'A');
|
||||||
|
|
||||||
static constexpr size_t IPAK_CHUNK_SIZE = 0x8000;
|
static constexpr size_t IPAK_CHUNK_SIZE = 0x8000;
|
||||||
static constexpr size_t IPAK_CHUNK_COUNT_PER_READ = 0x8;
|
static constexpr size_t IPAK_CHUNK_COUNT_PER_READ = 0x8;
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ namespace d3d11
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr auto TAG_RDEF = FileUtils::MakeMagic32('R', 'D', 'E', 'F');
|
constexpr auto TAG_RDEF = utils::MakeMagic32('R', 'D', 'E', 'F');
|
||||||
constexpr auto TAG_SHDR = FileUtils::MakeMagic32('S', 'H', 'D', 'R');
|
constexpr auto TAG_SHDR = utils::MakeMagic32('S', 'H', 'D', 'R');
|
||||||
|
|
||||||
constexpr auto CHUNK_TABLE_OFFSET = 28u;
|
constexpr auto CHUNK_TABLE_OFFSET = 28u;
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ namespace d3d9
|
|||||||
|
|
||||||
const char* constantTableComment;
|
const char* constantTableComment;
|
||||||
size_t constantTableCommentSize;
|
size_t constantTableCommentSize;
|
||||||
if (!FindComment(shaderByteCode, shaderByteCodeSize, FileUtils::MakeMagic32('C', 'T', 'A', 'B'), constantTableComment, constantTableCommentSize))
|
if (!FindComment(shaderByteCode, shaderByteCodeSize, utils::MakeMagic32('C', 'T', 'A', 'B'), constantTableComment, constantTableCommentSize))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (constantTableCommentSize < sizeof(ConstantTable))
|
if (constantTableCommentSize < sizeof(ConstantTable))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr auto FLAC_MAGIC = FileUtils::MakeMagic32('f', 'L', 'a', 'C');
|
constexpr auto FLAC_MAGIC = utils::MakeMagic32('f', 'L', 'a', 'C');
|
||||||
|
|
||||||
enum class MetaDataBlockType : unsigned
|
enum class MetaDataBlockType : unsigned
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Utils/FileUtils.h"
|
#include "Utils/FileUtils.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
constexpr uint32_t WAV_WAVE_ID = FileUtils::MakeMagic32('W', 'A', 'V', 'E');
|
constexpr uint32_t WAV_WAVE_ID = utils::MakeMagic32('W', 'A', 'V', 'E');
|
||||||
constexpr uint32_t WAV_CHUNK_ID_RIFF = FileUtils::MakeMagic32('R', 'I', 'F', 'F');
|
constexpr uint32_t WAV_CHUNK_ID_RIFF = utils::MakeMagic32('R', 'I', 'F', 'F');
|
||||||
constexpr uint32_t WAV_CHUNK_ID_FMT = FileUtils::MakeMagic32('f', 'm', 't', ' ');
|
constexpr uint32_t WAV_CHUNK_ID_FMT = utils::MakeMagic32('f', 'm', 't', ' ');
|
||||||
constexpr uint32_t WAV_CHUNK_ID_DATA = FileUtils::MakeMagic32('d', 'a', 't', 'a');
|
constexpr uint32_t WAV_CHUNK_ID_DATA = utils::MakeMagic32('d', 'a', 't', 'a');
|
||||||
|
|
||||||
struct WavChunkHeader
|
struct WavChunkHeader
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
|
|
||||||
namespace gltf
|
namespace gltf
|
||||||
{
|
{
|
||||||
constexpr uint32_t GLTF_MAGIC = FileUtils::MakeMagic32('g', 'l', 'T', 'F');
|
constexpr uint32_t GLTF_MAGIC = utils::MakeMagic32('g', 'l', 'T', 'F');
|
||||||
constexpr uint32_t GLTF_VERSION = 2u;
|
constexpr uint32_t GLTF_VERSION = 2u;
|
||||||
constexpr auto GLTF_VERSION_STRING = "2.0";
|
constexpr auto GLTF_VERSION_STRING = "2.0";
|
||||||
|
|
||||||
constexpr uint32_t CHUNK_MAGIC_JSON = FileUtils::MakeMagic32('J', 'S', 'O', 'N');
|
constexpr uint32_t CHUNK_MAGIC_JSON = utils::MakeMagic32('J', 'S', 'O', 'N');
|
||||||
constexpr uint32_t CHUNK_MAGIC_BIN = FileUtils::MakeMagic32('B', 'I', 'N', '\x00');
|
constexpr uint32_t CHUNK_MAGIC_BIN = utils::MakeMagic32('B', 'I', 'N', '\x00');
|
||||||
|
|
||||||
constexpr auto GLTF_LENGTH_OFFSET = 8u;
|
constexpr auto GLTF_LENGTH_OFFSET = 8u;
|
||||||
constexpr auto GLTF_JSON_CHUNK_LENGTH_OFFSET = 12u;
|
constexpr auto GLTF_JSON_CHUNK_LENGTH_OFFSET = 12u;
|
||||||
|
|||||||
@@ -41,15 +41,15 @@ namespace oat
|
|||||||
D3DFMT_V16U16 = 64,
|
D3DFMT_V16U16 = 64,
|
||||||
D3DFMT_A2W10V10U10 = 67,
|
D3DFMT_A2W10V10U10 = 67,
|
||||||
|
|
||||||
D3DFMT_UYVY = FileUtils::MakeMagic32('U', 'Y', 'V', 'Y'),
|
D3DFMT_UYVY = utils::MakeMagic32('U', 'Y', 'V', 'Y'),
|
||||||
D3DFMT_R8G8_B8G8 = FileUtils::MakeMagic32('R', 'G', 'B', 'G'),
|
D3DFMT_R8G8_B8G8 = utils::MakeMagic32('R', 'G', 'B', 'G'),
|
||||||
D3DFMT_YUY2 = FileUtils::MakeMagic32('Y', 'U', 'Y', '2'),
|
D3DFMT_YUY2 = utils::MakeMagic32('Y', 'U', 'Y', '2'),
|
||||||
D3DFMT_G8R8_G8B8 = FileUtils::MakeMagic32('G', 'R', 'G', 'B'),
|
D3DFMT_G8R8_G8B8 = utils::MakeMagic32('G', 'R', 'G', 'B'),
|
||||||
D3DFMT_DXT1 = FileUtils::MakeMagic32('D', 'X', 'T', '1'),
|
D3DFMT_DXT1 = utils::MakeMagic32('D', 'X', 'T', '1'),
|
||||||
D3DFMT_DXT2 = FileUtils::MakeMagic32('D', 'X', 'T', '2'),
|
D3DFMT_DXT2 = utils::MakeMagic32('D', 'X', 'T', '2'),
|
||||||
D3DFMT_DXT3 = FileUtils::MakeMagic32('D', 'X', 'T', '3'),
|
D3DFMT_DXT3 = utils::MakeMagic32('D', 'X', 'T', '3'),
|
||||||
D3DFMT_DXT4 = FileUtils::MakeMagic32('D', 'X', 'T', '4'),
|
D3DFMT_DXT4 = utils::MakeMagic32('D', 'X', 'T', '4'),
|
||||||
D3DFMT_DXT5 = FileUtils::MakeMagic32('D', 'X', 'T', '5'),
|
D3DFMT_DXT5 = utils::MakeMagic32('D', 'X', 'T', '5'),
|
||||||
|
|
||||||
D3DFMT_D16_LOCKABLE = 70,
|
D3DFMT_D16_LOCKABLE = 70,
|
||||||
D3DFMT_D32 = 71,
|
D3DFMT_D32 = 71,
|
||||||
@@ -78,7 +78,7 @@ namespace oat
|
|||||||
|
|
||||||
D3DFMT_Q16W16V16U16 = 110,
|
D3DFMT_Q16W16V16U16 = 110,
|
||||||
|
|
||||||
D3DFMT_MULTI2_ARGB8 = FileUtils::MakeMagic32('M', 'E', 'T', '1'),
|
D3DFMT_MULTI2_ARGB8 = utils::MakeMagic32('M', 'E', 'T', '1'),
|
||||||
|
|
||||||
// Floating point surface formats
|
// Floating point surface formats
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "DdsLoader.h"
|
#include "DdsLoader.h"
|
||||||
|
|
||||||
#include "Image/DdsTypes.h"
|
#include "Image/DdsTypes.h"
|
||||||
#include "Utils/ClassUtils.h"
|
|
||||||
#include "Utils/FileUtils.h"
|
#include "Utils/FileUtils.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ namespace
|
|||||||
{
|
{
|
||||||
class DdsLoaderInternal
|
class DdsLoaderInternal
|
||||||
{
|
{
|
||||||
static constexpr auto DDS_MAGIC = FileUtils::MakeMagic32('D', 'D', 'S', ' ');
|
static constexpr auto DDS_MAGIC = utils::MakeMagic32('D', 'D', 'S', ' ');
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DdsLoaderInternal(std::istream& stream)
|
explicit DdsLoaderInternal(std::istream& stream)
|
||||||
@@ -105,29 +104,29 @@ namespace
|
|||||||
{
|
{
|
||||||
switch (pf.dwFourCC)
|
switch (pf.dwFourCC)
|
||||||
{
|
{
|
||||||
case FileUtils::MakeMagic32('D', 'X', 'T', '1'):
|
case utils::MakeMagic32('D', 'X', 'T', '1'):
|
||||||
m_format = &ImageFormat::FORMAT_BC1;
|
m_format = &ImageFormat::FORMAT_BC1;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case FileUtils::MakeMagic32('D', 'X', 'T', '3'):
|
case utils::MakeMagic32('D', 'X', 'T', '3'):
|
||||||
m_format = &ImageFormat::FORMAT_BC2;
|
m_format = &ImageFormat::FORMAT_BC2;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case FileUtils::MakeMagic32('D', 'X', 'T', '5'):
|
case utils::MakeMagic32('D', 'X', 'T', '5'):
|
||||||
m_format = &ImageFormat::FORMAT_BC3;
|
m_format = &ImageFormat::FORMAT_BC3;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case FileUtils::MakeMagic32('A', 'T', 'I', '1'):
|
case utils::MakeMagic32('A', 'T', 'I', '1'):
|
||||||
case FileUtils::MakeMagic32('B', 'C', '4', 'U'):
|
case utils::MakeMagic32('B', 'C', '4', 'U'):
|
||||||
m_format = &ImageFormat::FORMAT_BC4;
|
m_format = &ImageFormat::FORMAT_BC4;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case FileUtils::MakeMagic32('A', 'T', 'I', '2'):
|
case utils::MakeMagic32('A', 'T', 'I', '2'):
|
||||||
case FileUtils::MakeMagic32('B', 'C', '5', 'U'):
|
case utils::MakeMagic32('B', 'C', '5', 'U'):
|
||||||
m_format = &ImageFormat::FORMAT_BC5;
|
m_format = &ImageFormat::FORMAT_BC5;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case FileUtils::MakeMagic32('D', 'X', '1', '0'):
|
case utils::MakeMagic32('D', 'X', '1', '0'):
|
||||||
return ReadDxt10Header();
|
return ReadDxt10Header();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
|
|
||||||
class SoundBank final : public ObjContainerReferenceable
|
class SoundBank final : public ObjContainerReferenceable
|
||||||
{
|
{
|
||||||
static constexpr uint32_t MAGIC = FileUtils::MakeMagic32('2', 'U', 'X', '#');
|
static constexpr uint32_t MAGIC = utils::MakeMagic32('2', 'U', 'X', '#');
|
||||||
static constexpr uint32_t VERSION = 14u;
|
static constexpr uint32_t VERSION = 14u;
|
||||||
|
|
||||||
std::string m_file_name;
|
std::string m_file_name;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class SoundBankWriterImpl : public SoundBankWriter
|
|||||||
{
|
{
|
||||||
static constexpr char BRANDING[] = "Created with OAT - OpenAssetTools";
|
static constexpr char BRANDING[] = "Created with OAT - OpenAssetTools";
|
||||||
static constexpr int64_t DATA_OFFSET = 0x800;
|
static constexpr int64_t DATA_OFFSET = 0x800;
|
||||||
static constexpr uint32_t MAGIC = FileUtils::MakeMagic32('2', 'U', 'X', '#');
|
static constexpr uint32_t MAGIC = utils::MakeMagic32('2', 'U', 'X', '#');
|
||||||
static constexpr uint32_t VERSION = 14u;
|
static constexpr uint32_t VERSION = 14u;
|
||||||
|
|
||||||
inline static const std::string PAD_DATA = std::string(16, '\x00');
|
inline static const std::string PAD_DATA = std::string(16, '\x00');
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ void BinOutput::AlignToFour(const char value) const
|
|||||||
const auto offset = m_stream.tellp();
|
const auto offset = m_stream.tellp();
|
||||||
if (offset % 4 > 0)
|
if (offset % 4 > 0)
|
||||||
{
|
{
|
||||||
const uint32_t alignmentValue = FileUtils::MakeMagic32(value, value, value, value);
|
const uint32_t alignmentValue = utils::MakeMagic32(value, value, value, value);
|
||||||
Write(&alignmentValue, 4u - (offset % 4u));
|
Write(&alignmentValue, 4u - (offset % 4u));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ public:
|
|||||||
std::vector<std::string> m_input_files;
|
std::vector<std::string> m_input_files;
|
||||||
std::string m_output_directory;
|
std::string m_output_directory;
|
||||||
|
|
||||||
|
// Generate a build log that is always written for the compiler to determine
|
||||||
|
// the last output time.
|
||||||
std::string m_build_log_file;
|
std::string m_build_log_file;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> m_defines;
|
std::vector<std::pair<std::string, std::string>> m_defines;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "SetDefineStreamProxy.h"
|
#include "SetDefineStreamProxy.h"
|
||||||
#include "TemplatingStreamProxy.h"
|
#include "TemplatingStreamProxy.h"
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "Utils/FileUtils.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -198,9 +199,9 @@ namespace templating
|
|||||||
if (m_first_line)
|
if (m_first_line)
|
||||||
m_first_line = false;
|
m_first_line = false;
|
||||||
else
|
else
|
||||||
m_output_stream << '\n';
|
m_output.Stream() << '\n';
|
||||||
|
|
||||||
m_output_stream << nextLine.m_line;
|
m_output.Stream() << nextLine.m_line;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -229,19 +230,35 @@ namespace templating
|
|||||||
|
|
||||||
const auto cachedData = m_output_cache.str();
|
const auto cachedData = m_output_cache.str();
|
||||||
if (!cachedData.empty())
|
if (!cachedData.empty())
|
||||||
m_output_stream << cachedData;
|
m_output.Stream() << cachedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
con::info("Templated file \"{}\"", m_output_file);
|
const auto outputResult = m_output.Close();
|
||||||
|
switch (outputResult)
|
||||||
|
{
|
||||||
|
case utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN:
|
||||||
|
con::info("Templated file: \"{}\"", m_output_file);
|
||||||
if (buildLogFile)
|
if (buildLogFile)
|
||||||
*buildLogFile << "Templated file \"" << m_output_file << "\"\n";
|
*buildLogFile << "Templated file: \"" << m_output_file << "\"\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case utils::TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE:
|
||||||
|
con::info("File was up to date: \"{}\"", m_output_file);
|
||||||
|
if (buildLogFile)
|
||||||
|
*buildLogFile << "File was up to date: \"" << m_output_file << "\"\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case utils::TextFileCheckDirtyResult::FAILURE:
|
||||||
|
con::error("Failed to write file: \"{}\"", m_output_file);
|
||||||
|
if (buildLogFile)
|
||||||
|
*buildLogFile << "Failed to write file: \"" << m_output_file << "\"\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
m_first_line = true;
|
m_first_line = true;
|
||||||
m_write_output_to_file = false;
|
m_write_output_to_file = false;
|
||||||
m_output_cache.clear();
|
m_output_cache.clear();
|
||||||
m_output_cache.str(std::string());
|
m_output_cache.str(std::string());
|
||||||
m_output_stream.close();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -327,7 +344,7 @@ namespace templating
|
|||||||
m_write_output_to_file = true;
|
m_write_output_to_file = true;
|
||||||
const auto cachedData = m_output_cache.str();
|
const auto cachedData = m_output_cache.str();
|
||||||
if (!cachedData.empty())
|
if (!cachedData.empty())
|
||||||
m_output_stream << cachedData;
|
m_output.Stream() << cachedData;
|
||||||
m_output_cache.clear();
|
m_output_cache.clear();
|
||||||
m_output_cache.str(std::string());
|
m_output_cache.str(std::string());
|
||||||
|
|
||||||
@@ -353,8 +370,8 @@ namespace templating
|
|||||||
if (!parentDir.empty())
|
if (!parentDir.empty())
|
||||||
create_directories(parentDir);
|
create_directories(parentDir);
|
||||||
|
|
||||||
m_output_stream = std::ofstream(m_output_file, std::ios::out | std::ios::binary);
|
m_output = utils::TextFileCheckDirtyOutput(m_output_file);
|
||||||
if (!m_output_stream.is_open())
|
if (!m_output.Open())
|
||||||
{
|
{
|
||||||
con::error("Failed to open output file \"{}\"", m_output_file);
|
con::error("Failed to open output file \"{}\"", m_output_file);
|
||||||
return false;
|
return false;
|
||||||
@@ -371,12 +388,12 @@ namespace templating
|
|||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
std::string m_output_file;
|
std::string m_output_file;
|
||||||
std::string m_default_output_file;
|
std::string m_default_output_file;
|
||||||
const fs::path m_output_directory;
|
fs::path m_output_directory;
|
||||||
|
|
||||||
bool m_first_line;
|
bool m_first_line;
|
||||||
bool m_skip_pass;
|
bool m_skip_pass;
|
||||||
bool m_write_output_to_file;
|
bool m_write_output_to_file;
|
||||||
std::ofstream m_output_stream;
|
utils::TextFileCheckDirtyOutput m_output;
|
||||||
std::ostringstream m_output_cache;
|
std::ostringstream m_output_cache;
|
||||||
};
|
};
|
||||||
} // namespace templating
|
} // namespace templating
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ bool UnlinkerArgs::ParseArgs(const int argc, const char** argv, bool& shouldCont
|
|||||||
// --search-path
|
// --search-path
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_SEARCH_PATH))
|
if (m_argument_parser.IsOptionSpecified(OPTION_SEARCH_PATH))
|
||||||
{
|
{
|
||||||
if (!FileUtils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_SEARCH_PATH), m_user_search_paths))
|
if (!utils::ParsePathsString(m_argument_parser.GetValueForOption(OPTION_SEARCH_PATH), m_user_search_paths))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
bool FileUtils::ParsePathsString(const std::string& pathsString, std::set<std::string>& output)
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace utils
|
||||||
{
|
{
|
||||||
|
bool ParsePathsString(const std::string& pathsString, std::set<std::string>& output)
|
||||||
|
{
|
||||||
std::ostringstream currentPath;
|
std::ostringstream currentPath;
|
||||||
auto pathStart = true;
|
auto pathStart = true;
|
||||||
auto quotationPos = 0; // 0 = before quotations, 1 = in quotations, 2 = after quotations
|
auto quotationPos = 0; // 0 = before quotations, 1 = in quotations, 2 = after quotations
|
||||||
|
|
||||||
for (auto character : pathsString)
|
for (const auto character : pathsString)
|
||||||
{
|
{
|
||||||
switch (character)
|
switch (character)
|
||||||
{
|
{
|
||||||
@@ -60,4 +65,115 @@ bool FileUtils::ParsePathsString(const std::string& pathsString, std::set<std::s
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextFileCheckDirtyOutput::TextFileCheckDirtyOutput()
|
||||||
|
: m_open(false),
|
||||||
|
m_has_existing_file(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFileCheckDirtyOutput::TextFileCheckDirtyOutput(fs::path path)
|
||||||
|
: m_path(std::move(path)),
|
||||||
|
m_open(false),
|
||||||
|
m_has_existing_file(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFileCheckDirtyOutput::~TextFileCheckDirtyOutput()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextFileCheckDirtyOutput::Open()
|
||||||
|
{
|
||||||
|
if (m_open)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto parentFolder(m_path);
|
||||||
|
parentFolder.remove_filename();
|
||||||
|
create_directories(parentFolder);
|
||||||
|
|
||||||
|
m_has_existing_file = fs::is_regular_file(m_path);
|
||||||
|
|
||||||
|
if (!m_has_existing_file)
|
||||||
|
{
|
||||||
|
m_file_stream = std::ofstream(m_path, std::fstream::out | std::fstream::binary);
|
||||||
|
if (!m_file_stream.is_open())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_open = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& TextFileCheckDirtyOutput::Stream()
|
||||||
|
{
|
||||||
|
if (!m_has_existing_file)
|
||||||
|
return m_file_stream;
|
||||||
|
|
||||||
|
return m_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextFileCheckDirtyResult TextFileCheckDirtyOutput::Close()
|
||||||
|
{
|
||||||
|
if (!m_open)
|
||||||
|
return TextFileCheckDirtyResult::FAILURE;
|
||||||
|
|
||||||
|
m_open = false;
|
||||||
|
|
||||||
|
if (m_has_existing_file)
|
||||||
|
{
|
||||||
|
const auto renderedContent = std::move(m_memory).str();
|
||||||
|
m_memory = std::ostringstream();
|
||||||
|
|
||||||
|
if (!FileIsDirty(renderedContent))
|
||||||
|
return TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE;
|
||||||
|
|
||||||
|
std::ofstream stream(m_path, std::fstream::out | std::fstream::binary);
|
||||||
|
if (!stream.is_open())
|
||||||
|
return TextFileCheckDirtyResult::FAILURE;
|
||||||
|
|
||||||
|
stream.write(renderedContent.data(), renderedContent.size());
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextFileCheckDirtyResult::OUTPUT_WRITTEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool TextFileCheckDirtyOutput::FileIsDirty(const std::string& renderedContent) const
|
||||||
|
{
|
||||||
|
const auto fileSize = static_cast<size_t>(fs::file_size(m_path));
|
||||||
|
const size_t contentSize = renderedContent.size();
|
||||||
|
if (fileSize != contentSize)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::ifstream oldFileStream(m_path, std::fstream::in | std::fstream::binary);
|
||||||
|
if (!oldFileStream.is_open())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
char buffer[4096];
|
||||||
|
size_t currentContentOffset = 0;
|
||||||
|
while (currentContentOffset < contentSize)
|
||||||
|
{
|
||||||
|
const auto expectedReadCount = std::min<size_t>(sizeof(buffer), contentSize - currentContentOffset);
|
||||||
|
oldFileStream.read(buffer, expectedReadCount);
|
||||||
|
if (oldFileStream.gcount() != expectedReadCount)
|
||||||
|
{
|
||||||
|
oldFileStream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buffer, renderedContent.data() + currentContentOffset, expectedReadCount) != 0)
|
||||||
|
{
|
||||||
|
oldFileStream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentContentOffset += expectedReadCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldFileStream.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // namespace utils
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class FileUtils
|
namespace utils
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
static constexpr uint32_t MakeMagic32(const char ch0, const char ch1, const char ch2, const char ch3)
|
static constexpr uint32_t MakeMagic32(const char ch0, const char ch1, const char ch2, const char ch3)
|
||||||
{
|
{
|
||||||
return static_cast<uint32_t>(ch0) | static_cast<uint32_t>(ch1) << 8 | static_cast<uint32_t>(ch2) << 16 | static_cast<uint32_t>(ch3) << 24;
|
return static_cast<uint32_t>(ch0) | static_cast<uint32_t>(ch1) << 8 | static_cast<uint32_t>(ch2) << 16 | static_cast<uint32_t>(ch3) << 24;
|
||||||
@@ -18,5 +20,38 @@ public:
|
|||||||
* \param output A set for strings to save the output to.
|
* \param output A set for strings to save the output to.
|
||||||
* \return \c true if the user input was valid and could be processed successfully, otherwise \c false.
|
* \return \c true if the user input was valid and could be processed successfully, otherwise \c false.
|
||||||
*/
|
*/
|
||||||
static bool ParsePathsString(const std::string& pathsString, std::set<std::string>& output);
|
bool ParsePathsString(const std::string& pathsString, std::set<std::string>& output);
|
||||||
};
|
|
||||||
|
enum class TextFileCheckDirtyResult : std::uint8_t
|
||||||
|
{
|
||||||
|
OUTPUT_WRITTEN,
|
||||||
|
OUTPUT_WAS_UP_TO_DATE,
|
||||||
|
FAILURE
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextFileCheckDirtyOutput final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextFileCheckDirtyOutput();
|
||||||
|
explicit TextFileCheckDirtyOutput(std::filesystem::path path);
|
||||||
|
~TextFileCheckDirtyOutput();
|
||||||
|
TextFileCheckDirtyOutput(const TextFileCheckDirtyOutput& other) = delete;
|
||||||
|
TextFileCheckDirtyOutput(TextFileCheckDirtyOutput&& other) noexcept = default;
|
||||||
|
TextFileCheckDirtyOutput& operator=(const TextFileCheckDirtyOutput& other) = delete;
|
||||||
|
TextFileCheckDirtyOutput& operator=(TextFileCheckDirtyOutput&& other) noexcept = default;
|
||||||
|
|
||||||
|
bool Open();
|
||||||
|
std::ostream& Stream();
|
||||||
|
TextFileCheckDirtyResult Close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] bool FileIsDirty(const std::string& renderedContent) const;
|
||||||
|
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
|
||||||
|
bool m_open;
|
||||||
|
bool m_has_existing_file;
|
||||||
|
std::ofstream m_file_stream;
|
||||||
|
std::ostringstream m_memory;
|
||||||
|
};
|
||||||
|
} // namespace utils
|
||||||
|
|||||||
@@ -347,6 +347,7 @@ function ZoneCode:project()
|
|||||||
.. ' -h "' .. path.join(path.getabsolute(ProjectFolder()), 'ZoneCode/Game/%{file.basename}/%{file.basename}_ZoneCode.h') .. '"'
|
.. ' -h "' .. path.join(path.getabsolute(ProjectFolder()), 'ZoneCode/Game/%{file.basename}/%{file.basename}_ZoneCode.h') .. '"'
|
||||||
.. ' -c "' .. path.join(path.getabsolute(ProjectFolder()), 'ZoneCode/Game/%{file.basename}/%{file.basename}_Commands.txt') .. '"'
|
.. ' -c "' .. path.join(path.getabsolute(ProjectFolder()), 'ZoneCode/Game/%{file.basename}/%{file.basename}_Commands.txt') .. '"'
|
||||||
.. ' -o "%{wks.location}/src/ZoneCode/Game/%{file.basename}"'
|
.. ' -o "%{wks.location}/src/ZoneCode/Game/%{file.basename}"'
|
||||||
|
.. ' --build-log "%{wks.location}/src/ZoneCode/Game/%{file.basename}.log"'
|
||||||
.. ' -g ZoneLoad'
|
.. ' -g ZoneLoad'
|
||||||
.. ' -g ZoneMark'
|
.. ' -g ZoneMark'
|
||||||
.. ' -g ZoneWrite'
|
.. ' -g ZoneWrite'
|
||||||
@@ -358,6 +359,9 @@ function ZoneCode:project()
|
|||||||
path.join(ProjectFolder(), "Common/Game/%{file.basename}/%{file.basename}_Assets.h"),
|
path.join(ProjectFolder(), "Common/Game/%{file.basename}/%{file.basename}_Assets.h"),
|
||||||
TargetDirectoryBuildTools .. "/" .. ExecutableByOs('ZoneCodeGenerator')
|
TargetDirectoryBuildTools .. "/" .. ExecutableByOs('ZoneCodeGenerator')
|
||||||
}
|
}
|
||||||
|
buildoutputs {
|
||||||
|
"%{wks.location}/src/ZoneCode/Game/%{file.basename}.log"
|
||||||
|
}
|
||||||
filter {}
|
filter {}
|
||||||
|
|
||||||
filter "files:**/IW3.gen"
|
filter "files:**/IW3.gen"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Templates/ZoneLoadTemplate.h"
|
#include "Templates/ZoneLoadTemplate.h"
|
||||||
#include "Templates/ZoneMarkTemplate.h"
|
#include "Templates/ZoneMarkTemplate.h"
|
||||||
#include "Templates/ZoneWriteTemplate.h"
|
#include "Templates/ZoneWriteTemplate.h"
|
||||||
|
#include "Utils/FileUtils.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
#include "Utils/StringUtils.h"
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
@@ -28,58 +29,66 @@ void CodeGenerator::SetupTemplates()
|
|||||||
m_template_mapping["assetstructtests"] = std::make_unique<AssetStructTestsTemplate>();
|
m_template_mapping["assetstructtests"] = std::make_unique<AssetStructTestsTemplate>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGenerator::GenerateCodeOncePerTemplate(const OncePerTemplateRenderingContext& context, ICodeTemplate* codeTemplate) const
|
utils::TextFileCheckDirtyResult CodeGenerator::GenerateCodeOncePerTemplate(const OncePerTemplateRenderingContext& context, ICodeTemplate* codeTemplate) const
|
||||||
{
|
{
|
||||||
|
bool wroteAtLeastOneFile = false;
|
||||||
for (const auto& codeFile : codeTemplate->GetFilesToRenderOncePerTemplate(context))
|
for (const auto& codeFile : codeTemplate->GetFilesToRenderOncePerTemplate(context))
|
||||||
{
|
{
|
||||||
fs::path p(m_args->m_output_directory);
|
fs::path outputPath(m_args->m_output_directory);
|
||||||
p.append(codeFile.m_file_name);
|
outputPath.append(codeFile.m_file_name);
|
||||||
|
|
||||||
auto parentFolder(p);
|
utils::TextFileCheckDirtyOutput out(outputPath);
|
||||||
parentFolder.remove_filename();
|
if (!out.Open())
|
||||||
create_directories(parentFolder);
|
|
||||||
|
|
||||||
std::ofstream stream(p, std::fstream::out | std::fstream::binary);
|
|
||||||
|
|
||||||
if (!stream.is_open())
|
|
||||||
{
|
{
|
||||||
con::error("Failed to open file '{}'", p.string());
|
con::error("Failed to open file '{}'", outputPath.string());
|
||||||
return false;
|
return utils::TextFileCheckDirtyResult::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
codeTemplate->RenderOncePerTemplateFile(stream, codeFile.m_tag, context);
|
codeTemplate->RenderOncePerTemplateFile(out.Stream(), codeFile.m_tag, context);
|
||||||
|
|
||||||
stream.close();
|
const auto fileResult = out.Close();
|
||||||
|
if (fileResult == utils::TextFileCheckDirtyResult::FAILURE)
|
||||||
|
{
|
||||||
|
con::error("Failed to write file '{}'", outputPath.string());
|
||||||
|
return utils::TextFileCheckDirtyResult::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (fileResult == utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN)
|
||||||
|
wroteAtLeastOneFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wroteAtLeastOneFile ? utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN : utils::TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGenerator::GenerateCodeOncePerAsset(const OncePerAssetRenderingContext& context, ICodeTemplate* codeTemplate) const
|
utils::TextFileCheckDirtyResult CodeGenerator::GenerateCodeOncePerAsset(const OncePerAssetRenderingContext& context, ICodeTemplate* codeTemplate) const
|
||||||
{
|
{
|
||||||
|
bool wroteAtLeastOneFile = false;
|
||||||
for (const auto& codeFile : codeTemplate->GetFilesToRenderOncePerAsset(context))
|
for (const auto& codeFile : codeTemplate->GetFilesToRenderOncePerAsset(context))
|
||||||
{
|
{
|
||||||
fs::path p(m_args->m_output_directory);
|
fs::path outputPath(m_args->m_output_directory);
|
||||||
p.append(codeFile.m_file_name);
|
outputPath.append(codeFile.m_file_name);
|
||||||
|
|
||||||
auto parentFolder(p);
|
utils::TextFileCheckDirtyOutput out(outputPath);
|
||||||
parentFolder.remove_filename();
|
if (!out.Open())
|
||||||
create_directories(parentFolder);
|
|
||||||
|
|
||||||
std::ofstream stream(p, std::fstream::out | std::fstream::binary);
|
|
||||||
|
|
||||||
if (!stream.is_open())
|
|
||||||
{
|
{
|
||||||
con::error("Failed to open file '{}'", p.string());
|
con::error("Failed to open file '{}'", outputPath.string());
|
||||||
return false;
|
return utils::TextFileCheckDirtyResult::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
codeTemplate->RenderOncePerAssetFile(stream, codeFile.m_tag, context);
|
codeTemplate->RenderOncePerAssetFile(out.Stream(), codeFile.m_tag, context);
|
||||||
|
|
||||||
stream.close();
|
const auto fileResult = out.Close();
|
||||||
|
if (fileResult == utils::TextFileCheckDirtyResult::FAILURE)
|
||||||
|
{
|
||||||
|
con::error("Failed to write file '{}'", outputPath.string());
|
||||||
|
return utils::TextFileCheckDirtyResult::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (fileResult == utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN)
|
||||||
|
wroteAtLeastOneFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wroteAtLeastOneFile ? utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN : utils::TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGenerator::GetAssetWithName(const IDataRepository* repository, const std::string& name, StructureInformation*& asset)
|
bool CodeGenerator::GetAssetWithName(const IDataRepository* repository, const std::string& name, StructureInformation*& asset)
|
||||||
@@ -135,28 +144,55 @@ bool CodeGenerator::GenerateCode(const IDataRepository* repository)
|
|||||||
for (auto* asset : assets)
|
for (auto* asset : assets)
|
||||||
{
|
{
|
||||||
auto context = OncePerAssetRenderingContext::BuildContext(repository, asset);
|
auto context = OncePerAssetRenderingContext::BuildContext(repository, asset);
|
||||||
if (!GenerateCodeOncePerAsset(*context, foundTemplate->second.get()))
|
const auto result = GenerateCodeOncePerAsset(*context, foundTemplate->second.get());
|
||||||
|
switch (result)
|
||||||
{
|
{
|
||||||
|
case utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN:
|
||||||
|
con::info("Successfully generated code for asset '{}' with preset '{}'", asset->m_definition->GetFullName(), foundTemplate->first);
|
||||||
|
break;
|
||||||
|
case utils::TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE:
|
||||||
|
con::info("Code was up to date for asset '{}' with preset '{}'", asset->m_definition->GetFullName(), foundTemplate->first);
|
||||||
|
break;
|
||||||
|
case utils::TextFileCheckDirtyResult::FAILURE:
|
||||||
con::error("Failed to generate code for asset '{}' with preset '{}'", asset->m_definition->GetFullName(), foundTemplate->first);
|
con::error("Failed to generate code for asset '{}' with preset '{}'", asset->m_definition->GetFullName(), foundTemplate->first);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
con::info("Successfully generated code for asset '{}' with preset '{}'", asset->m_definition->GetFullName(), foundTemplate->first);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto context = OncePerTemplateRenderingContext::BuildContext(repository);
|
auto context = OncePerTemplateRenderingContext::BuildContext(repository);
|
||||||
if (!GenerateCodeOncePerTemplate(*context, foundTemplate->second.get()))
|
const auto result = GenerateCodeOncePerTemplate(*context, foundTemplate->second.get());
|
||||||
|
switch (result)
|
||||||
{
|
{
|
||||||
|
case utils::TextFileCheckDirtyResult::OUTPUT_WRITTEN:
|
||||||
|
con::info("Successfully generated code with preset '{}'", foundTemplate->first);
|
||||||
|
break;
|
||||||
|
case utils::TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE:
|
||||||
|
con::info("Code was up to date for preset '{}'", foundTemplate->first);
|
||||||
|
break;
|
||||||
|
case utils::TextFileCheckDirtyResult::FAILURE:
|
||||||
con::error("Failed to generate code with preset '{}'", foundTemplate->first);
|
con::error("Failed to generate code with preset '{}'", foundTemplate->first);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
con::info("Successfully generated code with preset '{}'", foundTemplate->first);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto end = std::chrono::steady_clock::now();
|
const auto end = std::chrono::steady_clock::now();
|
||||||
con::debug("Generating code took {}ms", std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
|
const auto timeInMs = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||||
|
con::debug("Generating code took {}ms", timeInMs);
|
||||||
|
|
||||||
|
if (!m_args->m_build_log_file.empty())
|
||||||
|
{
|
||||||
|
std::ofstream buildLogFile(m_args->m_build_log_file);
|
||||||
|
if (buildLogFile.is_open())
|
||||||
|
{
|
||||||
|
buildLogFile << "Generating code took " << timeInMs << "ms\n";
|
||||||
|
buildLogFile.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
con::error("Failed to open build log file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ICodeTemplate.h"
|
#include "ICodeTemplate.h"
|
||||||
|
#include "Utils/FileUtils.h"
|
||||||
#include "ZoneCodeGeneratorArguments.h"
|
#include "ZoneCodeGeneratorArguments.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -17,8 +18,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
void SetupTemplates();
|
void SetupTemplates();
|
||||||
|
|
||||||
bool GenerateCodeOncePerTemplate(const OncePerTemplateRenderingContext& context, ICodeTemplate* codeTemplate) const;
|
utils::TextFileCheckDirtyResult GenerateCodeOncePerTemplate(const OncePerTemplateRenderingContext& context, ICodeTemplate* codeTemplate) const;
|
||||||
bool GenerateCodeOncePerAsset(const OncePerAssetRenderingContext& context, ICodeTemplate* codeTemplate) const;
|
utils::TextFileCheckDirtyResult GenerateCodeOncePerAsset(const OncePerAssetRenderingContext& context, ICodeTemplate* codeTemplate) const;
|
||||||
|
|
||||||
static bool GetAssetWithName(const IDataRepository* repository, const std::string& name, StructureInformation*& asset);
|
static bool GetAssetWithName(const IDataRepository* repository, const std::string& name, StructureInformation*& asset);
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadHeaderData()
|
[[nodiscard]] bool ReadHeaderData() const
|
||||||
{
|
{
|
||||||
for (const auto& headerFile : m_args.m_header_paths)
|
for (const auto& headerFile : m_args.m_header_paths)
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadCommandsData()
|
[[nodiscard]] bool ReadCommandsData() const
|
||||||
{
|
{
|
||||||
for (const auto& commandsFile : m_args.m_command_paths)
|
for (const auto& commandsFile : m_args.m_command_paths)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -85,6 +85,13 @@ const CommandLineOption* const OPTION_GENERATE =
|
|||||||
.WithParameter("preset")
|
.WithParameter("preset")
|
||||||
.Reusable()
|
.Reusable()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
const CommandLineOption* const OPTION_BUILD_LOG =
|
||||||
|
CommandLineOption::Builder::Create()
|
||||||
|
.WithLongName("build-log")
|
||||||
|
.WithDescription("Specify a file to write a build log to.")
|
||||||
|
.WithParameter("logFilePath")
|
||||||
|
.Build();
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
|
const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
|
||||||
@@ -97,6 +104,7 @@ const CommandLineOption* const COMMAND_LINE_OPTIONS[]{
|
|||||||
OPTION_OUTPUT_FOLDER,
|
OPTION_OUTPUT_FOLDER,
|
||||||
OPTION_PRINT,
|
OPTION_PRINT,
|
||||||
OPTION_GENERATE,
|
OPTION_GENERATE,
|
||||||
|
OPTION_BUILD_LOG,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -170,6 +178,10 @@ bool ZoneCodeGeneratorArguments::ParseArgs(const int argc, const char** argv, bo
|
|||||||
else
|
else
|
||||||
m_output_directory = ".";
|
m_output_directory = ".";
|
||||||
|
|
||||||
|
// --build-log
|
||||||
|
if (m_argument_parser.IsOptionSpecified(OPTION_BUILD_LOG))
|
||||||
|
m_build_log_file = m_argument_parser.GetValueForOption(OPTION_BUILD_LOG);
|
||||||
|
|
||||||
// -h; --header
|
// -h; --header
|
||||||
if (m_argument_parser.IsOptionSpecified(OPTION_HEADER))
|
if (m_argument_parser.IsOptionSpecified(OPTION_HEADER))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ public:
|
|||||||
std::vector<std::string> m_command_paths;
|
std::vector<std::string> m_command_paths;
|
||||||
std::string m_output_directory;
|
std::string m_output_directory;
|
||||||
|
|
||||||
|
// Generate a build log that is always written for the compiler to determine
|
||||||
|
// the last output time.
|
||||||
|
std::string m_build_log_file;
|
||||||
|
|
||||||
std::vector<std::string> m_template_names;
|
std::vector<std::string> m_template_names;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ function useSourceTemplating(projectName)
|
|||||||
local templateFile = templateFiles[i]
|
local templateFile = templateFiles[i]
|
||||||
local relativeTemplatePath = path.getrelative(projectFolder, templateFile)
|
local relativeTemplatePath = path.getrelative(projectFolder, templateFile)
|
||||||
local relativeResultPath = path.replaceextension(relativeTemplatePath, "")
|
local relativeResultPath = path.replaceextension(relativeTemplatePath, "")
|
||||||
|
local relativeLogFilePath = path.replaceextension(relativeTemplatePath, ".log")
|
||||||
local resultExtension = path.getextension(relativeResultPath)
|
local resultExtension = path.getextension(relativeResultPath)
|
||||||
|
|
||||||
local data = io.readfile(templateFile)
|
local data = io.readfile(templateFile)
|
||||||
@@ -38,8 +39,12 @@ function useSourceTemplating(projectName)
|
|||||||
buildcommands {
|
buildcommands {
|
||||||
'"' .. TargetDirectoryBuildTools .. '/' .. ExecutableByOs('RawTemplater') .. '"'
|
'"' .. TargetDirectoryBuildTools .. '/' .. ExecutableByOs('RawTemplater') .. '"'
|
||||||
.. ' -o "%{prj.location}/"'
|
.. ' -o "%{prj.location}/"'
|
||||||
|
.. " --build-log \"" .. relativeLogFilePath .. "\""
|
||||||
.. " %{file.relpath}"
|
.. " %{file.relpath}"
|
||||||
}
|
}
|
||||||
|
buildoutputs {
|
||||||
|
"%{prj.location}/" .. relativeLogFilePath
|
||||||
|
}
|
||||||
for i = 1, #games do
|
for i = 1, #games do
|
||||||
local gameName = games[i]
|
local gameName = games[i]
|
||||||
local outputFileName = path.replaceextension(path.replaceextension(relativeResultPath, "") .. gameName, resultExtension)
|
local outputFileName = path.replaceextension(path.replaceextension(relativeResultPath, "") .. gameName, resultExtension)
|
||||||
|
|||||||
Reference in New Issue
Block a user