summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2018-12-30 13:18:07 +0800
committerJohn Hodge <tpg@ucc.asn.au>2018-12-30 13:18:07 +0800
commitbd64912c9847479800ba24c1e1fea7191197c591 (patch)
treebb6e6dd5af0d962df3998b931600e4bc9fc685ff
parentc2af54e57545b55be1a5c32cfe4ffbc4b6e114a4 (diff)
downloadmrust-bd64912c9847479800ba24c1e1fea7191197c591.tar.gz
minicargo - Cleanup and planning for better `cfg()` handing
-rw-r--r--tools/minicargo/Makefile2
-rw-r--r--tools/minicargo/cfg.cpp262
-rw-r--r--tools/minicargo/cfg.hpp9
-rw-r--r--tools/minicargo/manifest.cpp175
4 files changed, 278 insertions, 170 deletions
diff --git a/tools/minicargo/Makefile b/tools/minicargo/Makefile
index 363ef4b9..862f6b3c 100644
--- a/tools/minicargo/Makefile
+++ b/tools/minicargo/Makefile
@@ -13,7 +13,7 @@ V ?= @
OBJDIR := .obj/
BIN := ../bin/minicargo$(EXESUF)
-OBJS := main.o build.o manifest.o repository.o
+OBJS := main.o build.o manifest.o repository.o cfg.o
LINKFLAGS := -g -lpthread
CXXFLAGS := -Wall -std=c++14 -g -O2
diff --git a/tools/minicargo/cfg.cpp b/tools/minicargo/cfg.cpp
new file mode 100644
index 00000000..e8c732d8
--- /dev/null
+++ b/tools/minicargo/cfg.cpp
@@ -0,0 +1,262 @@
+/*
+ * mrustc "minicargo" (minimal cargo clone)
+ * - By John Hodge (Mutabah)
+ *
+ * cfg.cpp
+ * - Handling of target configuration (in manifest nodes)
+ */
+#include <iostream> // cerr
+#include "debug.h"
+#include <cassert>
+#include <algorithm>
+#include <string>
+#include <cstring>
+#include "cfg.hpp"
+
+// TODO: Extract this from the target at runtime (by invoking the compiler on the passed target)
+#ifdef _WIN32
+//# define TARGET_NAME "i586-windows-msvc"
+# define CFG_UNIX false
+# define CFG_WINDOWS true
+#elif defined(__NetBSD__)
+//# define TARGET_NAME "x86_64-unknown-netbsd"
+# define CFG_UNIX true
+# define CFG_WINDOWS false
+#else
+//# define TARGET_NAME "x86_64-unknown-linux-gnu"
+# define CFG_UNIX true
+# define CFG_WINDOWS false
+#endif
+
+class CfgParseLexer
+{
+public:
+ class Tok
+ {
+ friend class CfgParseLexer;
+ public:
+ enum Type {
+ EndOfStream,
+ Operator,
+ Ident,
+ String,
+ };
+ private:
+ Type m_ty;
+ const char* s;
+ const char* e;
+ ::std::string m_val;
+ Tok():
+ m_ty(EndOfStream), s(nullptr),e(nullptr)
+ {
+ }
+ Tok(const char* s):
+ m_ty(Operator), s(s), e(s+1), m_val()
+ {
+ }
+ Tok(const char* s, const char* e):
+ m_ty(Ident), s(s), e(e), m_val()
+ {
+ }
+ Tok(const char* s, const char* e, ::std::string val):
+ m_ty(String), s(s), e(e), m_val(::std::move(val))
+ {
+ }
+ public:
+ bool operator==(char c) const {
+ return (m_ty == Operator && *s == c);
+ }
+ bool operator!=(char c) const { return !(*this == c); }
+ bool operator==(const char* v) const {
+ return strlen(v) == static_cast<unsigned>(e - s) && memcmp(s, v, e-s) == 0;
+ }
+ bool operator!=(const char* v) const { return !(*this == v); }
+
+ const Type ty() const { return m_ty; }
+ const ::std::string& str() const {
+ return m_val;
+ }
+ ::std::string to_string() const {
+ return ::std::string(s, e);
+ }
+ };
+private:
+ const char* m_pos;
+ Tok m_cur;
+
+public:
+ CfgParseLexer(const char* s):
+ m_pos(s),
+ m_cur(nullptr,nullptr)
+ {
+ consume();
+ }
+ const Tok& cur() const {
+ return m_cur;
+ }
+
+ Tok consume() {
+ auto rv = m_cur;
+ m_cur = get_next();
+ //::std::cout << "consume: " << rv.to_string() << " => " << m_cur.to_string() << ::std::endl;
+ return rv;
+ }
+ bool consume_if(char c) {
+ if( cur() == c ) {
+ consume();
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ bool consume_if(const char* s) {
+ if( cur() == s ) {
+ consume();
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+private:
+ Tok get_next();
+};
+
+struct CfgChecker
+{
+ const char* target_env;
+ const char* target_os;
+ const char* target_arch;
+
+ bool check_cfg(CfgParseLexer& p) const;
+};
+
+CfgChecker gCfgChecker {
+ (CFG_WINDOWS ? "msvc" : "gnu"),
+ (CFG_WINDOWS ? "windows" : "linux"),
+ "x86"
+ };
+
+CfgParseLexer::Tok CfgParseLexer::get_next()
+{
+ while(*m_pos == ' ')
+ m_pos ++;
+ if(*m_pos == 0)
+ return Tok();
+ switch(*m_pos)
+ {
+ case '(': case ')':
+ case ',': case '=':
+ return Tok(m_pos++);
+ case '"': {
+ ::std::string str;
+ auto s = m_pos;
+ m_pos ++;
+ while( *m_pos != '"' )
+ {
+ if( *m_pos == '\\' )
+ {
+ TODO("Escape sequences in cfg parser");
+ }
+ str += *m_pos;
+ m_pos ++;
+ }
+ m_pos ++;
+ return Tok(s, m_pos, str); }
+ default:
+ if( isalnum(*m_pos) || *m_pos == '_' )
+ {
+ auto s = m_pos;
+ while(isalnum(*m_pos) || *m_pos == '_')
+ m_pos ++;
+ return Tok(s, m_pos);
+ }
+ else
+ {
+ throw ::std::runtime_error(format("Unexpected character in cfg() - ", *m_pos));
+ }
+ }
+}
+
+bool Cfg_Check(const char* cfg_string)
+{
+ CfgParseLexer p { cfg_string + 4 };
+
+ if( gCfgChecker.target_os == nullptr )
+ {
+ // TODO: If the checker isn't initialised, invoke the compiler and ask it to dump the current target
+ // - It's pre-initialised above currently
+ }
+
+ bool success = gCfgChecker.check_cfg(p);
+ if( !p.consume_if(")") )
+ throw ::std::runtime_error(format("Expected ')' after cfg condition - got", p.cur().to_string()));
+ return success;
+}
+
+bool CfgChecker::check_cfg(CfgParseLexer& p) const
+{
+ auto name = p.consume();
+ if( name.ty() != CfgParseLexer::Tok::Ident )
+ throw ::std::runtime_error("Expected an identifier");
+ // Combinators
+ if( p.consume_if('(') ) {
+ bool rv;
+ if( false ) {
+ }
+ else if( name == "not" ) {
+ rv = !check_cfg(p);
+ }
+ else if( name == "all" ) {
+ rv = true;
+ do
+ {
+ rv &= check_cfg(p);
+ } while(p.consume_if(','));
+ }
+ else {
+ TODO("Unknown fragment in cfg - " << name.to_string());
+ }
+ if( !p.consume_if(')') )
+ throw ::std::runtime_error("Expected ')' after combinator content");
+ return rv;
+ }
+ // Values
+ else if( p.consume_if('=') ) {
+ auto t = p.consume();
+ if( t.ty() != CfgParseLexer::Tok::String )
+ throw ::std::runtime_error("Expected a string after `=`");
+ const auto& val = t.str();
+
+ if( false ) {
+ }
+ else if( name == "target_env" )
+ return val == this->target_env;
+ else if( name == "target_os" )
+ return val == this->target_os;
+ else if( name == "target_arch" )
+ return val == this->target_arch;
+ else {
+ TODO("Unknown fragment in cfg - " << name.to_string());
+ }
+ }
+ // Flags
+ else {
+ if( false ) {
+ }
+ else if( name == "unix" ) {
+ return CFG_UNIX;
+ }
+ else if( name == "windows" ) {
+ return CFG_WINDOWS;
+ }
+ else if( name == "stage0" ) {
+ return false;
+ }
+ else {
+ TODO("Unknown fragment in cfg - " << name.to_string());
+ }
+ }
+ throw ::std::runtime_error("Hit end of check_cfg");
+}
diff --git a/tools/minicargo/cfg.hpp b/tools/minicargo/cfg.hpp
new file mode 100644
index 00000000..907c8079
--- /dev/null
+++ b/tools/minicargo/cfg.hpp
@@ -0,0 +1,9 @@
+/*
+ * mrustc "minicargo" (minimal cargo clone)
+ * - By John Hodge (Mutabah)
+ *
+ * cfg.cpp
+ * - Handling of target configuration (in manifest nodes)
+ */
+#pragma once
+extern bool Cfg_Check(const char* cfg_string);
diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp
index bbaa24f6..79db0e35 100644
--- a/tools/minicargo/manifest.cpp
+++ b/tools/minicargo/manifest.cpp
@@ -13,20 +13,15 @@
#include <algorithm>
#include <cctype> // toupper
#include "repository.h"
+#include "cfg.hpp"
// TODO: Extract this from the target at runtime (by invoking the compiler on the passed target)
#ifdef _WIN32
# define TARGET_NAME "i586-windows-msvc"
-# define CFG_UNIX false
-# define CFG_WINDOWS true
#elif defined(__NetBSD__)
# define TARGET_NAME "x86_64-unknown-netbsd"
-# define CFG_UNIX true
-# define CFG_WINDOWS false
#else
# define TARGET_NAME "x86_64-unknown-linux-gnu"
-# define CFG_UNIX true
-# define CFG_WINDOWS false
#endif
static ::std::vector<::std::shared_ptr<PackageManifest>> g_loaded_manifests;
@@ -241,169 +236,7 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
// - It can be a target spec, or a cfg(foo) same as rustc
bool success;
if( cfg.substr(0, 4) == "cfg(" ) {
- class Parser
- {
- public:
- class Tok
- {
- friend class Parser;
- const char* s;
- const char* e;
- Tok(const char* s, const char* e):
- s(s), e(e)
- {
- }
- public:
- bool operator==(const char* v) const {
- return (strlen(v) == e - s) && memcmp(s, v, e-s) == 0;
- }
- bool operator!=(const char* v) const {
- return (strlen(v) != e - s) || memcmp(s, v, e-s) != 0;
- }
- ::std::string to_string() const {
- return ::std::string(s, e);
- }
- };
- private:
- const char* m_pos;
- Tok m_cur;
-
- public:
- Parser(const char* s):
- m_pos(s),
- m_cur(nullptr,nullptr)
- {
- consume();
- }
- const Tok& cur() const {
- return m_cur;
- }
-
- Tok consume() {
- auto rv = m_cur;
- m_cur = get_next();
- //::std::cout << "consume: " << rv.to_string() << " => " << m_cur.to_string() << ::std::endl;
- return rv;
- }
- bool consume_if(const char* s) {
- if( cur() == s ) {
- consume();
- return true;
- }
- else {
- return false;
- }
- }
- private:
- Tok get_next() {
- while(*m_pos == ' ')
- m_pos ++;
- if(*m_pos == 0)
- return Tok { m_pos, m_pos };
- switch(*m_pos)
- {
- case '(': case ')':
- case ',': case '=':
- return Tok { m_pos++, m_pos };
- case '"': {
- auto s = m_pos;
- m_pos ++;
- while( *m_pos != '"' )
- {
- if( *m_pos == '\\' )
- {
- TODO("Escape sequences in cfg parser");
- }
- m_pos ++;
- }
- m_pos ++;
- return Tok { s, m_pos }; }
- default:
- if( isalnum(*m_pos) || *m_pos == '_' )
- {
- auto s = m_pos;
- while(isalnum(*m_pos) || *m_pos == '_')
- m_pos ++;
- return Tok { s, m_pos };
- }
- else
- {
- throw ::std::runtime_error(format("Unexpected character in cfg() - ", *m_pos));
- }
- }
- }
- };
-
- struct H {
- static bool check_cfg(Parser& p)
- {
- if( p.consume_if("not") ) {
- if( !p.consume_if("(") )
- throw ::std::runtime_error("Expected '(' after `not`");
- auto rv = !check_cfg(p);
- if( !p.consume_if(")") )
- throw ::std::runtime_error("Expected ')' after `not` content");
- return rv;
- }
- else if( p.consume_if("all") ) {
- if( !p.consume_if("(") )
- throw ::std::runtime_error("Expected '(' after `all`");
- bool rv = true;
- do
- {
- rv &= check_cfg(p);
- } while(p.consume_if(","));
- if( !p.consume_if(")") )
- throw ::std::runtime_error("Expected ')' after `all` content");
- return rv;
- }
- // Strings
- else if( p.consume_if("target_os") ) {
- if( !p.consume_if("=") )
- throw ::std::runtime_error("Expected '=' after target_os");
- auto t = p.consume();
- if( t == "\"emscripten\"" ) {
- return false;
- }
- else if( t == "\"macos\"" ) {
- return false;
- }
- else {
- TODO("Handle target_os string - " << t.to_string());
- }
- }
- else if( p.consume_if("target_arch") ) {
- if( !p.consume_if("=") )
- throw ::std::runtime_error("Expected '=' after target");
- auto t = p.consume();
- if( t == "\"wasm32\"" ) {
- return false;
- }
- else{
- TODO("Handle target_arch string - " << t.to_string());
- }
- }
- // Flags
- else if( p.consume_if("unix") ) {
- return CFG_UNIX;
- }
- else if( p.consume_if("windows") ) {
- return CFG_WINDOWS;
- }
- else if( p.consume_if("stage0") ) {
- return false;
- }
- else {
- TODO("Unknown fragment in cfg - " << p.cur().to_string());
- throw ::std::runtime_error("");
- }
- }
- };
-
- Parser p { cfg.data() + 4 };
- success = H::check_cfg(p);
- if( !p.consume_if(")") )
- throw ::std::runtime_error(format("Expected ')' after cfg condition - got", p.cur().to_string()));
+ success = Cfg_Check(cfg.c_str());
}
else {
// It's a target name
@@ -428,6 +261,10 @@ PackageManifest PackageManifest::load_from_toml(const ::std::string& path)
it->fill_from_kv(was_added, key_val, 4);
}
+ else if( real_section == "dev-dependencies" )
+ {
+ // TODO: Developemnt (test/bench) deps
+ }
else
{
TODO("Unknown manifest section for target - " << real_section);