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