diff options
author | John Hodge <tpg@ucc.asn.au> | 2017-08-20 22:16:09 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2017-08-20 22:16:09 +0800 |
commit | 739443094434e2622abd1fea5d2b5a03bc1ba0ef (patch) | |
tree | dbc593a8fd14e95c2c73dd441e513aee21d03824 | |
parent | 10e0d9a2609cc2b4d30c38e7f1f20e11de432fd6 (diff) | |
parent | a99e49b7505d2912d8699d4c791b8b30c194024b (diff) | |
download | mrust-739443094434e2622abd1fea5d2b5a03bc1ba0ef.tar.gz |
Merge branch 'master' of https://github.com/thepowersgang/mrustc
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/ast/crate.cpp | 23 | ||||
-rw-r--r-- | src/ast/crate.hpp | 3 | ||||
-rw-r--r-- | src/expand/format_args.cpp | 2 | ||||
-rw-r--r-- | src/hir/from_ast_expr.cpp | 2 | ||||
-rw-r--r-- | src/main.cpp | 11 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 246 | ||||
-rw-r--r-- | tools/minicargo/Makefile | 6 | ||||
-rw-r--r-- | tools/minicargo/build.cpp | 230 | ||||
-rw-r--r-- | tools/minicargo/debug.h | 4 | ||||
-rw-r--r-- | tools/minicargo/helpers.h | 191 | ||||
-rw-r--r-- | tools/minicargo/main.cpp | 39 | ||||
-rw-r--r-- | tools/minicargo/manifest.cpp | 174 | ||||
-rw-r--r-- | tools/minicargo/manifest.h | 52 | ||||
-rw-r--r-- | tools/minicargo/repository.cpp | 70 | ||||
-rw-r--r-- | tools/minicargo/repository.h | 29 | ||||
-rw-r--r-- | tools/minicargo/toml.cpp | 13 | ||||
-rw-r--r-- | tools/minicargo/toml.h | 21 | ||||
-rw-r--r-- | vsproject/minicargo/minicargo.vcxproj | 2 | ||||
-rw-r--r-- | vsproject/minicargo/minicargo.vcxproj.filters | 6 | ||||
-rw-r--r-- | vsproject/mrustc.sln | 3 | ||||
-rw-r--r-- | vsproject/mrustc.vcxproj.filters | 180 |
22 files changed, 1036 insertions, 272 deletions
@@ -45,3 +45,4 @@ /bnf/rust.tab.h /bnf/rust.output /bnf/test.bin +/vsproject/output diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index 394cd47b..f003a00b 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -8,6 +8,9 @@ #include <hir/main_bindings.hpp> // HIR_Deserialise #include <fstream> +::std::vector<::std::string> AST::g_crate_load_dirs = { }; +::std::map<::std::string, ::std::string> AST::g_crate_overrides; + namespace { bool check_item_cfg(const ::AST::MetaItems& attrs) { @@ -99,15 +102,23 @@ void Crate::load_externs() void Crate::load_extern_crate(Span sp, const ::std::string& name) { DEBUG("Loading crate '" << name << "'"); - // TODO: Search a list of load paths for the crate - ::std::vector< ::std::string> paths { "output/", "output/test_deps/" }; ::std::string path; - for(const auto& p : paths){ - path = p + "lib" + name + ".hir"; + auto it = g_crate_overrides.find(name); + if(it != g_crate_overrides.end()) + { + path = it->second; + } + else + { + // Search a list of load paths for the crate + for(const auto& p : g_crate_load_dirs) + { + path = p + "/lib" + name + ".hir"; - if( ::std::ifstream(path).good() ) { - break ; + if( ::std::ifstream(path).good() ) { + break ; + } } } if( !::std::ifstream(path).good() ) { diff --git a/src/ast/crate.hpp b/src/ast/crate.hpp index f9594a83..53dea1b9 100644 --- a/src/ast/crate.hpp +++ b/src/ast/crate.hpp @@ -89,4 +89,7 @@ public: const MacroRules* find_macro_rules(const ::std::string& name) const; }; +extern ::std::vector<::std::string> g_crate_load_dirs; +extern ::std::map<::std::string, ::std::string> g_crate_overrides; + } // namespace AST diff --git a/src/expand/format_args.cpp b/src/expand/format_args.cpp index 92afcbb2..e4c02b8b 100644 --- a/src/expand/format_args.cpp +++ b/src/expand/format_args.cpp @@ -477,7 +477,7 @@ class CFormatArgsExpander: auto expr_tt = TokenTree(Token( InterpolatedFragment(InterpolatedFragment::EXPR, Parse_Expr0(lex).release()) )); - auto ins_rv = named_args_index.insert( ::std::make_pair(mv$(name), named_args.size()) ); + auto ins_rv = named_args_index.insert( ::std::make_pair(mv$(name), static_cast<unsigned>(named_args.size())) ); if( ins_rv.second == false ) { ERROR(sp, E0000, "Duplicate definition of named argument `" << ins_rv.first->first << "`"); } diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 9bbb0418..545873ed 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -441,6 +441,8 @@ struct LowerHIR_ExprNode_Visitor: case CORETYPE_U32: return ::HIR::CoreType::U32; case CORETYPE_I64: return ::HIR::CoreType::I64; case CORETYPE_U64: return ::HIR::CoreType::U64; + case CORETYPE_I128: return ::HIR::CoreType::I128; + case CORETYPE_U128: return ::HIR::CoreType::U128; case CORETYPE_INT: return ::HIR::CoreType::Isize; case CORETYPE_UINT: return ::HIR::CoreType::Usize; diff --git a/src/main.cpp b/src/main.cpp index 7b1d94be..b883a828 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -224,6 +224,11 @@ int main(int argc, char *argv[]) // Load external crates. CompilePhaseV("LoadCrates", [&]() { + // Hacky! + for(const auto& ld : params.lib_search_dirs) + { + AST::g_crate_load_dirs.push_back(ld); + } crate.load_externs(); }); @@ -570,6 +575,12 @@ int main(int argc, char *argv[]) // ::std::cerr << "Internal Compiler Error: " << e << ::std::endl; // return 2; //} + + // TODO: Make this conditional +#if 0 + ::std::cout << "Press enter to exit..." << ::std::endl; + ::std::cin.get(); +#endif return 0; } diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 973aa33a..b7c3806a 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -499,7 +499,9 @@ namespace { break; case Compiler::Msvc: is_windows = true; + // TODO: Look up these paths in the registry and use CreateProcess instead of system args.push_back(cache_str( detect_msvc().path_vcvarsall )); + //args.push_back("amd64"); args.push_back("&"); args.push_back("cl.exe"); args.push_back("/nologo"); @@ -568,8 +570,9 @@ namespace { } //DEBUG("- " << cmd_ss.str()); ::std::cout << "Running comamnd - " << cmd_ss.str() << ::std::endl; - if( system(cmd_ss.str().c_str()) ) + if( system(cmd_ss.str().c_str()) != 0 ) { + ::std::cerr << "C Compiler failed to execute" << ::std::endl; abort(); } } @@ -2036,82 +2039,17 @@ namespace { if( e.flag_idx != ~0u ) m_of << indent << "}\n"; break; } - case ::MIR::Statement::TAG_Asm: { - const auto& e = stmt.as_Asm(); - - struct H { - static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { - return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end(); - } - static const char* convert_reg(const char* r) { - if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) { - return "a"; - } - else { - return r; - } - } - }; - bool is_volatile = H::has_flag(e.flags, "volatile"); - bool is_intel = H::has_flag(e.flags, "intel"); - - m_of << indent << "__asm__ "; - if(is_volatile) m_of << "__volatile__"; - // TODO: Convert format string? - // TODO: Use a C-specific escaper here. - m_of << "(\"" << (is_intel ? ".syntax intel; " : ""); - for(auto it = e.tpl.begin(); it != e.tpl.end(); ++it) - { - if( *it == '\n' ) - m_of << ";\\n"; - else if( *it == '"' ) - m_of << "\\\""; - else if( *it == '\\' ) - m_of << "\\\\"; - else if( *it == '/' && *(it+1) == '/' ) - { - while( it != e.tpl.end() || *it == '\n' ) - ++it; - -- it; - } - else if( *it == '%' && *(it+1) == '%' ) - m_of << "%"; - else if( *it == '%' && !isdigit(*(it+1)) ) - m_of << "%%"; - else - m_of << *it; - } - m_of << (is_intel ? ".syntax att; " : "") << "\""; - m_of << ": "; - for(unsigned int i = 0; i < e.outputs.size(); i ++ ) - { - const auto& v = e.outputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\""; - switch(v.first[0]) - { - case '=': m_of << "="; break; - case '+': m_of << "+"; break; - default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); - } - m_of << H::convert_reg(v.first.c_str()+1); - m_of << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.inputs.size(); i ++ ) - { - const auto& v = e.inputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.clobbers.size(); i ++ ) + case ::MIR::Statement::TAG_Asm: + switch(m_compiler) { - if( i != 0 ) m_of << ", "; - m_of << "\"" << e.clobbers[i] << "\""; + case Compiler::Gcc: + this->emit_asm_gcc(mir_res, stmt.as_Asm(), indent_level); + break; + case Compiler::Msvc: + this->emit_asm_msvc(mir_res, stmt.as_Asm(), indent_level); + break; } - m_of << ");\n"; - break; } + break; case ::MIR::Statement::TAG_Assign: { const auto& e = stmt.as_Assign(); DEBUG("- " << e.dst << " = " << e.src); @@ -2815,6 +2753,121 @@ namespace { } m_of << " );\n"; } + void emit_asm_gcc(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement::Data_Asm& e, unsigned indent_level) + { + auto indent = RepeatLitStr{ "\t", static_cast<int>(indent_level) }; + struct H { + static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { + return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x) {return x == des; }) != flags.end(); + } + static const char* convert_reg(const char* r) { + if (::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0) { + return "a"; + } + else { + return r; + } + } + }; + bool is_volatile = H::has_flag(e.flags, "volatile"); + bool is_intel = H::has_flag(e.flags, "intel"); + + + m_of << indent << "__asm__ "; + if (is_volatile) m_of << "__volatile__"; + // TODO: Convert format string? + // TODO: Use a C-specific escaper here. + m_of << "(\"" << (is_intel ? ".syntax intel; " : ""); + for (auto it = e.tpl.begin(); it != e.tpl.end(); ++it) + { + if (*it == '\n') + m_of << ";\\n"; + else if (*it == '"') + m_of << "\\\""; + else if (*it == '\\') + m_of << "\\\\"; + else if (*it == '/' && *(it + 1) == '/') + { + while (it != e.tpl.end() || *it == '\n') + ++it; + --it; + } + else if (*it == '%' && *(it + 1) == '%') + m_of << "%"; + else if (*it == '%' && !isdigit(*(it + 1))) + m_of << "%%"; + else + m_of << *it; + } + m_of << (is_intel ? ".syntax att; " : "") << "\""; + m_of << ": "; + for (unsigned int i = 0; i < e.outputs.size(); i++) + { + const auto& v = e.outputs[i]; + if (i != 0) m_of << ", "; + m_of << "\""; + switch (v.first[0]) + { + case '=': m_of << "="; break; + case '+': m_of << "+"; break; + default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); + } + m_of << H::convert_reg(v.first.c_str() + 1); + m_of << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for (unsigned int i = 0; i < e.inputs.size(); i++) + { + const auto& v = e.inputs[i]; + if (i != 0) m_of << ", "; + m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for (unsigned int i = 0; i < e.clobbers.size(); i++) + { + if (i != 0) m_of << ", "; + m_of << "\"" << e.clobbers[i] << "\""; + } + m_of << ");\n"; + } + void emit_asm_msvc(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement::Data_Asm& e, unsigned indent_level) + { + auto indent = RepeatLitStr{ "\t", static_cast<int>(indent_level) }; + + if( !e.inputs.empty() || !e.outputs.empty() ) + { + MIR_TODO(mir_res, "Inputs/outputs in msvc inline assembly"); +#if 0 + m_of << indent << "{\n"; + for(size_t i = 0; i < e.inputs.size(); i ++) + { + m_of << indent << "auto asm_i_" << i << " = "; + emit_lvalue(e.inputs[i]); + } +#endif + } + + m_of << indent << "__asm {\n"; + + m_of << indent << "\t"; + for (auto it = e.tpl.begin(); it != e.tpl.end(); ++it) + { + if (*it == ';') + { + m_of << "\n"; + m_of << indent << "\t"; + } + else + m_of << *it; + } + + m_of << "\n" << indent << "}"; + if (!e.inputs.empty() || !e.outputs.empty()) + { + m_of << "}"; + } + m_of << ";\n"; + } private: const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params) { @@ -2960,6 +3013,7 @@ namespace { m_of << ", "<<o_succ<<", "<<o_fail<<")"; break; case Compiler::Msvc: + emit_lvalue(e.ret_val); m_of << "._0 = "; emit_msvc_atomic_op("InterlockedCompareExchange", ""); // TODO: Use ordering if(params.m_types.at(0) == ::HIR::CoreType::Usize || params.m_types.at(0) == ::HIR::CoreType::Isize) { @@ -2969,6 +3023,8 @@ namespace { { emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", "; emit_param(e.args.at(2)); m_of << ")"; } + m_of << ";\n\t"; + emit_lvalue(e.ret_val); m_of << "._1 = ("; emit_lvalue(e.ret_val); m_of << "._0 == "; emit_param(e.args.at(2)); m_of << ")"; break; } }; @@ -3349,7 +3405,16 @@ namespace { { m_of << "shl128"; if(params.m_types.at(0) == ::HIR::CoreType::I128) m_of << "s"; - m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ")"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; + emit_param(e.args.at(1)); + // If the shift type is a u128/i128, get the inner + ::HIR::TypeRef tmp; + const auto& shift_ty = mir_res.get_param_type(tmp, e.args.at(1)); + if( shift_ty == ::HIR::CoreType::I128 || shift_ty == ::HIR::CoreType::U128 ) + { + m_of << ".lo"; + } + m_of << ")"; } else { @@ -3362,7 +3427,16 @@ namespace { { m_of << "shr128"; if (params.m_types.at(0) == ::HIR::CoreType::I128) m_of << "s"; - m_of << "("; emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ")"; + m_of << "("; emit_param(e.args.at(0)); m_of << ", "; + emit_param(e.args.at(1)); + // If the shift type is a u128/i128, get the inner + ::HIR::TypeRef tmp; + const auto& shift_ty = mir_res.get_param_type(tmp, e.args.at(1)); + if( shift_ty == ::HIR::CoreType::I128 || shift_ty == ::HIR::CoreType::U128 ) + { + m_of << ".lo"; + } + m_of << ")"; } else { @@ -4154,13 +4228,21 @@ namespace { m_of << "\", " << ::std::dec << c.size() << ")"; ), (Const, - // TODO: This should have been eliminated? - // NOTE: GCC hack - statement expressions + // TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references) ::HIR::TypeRef ty; const auto& lit = get_literal_for_const(c.p, ty); - m_of << "({"; emit_ctype(ty, FMT_CB(ss, ss<<"v";)); m_of << "; "; - assign_from_literal([&](){ m_of << "v"; }, ty, lit); - m_of << "; v;})"; + if(lit.is_Integer() || lit.is_Float() || lit.is_String()) + { + emit_literal(ty, lit, {}); + } + else + { + // NOTE: GCC hack - statement expressions + MIR_ASSERT(*m_mir_res, m_compiler == Compiler::Gcc, "TODO: Support inline constants without statement expressions"); + m_of << "({"; emit_ctype(ty, FMT_CB(ss, ss<<"v";)); m_of << "; "; + assign_from_literal([&](){ m_of << "v"; }, ty, lit); + m_of << "; v;})"; + } ), (ItemAddr, TU_MATCHA( (c.m_data), (pe), diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile index ff7a5f4f..ab3f8531 100644 --- a/tools/minicargo/Makefile +++ b/tools/minicargo/Makefile @@ -9,10 +9,11 @@ V ?= @ OBJDIR := .obj/ BIN := ../bin/minicargo -OBJS := main.o +OBJS := main.o build.o manifest.o repository.o +OBJS += toml.o LINKFLAGS := -CXXFLAGS := -Wall +CXXFLAGS := -Wall -std=c++14 OBJS := $(OBJS:%=$(OBJDIR)%) @@ -29,6 +30,7 @@ $(BIN): $(OBJS) $V$(CXX) -o $@ $(OBJS) $(LINKFLAGS) $(OBJDIR)%.o: %.cpp + @mkdir -p $(dir $@) @echo [CXX] $< $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 1d9b30ba..8127fbf0 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -1,8 +1,20 @@ /* */ #include "manifest.h" +#include "debug.h" #include <vector> #include <algorithm> +#include <sstream> // stringstream +#include "helpers.h" // path +#ifdef _WIN32 +# include <Windows.h> +#else +# include <spawn.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/wait.h> +# include <fcntl.h> +#endif struct BuildList { @@ -12,6 +24,7 @@ struct BuildList }; ::std::vector<BuildEnt> m_list; + void add_dependencies(const PackageManifest& p, unsigned level); void add_package(const PackageManifest& p, unsigned level); void sort_list(); @@ -41,28 +54,79 @@ struct BuildList } }; +class Builder +{ + class StringList + { + ::std::vector<::std::string> m_cached; + ::std::vector<const char*> m_strings; + public: + StringList() + { + } + + const ::std::vector<const char*>& get_vec() const + { + return m_strings; + } + + void push_back(::std::string s) + { + m_cached.push_back(::std::move(s)); + m_strings.push_back(m_cached.back().c_str()); + } + void push_back(const char* s) + { + m_strings.push_back(s); + } + }; + +public: + bool build_target(const PackageManifest& manifest, const PackageTarget& target) const; + bool build_library(const PackageManifest& manifest) const; + +private: + bool spawn_process(const StringList& args, const ::helpers::path& logfile) const; +}; + void MiniCargo_Build(const PackageManifest& manifest) { BuildList list; - // Generate sorted dependency list - for (const auto& dep : manifest.dependencies()) + + list.add_dependencies(manifest, 0); + + list.sort_list(); + // dedup? + for(const auto& p : list.iter()) { - list.add_package(dep.get_package(), 1); + DEBUG("WILL BUILD " << p.name() << " from " << p.manifest_path()); } - // Build dependencies + Builder builder; for(const auto& p : list.iter()) { - if( ! p.build_lib() ) - return ; + if( ! builder.build_library(p) ) + { + return; + } } - if( ! manifest.build_lib() ) - return ; // TODO: If the manifest doesn't have a library, build the binary + builder.build_library(manifest); } +void BuildList::add_dependencies(const PackageManifest& p, unsigned level) +{ + for (const auto& dep : p.dependencies()) + { + if( dep.is_optional() ) + { + continue ; + } + add_package(dep.get_package(), level+1); + } +} void BuildList::add_package(const PackageManifest& p, unsigned level) { for(auto& ent : m_list) @@ -82,4 +146,154 @@ void BuildList::add_package(const PackageManifest& p, unsigned level) void BuildList::sort_list() { ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level < b.level; }); + + for(auto it = m_list.begin(); it != m_list.end(); ) + { + auto it2 = ::std::find_if(m_list.begin(), it, [&](const auto& x){ return x.package == it->package; }); + if( it2 != it ) + { + it = m_list.erase(it); + } + else + { + ++it; + } + } +} + +bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const +{ + auto outdir = ::helpers::path("output"); + auto outfile = outdir / ::format("lib", target.m_name, ".hir"); + + // TODO: Determine if it needs re-running + // Rerun if: + // > `outfile` is missing + // > mrustc/minicargo is newer than `outfile` + // > build script has changed + // > any input file has changed (requires depfile from mrustc) + + StringList args; + args.push_back(::helpers::path(manifest.manifest_path()).parent() / ::helpers::path(target.m_path)); + args.push_back("--crate-name"); args.push_back(target.m_name.c_str()); + args.push_back("--crate-type"); args.push_back("rlib"); + args.push_back("-o"); args.push_back(outfile); + args.push_back("-L"); args.push_back(outdir); + //for(const auto& dir : manifest.build_script.rustc_link_search) { + // args.push_back("-L"); args.push_back(dir.second.c_str()); + //} + //for(const auto& lib : manifest.build_script.rustc_link_lib) { + // args.push_back("-l"); args.push_back(lib.second.c_str()); + //} + //for(const auto& cfg : manifest.build_script.rustc_cfg) { + // args.push_back("--cfg"); args.push_back(cfg.c_str()); + //} + //for(const auto& flag : manifest.build_script.rustc_flags) { + // args.push_back(flag.c_str()); + //} + // TODO: Environment variables (rustc_env) + + return this->spawn_process(args, outfile + "_dbg.txt"); +} +bool Builder::build_library(const PackageManifest& manifest) const +{ + if( manifest.build_script() != "" ) + { + // Locate a build script override file + // > Note, override file can specify a list of commands to run. + //manifest.script_output = BuildScript::load( override_file ); + // Otherwise, compile and run build script + //manifest.script_output = BuildScript::load( ::helpers::path("output") / "build_" + manifest.name + ".txt" ); + // Parse build script output. + throw ::std::runtime_error("TODO: Build script"); + } + + return this->build_target(manifest, manifest.get_library()); +} +bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfile) const +{ +#ifdef _WIN32 + ::std::stringstream cmdline; + cmdline << "mrustc.exe"; + for (const auto& arg : args.get_vec()) + cmdline << " " << arg; + auto cmdline_str = cmdline.str(); + DEBUG("Calling " << cmdline_str); + + CreateDirectory(static_cast<::std::string>(logfile.parent()).c_str(), NULL); + + STARTUPINFO si = { 0 }; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = NULL; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + { + SECURITY_ATTRIBUTES sa = { 0 }; + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + si.hStdOutput = CreateFile( static_cast<::std::string>(logfile).c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + DWORD tmp; + WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); + WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); + } + PROCESS_INFORMATION pi = { 0 }; + char env[] = + "MRUSTC_DEBUG=""\0" + ; + CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); + CloseHandle(si.hStdOutput); + WaitForSingleObject(pi.hProcess, INFINITE); + DWORD status = 1; + GetExitCodeProcess(pi.hProcess, &status); + if (status != 0) + { + DEBUG("Compiler exited with non-zero exit status " << status); + return false; + } +#else + + // Create logfile output directory + mkdir(static_cast<::std::string>(logfile.parent()).c_str(), 0755); + + // Create handles such that the log file is on stdout + ::std::string logfile_str = logfile; + pid_t pid; + posix_spawn_file_actions_t fa; + { + posix_spawn_file_actions_init(&fa); + posix_spawn_file_actions_addopen(&fa, 1, logfile_str.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644); + } + + // Generate `argv` + auto argv = args.get_vec(); + argv.insert(argv.begin(), "mrustc"); + DEBUG("Calling " << argv); + argv.push_back(nullptr); + + // Generate `envp` + ::std::vector<const char*> envp; + extern char **environ; + for(auto p = environ; *p; p++) + { + envp.push_back(*p); + } + envp.push_back(nullptr); + + if( posix_spawn(&pid, "../bin/mrustc", &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 ) + { + perror("posix_spawn"); + DEBUG("Unable to spawn compiler"); + posix_spawn_file_actions_destroy(&fa); + return false; + } + posix_spawn_file_actions_destroy(&fa); + int status = -1; + waitpid(pid, &status, 0); + if( WEXITSTATUS(status) != 0 ) + { + DEBUG("Compiler exited with non-zero exit status " << WEXITSTATUS(status)); + return false; + } +#endif + return true; } diff --git a/tools/minicargo/debug.h b/tools/minicargo/debug.h index 5cc338e3..bff9ddf3 100644 --- a/tools/minicargo/debug.h +++ b/tools/minicargo/debug.h @@ -10,10 +10,10 @@ extern void Debug_Print(::std::function<void(::std::ostream& os)> cb); #define TODO(fmt) do { Debug_Print([&](auto& os){ os << "DEBUG: " << fmt; }); abort(); } while(0) namespace { - static void format_to_stream(::std::ostream& os) { + static inline void format_to_stream(::std::ostream& os) { } template<typename T, typename... A> - static void format_to_stream(::std::ostream& os, const T& v, const A&... a) { + static inline void format_to_stream(::std::ostream& os, const T& v, const A&... a) { os << v; format_to_stream(os, a...); } diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index d811f21a..f2679ef4 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -1,17 +1,41 @@ #pragma once #include <string> +#include <cstring> namespace helpers { +class string_view +{ + const char* m_start; + const size_t m_len; +public: + string_view(const char* s, size_t n): + m_start(s), m_len(n) + { + } + + bool operator==(const ::std::string& s) const { + return *this == s.c_str(); + } + bool operator==(const char* s) const { + if(::std::strncmp(m_start, s, m_len) != 0) + return false; + return s[m_len] == '\0'; + } + friend ::std::string& operator+=(::std::string& x, const string_view& sv) { + x.append(sv.m_start, sv.m_start+sv.m_len); + return x; + } +}; /// Path helper class (because I don't want to include boost) class path { #ifdef _WIN32 - const char SEP = '\\'; + static const char SEP = '\\'; #else - const char SEP = '/'; + static const char SEP = '/'; #endif ::std::string m_str; @@ -56,13 +80,25 @@ public: throw ::std::runtime_error("Appending an absolute path to another path"); return *this / p.m_str.c_str(); } + /// Append a relative path path operator/(const char* o) const { + if (o[0] == '/') + throw ::std::runtime_error("Appending an absolute path to another path"); auto rv = *this; rv.m_str.push_back(SEP); rv.m_str.append(o); return rv; } + /// Add an arbitary string to the final component + path operator+(const char* o) const + { + if( ::std::strchr(o, SEP) != nullptr ) + throw ::std::runtime_error("Appending a string containing the path separator (with operator+)"); + auto rv = *this; + rv.m_str.append(o); + return rv; + } path parent() const { @@ -84,10 +120,159 @@ public: return m_str; } + class ComponentsIter + { + const path& p; + size_t pos; + size_t end; + + friend class path; + ComponentsIter(const path& p, size_t i): p(p), pos(i) { + end = p.m_str.find(SEP, pos); + if(end == ::std::string::npos) + end = p.m_str.size(); + } + public: + string_view operator*() const { + return string_view(p.m_str.c_str() + pos, end - pos); + } + void operator++() { + if(end == p.m_str.size()) + pos = end; + else + { + pos = end+1; + end = p.m_str.find(SEP, pos); + if(end == ::std::string::npos) + end = p.m_str.size(); + } + } + bool operator!=(const ComponentsIter& x) const { + return pos != x.pos; + } + }; + ComponentsIter begin() const { + return ComponentsIter(*this, 0); + } + ComponentsIter end() const { + return ComponentsIter(*this, m_str.size()); + } + + path normalise() const + { + path rv; + rv.m_str.reserve( m_str.size()+1 ); + + for(auto comp : *this) + { + if( comp == "." ) { + // Ignore. + } + else if( comp == ".." ) + { + // If the path is empty, OR the last element is a "..", push the element + if( rv.m_str.empty() + || (rv.m_str.size() == 3 && rv.m_str[0] == '.' && rv.m_str[1] == '.' && rv.m_str[2] == SEP) + || (rv.m_str.size() > 4 && *(rv.m_str.end()-4) == SEP && *(rv.m_str.end()-3) == '.' && *(rv.m_str.end()-2) == '.' && *(rv.m_str.end()-1) == SEP ) + ) + { + // Push + rv.m_str += comp; + rv.m_str += SEP; + } + else + { + rv.m_str.pop_back(); + auto pos = rv.m_str.find_last_of(SEP); + if(pos == ::std::string::npos) + { + rv.m_str.resize(0); + } + else if( pos == 0 ) + { + // Keep. + } + else + { + rv.m_str.resize(pos+1); + } + } + } + else { + rv.m_str += comp; + rv.m_str += SEP; + } + } + rv.m_str.pop_back(); + return rv; + } +#if 0 + void normalise_in_place() + { + size_t insert_point = 0; + + for(size_t read_pos = 0; read_pos < m_str.size(); read_pos ++) + { + auto pos = m_str.find_first_of(SEP, read_pos); + if(pos == ::std::string::npos) + pos = m_str.size(); + auto comp = string_view(m_str.c_str() + read_pos, pos - read_pos); + + bool append; + if(comp == ".") + { + // Advance read without touching insert + append = false; + } + else if( comp == ".." ) + { + // Consume parent (if not a relative component already) + // Move insertion point back to the previous separator + auto pos = m_str.find_last_of(SEP, insert_point); + if(pos == ::std::string::npos) + { + // Only one component currently (or empty) + append = true; + } + else if(string_view(m_str.c_str() + pos+1, insert_point - pos-1) == "..") + { + // Last component is ".." - keep adding + append = true; + } + else + { + insert_point = pos; + append = false; + } + } + else + { + append = true; + } + + if(append) + { + if( read_pos != insert_point ) + { + //assert(read_pos > insert_point); + while(read_pos < pos) + { + m_str[insert_point++] = m_str[read_pos++]; + } + } + } + else + { + read_pos = pos; + } + } + } +#endif + friend ::std::ostream& operator<<(::std::ostream& os, const path& p) { return os << p.m_str; } }; -} // namespace helpers
\ No newline at end of file +} // namespace helpers diff --git a/tools/minicargo/main.cpp b/tools/minicargo/main.cpp index c2fe4c2e..236b9d77 100644 --- a/tools/minicargo/main.cpp +++ b/tools/minicargo/main.cpp @@ -6,9 +6,11 @@ */ #include <iostream> #include <cstring> // strcmp +#include <map> #include "debug.h" #include "manifest.h" #include "helpers.h" +#include "repository.h" extern void MiniCargo_Build(const PackageManifest& manifest); @@ -22,6 +24,8 @@ struct ProgramOptions const char* output_directory = nullptr; + const char* vendor_dir = nullptr; + int parse(int argc, const char* argv[]); void usage() const; }; @@ -33,19 +37,34 @@ int main(int argc, const char* argv[]) return 1; } - // 1. Load the Cargo.toml file from the passed directory - auto m = PackageManifest::load_from_toml( ::helpers::path(opts.directory ? opts.directory : ".") / "Cargo.toml" ); + try + { + // Load package database + Repository repo; + // TODO: load repository from a local cache + if( opts.vendor_dir ) + { + repo.load_vendored(opts.vendor_dir); + } + + // 1. Load the Cargo.toml file from the passed directory + auto dir = ::helpers::path(opts.directory ? opts.directory : "."); + auto m = PackageManifest::load_from_toml( dir / "Cargo.toml" ); + + m.load_dependencies(repo); - // 2. Recursively load dependency manifests - for(const auto& dep : m.dependencies()) + // 3. Build dependency tree + MiniCargo_Build(m); + } + catch(const ::std::exception& e) { - throw "TODO: Deps"; + ::std::cerr << "EXCEPTION: " << e.what() << ::std::endl; + ::std::cout << "Press enter to exit..." << ::std::endl; + ::std::cin.get(); + return 1; } - // 3. Build dependency tree - MiniCargo_Build(m); - - ::std::cout << "Press any key to exit..." << ::std::endl; + ::std::cout << "Press enter to exit..." << ::std::endl; ::std::cin.get(); return 0; } @@ -106,9 +125,9 @@ void ProgramOptions::usage() const } - void Debug_Print(::std::function<void(::std::ostream& os)> cb) { cb(::std::cout); ::std::cout << ::std::endl; } + diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 22b63005..1bb815d8 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -6,10 +6,7 @@ #include "helpers.h" #include <cassert> #include <algorithm> -#include <sstream> -#ifdef _WIN32 -#include <Windows.h> -#endif +#include "repository.h" static ::std::vector<::std::shared_ptr<PackageManifest>> g_loaded_manifests; @@ -25,13 +22,14 @@ namespace PackageManifest PackageManifest::load_from_toml(const ::std::string& path) { PackageManifest rv; - rv.m_manmifest_path = path; + rv.m_manifest_path = path; TomlFile toml_file(path); for(auto key_val : toml_file) { assert(key_val.path.size() > 0); + DEBUG(key_val.path << " = " << key_val.value); const auto& section = key_val.path[0]; if( section == "package" ) { @@ -40,6 +38,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) if(key == "authors") { // TODO: Use the `authors` key + // - Ignore ofr now. } else if( key == "name" ) { @@ -59,6 +58,20 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) { rv.m_version = PackageVersion::from_string(key_val.value.as_string()); } + else if( key == "build" ) + { + if(rv.m_build_script != "" ) + { + // TODO: Warn/error + throw ::std::runtime_error("Build script path set twice"); + } + rv.m_build_script = key_val.value.as_string(); + if(rv.m_build_script == "") + { + // TODO: Error + throw ::std::runtime_error("Build script path cannot be empty"); + } + } else { // Unknown value in `package` @@ -67,12 +80,12 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) } else if( section == "lib" ) { - // TODO: Parse information related to use as a library // 1. Find (and add if needed) the `lib` descriptor auto it = ::std::find_if(rv.m_targets.begin(), rv.m_targets.end(), [](const auto& x){ return x.m_type == PackageTarget::Type::Lib; }); if(it == rv.m_targets.end()) it = rv.m_targets.insert(it, PackageTarget { PackageTarget::Type::Lib }); + // 2. Parse from the key-value pair target_edit_from_kv(*it, key_val, 1); } else if( section == "bin" ) @@ -97,6 +110,17 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) target_edit_from_kv(*it, key_val, 2); } + else if (section == "bench") + { + assert(key_val.path.size() > 1); + unsigned idx = ::std::stoi(key_val.path[1]); + + auto it = ::std::find_if(rv.m_targets.begin(), rv.m_targets.end(), [&idx](const auto& x) { return x.m_type == PackageTarget::Type::Bench && idx-- == 0; }); + if (it == rv.m_targets.end()) + it = rv.m_targets.insert(it, PackageTarget{ PackageTarget::Type::Bench }); + + target_edit_from_kv(*it, key_val, 2); + } else if( section == "dependencies" ) { assert(key_val.path.size() > 1); @@ -133,22 +157,28 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) // Set path specification of the named depenency ref.m_path = key_val.value.as_string(); } - else if (attr == "git") + else if( attr == "git" ) { // Load from git repo. TODO("Support git dependencies"); } - else if (attr == "branch") + else if( attr == "branch" ) { // Specify git branch TODO("Support git dependencies (branch)"); } - else if( attr == "version") + else if( attr == "version" ) { assert(key_val.path.size() == 3); // Parse version specifier ref.m_version = PackageVersionSpec::from_string(key_val.value.as_string()); } + else if( attr == "optional" ) + { + assert(key_val.path.size() == 3); + ref.m_optional = key_val.value.as_bool(); + // TODO: Add a feature with the same name as the dependency. + } else { // TODO: Error @@ -156,13 +186,31 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) } } } + else if( section == "build-dependencies" ) + { + // TODO: Build deps + } + else if( section == "dev-dependencies" ) + { + // TODO: Developemnt (test/bench) deps + } else if( section == "patch" ) { //const auto& repo = key_val.path[1]; + TODO("Support repository patches"); + } + else if( section == "target" ) + { + // TODO: Target opts? + } + else if( section == "features" ) + { + // TODO: Features } else { // Unknown manifest section + TODO("Unknown manifest section " << section); } } @@ -189,36 +237,40 @@ namespace assert(kv.path.size() == base_idx + 1); target.m_enable_test = kv.value.as_bool(); } - else if (key == "doctest") + else if( key == "doctest" ) { assert(kv.path.size() == base_idx + 1); target.m_enable_doctest = kv.value.as_bool(); } - else if (key == "bench") + else if( key == "bench" ) { assert(kv.path.size() == base_idx + 1); target.m_enable_bench = kv.value.as_bool(); } - else if (key == "doc") + else if( key == "doc" ) { assert(kv.path.size() == base_idx + 1); target.m_enable_doc = kv.value.as_bool(); } - else if (key == "plugin") + else if( key == "plugin" ) { assert(kv.path.size() == base_idx + 1); target.m_is_plugin = kv.value.as_bool(); } - else if (key == "proc-macro") + else if( key == "proc-macro" ) { assert(kv.path.size() == base_idx + 1); target.m_is_proc_macro = kv.value.as_bool(); } - else if (key == "harness") + else if( key == "harness" ) { assert(kv.path.size() == base_idx + 1); target.m_is_own_harness = kv.value.as_bool(); } + else if( key == "crate-type" ) + { + // TODO: Support crate types + } else { throw ::std::runtime_error( ::format("TODO: Handle target option `", key, "`") ); @@ -226,67 +278,59 @@ namespace } } - -bool PackageManifest::build_lib() const +const PackageTarget& PackageManifest::get_library() const { auto it = ::std::find_if(m_targets.begin(), m_targets.end(), [](const auto& x) { return x.m_type == PackageTarget::Type::Lib; }); if (it == m_targets.end()) { throw ::std::runtime_error(::format("Package ", m_name, " doesn't have a library")); } + return *it; +} - auto outfile = ::helpers::path("output") / ::format("lib", it->m_name, ".hir"); - - ::std::vector<::std::string> args; - args.push_back( ::helpers::path(m_manmifest_path).parent() / ::helpers::path(it->m_path) ); - args.push_back("--crate-name"); args.push_back(it->m_name); - args.push_back("--crate-type"); args.push_back("rlib"); - args.push_back("-o"); args.push_back( ::helpers::path("output") / ::format("lib", it->m_name, ".hir") ); -#ifdef _WIN32 - ::std::stringstream cmdline; - cmdline << "mrustc.exe"; - for(const auto& arg : args) - cmdline << " " << arg; - auto cmdline_str = cmdline.str(); - DEBUG("Calling " << cmdline_str); +void PackageManifest::load_dependencies(Repository& repo) +{ + DEBUG("Loading depencencies for " << m_name); + auto base_path = ::helpers::path(m_manifest_path).parent(); - CreateDirectory(static_cast<::std::string>(outfile.parent()).c_str(), NULL); + // 2. Recursively load dependency manifests + for(auto& dep : m_dependencies) + { + if( dep.m_optional ) + { + // TODO: Check for feature that enables this (option to a feature with no '/') + continue ; + } + dep.load_manifest(repo, base_path); + } +} - STARTUPINFO si = {0}; - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = NULL; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); +void PackageRef::load_manifest(Repository& repo, const ::helpers::path& base_path) +{ + // If the path isn't set, check for: + // - Git (checkout and use) + // - Version and repository (check vendored, check cache, download into cache) + if( ! this->has_path() ) { - SECURITY_ATTRIBUTES sa = {0}; - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - si.hStdOutput = CreateFile( (static_cast<::std::string>(outfile) + "_dbg.txt").c_str(), GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - DWORD tmp; - WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); - WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); + if( this->has_git() ) + { + DEBUG("Load dependency " << this->name() << " from git"); + throw "TODO: Git"; + } + else + { + DEBUG("Load dependency " << this->name() << " from repo"); + m_manifest = repo.find(this->name(), this->get_version()); + } } - PROCESS_INFORMATION pi = {0}; - CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, "MRUSTC_DEBUG=Parse\0", NULL, &si, &pi); - CloseHandle(si.hStdOutput); - WaitForSingleObject(pi.hProcess, INFINITE); - DWORD status = 1; - GetExitCodeProcess(pi.hProcess, &status); - if(status != 0) + else { - DEBUG("Compiler exited with non-zero exit status " << status); - return false; + DEBUG("Load dependency " << m_name << " from path " << m_path); + // Search for a copy of this already loaded + m_manifest = repo.from_path(base_path / ::helpers::path(m_path) / "Cargo.toml"); } -#elif defined(__posix__) - //spawn(); -#else -#endif - return true; -} -const PackageManifest& PackageRef::get_package() const -{ - throw ""; + m_manifest->load_dependencies(repo); } PackageVersion PackageVersion::from_string(const ::std::string& s) @@ -308,4 +352,8 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) PackageVersionSpec rv; throw ""; return rv; -}
\ No newline at end of file +} +bool PackageVersionSpec::accepts(const PackageVersion& v) const +{ + throw ""; +} diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 108a8d2b..428a9721 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -3,8 +3,10 @@ #include <string> #include <vector> #include <memory> +#include "helpers.h" class PackageManifest; +class Repository; struct PackageVersion { @@ -13,6 +15,15 @@ struct PackageVersion unsigned patch; static PackageVersion from_string(const ::std::string& s); + bool operator<(const PackageVersion& x) const { + if( major < x.major ) return true; + if( major > x.major ) return false; + if( minor < x.minor ) return true; + if( minor > x.minor ) return false; + if( minor < x.patch ) return true; + if( patch > x.patch ) return false; + return false; + } }; struct PackageVersionSpec { @@ -28,10 +39,14 @@ struct PackageVersionSpec Type ty; PackageVersion ver; }; + // TODO: Just upper and lower? ::std::vector<Bound> m_bounds; - // TODO: Just upper and lower? + // Construct from a string static PackageVersionSpec from_string(const ::std::string& s); + + /// Check if this spec accepts the passed version + bool accepts(const PackageVersion& v) const; }; class PackageRef @@ -40,6 +55,7 @@ class PackageRef ::std::string m_name; PackageVersionSpec m_version; + bool m_optional = false; ::std::string m_path; ::std::shared_ptr<PackageManifest> m_manifest; @@ -49,7 +65,22 @@ class PackageRef } public: - const PackageManifest& get_package() const; + const ::std::string& name() const { return m_name; } + //const ::std::string& get_repo_name() const { return m_repo; } + const PackageVersionSpec& get_version() const { return m_version; } + + bool is_optional() const { return m_optional; } + + const bool has_path() const { return m_path != ""; } + const ::std::string& path() const { return m_path; } + const bool has_git() const { return false; } + + const PackageManifest& get_package() const { + if(!m_manifest) throw ::std::runtime_error("Manifest not loaded for package " + m_name); + return *m_manifest; + } + + void load_manifest(Repository& repo, const ::helpers::path& base_path); }; struct PackageTarget @@ -93,11 +124,13 @@ struct PackageTarget class PackageManifest { - ::std::string m_manmifest_path; + ::std::string m_manifest_path; ::std::string m_name; PackageVersion m_version; + ::std::string m_build_script; + ::std::vector<PackageRef> m_dependencies; ::std::vector<PackageTarget> m_targets; @@ -109,9 +142,20 @@ class PackageManifest PackageManifest(); public: static PackageManifest load_from_toml(const ::std::string& path); - bool build_lib() const; + const PackageTarget& get_library() const; + + + const ::std::string& manifest_path() const { + return m_manifest_path; + } + const ::std::string& name() const { + return m_name; + } + const ::std::string& build_script() const { return m_build_script; } const ::std::vector<PackageRef>& dependencies() const { return m_dependencies; } + + void load_dependencies(Repository& repo); }; diff --git a/tools/minicargo/repository.cpp b/tools/minicargo/repository.cpp new file mode 100644 index 00000000..0a097f66 --- /dev/null +++ b/tools/minicargo/repository.cpp @@ -0,0 +1,70 @@ +/* + */ +#include "repository.h" +#include "debug.h" + +void Repository::load_cache(const ::helpers::path& path) +{ + throw ""; +} +void Repository::load_vendored(const ::helpers::path& path) +{ + // Enumerate folders in this folder, try to open Cargo.toml files + // Extract package name and version from each manifest +} + +::std::shared_ptr<PackageManifest> Repository::from_path(::helpers::path path) +{ + DEBUG("Repository::from_path(" << path << ")"); + // 1. Normalise path + path = path.normalise(); + DEBUG("path = " << path); + + auto it = m_path_cache.find(path); + if(it == m_path_cache.end()) + { + ::std::shared_ptr<PackageManifest> rv ( new PackageManifest(PackageManifest::load_from_toml(path)) ); + + m_path_cache.insert( ::std::make_pair(::std::move(path), rv) ); + + return rv; + } + else + { + return it->second; + } +} +::std::shared_ptr<PackageManifest> Repository::find(const ::std::string& name, const PackageVersionSpec& version) +{ + auto itp = m_cache.equal_range(name); + + Entry* best = nullptr; + for(auto i = itp.first; i != itp.second; ++i) + { + if( version.accepts(i->second.version) ) + { + if( !best || best->version < i->second.version ) + { + best = &i->second; + } + } + } + + if( best ) + { + if( !best->loaded_manifest ) + { + if( best->manifest_path == "" ) + { + throw "TODO: Download package"; + } + best->loaded_manifest = ::std::shared_ptr<PackageManifest>( new PackageManifest(PackageManifest::load_from_toml(best->manifest_path)) ); + } + + return best->loaded_manifest; + } + else + { + return {}; + } +} diff --git a/tools/minicargo/repository.h b/tools/minicargo/repository.h new file mode 100644 index 00000000..0b186077 --- /dev/null +++ b/tools/minicargo/repository.h @@ -0,0 +1,29 @@ +#pragma once + +#include <string> +#include <map> +#include "helpers.h" +#include "manifest.h" + +class Repository +{ + struct Entry + { + /// Path to the Cargo.toml file in the package root + ::std::string manifest_path; + /// Package version + PackageVersion version; + /// (Cached) loaded manifest + ::std::shared_ptr<PackageManifest> loaded_manifest; + }; + + ::std::multimap<::std::string, Entry> m_cache; + // path => manifest + ::std::map<::std::string, ::std::shared_ptr<PackageManifest>> m_path_cache; +public: + void load_cache(const ::helpers::path& path); + void load_vendored(const ::helpers::path& path); + + ::std::shared_ptr<PackageManifest> from_path(::helpers::path path); + ::std::shared_ptr<PackageManifest> find(const ::std::string& name, const PackageVersionSpec& version); +}; diff --git a/tools/minicargo/toml.cpp b/tools/minicargo/toml.cpp index 7d4b0685..fe81fa3c 100644 --- a/tools/minicargo/toml.cpp +++ b/tools/minicargo/toml.cpp @@ -158,14 +158,14 @@ TomlKeyValue TomlFile::get_next_value() { case Token::Type::String: rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { t.m_data }; break; case Token::Type::SquareOpen: rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value.m_type = TomlValue::Type::List; @@ -197,14 +197,14 @@ TomlKeyValue TomlFile::get_next_value() if( t.m_data == "true" ) { rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { true }; } else if( t.m_data == "false" ) { rv.path = m_current_block; - rv.path.insert(rv.path.begin(), m_current_composite.begin(), m_current_composite.end()); + rv.path.insert(rv.path.end(), m_current_composite.begin(), m_current_composite.end()); rv.path.push_back(key_name); rv.value = TomlValue { false }; @@ -242,7 +242,7 @@ TomlKeyValue TomlFile::get_next_value() Token Token::lex_from(::std::ifstream& is) { auto rv = Token::lex_from_inner(is); - DEBUG("lex_from: " << rv); + //DEBUG("lex_from: " << rv); return rv; } Token Token::lex_from_inner(::std::ifstream& is) @@ -307,7 +307,7 @@ Token Token::lex_from_inner(::std::ifstream& is) if(isalpha(c)) { // Identifier - while(isalnum(c) || c == '-') + while(isalnum(c) || c == '-' || c == '_') { str += (char)c; c = is.get(); @@ -317,6 +317,7 @@ Token Token::lex_from_inner(::std::ifstream& is) } else { + throw ::std::runtime_error(::format("Unexpected chracter '", (char)c, "' in file")); throw ""; } } diff --git a/tools/minicargo/toml.h b/tools/minicargo/toml.h index 1c8f90d5..6f145a2e 100644 --- a/tools/minicargo/toml.h +++ b/tools/minicargo/toml.h @@ -2,6 +2,7 @@ #include <fstream> #include <vector> +#include <string> #include <unordered_map> class TomlFileIter; @@ -54,7 +55,7 @@ struct TomlValue { } - const char* what() const override { + const char* what() const noexcept override { return "toml type error"; } }; @@ -91,6 +92,24 @@ struct TomlValue } return m_int_value != 0; } + + friend ::std::ostream& operator<<(::std::ostream& os, const TomlValue& x) { + switch(x.m_type) + { + case Type::Boolean: os << (x.m_int_value != 0 ? "true" : "false"); break; + case Type::Integer: os << x.m_int_value; break; + case Type::List: + os << "["; + for(auto& e : x.m_sub_values) + os << e << ","; + os << "]"; + break; + case Type::String: + os << "\"" << x.m_str_value << "\""; + break; + } + return os; + } }; struct TomlKeyValue diff --git a/vsproject/minicargo/minicargo.vcxproj b/vsproject/minicargo/minicargo.vcxproj index 9c82ff56..9fe4e4a7 100644 --- a/vsproject/minicargo/minicargo.vcxproj +++ b/vsproject/minicargo/minicargo.vcxproj @@ -113,12 +113,14 @@ <ClCompile Include="..\..\tools\minicargo\build.cpp" /> <ClCompile Include="..\..\tools\minicargo\main.cpp" /> <ClCompile Include="..\..\tools\minicargo\manifest.cpp" /> + <ClCompile Include="..\..\tools\minicargo\repository.cpp" /> <ClCompile Include="..\..\tools\minicargo\toml.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\tools\minicargo\debug.h" /> <ClInclude Include="..\..\tools\minicargo\helpers.h" /> <ClInclude Include="..\..\tools\minicargo\manifest.h" /> + <ClInclude Include="..\..\tools\minicargo\repository.h" /> <ClInclude Include="..\..\tools\minicargo\toml.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> diff --git a/vsproject/minicargo/minicargo.vcxproj.filters b/vsproject/minicargo/minicargo.vcxproj.filters index b21142bb..be88124d 100644 --- a/vsproject/minicargo/minicargo.vcxproj.filters +++ b/vsproject/minicargo/minicargo.vcxproj.filters @@ -27,6 +27,9 @@ <ClCompile Include="..\..\tools\minicargo\toml.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\tools\minicargo\repository.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\tools\minicargo\helpers.h"> @@ -41,5 +44,8 @@ <ClInclude Include="..\..\tools\minicargo\debug.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\tools\minicargo\repository.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project>
\ No newline at end of file diff --git a/vsproject/mrustc.sln b/vsproject/mrustc.sln index 3aebce2e..abeaf785 100644 --- a/vsproject/mrustc.sln +++ b/vsproject/mrustc.sln @@ -8,6 +8,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tu_test", "tu_test\tu_test.vcxproj", "{F0A80ABB-A11A-492C-B5FC-E26C29A988D8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minicargo", "minicargo\minicargo.vcxproj", "{15F3D38B-14FF-4872-805D-6D9C52920842}" + ProjectSection(ProjectDependencies) = postProject + {12AA9964-C1BD-406A-9545-43EE63230EBE} = {12AA9964-C1BD-406A-9545-43EE63230EBE} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/vsproject/mrustc.vcxproj.filters b/vsproject/mrustc.vcxproj.filters index e5afb22e..cfcdb9b9 100644 --- a/vsproject/mrustc.vcxproj.filters +++ b/vsproject/mrustc.vcxproj.filters @@ -57,6 +57,18 @@ <Filter Include="Header Files\mir"> <UniqueIdentifier>{1233e2f6-7b44-4379-9f43-d572b8944ba0}</UniqueIdentifier> </Filter> + <Filter Include="Header Files\parse"> + <UniqueIdentifier>{3709226c-e95b-4da0-9735-42e2a5cad1a7}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\expand"> + <UniqueIdentifier>{c78c419b-2b25-4c6f-8f91-95a9d0142fff}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\trans"> + <UniqueIdentifier>{6bbfdfb3-9557-43a9-bddd-07a243569fa3}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\hir"> + <UniqueIdentifier>{e3219c19-8898-418e-b2ba-84254977a792}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="..\src\debug.cpp"> @@ -382,63 +394,21 @@ <ClInclude Include="..\src\coretypes.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\ast\crate.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\ast\pattern.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\expand\cfg.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\expand\macro_rules.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\hir\crate_ptr.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\expr.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\expr_ptr.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\from_ast.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\generic_params.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\hir.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\hir\path.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\hir\pattern.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\type.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\hir\visitor.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\hir_conv\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="..\src\hir_expand\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\hir_typeck\expr_visit.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\hir_typeck\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\hir_typeck\static.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\include\cpp_unpack.h"> <Filter>Header Files</Filter> </ClInclude> @@ -457,12 +427,6 @@ <ClInclude Include="..\src\include\rustic.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\include\serialise.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\include\serialiser_texttree.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\include\span.hpp"> <Filter>Header Files</Filter> </ClInclude> @@ -487,57 +451,21 @@ <ClInclude Include="..\src\macro_rules\pattern_checks.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\mir\from_hir.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\mir\main_bindings.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\parse\eTokenType.enum.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\parse\common.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\parse\interpolated_fragment.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\parse\lex.hpp"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="..\src\parse\parseerror.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\parse\token.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\parse\tokentree.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\resolve\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\parse\ttstream.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\parse\tokenstream.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\trans\codegen.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\trans\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="..\src\trans\mangling.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\trans\trans_list.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\mir\visit_crate_mir.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\ast\attrs.hpp"> <Filter>Header Files\ast</Filter> </ClInclude> @@ -583,6 +511,90 @@ <ClInclude Include="..\src\ast\types.hpp"> <Filter>Header Files\ast</Filter> </ClInclude> + <ClInclude Include="..\src\ast\crate.hpp"> + <Filter>Header Files\ast</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\common.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\crate_ptr.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\eTokenType.enum.h"> + <Filter>Header Files\parse</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\expr_ptr.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\hir_typeck\expr_visit.hpp"> + <Filter>Header Files\hir_typeck</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\expr.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\mir\main_bindings.hpp"> + <Filter>Header Files\mir</Filter> + </ClInclude> + <ClInclude Include="..\src\include\serialise.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\include\serialiser_texttree.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\expand\cfg.hpp"> + <Filter>Header Files\expand</Filter> + </ClInclude> + <ClInclude Include="..\src\trans\codegen.hpp"> + <Filter>Header Files\trans</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\from_ast.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\hir.hpp"> + <Filter>Header Files\mir</Filter> + </ClInclude> + <ClInclude Include="..\src\mir\from_hir.hpp"> + <Filter>Header Files\mir</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\generic_params.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\interpolated_fragment.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\pattern.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\ast\pattern.hpp"> + <Filter>Header Files\ast</Filter> + </ClInclude> + <ClInclude Include="..\src\hir_typeck\static.hpp"> + <Filter>Header Files\hir_typeck</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\type.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\hir\visitor.hpp"> + <Filter>Header Files\hir</Filter> + </ClInclude> + <ClInclude Include="..\src\mir\visit_crate_mir.hpp"> + <Filter>Header Files\mir</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\token.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\tokenstream.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> + <ClInclude Include="..\src\trans\trans_list.hpp"> + <Filter>Header Files\trans</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\ttstream.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\tokentree.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="packages.config" /> |