Просмотр исходного кода

Refactoring to separate libraries from projects, and use ranges

default_compile_flags
vector-of-bool 5 лет назад
Родитель
Сommit
c557b2ef05
9 измененных файлов: 244 добавлений и 57 удалений
  1. +21
    -8
      src/dds/build.cpp
  2. +1
    -1
      src/dds/compile.cpp
  3. +67
    -0
      src/dds/library.cpp
  4. +37
    -0
      src/dds/library.hpp
  5. +34
    -0
      src/dds/project.cpp
  6. +30
    -0
      src/dds/project.hpp
  7. +19
    -47
      src/dds/source.cpp
  8. +0
    -1
      src/dds/source.hpp
  9. +35
    -0
      src/dds/util.hpp

+ 21
- 8
src/dds/build.cpp Просмотреть файл

@@ -3,11 +3,16 @@
#include <dds/compile.hpp>
#include <dds/logging.hpp>
#include <dds/proc.hpp>
#include <dds/project.hpp>
#include <dds/source.hpp>
#include <dds/toolchain.hpp>
#include <libman/index.hpp>
#include <libman/parse.hpp>

#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>

#include <algorithm>
#include <chrono>
#include <iomanip>
@@ -166,8 +171,11 @@ void link_apps(const source_list& sources,
}

dds::compilation_set collect_compiles(const build_params& params, const library_manifest& man) {
source_list sources = source_file::collect_pf_sources(params.root);
const bool need_compile_deps = params.build_tests || params.build_apps || params.build_deps;
auto project = project::from_directory(params.root);
assert(project.main_library());
const auto& sources = project.main_library()->sources();

const bool need_compile_deps = params.build_tests || params.build_apps || params.build_deps;

std::vector<fs::path> dep_includes;
std::vector<std::string> dep_defines;
@@ -268,14 +276,19 @@ void dds::build(const build_params& params, const library_manifest& man) {

compiles.execute_all(params.toolchain, params.parallel_jobs);

source_list sources = source_file::collect_pf_sources(params.root);
using namespace ranges::view;

source_list sources = compiles.compilations //
| transform(DDS_TL(_1.source)) //
| ranges::to_vector;

archive_spec arc;
for (const auto& comp : compiles.compilations) {
if (comp.source.kind == source_kind::source) {
arc.input_files.push_back(comp.obj);
}
}
// Collect object files that make up that library
arc.input_files = compiles.compilations
// Only library sources
| filter(DDS_TL(_1.source.kind == source_kind::source)) //
| transform(DDS_TL(_1.obj)) //
| ranges::to_vector;

arc.out_path = params.out_root
/ (fmt::format("lib{}{}", params.export_name, params.toolchain.archive_suffix()));

+ 1
- 1
src/dds/compile.cpp Просмотреть файл

@@ -39,7 +39,7 @@ void file_compilation::compile(const toolchain& tc) const {
if (!compile_res.okay()) {
spdlog::error("Compilation failed: {}", source.path.string());
spdlog::error("Subcommand FAILED: {}\n{}", quote_command(cmd), compile_res.output);
throw compile_failure("Compilation failed.");
throw compile_failure(fmt::format("Compilation failed for {}.", source.path.string()));
}

// MSVC prints the filename of the source file. Dunno why, but they do.

+ 67
- 0
src/dds/library.cpp Просмотреть файл

@@ -0,0 +1,67 @@
#include <dds/library.hpp>

#include <spdlog/spdlog.h>

using namespace dds;

namespace {

struct pf_info {
source_list sources;
fs::path inc_dir;
fs::path src_dir;
};

pf_info collect_pf_sources(path_ref path) {
auto include_dir = path / "include";
auto src_dir = path / "src";

source_list sources;

if (fs::exists(include_dir)) {
if (!fs::is_directory(include_dir)) {
throw std::runtime_error("The `include` at the root of the project is not a directory");
}
auto inc_sources = source_file::collect_for_dir(include_dir);
// Drop any source files we found within `include/`
erase_if(sources, [&](auto& info) {
if (info.kind != source_kind::header) {
spdlog::warn("Source file in `include` will not be compiled: {}",
info.path.string());
return true;
}
return false;
});
extend(sources, inc_sources);
}

if (fs::exists(src_dir)) {
if (!fs::is_directory(src_dir)) {
throw std::runtime_error("The `src` at the root of the project is not a directory");
}
auto src_sources = source_file::collect_for_dir(src_dir);
extend(sources, src_sources);
}

return {std::move(sources), include_dir, src_dir};
}

} // namespace

library library::from_directory(path_ref lib_dir, std::string_view name) {
auto [sources, inc_dir, src_dir] = collect_pf_sources(lib_dir);

auto lib = library(name, std::move(sources));;

if (fs::exists(inc_dir)) {
lib._pub_inc_dir = inc_dir;
if (fs::exists(src_dir)) {
lib._priv_inc_dir = src_dir;
}
} else {
lib._pub_inc_dir = src_dir;
lib._priv_inc_dir = src_dir;
}

return lib;
}

+ 37
- 0
src/dds/library.hpp Просмотреть файл

@@ -0,0 +1,37 @@
#pragma once

#include <dds/source.hpp>

#include <optional>
#include <string>

namespace dds {

struct library_ident {
std::string namespace_;
std::string name;
};

class library {
std::string _name;
source_list _sources;
fs::path _pub_inc_dir;
fs::path _priv_inc_dir;

library(std::string_view name, source_list&& src)
: _name(name)
, _sources(std::move(src)) {}

public:
static library from_directory(path_ref, std::string_view name);
static library from_directory(path_ref path) {
return from_directory(path, path.filename().string());
}

path_ref public_include_dir() const noexcept { return _pub_inc_dir; }
path_ref private_include_dir() const noexcept { return _priv_inc_dir; }

const source_list& sources() const noexcept { return _sources; }
};

} // namespace dds

+ 34
- 0
src/dds/project.cpp Просмотреть файл

@@ -0,0 +1,34 @@
#include <dds/project.hpp>

#include <dds/source.hpp>

#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>

using namespace dds;

namespace {

bool has_library_dirs(path_ref p) { return fs::exists(p / "src") || fs::exists(p / "include"); }

std::vector<library> collect_submodules(path_ref pf_libs_dir) {
if (!fs::exists(pf_libs_dir)) {
return {};
}
using namespace ranges::view;
return fs::directory_iterator(pf_libs_dir) //
| filter(has_library_dirs) //
| transform(DDS_TL(library::from_directory(_1))) //
| ranges::to_vector;
}

} // namespace

project project::from_directory(path_ref pf_dir_path) {
std::optional<library> main_lib;
if (has_library_dirs(pf_dir_path)) {
main_lib = library::from_directory(pf_dir_path);
}
return project(std::move(main_lib), collect_submodules(pf_dir_path / "libs"));
}

+ 30
- 0
src/dds/project.hpp Просмотреть файл

@@ -0,0 +1,30 @@
#pragma once

#include <dds/library.hpp>
#include <dds/util.hpp>

#include <optional>
#include <vector>

namespace dds {

class project {
std::optional<library> _main_lib;
std::vector<library> _submodules;

project(std::optional<library>&& ml, std::vector<library>&& mods)
: _main_lib(std::move(ml))
, _submodules(std::move(mods)) {}

public:
static project from_directory(path_ref pr_dir);

const library* main_library() const noexcept {
if (_main_lib) {
return &*_main_lib;
}
return nullptr;
}
};

} // namespace dds

+ 19
- 47
src/dds/source.cpp Просмотреть файл

@@ -2,6 +2,10 @@

#include <spdlog/spdlog.h>

#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>

#include <algorithm>
#include <optional>
#include <vector>
@@ -61,51 +65,19 @@ std::optional<source_file> source_file::from_path(path_ref path) noexcept {
return source_file{path, *kind};
}

source_list source_file::collect_for_dir(path_ref path) {
source_list ret;
for (auto entry : fs::recursive_directory_iterator(path)) {
if (!entry.is_regular_file()) {
continue;
}
auto sf = source_file::from_path(entry.path());
if (!sf) {
spdlog::warn("Couldn't infer a source file kind for file: {}", entry.path().string());
}
ret.emplace_back(std::move(*sf));
}
return ret;
source_list source_file::collect_for_dir(path_ref src) {
using namespace ranges::view;
// Strips nullopt elements and lifts the value from the results
auto drop_nulls = //
filter(DDS_TL(_1.has_value())) //
| transform(DDS_TL(*_1));

// Collect all source files from the directory
return //
fs::recursive_directory_iterator(src) //
| filter(DDS_TL(_1.is_regular_file())) //
| transform(DDS_TL(source_file::from_path(_1))) //
// source_file::from_path returns an optional. Drop nulls
| drop_nulls //
| ranges::to_vector;
}

source_list source_file::collect_pf_sources(path_ref path) {
auto include_dir = path / "include";
auto src_dir = path / "src";

source_list sources;

if (fs::exists(include_dir)) {
if (!fs::is_directory(include_dir)) {
throw std::runtime_error("The `include` at the root of the project is not a directory");
}
auto inc_sources = source_file::collect_for_dir(include_dir);
// Drop any source files we found within `include/`
erase_if(sources, [&](auto& info) {
if (info.kind != source_kind::header) {
spdlog::warn("Source file in `include` will not be compiled: {}",
info.path.string());
return true;
}
return false;
});
extend(sources, inc_sources);
}

if (fs::exists(src_dir)) {
if (!fs::is_directory(src_dir)) {
throw std::runtime_error("The `src` at the root of the project is not a directory");
}
auto src_sources = source_file::collect_for_dir(src_dir);
extend(sources, src_sources);
}

return sources;
}

+ 0
- 1
src/dds/source.hpp Просмотреть файл

@@ -21,7 +21,6 @@ struct source_file {

static std::optional<source_file> from_path(path_ref) noexcept;
static std::vector<source_file> collect_for_dir(path_ref);
static std::vector<source_file> collect_pf_sources(path_ref);
};

using source_list = std::vector<source_file>;

+ 35
- 0
src/dds/util.hpp Просмотреть файл

@@ -8,6 +8,41 @@

namespace dds {

namespace detail {

template <std::size_t I,
typename A = std::nullptr_t,
typename B = std::nullptr_t,
typename C = std::nullptr_t,
typename D = std::nullptr_t>
decltype(auto) nth_arg(A&& a = nullptr, B&& b = nullptr, C&& c = nullptr, D&& d = nullptr) {
if constexpr (I == 0) {
return (A &&) a;
} else if constexpr (I == 1) {
return (B &&) b;
} else if constexpr (I == 2) {
return (C &&) c;
} else if constexpr (I == 3) {
return (D &&) d;
}
}

} // namespace detail

// Based on https://github.com/Quincunx271/TerseLambda
#define DDS_CTL(...) \
(auto&&... _args_)->auto { \
[[maybe_unused]] auto&& _1 = ::dds::detail::nth_arg<0>((decltype(_args_)&&)(_args_)...); \
[[maybe_unused]] auto&& _2 = ::dds::detail::nth_arg<1>((decltype(_args_)&&)(_args_)...); \
[[maybe_unused]] auto&& _3 = ::dds::detail::nth_arg<2>((decltype(_args_)&&)(_args_)...); \
[[maybe_unused]] auto&& _4 = ::dds::detail::nth_arg<3>((decltype(_args_)&&)(_args_)...); \
static_assert(sizeof...(_args_) <= 4); \
decltype(auto) result = (__VA_ARGS__); \
return result; \
}

#define DDS_TL [] DDS_CTL

inline namespace file_utils {

namespace fs = std::filesystem;

Загрузка…
Отмена
Сохранить