From ee38738e083079e4f8d529ac58781aae47e09188 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 10:46:02 +0800 Subject: Codegen C - Rough support for msvc inline assembly --- src/trans/codegen_c.cpp | 216 ++++++++++++++++++++++++++++++------------------ 1 file changed, 137 insertions(+), 79 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 973aa33a..23d02531 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2036,82 +2036,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 +2750,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(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(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) { @@ -4154,13 +4204,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), -- cgit v1.2.3 From 4ca497d863c1c93689e5dd7581c164d1ce885569 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 10:46:26 +0800 Subject: Minicargo - Move build invocations to build.cpp --- tools/minicargo/build.cpp | 111 +++++++++++++++++++++++++++++++++++++++++-- tools/minicargo/helpers.h | 12 +++++ tools/minicargo/manifest.cpp | 71 ++++++++------------------- tools/minicargo/manifest.h | 12 ++++- 4 files changed, 148 insertions(+), 58 deletions(-) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 1d9b30ba..ace0dd13 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -1,8 +1,14 @@ /* */ #include "manifest.h" +#include "debug.h" #include #include +#include // stringstream +#include "helpers.h" // path +#ifdef _WIN32 +#include +#endif struct BuildList { @@ -41,6 +47,41 @@ struct BuildList } }; +class Builder +{ + class StringList + { + ::std::vector<::std::string> m_cached; + ::std::vector m_strings; + public: + StringList() + { + } + + const ::std::vector& 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; @@ -52,15 +93,17 @@ void MiniCargo_Build(const PackageManifest& manifest) // 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_package(const PackageManifest& p, unsigned level) @@ -83,3 +126,63 @@ void BuildList::sort_list() { ::std::sort(m_list.begin(), m_list.end(), [](const auto& a, const auto& b){ return a.level < b.level; }); } + +bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& target) const +{ + auto outfile = ::helpers::path("output") / ::format("lib", target.m_name, ".hir"); + + 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); + + return this->spawn_process(args, outfile + "_dbg.txt"); +} +bool Builder::build_library(const PackageManifest& manifest) const +{ + 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 }; + CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, "MRUSTC_DEBUG=\0", 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 + // TODO: posix_spawn + return false; +#endif + return true; +} diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index d811f21a..d9fe7e3c 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -56,13 +56,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 { diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 22b63005..90bb68a5 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -25,7 +25,7 @@ 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); @@ -40,6 +40,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" ) { @@ -67,12 +68,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 +98,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); @@ -159,10 +171,12 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) else if( section == "patch" ) { //const auto& repo = key_val.path[1]; + TODO("Support repository patches"); } else { // Unknown manifest section + TODO("Unknown manifest section " << section); } } @@ -226,66 +240,19 @@ 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")); } - - 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); - - CreateDirectory(static_cast<::std::string>(outfile.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>(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); - } - 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) - { - DEBUG("Compiler exited with non-zero exit status " << status); - return false; - } -#elif defined(__posix__) - //spawn(); -#else -#endif - return true; + return *it; } const PackageManifest& PackageRef::get_package() const { + DEBUG("TODO: PackageRef::get_package()"); throw ""; } diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 108a8d2b..054347fb 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -93,7 +93,7 @@ struct PackageTarget class PackageManifest { - ::std::string m_manmifest_path; + ::std::string m_manifest_path; ::std::string m_name; PackageVersion m_version; @@ -109,8 +109,16 @@ 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::vector& dependencies() const { return m_dependencies; } -- cgit v1.2.3 From 19f32ced09e7538cde01cb443b19e0a7a1c5667f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 20:54:45 +0800 Subject: minicargo - Dependency loading --- tools/minicargo/build.cpp | 47 ++++++- tools/minicargo/helpers.h | 176 +++++++++++++++++++++++++- tools/minicargo/main.cpp | 39 ++++-- tools/minicargo/manifest.cpp | 109 +++++++++++++--- tools/minicargo/manifest.h | 39 +++++- tools/minicargo/repository.cpp | 70 ++++++++++ tools/minicargo/repository.h | 29 +++++ tools/minicargo/toml.cpp | 13 +- tools/minicargo/toml.h | 19 +++ vsproject/minicargo/minicargo.vcxproj | 2 + vsproject/minicargo/minicargo.vcxproj.filters | 6 + 11 files changed, 507 insertions(+), 42 deletions(-) create mode 100644 tools/minicargo/repository.cpp create mode 100644 tools/minicargo/repository.h diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index ace0dd13..352a4dcd 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -18,6 +18,7 @@ struct BuildList }; ::std::vector m_list; + void add_dependencies(const PackageManifest& p, unsigned level); void add_package(const PackageManifest& p, unsigned level); void sort_list(); @@ -85,13 +86,16 @@ private: 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()) @@ -106,6 +110,17 @@ void MiniCargo_Build(const PackageManifest& manifest) 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) @@ -125,17 +140,32 @@ 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 outfile = ::helpers::path("output") / ::format("lib", target.m_name, ".hir"); + auto outdir = ::helpers::path("output"); + auto outfile = outdir / ::format("lib", target.m_name, ".hir"); 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); return this->spawn_process(args, outfile + "_dbg.txt"); } @@ -157,6 +187,7 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi STARTUPINFO si = { 0 }; si.cb = sizeof(si); +#if 1 si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = NULL; si.hStdError = GetStdHandle(STD_ERROR_HANDLE); @@ -169,8 +200,12 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); } +#endif PROCESS_INFORMATION pi = { 0 }; - CreateProcessA("x64\\Release\\mrustc.exe", (LPSTR)cmdline_str.c_str(), NULL, NULL, TRUE, 0, "MRUSTC_DEBUG=\0", NULL, &si, &pi); + 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; diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index d9fe7e3c..35e791f1 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -4,14 +4,37 @@ 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; @@ -96,6 +119,155 @@ 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; 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 #include // strcmp +#include #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 cb) { cb(::std::cout); ::std::cout << ::std::endl; } + diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index 90bb68a5..d068b7bf 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -6,10 +6,7 @@ #include "helpers.h" #include #include -#include -#ifdef _WIN32 -#include -#endif +#include "repository.h" static ::std::vector<::std::shared_ptr> g_loaded_manifests; @@ -32,6 +29,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& 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" ) { @@ -60,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` @@ -145,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 @@ -168,11 +186,23 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) } } } + else if( section == "build-dependencies" ) + { + // TODO: Build 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 @@ -203,36 +233,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, "`") ); @@ -250,10 +284,49 @@ const PackageTarget& PackageManifest::get_library() const return *it; } -const PackageManifest& PackageRef::get_package() const +void PackageManifest::load_dependencies(Repository& repo) { - DEBUG("TODO: PackageRef::get_package()"); - throw ""; + DEBUG("Loading depencencies for " << m_name); + auto base_path = ::helpers::path(m_manifest_path).parent(); + + // 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); + } +} + +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() ) + { + 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()); + } + } + else + { + 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"); + } + + m_manifest->load_dependencies(repo); } PackageVersion PackageVersion::from_string(const ::std::string& s) @@ -275,4 +348,8 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) PackageVersionSpec rv; throw ""; return rv; +} +bool PackageVersionSpec::accepts(const PackageVersion& v) const +{ + throw ""; } \ No newline at end of file diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 054347fb..0e6c2d81 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -3,8 +3,10 @@ #include #include #include +#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 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 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 @@ -98,6 +129,8 @@ class PackageManifest ::std::string m_name; PackageVersion m_version; + ::std::string m_build_script; + ::std::vector m_dependencies; ::std::vector m_targets; @@ -122,4 +155,6 @@ public: const ::std::vector& 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 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 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 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( 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 +#include +#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 loaded_manifest; + }; + + ::std::multimap<::std::string, Entry> m_cache; + // path => manifest + ::std::map<::std::string, ::std::shared_ptr> m_path_cache; +public: + void load_cache(const ::helpers::path& path); + void load_vendored(const ::helpers::path& path); + + ::std::shared_ptr from_path(::helpers::path path); + ::std::shared_ptr 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..17517ca3 100644 --- a/tools/minicargo/toml.h +++ b/tools/minicargo/toml.h @@ -2,6 +2,7 @@ #include #include +#include #include class TomlFileIter; @@ -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 @@ + + 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 @@ Source Files + + Source Files + @@ -41,5 +44,8 @@ Header Files + + Header Files + \ No newline at end of file -- cgit v1.2.3 From aa44379d158085d649d9ab3514e0c2276d2d5076 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 20:56:00 +0800 Subject: Load Crates - Search passed library directories for crates --- src/ast/crate.cpp | 23 +++++++++++++++++------ src/ast/crate.hpp | 3 +++ src/main.cpp | 11 +++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) 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_Deserialise #include +::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/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; } -- cgit v1.2.3 From 3d2faba77cdb2695753a4c62641b7f92a573869b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 20:56:24 +0800 Subject: Misc - Visual studio cleanups --- .gitignore | 1 + src/expand/format_args.cpp | 2 +- vsproject/mrustc.sln | 3 + vsproject/mrustc.vcxproj.filters | 180 +++++++++++++++++++++------------------ 4 files changed, 101 insertions(+), 85 deletions(-) diff --git a/.gitignore b/.gitignore index 4488f48c..b1d89c5d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ /bnf/rust.tab.h /bnf/rust.output /bnf/test.bin +/vsproject/output 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(named_args.size())) ); if( ins_rv.second == false ) { ERROR(sp, E0000, "Duplicate definition of named argument `" << ins_rv.first->first << "`"); } 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 @@ {1233e2f6-7b44-4379-9f43-d572b8944ba0} + + {3709226c-e95b-4da0-9735-42e2a5cad1a7} + + + {c78c419b-2b25-4c6f-8f91-95a9d0142fff} + + + {6bbfdfb3-9557-43a9-bddd-07a243569fa3} + + + {e3219c19-8898-418e-b2ba-84254977a792} + @@ -382,63 +394,21 @@ Header Files - - Header Files - - - Header Files - - - Header Files - Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files - - Header Files - - - Header Files - - - Header Files - Header Files Header Files - - Header Files - Header Files - - Header Files - Header Files @@ -457,12 +427,6 @@ Header Files - - Header Files - - - Header Files - Header Files @@ -487,57 +451,21 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files Header Files - - Header Files - - - Header Files - Header Files - - Header Files - - - Header Files - - - Header Files - Header Files Header Files - - Header Files - - - Header Files - Header Files\ast @@ -583,6 +511,90 @@ Header Files\ast + + Header Files\ast + + + Header Files\parse + + + Header Files\hir + + + Header Files\parse + + + Header Files\hir + + + Header Files\hir_typeck + + + Header Files\hir + + + Header Files\mir + + + Header Files\hir + + + Header Files\hir + + + Header Files\expand + + + Header Files\trans + + + Header Files\hir + + + Header Files\mir + + + Header Files\mir + + + Header Files\hir + + + Header Files\parse + + + Header Files\hir + + + Header Files\ast + + + Header Files\hir_typeck + + + Header Files\hir + + + Header Files\hir + + + Header Files\mir + + + Header Files\parse + + + Header Files\parse + + + Header Files\trans + + + Header Files\parse + + + Header Files\parse + -- cgit v1.2.3 From a463c0ec69b7cdefc26277ec5f3b36def7b7f70e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 21:00:14 +0800 Subject: Codegen C - Fix a few bugs with MSVC mode --- src/trans/codegen_c.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 23d02531..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(); } } @@ -3010,6 +3013,7 @@ namespace { m_of << ", "< Date: Sun, 20 Aug 2017 21:00:31 +0800 Subject: HIR From AST - i128/u128 --- src/hir/from_ast_expr.cpp | 2 ++ 1 file changed, 2 insertions(+) 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; -- cgit v1.2.3 From 72571e39e4659cb32b82c633d45a0fcd7b8c5ffb Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 21:36:50 +0800 Subject: minicargo - Build script planning --- tools/minicargo/build.cpp | 31 +++++++++++++++++++++++++++++++ tools/minicargo/manifest.h | 1 + 2 files changed, 32 insertions(+) diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index 352a4dcd..55e45c49 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -160,17 +160,48 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& 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 diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index 0e6c2d81..428a9721 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -152,6 +152,7 @@ public: const ::std::string& name() const { return m_name; } + const ::std::string& build_script() const { return m_build_script; } const ::std::vector& dependencies() const { return m_dependencies; } -- cgit v1.2.3 From a99e49b7505d2912d8699d4c791b8b30c194024b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 20 Aug 2017 22:15:35 +0800 Subject: minicargo - Makefile and posix_spawn --- tools/minicargo/Makefile | 6 +++-- tools/minicargo/build.cpp | 55 ++++++++++++++++++++++++++++++++++++++++---- tools/minicargo/debug.h | 4 ++-- tools/minicargo/helpers.h | 3 ++- tools/minicargo/manifest.cpp | 6 ++++- tools/minicargo/toml.h | 2 +- 6 files changed, 64 insertions(+), 12 deletions(-) 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 55e45c49..8127fbf0 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -7,7 +7,13 @@ #include // stringstream #include "helpers.h" // path #ifdef _WIN32 -#include +# include +#else +# include +# include +# include +# include +# include #endif struct BuildList @@ -218,7 +224,6 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi STARTUPINFO si = { 0 }; si.cb = sizeof(si); -#if 1 si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = NULL; si.hStdError = GetStdHandle(STD_ERROR_HANDLE); @@ -231,7 +236,6 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi WriteFile(si.hStdOutput, cmdline_str.data(), cmdline_str.size(), &tmp, NULL); WriteFile(si.hStdOutput, "\n", 1, &tmp, NULL); } -#endif PROCESS_INFORMATION pi = { 0 }; char env[] = "MRUSTC_DEBUG=""\0" @@ -247,8 +251,49 @@ bool Builder::spawn_process(const StringList& args, const ::helpers::path& logfi return false; } #else - // TODO: posix_spawn - return false; + + // 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 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 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 - 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 35e791f1..f2679ef4 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace helpers { @@ -274,4 +275,4 @@ public: } }; -} // namespace helpers \ No newline at end of file +} // namespace helpers diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index d068b7bf..1bb815d8 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -190,6 +190,10 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path) { // TODO: Build deps } + else if( section == "dev-dependencies" ) + { + // TODO: Developemnt (test/bench) deps + } else if( section == "patch" ) { //const auto& repo = key_val.path[1]; @@ -352,4 +356,4 @@ PackageVersionSpec PackageVersionSpec::from_string(const ::std::string& s) bool PackageVersionSpec::accepts(const PackageVersion& v) const { throw ""; -} \ No newline at end of file +} diff --git a/tools/minicargo/toml.h b/tools/minicargo/toml.h index 17517ca3..6f145a2e 100644 --- a/tools/minicargo/toml.h +++ b/tools/minicargo/toml.h @@ -55,7 +55,7 @@ struct TomlValue { } - const char* what() const override { + const char* what() const noexcept override { return "toml type error"; } }; -- cgit v1.2.3