Start support for multiple build targets.

This commit is contained in:
jmsgrogan 2024-01-28 16:28:16 +00:00
parent e3e03dc31f
commit 3dce256213
52 changed files with 1044 additions and 340 deletions

View file

@ -8,8 +8,13 @@ g++ $SOURCE_DIR/main.cpp \
$CORE_SRC_DIR/base_types/Error.cpp \
$CORE_SRC_DIR/base_types/Index.cpp \
$CORE_SRC_DIR/base_types/Char.cpp \
$SOURCE_DIR/base/compiler/BuildLibrary.cpp \
$SOURCE_DIR/base/compiler/BuildSession.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildEnvironment.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildConfig.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildBinary.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildTarget.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildLibrary.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildExecutable.cpp \
$SOURCE_DIR/base/compiler/buildsystem/BuildSession.cpp \
$CORE_SRC_DIR/data_structures/String.cpp \
$CORE_SRC_DIR/filesystem/FileSystemPath.cpp \
$CORE_SRC_DIR/filesystem/File.cpp \
@ -18,17 +23,24 @@ g++ $SOURCE_DIR/main.cpp \
$CORE_SRC_DIR/filesystem/Directory.cpp \
$CORE_SRC_DIR/logging/ConsoleLogger.cpp \
$CORE_SRC_DIR/logging/Logger.cpp \
$CORE_SRC_DIR/serialization/yaml/YamlDocuments.cpp \
$CORE_SRC_DIR/serialization/yaml/YamlDocument.cpp \
$CORE_SRC_DIR/serialization/yaml/YamlParser.cpp \
$CORE_SRC_DIR/streams/FileStream.cpp \
$CORE_SRC_DIR/streams/Stream.cpp \
$CORE_SRC_DIR/system/process/Process.cpp \
$CORE_SRC_DIR/time/Time.cpp \
-o builder -g -fno-exceptions -fno-rtti \
-I$CORE_SRC_DIR/base_types \
-I$SOURCE_DIR/base/compiler \
-I$SOURCE_DIR/base/compiler/buildsystem \
-I$CORE_SRC_DIR/data_structures \
-I$CORE_SRC_DIR/encoding \
-I$CORE_SRC_DIR/filesystem \
-I$CORE_SRC_DIR/filesystem/posix \
-I$CORE_SRC_DIR/logging \
-I$CORE_SRC_DIR/memory \
-I$CORE_SRC_DIR/serialization/yaml \
-I$CORE_SRC_DIR/streams \
-I$CORE_SRC_DIR/system/process \
-I$CORE_SRC_DIR/time

View file

@ -1,42 +0,0 @@
#include "BuildLibrary.h"
#include "Logger.h"
#include "Directory.h"
BuildLibrary::BuildLibrary(const FileSystemPath& build_config)
: m_build_config(build_config)
{
}
Status BuildLibrary::scan()
{
LOG_INFO("Scanning build file at: " << m_build_config);
const auto search_dir = m_build_config.parent_path();
m_name = search_dir.stem().str();
STATUS_CHECK(Directory::getFilesWithExtension(search_dir,
".cpp",
m_sources,
true), "Error collecting source files")
m_include_dirs.push_back(search_dir);
STATUS_CHECK(Directory::getAllSubDirectories(search_dir,
m_include_dirs), "Error collecting include dirs")
return {};
}
const String& BuildLibrary::get_name() const
{
return m_name;
}
const Vector<FileSystemPath>& BuildLibrary::get_sources() const
{
return m_sources;
}
const Vector<FileSystemPath>& BuildLibrary::get_include_dirs() const
{
return m_include_dirs;
}

View file

@ -1,26 +0,0 @@
#pragma once
#include "FileSystemPath.h"
#include "String.h"
class BuildLibrary
{
public:
BuildLibrary() = default;
BuildLibrary(const FileSystemPath& build_config);
const Vector<FileSystemPath>& get_sources() const;
const Vector<FileSystemPath>& get_include_dirs() const;
const String& get_name() const;
Status scan();
private:
FileSystemPath m_build_config;
Vector<FileSystemPath> m_sources;
Vector<FileSystemPath> m_include_dirs;
String m_name;
};

View file

@ -1,131 +0,0 @@
#include "BuildSession.h"
#include "Logger.h"
#include "Process.h"
#include "Directory.h"
BuildSession::BuildSession(const String& source_dir,
const String& build_dir)
: m_source_dir(source_dir)
{
if (build_dir.empty())
{
m_build_dir = FileSystemPath::current_dir().value();
}
else
{
m_build_dir = build_dir;
}
const auto build_str = m_build_dir.str() + "/build";
m_build_dir = FileSystemPath(build_str);
m_compiler_flags.push_back("-g");
m_compiler_flags.push_back("-fno-exceptions");
m_compiler_flags.push_back("-fno-rtti");
}
Status BuildSession::scan()
{
LOG_INFO("Scanning sources at:" << m_source_dir);
Vector<FileSystemPath> yaml_files;
STATUS_CHECK(Directory::getFilesWithExtension(
m_source_dir,
".yaml",
yaml_files,
true), "Error looking for build files");
for(const auto& yaml_file : yaml_files)
{
if (yaml_file.file_name() == "build")
{
STATUS_CHECK(add_library(yaml_file),
"Error adding library");
}
}
return {};
}
Status BuildSession::add_library(const FileSystemPath& config_path)
{
LOG_INFO("Adding library at: " << config_path);
BuildLibrary lib(config_path);
STATUS_CHECK(lib.scan(), "Error scanning library");
m_libraries.push_back(lib);
return {};
}
Status BuildSession::build()
{
LOG_INFO("Creating dir: " << m_build_dir);
Directory::create(m_build_dir, true);
for(auto& library : m_libraries)
{
auto run_status = compile_library(library);
if (!run_status.ok())
{
return run_status;
}
run_status = create_archive(library);
if (!run_status.ok())
{
return run_status;
}
//break;
}
return {};
}
Status BuildSession::compile_library(BuildLibrary& lib)
{
for(const auto& source : lib.get_sources())
{
const auto run_status = compile_source_file(source, lib);
if (!run_status.ok())
{
return run_status;
}
//break;
}
return {};
}
Status BuildSession::create_archive(BuildLibrary& lib)
{
Vector<String> args;
args.push_back("rcs");
auto name = "lib" + lib.get_name() + ".a";
args.push_back(name);
for(const auto& source : lib.get_sources())
{
const auto output_path = m_build_dir / source.file_name();
const auto output_file = output_path.str() + ".o";
args.push_back(output_file);
}
LOG_INFO("Archiving " << name);
return Process::launch(m_archive_command, args);
}
Status BuildSession::compile_source_file(const FileSystemPath& source,
const BuildLibrary& lib)
{
Vector<String> args = m_compiler_flags;
args.push_back("-c");
add_include_dirs(args, lib);
args.push_back(source.str());
const auto output_path = m_build_dir / source.file_name();
args.push_back("-o");
args.push_back(output_path.str() + ".o");
LOG_INFO("Compiling " << source.file_name());
return Process::launch(m_compiler_command, args);
}
void BuildSession::add_include_dirs(Vector<String>& args, const BuildLibrary& lib)
{
for(const auto& include_dir : lib.get_include_dirs())
{
args.push_back(_s("-I") + include_dir.str());
}
}

View file

@ -1,34 +0,0 @@
#pragma once
#include "BuildLibrary.h"
#include "Error.h"
class BuildSession
{
public:
BuildSession(const String& source_dir,
const String& build_dir = {});
Status scan();
Status build();
Status add_library(const FileSystemPath& config_path);
private:
Status compile_library(BuildLibrary& lib);
Status compile_source_file(const FileSystemPath& source,
const BuildLibrary& lib);
void add_include_dirs(Vector<String>& args, const BuildLibrary& lib);
Status create_archive(BuildLibrary& lib);
String m_compiler_command{"/usr/bin/g++"};
String m_archive_command{"/usr/bin/ar"};
Vector<String> m_compiler_flags;
FileSystemPath m_source_dir;
FileSystemPath m_build_dir;
Vector<BuildLibrary> m_libraries;
};

View file

@ -0,0 +1,121 @@
#include "BuildBinary.h"
#include "Directory.h"
#include "Logger.h"
#include "Process.h"
BuildBinary::BuildBinary(BuildTargetType binary_type)
: BuildTarget(binary_type)
{
}
BuildBinary::BuildBinary(Ptr<BuildConfig> config)
: BuildTarget(std::move(config))
{
}
const Vector<FileSystemPath>& BuildBinary::get_sources() const
{
return m_sources;
}
Status BuildBinary::populate_sources_dirs()
{
return Directory::getFilesWithExtension(get_directory(),
".cpp",
m_sources,
true);
}
Status BuildBinary::build()
{
for(auto target : m_dependencies)
{
target->build();
}
if (const auto rc = compile_sources(); !rc.ok())
{
return rc;
}
if (const auto rc = create_archive(); !rc.ok())
{
return rc;
}
return {};
}
Status BuildBinary::configure(const BuildEnvironment& env)
{
if(const auto rc = BuildTarget::configure(env); !rc.ok())
{
return rc;
}
STATUS_CHECK(populate_sources_dirs(),
"Error collecting source files");
m_compiler_flags = env.get_compiler_flags();
m_compiler_command = env.get_compiler_command();
m_archive_command = env.get_archive_command();
m_build_dir = env.get_build_dir();
return {};
}
Status BuildBinary::compile_sources()
{
for(const auto& src : m_sources)
{
if (const auto rc = compile_file(src); !rc.ok())
{
return rc;
}
}
return {};
}
void BuildBinary::add_include_dirs(Vector<String>& args)
{
Vector<FileSystemPath> dirs;
get_public_include_dirs(dirs);
for(const auto& dir : dirs)
{
args.push_back("-I" + dir.str());
}
}
Status BuildBinary::compile_file(const FileSystemPath& source)
{
Vector<String> args = m_compiler_flags;
args.push_back("-c");
add_include_dirs(args);
args.push_back(source.str());
const auto output_path = m_build_dir / source.file_name();
args.push_back("-o");
args.push_back(output_path.str() + ".o");
LOG_INFO("Compiling " << source.file_name());
return Process::launch(m_compiler_command, args);
}
Status BuildBinary::create_archive()
{
Vector<String> args;
args.push_back("rcs");
auto name = "lib" + get_name() + ".a";
args.push_back(name);
for(const auto& src : get_sources())
{
const auto output_path = m_build_dir / src.file_name();
const auto output_file = output_path.str() + ".o";
args.push_back(output_file);
}
LOG_INFO("Archiving " << name);
return Process::launch(m_archive_command, args);
}

View file

@ -0,0 +1,37 @@
#pragma once
#include "BuildTarget.h"
class BuildBinary : public BuildTarget
{
public:
BuildBinary(BuildTargetType binary_type);
BuildBinary(Ptr<BuildConfig> config);
virtual ~BuildBinary() = default;
Status build() override;
Status configure(const BuildEnvironment& env) override;
const Vector<FileSystemPath>& get_sources() const;
private:
void add_include_dirs(Vector<String>& args);
Status populate_sources_dirs();
Status create_archive();
Status compile_sources();
Status compile_file(const FileSystemPath& source);
Vector<String> m_compiler_flags;
String m_compiler_command;
String m_archive_command;
FileSystemPath m_build_dir;
Vector<String> m_public_header_dependencies;
Vector<FileSystemPath> m_sources;
};

View file

@ -0,0 +1,33 @@
#include "BuildConfig.h"
#include "YamlParser.h"
BuildConfig::BuildConfig(const FileSystemPath& path)
: m_path(path)
{
}
Status BuildConfig::load()
{
YamlParser yaml_parser;
if (const auto rc = yaml_parser.parse(m_path, m_content); !rc.ok())
{
return rc;
}
return {};
}
FileSystemPath BuildConfig::get_directory() const
{
return m_path.parent_path();
}
String BuildConfig::get_directory_name() const
{
return get_directory().stem().str();
}
BuildTargetType BuildConfig::get_target_type() const
{
return m_type;
}

View file

@ -0,0 +1,27 @@
#pragma once
#include "FileSystemPath.h"
#include "YamlDocuments.h"
#include "Error.h"
#include "BuildTargetType.h"
class BuildConfig
{
public:
BuildConfig() = default;
BuildConfig(const FileSystemPath& path);
Status load();
FileSystemPath get_directory() const;
String get_directory_name() const;
BuildTargetType get_target_type() const;
private:
BuildTargetType m_type{BuildTargetType::STATIC_LIBRARY};
YamlDocuments m_content;
FileSystemPath m_path;
};

View file

@ -0,0 +1,46 @@
#include "BuildEnvironment.h"
BuildEnvironment::BuildEnvironment(const FileSystemPath& source_dir,
const FileSystemPath& build_dir)
: m_build_dir(build_dir),
m_source_dir(source_dir)
{
m_compiler_flags.push_back("-g");
m_compiler_flags.push_back("-fno-exceptions");
m_compiler_flags.push_back("-fno-rtti");
}
const Vector<String>& BuildEnvironment::get_compiler_flags() const
{
return m_compiler_flags;
}
const String& BuildEnvironment::get_compiler_command() const
{
return m_compiler_command;
}
const String& BuildEnvironment::get_archive_command() const
{
return m_archive_command;
}
const FileSystemPath& BuildEnvironment::get_build_dir() const
{
return m_build_dir;
}
const FileSystemPath& BuildEnvironment::get_source_dir() const
{
return m_source_dir;
}
FileSystemPath BuildEnvironment::get_test_dir() const
{
return m_source_dir / "test";
}
void BuildEnvironment::set_build_dir(const FileSystemPath& dir)
{
m_build_dir = dir;
}

View file

@ -0,0 +1,31 @@
#pragma once
#include "Vector.h"
#include "FileSystemPath.h"
class BuildEnvironment
{
public:
BuildEnvironment(const FileSystemPath& source_dir, const FileSystemPath& build_dir = {});
const Vector<String>& get_compiler_flags() const;
const String& get_compiler_command() const;
const String& get_archive_command() const;
const FileSystemPath& get_build_dir() const;
const FileSystemPath& get_source_dir() const;
FileSystemPath get_test_dir() const;
void set_build_dir(const FileSystemPath& dir);
private:
String m_compiler_command{"/usr/bin/g++"};
String m_archive_command{"/usr/bin/ar"};
Vector<String> m_compiler_flags;
FileSystemPath m_build_dir;
FileSystemPath m_source_dir;
};

View file

@ -0,0 +1,6 @@
#include "BuildExecutable.h"
BuildExecutable::BuildExecutable(Ptr<BuildConfig> config)
: BuildBinary(std::move(config))
{
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "BuildBinary.h"
class BuildExecutable : public BuildBinary
{
public:
BuildExecutable() = default;
BuildExecutable(Ptr<BuildConfig> config);
virtual ~BuildExecutable() = default;
};

View file

@ -0,0 +1,17 @@
#include "BuildLibrary.h"
BuildLibrary::BuildLibrary(BuildTargetType lib_type)
: BuildBinary(lib_type)
{
}
BuildLibrary::BuildLibrary(Ptr<BuildConfig> config)
: BuildBinary(std::move(config))
{
}
Status BuildLibrary::build()
{
return BuildBinary::build();
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "BuildBinary.h"
class BuildLibrary : public BuildBinary
{
public:
BuildLibrary(BuildTargetType lib_type);
BuildLibrary(Ptr<BuildConfig> config);
virtual ~BuildLibrary() = default;
Status build() override;
};

View file

@ -0,0 +1,86 @@
#include "BuildSession.h"
#include "Logger.h"
#include "Directory.h"
BuildSession::BuildSession(const FileSystemPath& source_dir,
const FileSystemPath& build_dir)
: m_build_environment(source_dir)
{
auto working_build_dir = build_dir;
if (working_build_dir.is_empty().value())
{
working_build_dir = FileSystemPath::current_dir().value();
}
m_build_environment.set_build_dir(working_build_dir / "build");
}
Status BuildSession::configure()
{
LOG_INFO("Configuring project at:" << m_build_environment.get_source_dir());
Vector<FileSystemPath> yaml_files;
STATUS_CHECK(Directory::getFilesWithExtension(
m_build_environment.get_source_dir(),
".yaml",
yaml_files,
true), "Error looking for build files");
for(const auto& yaml_file : yaml_files)
{
if (yaml_file.file_name() == "build")
{
STATUS_CHECK(add_target(yaml_file),
"Error adding target at: " + yaml_file.stem().str());
}
}
return configure_tests();
}
Status BuildSession::add_target(const FileSystemPath& config_path)
{
LOG_INFO("Adding target at: " << config_path);
auto target = BuildTarget::create(config_path);
STATUS_CHECK(target->configure(m_build_environment), "Error configuring target");
m_targets.push_back(std::move(target));
return {};
}
Status BuildSession::configure_tests()
{
const auto test_dir = m_build_environment.get_test_dir();
LOG_INFO("Scanning test files at:" << test_dir);
Vector<FileSystemPath> candidate_test_files;
STATUS_CHECK(Directory::getFilesWithExtension(
test_dir,
".cpp",
candidate_test_files,
true), "Error looking for test files");
Vector<FileSystemPath> test_files;
for(const auto& test_file : candidate_test_files)
{
if (test_file.stem().starts_with("Test"))
{
if (test_file.contains("core"))
{
LOG_INFO("Adding " << test_file);
test_files.push_back(test_file);
}
}
}
return {};
}
Status BuildSession::build()
{
LOG_INFO("Starting build at: " << m_build_environment.get_build_dir());
Directory::create(m_build_environment.get_build_dir(), true);
for(auto& target : m_targets)
{
auto run_status = target->build();
if (!run_status.ok())
{
return run_status;
}
}
return {};
}

View file

@ -0,0 +1,26 @@
#pragma once
#include "BuildEnvironment.h"
#include "BuildTarget.h"
#include "FileSystemPath.h"
#include "Error.h"
#include "Pointer.h"
class BuildSession
{
public:
BuildSession(const FileSystemPath& source_dir,
const FileSystemPath& build_dir = {});
Status build();
Status configure();
private:
Status add_target(const FileSystemPath& config_path);
Status configure_tests();
BuildEnvironment m_build_environment;
Vector<Ptr<BuildTarget> > m_targets;
};

View file

@ -0,0 +1,105 @@
#include "BuildTarget.h"
#include "Logger.h"
#include "Directory.h"
#include "YamlParser.h"
#include "BuildLibrary.h"
#include "BuildExecutable.h"
Ptr<BuildTarget> BuildTarget::create(const FileSystemPath& build_config_path)
{
auto build_config = Ptr<BuildConfig>::create(build_config_path);
build_config->load();
auto build_type = build_config->get_target_type();
if (build_type == BuildTargetType::SHARED_LIBRARY || build_type == BuildTargetType::SHARED_LIBRARY)
{
Ptr<BuildTarget> target_type;
target_type = Ptr<BuildLibrary>::create(std::move(build_config));
return std::move(target_type);
}
else
{
Ptr<BuildTarget> target_type;
target_type = Ptr<BuildExecutable>::create(std::move(build_config));
return std::move(target_type);
}
}
BuildTarget::BuildTarget(BuildTargetType target_type)
: m_type(target_type)
{
}
BuildTarget::BuildTarget(Ptr<BuildConfig> config)
: m_build_config(std::move(config)),
m_type(m_build_config->get_target_type())
{
}
void BuildTarget::add_dependency(BuildTarget* dependency)
{
m_dependencies.push_back(dependency);
}
BuildTargetType BuildTarget::get_type() const
{
return m_type;
}
const Vector<BuildTarget*>& BuildTarget::get_dependencies() const
{
return m_dependencies;
}
const Vector<String>& BuildTarget::get_dependency_names() const
{
return m_dependency_names;
}
const String& BuildTarget::get_name() const
{
return m_name;
}
void BuildTarget::get_public_include_dirs(Vector<FileSystemPath>& dirs) const
{
dirs.extend(m_include_dirs);
for(auto target : m_dependencies)
{
target->get_public_include_dirs(dirs);
}
}
Status BuildTarget::load_config()
{
STATUS_CHECK(m_build_config->load(), "Failed to load build config.");
m_name = m_build_config->get_directory_name();
return {};
}
FileSystemPath BuildTarget::get_directory() const
{
return m_build_config->get_directory();
}
Status BuildTarget::populate_include_dirs()
{
const auto search_dir = get_directory();
m_include_dirs.push_back(search_dir);
return Directory::getAllSubDirectories(search_dir, m_include_dirs);
}
Status BuildTarget::configure(const BuildEnvironment& env)
{
for(auto target : m_dependencies)
{
target->configure(env);
}
const auto search_dir = get_directory();
LOG_INFO("Scanning build file at: " << search_dir);
STATUS_CHECK(populate_include_dirs(), "Error populating include dirs");
return {};
}

View file

@ -0,0 +1,52 @@
#pragma once
#include "BuildConfig.h"
#include "FileSystemPath.h"
#include "String.h"
#include "Vector.h"
#include "BuildEnvironment.h"
class BuildTarget
{
public:
BuildTarget(BuildTargetType target_type);
BuildTarget(Ptr<BuildConfig> config);
static Ptr<BuildTarget> create(const FileSystemPath& build_config_path);
virtual ~BuildTarget() = default;
virtual Status build() = 0;
void add_dependency(BuildTarget* dependency);
virtual Status configure(const BuildEnvironment& env);
BuildTargetType get_type() const;
void get_public_include_dirs(Vector<FileSystemPath>& dirs) const;
const String& get_name() const;
const Vector<BuildTarget*>& get_dependencies() const;
const Vector<String>& get_dependency_names() const;
protected:
FileSystemPath get_directory() const;
Vector<BuildTarget*> m_dependencies;
private:
Status populate_include_dirs();
Status load_config();
Vector<String> m_dependency_names;
Ptr<BuildConfig> m_build_config;
Vector<FileSystemPath> m_include_dirs;
String m_name;
BuildTargetType m_type{BuildTargetType::UNSET};
};

View file

@ -0,0 +1,9 @@
#pragma once
enum class BuildTargetType
{
UNSET,
SHARED_LIBRARY,
STATIC_LIBRARY,
EXECUTABLE
};

View file

@ -1,27 +0,0 @@
set(MODULE_NAME compression)
list(APPEND SOURCES
StreamCompressor.cpp
huffman/HuffmanEncoder.cpp
huffman/HuffmanStream.cpp
huffman/HuffmanCodeLengthTable.cpp
huffman/HuffmanTree.cpp
RunLengthEncoder.cpp
ZlibEncoder.cpp
deflate/DeflateEncoder.cpp
deflate/DeflateBlock.cpp
Lz77Encoder.cpp
CyclicRedundancyChecker.cpp
)
add_library(${MODULE_NAME} SHARED ${SOURCES})
target_include_directories(${MODULE_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/deflate
${CMAKE_CURRENT_SOURCE_DIR}/huffman
)
target_link_libraries(${MODULE_NAME} PUBLIC core)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/base)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )

View file

@ -47,4 +47,16 @@ const Error& Status::error() const
bool Status::ok() const
{
return m_ok;
}
String Status::str() const
{
if (!m_ok)
{
return m_error.msg();
}
else
{
return {};
}
}

View file

@ -48,14 +48,16 @@ public:
Status(const Error& err);
const Error& error() const;
static Status with_errno(const String& prefix_msg);
void on_errno(const String& prefix_msg);
const Error& error() const;
bool ok() const;
String str() const;
private:
Error m_error;
bool m_ok{true};

View file

@ -25,6 +25,37 @@ String::String(const char* data)
append(data);
}
bool String::contains(const String& term) const
{
if (empty() || term.empty())
{
return false;
}
if (term.size() > size())
{
return false;
}
size_t match_idx{0};
for(std::size_t idx=0; idx<size();idx++)
{
if (term[match_idx] == m_data[idx])
{
match_idx++;
if (match_idx == term.size())
{
return true;
}
}
else
{
match_idx = 0;
}
}
return false;
}
String String::fmt(const char* fmt, ...)
{
String ret;
@ -297,6 +328,26 @@ void String::split(Vector<String>& output, char delimiter) const
}
}
bool String::starts_with(const String& prefix) const
{
if (size() < prefix.size())
{
return false;
}
if (prefix.empty() && (!empty()))
{
return false;
}
for(size_t idx=0; idx<prefix.size();idx++)
{
if (prefix[idx] != m_data[idx])
{
return false;
}
}
return true;
}
String String::to_string(size_t input)
{
String conv;

View file

@ -22,6 +22,8 @@ public:
void append(const Vector<Byte>& data);
bool contains(const String& term) const;
const Vector<char>& data() const;
bool empty() const;
@ -51,6 +53,8 @@ public:
void split(Vector<String>& output, char delimiter = ' ') const;
bool starts_with(const String& prefix) const;
static String to_string(size_t input);
void to_bytes(Vector<Byte>& bytes) const;

View file

@ -1,6 +1,6 @@
#pragma once
#include "Stream.h"
#include "IOStream.h"
#include "Byte.h"
#include "Error.h"

View file

@ -14,6 +14,12 @@ FileSystemPath::FileSystemPath(const String& path)
{
}
FileSystemPath::FileSystemPath(const char* path)
: m_path(path)
{
}
const String& FileSystemPath::str() const
{
return m_path;
@ -139,6 +145,16 @@ FileSystemPath FileSystemPath::stem() const
}
}
bool FileSystemPath::starts_with(const String& prefix) const
{
return m_path.starts_with(prefix);
}
bool FileSystemPath::contains(const String& term) const
{
return m_path.contains(term);
}
String FileSystemPath::file_name() const
{
String name_and_ext;

View file

@ -10,6 +10,8 @@ public:
FileSystemPath(const String& path);
FileSystemPath(const char* path);
const String& str() const;
static Result<FileSystemPath> current_dir();
@ -38,6 +40,10 @@ public:
FileSystemPath stem() const;
bool contains(const String& term) const;
bool starts_with(const String& prefix) const;
FileSystemPath operator/ (const char* body) const
{
String ret = m_path;

View file

@ -1,7 +1,7 @@
#pragma once
#include "FileSystemPath.h"
#include "Stream.h"
#include "IOStream.h"
#include "JsonDocument.h"
class JsonParser

View file

@ -1,6 +1,14 @@
#pragma once
#include "Dictionary.h"
#include "Pointer.h"
class YamlDocument
{
public:
YamlDocument()
{
}
Ptr<Dictionary> m_root;
};

View file

@ -0,0 +1,11 @@
#include "YamlDocuments.h"
void YamlDocuments::add_document(Ptr<YamlDocument> doc)
{
m_documents.push_back(std::move(doc));
}
const Vector<Ptr<YamlDocument> >& YamlDocuments::get_documents() const
{
return m_documents;
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "Vector.h"
#include "Pointer.h"
#include "YamlDocument.h"
class YamlDocuments
{
public:
void add_document(Ptr<YamlDocument> doc);
const Vector<Ptr<YamlDocument> >& get_documents() const;
private:
Vector<Ptr<YamlDocument> > m_documents;
};

View file

@ -0,0 +1,14 @@
#include "YamlParser.h"
#include "FileStream.h"
Status YamlParser::parse(const FileSystemPath& path, YamlDocuments& result)
{
InputFileStream f(path);
return parse(f, result);
}
Status YamlParser::parse(InputStream<Byte>& input, YamlDocuments& result)
{
return {};
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "IOStream.h"
#include "YamlDocuments.h"
#include "FileSystemPath.h"
class YamlParser
{
public:
Status parse(const FileSystemPath& path, YamlDocuments& result);
Status parse(InputStream<Byte>& input, YamlDocuments& result);
};

View file

@ -2,9 +2,9 @@
#include "Bits.h"
Optional<Byte> BinaryStream::getNextByte(InputStream<Byte>& stream)
bool BinaryStream::getNextByte(InputStream<Byte>& stream, Byte& ret)
{
return stream.get();
return stream.get(ret);
}
bool BinaryStream::getNextNBytes(InputStream<Byte>& stream, Byte* buffer, size_t number)

View file

@ -1,6 +1,6 @@
#pragma once
#include "Stream.h"
#include "IOStream.h"
#include "String.h"
#include "Optional.h"
#include "Byte.h"
@ -8,7 +8,6 @@
class BinaryStream
{
public:
template<typename T>
static bool write(OutputStream<Byte>* stream, T data)
{
@ -16,7 +15,7 @@ public:
return true;
}
static Optional<Byte> getNextByte(InputStream<Byte>& stream);
static bool getNextByte(InputStream<Byte>& stream, Byte& ret);
static bool getNextNBytes(InputStream<Byte>& stream, Byte* buffer, size_t numBytes);

View file

@ -1,6 +1,6 @@
#pragma once
#include "Stream.h"
#include "IOStream.h"
#include "String.h"
using OutputByteStream = OutputByteStream<Byte>;

View file

@ -0,0 +1,58 @@
#include "FileStream.h"
InputFileStream::InputFileStream(const FileSystemPath& path)
: m_file(path),
m_buffer(Vector<Byte>(m_buffer_size))
{
}
bool InputFileStream::finished() const
{
return m_end_of_stream == true;
}
bool InputFileStream::get(Byte& item)
{
if (m_buffer_offset >= m_buffer_current_size)
{
if (m_end_of_file)
{
m_end_of_stream = true;
return false;
}
m_buffer_offset = 0;
if (const auto rc = m_file.read(m_buffer); !rc.ok())
{
on_error(rc);
return false;
}
m_buffer_current_size = m_buffer.size();
if (m_buffer_current_size < m_buffer_size)
{
m_end_of_file = true;
}
if (m_buffer_current_size == 0)
{
m_end_of_stream = true;
return false;
}
item = m_buffer[m_buffer_offset];
m_buffer_offset++;
return true;
}
else
{
item = m_buffer[m_buffer_offset];
m_buffer_offset++;
return true;
}
}
bool InputFileStream::good() const
{
return !m_end_of_stream && Stream::good();
}

View file

@ -1,32 +1,29 @@
#pragma once
#include "Byte.h"
#include "Stream.h"
#include "IOStream.h"
#include "FileSystemPath.h"
#include "File.h"
#include "Vector.h"
class InputFileStream : public InputStream<Byte>
{
public:
InputFileStream(const FileSystemPath& path)
: File(path)
{
InputFileStream(const FileSystemPath& path);
}
bool finished() const;
bool good() const override
{
return
}
bool good() const override;
bool get(T& item) = 0;
bool get(Byte& item);
private:
void finished()
{
}
File mFile;
File m_file;
bool m_end_of_file{false};
bool m_end_of_stream{false};
size_t m_buffer_offset{0};
size_t m_buffer_current_size{0};
size_t m_buffer_size{4096};
Vector<Byte> m_buffer;
Status mStatus;
};

View file

@ -0,0 +1,41 @@
#pragma once
#include "Vector.h"
#include "Stream.h"
template<typename T>
class InputStream : public Stream
{
public:
virtual bool get(T& item) = 0;
virtual int get(Vector<T>& items)
{
size_t count = 0;
T item;
while(good() && count < items.size())
{
if (const auto ok = get(item); !ok)
{
break;
}
items[count] = item;
count++;
}
if (has_error())
{
return -1;
}
else
{
return count;
}
}
};
template<typename T>
class OutputStream : public Stream
{
public:
virtual int write(T* data, size_t size) = 0;
};

View file

@ -20,8 +20,7 @@ bool InputBitStream::readNextByte(Byte& buffer)
{
if (mStream->good())
{
buffer = static_cast<Byte>(mStream->get());
return true;
return mStream->get(buffer);
}
else
{

View file

@ -1,7 +1,7 @@
#pragma once
#include "BitStream.h"
#include "Stream.h"
#include "IOStream.h"
#include "Byte.h"
class InputBitStream : public BitStream

View file

@ -1,7 +1,7 @@
#pragma once
#include "BitStream.h"
#include "Stream.h"
#include "IOStream.h"
#include "Byte.h"
class OutputBitStream : public BitStream

View file

@ -0,0 +1,23 @@
#include "Stream.h"
bool Stream::good() const
{
return m_has_error;
}
const Status& Stream::get_last_error() const
{
return m_last_error;
}
void Stream::on_error(const String& msg)
{
m_has_error = true;
m_last_error = Status(Error(msg));
}
void Stream::on_error(const Status& status)
{
m_has_error = true;
m_last_error = status;
}

View file

@ -1,34 +1,25 @@
#pragma once
#include "Optional.h"
#include <cstddef>
#include "Error.h"
template<typename T>
class Stream
{
public:
virtual bool good() const = 0;
};
const Status& get_last_error() const;
template<typename T>
class InputStream : public Stream<T>
{
public:
Optional<T> get()
virtual bool good() const;
bool has_error() const
{
T item;
if (get(item))
{
return {item};
}
return {};
return m_has_error;
}
virtual bool get(T& item) = 0;
protected:
void on_error(const String& msg);
void on_error(const Status& status);
bool m_has_error{false};
Status m_last_error;
};
template<typename T>
class OutputStream : public Stream<T>
{
public:
virtual void write(T* data, size_t size) = 0;
};

View file

@ -0,0 +1,32 @@
#include "StringStream.h"
StringStream::StringStream(const String& str)
{
str.to_bytes(m_buffer);
}
bool StringStream::finished() const
{
return m_end_of_stream;
}
bool StringStream::good() const
{
return !m_end_of_stream && InputStream<Byte>::good();
}
bool StringStream::get(Byte& item)
{
if (m_end_of_stream)
{
return false;
}
if (m_offset >= m_buffer.size())
{
m_end_of_stream = true;
return false;
}
item = m_buffer[m_offset];
m_offset++;
return true;
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "IOStream.h"
#include "String.h"
class StringStream : public InputStream<Byte>
{
public:
StringStream(const String& str);
bool finished() const;
bool good() const override;
bool get(Byte& item);
private:
bool m_end_of_stream{false};
size_t m_offset{0};
VecBytes m_buffer;
};

View file

@ -1,26 +1,26 @@
#include "BuildSession.h"
#include "ConsoleLogger.h"
#include "FileSystemPath.h"
int main(int argc, char** argv)
{
if (argc == 1)
if (argc <= 1)
{
LOG_ERROR("Missing arg with path to source dir");
return -1;
}
BuildSession build(argv[1]);
const auto scan_status = build.scan();
if (!scan_status.ok())
FileSystemPath source_path(argv[1]);
BuildSession build(source_path);
if (const auto rc = build.configure(); !rc.ok())
{
LOG_ERROR("Scan failed with " << scan_status.error().msg());
LOG_ERROR("Configure failed with " << rc);
return -1;
}
const auto build_status = build.build();
if (!build_status.ok())
if (const auto rc = build.build(); !rc.ok())
{
LOG_ERROR("Build failed with " << build_status.error().msg());
LOG_ERROR("Build failed with " << rc);
return -1;
}
return 0;

View file

@ -8,14 +8,21 @@ g++ $SCRIPT_DIR/test_runner.cpp \
$CORE_SRC_DIR/base_types/Index.cpp \
$CORE_SRC_DIR/base_types/Char.cpp \
$CORE_SRC_DIR/data_structures/String.cpp \
$CORE_SRC_DIR/filesystem/File.cpp \
$CORE_SRC_DIR/filesystem/FileSystemPath.cpp \
$CORE_SRC_DIR/logging/Logger.cpp \
$CORE_SRC_DIR/logging/ConsoleLogger.cpp \
$CORE_SRC_DIR/serialization/yaml/YamlDocument.cpp \
$CORE_SRC_DIR/serialization/yaml/YamlDocuments.cpp \
$CORE_SRC_DIR/serialization/yaml/YamlParser.cpp \
$CORE_SRC_DIR/streams/Stream.cpp \
$CORE_SRC_DIR/streams/StringStream.cpp \
$CORE_SRC_DIR/time/Time.cpp \
$SCRIPT_DIR/test_utils/TestCaseRunner.cpp \
$SCRIPT_DIR/core/TestFileSystemPath.cpp \
$SCRIPT_DIR/core/TestString.cpp \
$SCRIPT_DIR/core/TestVector.cpp \
$SCRIPT_DIR/core/TestYamlParser.cpp \
-o test_runner -g \
-I$SCRIPT_DIR/test_utils \
-I$CORE_SRC_DIR \
@ -24,6 +31,8 @@ g++ $SCRIPT_DIR/test_runner.cpp \
-I$CORE_SRC_DIR/data_structures \
-I$CORE_SRC_DIR/base_types \
-I$CORE_SRC_DIR/memory \
-I$CORE_SRC_DIR/time \
-I$CORE_SRC_DIR/system/process \
-I$CORE_SRC_DIR/streams \
-I$CORE_SRC_DIR/serialization/yaml \
-I$CORE_SRC_DIR/time \
-I$CORE_SRC_DIR/filesystem

View file

@ -1,13 +0,0 @@
include(TestTargets)
unit_tests(
MODULE_NAME core
FILES
TestBits.cpp
TestBitStream.cpp
TestDataStructures.cpp
TestTomlReader.cpp
TestStringUtils.cpp
DEPENDENCIES
core
)

View file

@ -2,8 +2,6 @@
#include "TestFramework.h"
#include <stdio.h>
TEST_CASE(TestVectorExtend, "core")
{
Vector<size_t> vec;

View file

@ -0,0 +1,19 @@
#include "TestFramework.h"
#include "YamlParser.h"
#include "StringStream.h"
TEST_CASE(TestYamlParser, "core")
{
const auto content = R"(depends:
headers:
public:
- core)";
StringStream stream(content);
YamlDocuments yaml_docs;
YamlParser parser;
const auto status = parser.parse(stream, yaml_docs);
REQUIRE(status.ok());
}