diff options
author | John Hodge <tpg@mutabah.net> | 2017-08-30 21:08:51 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2017-08-31 16:31:24 +0800 |
commit | 5dce4fe24f29818b250eda177c68da5e2c7ee487 (patch) | |
tree | 5293dec3a5d154634ae211fe60997afd4bbccd67 | |
parent | 4e9adae0c15e163290426db1c7d1956abc4c56f5 (diff) | |
download | mrust-5dce4fe24f29818b250eda177c68da5e2c7ee487.tar.gz |
minicargo - Build scripts working (mostly)
-rw-r--r-- | tools/minicargo/build.cpp | 155 | ||||
-rw-r--r-- | tools/minicargo/build.h | 5 | ||||
-rw-r--r-- | tools/minicargo/helpers.h | 5 | ||||
-rw-r--r-- | tools/minicargo/manifest.cpp | 44 | ||||
-rw-r--r-- | tools/minicargo/manifest.h | 3 | ||||
-rw-r--r-- | tools/minicargo/path.cpp | 36 | ||||
-rw-r--r-- | tools/minicargo/path.h | 55 |
7 files changed, 265 insertions, 38 deletions
diff --git a/tools/minicargo/build.cpp b/tools/minicargo/build.cpp index f3cc74b4..56f9b076 100644 --- a/tools/minicargo/build.cpp +++ b/tools/minicargo/build.cpp @@ -8,14 +8,21 @@ #include <sstream> // stringstream #ifdef _WIN32 # include <Windows.h> -# define EXESUF ".exe" #else +# include <unistd.h> // getcwd/chdir # include <spawn.h> # include <sys/types.h> # include <sys/stat.h> # include <sys/wait.h> # include <fcntl.h> +#endif + +#ifdef _WIN32 +# define EXESUF ".exe" +# define TARGET "x86_64-windows-msvc" +#else # define EXESUF "" +# define TARGET "x86_64-unknown-linux-gnu" #endif struct BuildList @@ -65,6 +72,7 @@ public: { } StringList(const StringList&) = delete; + StringList(StringList&&) = default; const ::std::vector<const char*>& get_vec() const { @@ -108,6 +116,51 @@ public: m_strings.push_back(s); } }; +class StringListKV: private StringList +{ + ::std::vector<const char*> m_keys; +public: + StringListKV() + { + } + StringListKV(StringListKV&& x): + StringList(::std::move(x)), + m_keys(::std::move(x.m_keys)) + { + } + + void push_back(const char* k, ::std::string v) + { + m_keys.push_back(k); + StringList::push_back(v); + } + void push_back(const char* k, const char* v) + { + m_keys.push_back(k); + StringList::push_back(v); + } + + struct Iter { + const StringListKV& v; + size_t i; + + void operator++() { + this->i++; + } + ::std::pair<const char*,const char*> operator*() { + return ::std::make_pair(this->v.m_keys[this->i], this->v.get_vec()[this->i]); + } + bool operator!=(const Iter& x) const { + return this->i != x.i; + } + }; + Iter begin() const { + return Iter { *this, 0 }; + } + Iter end() const { + return Iter { *this, m_keys.size() }; + } +}; struct Timestamp { @@ -293,8 +346,9 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& args.push_back(flag.c_str()); } // TODO: Environment variables (rustc_env) + StringListKV env; - return this->spawn_process_mrustc(args, outfile + "_dbg.txt"); + return this->spawn_process_mrustc(args, ::std::move(env), outfile + "_dbg.txt"); } ::std::string Builder::build_build_script(const PackageManifest& manifest) const { @@ -307,7 +361,7 @@ bool Builder::build_target(const PackageManifest& manifest, const PackageTarget& args.push_back("-o"); args.push_back(outfile); args.push_back("-L"); args.push_back(m_output_dir.str().c_str()); - if( this->spawn_process_mrustc(args, outfile + "_dbg.txt") ) + if( this->spawn_process_mrustc(args, {}, outfile + "_dbg.txt") ) return outfile; else return ""; @@ -327,17 +381,68 @@ bool Builder::build_library(const PackageManifest& manifest) const } else { - // Otherwise, compile and run build script - // - Load dependencies for the build script - // - TODO: Should this have already been done - // - Build the script itself - auto script_exe = this->build_build_script( manifest ); - if( script_exe == "" ) - return false; - // - Run the script and put output in the right dir auto out_file = m_output_dir / "build_" + manifest.name().c_str() + ".txt"; - if( !this->spawn_process(script_exe.c_str(), {}, out_file) ) - return false; + // If the build script output doesn't exist (TODO: Or is older than ...) + bool run_build_script = true; + auto ts_result = this->get_timestamp(out_file); + if( ts_result == Timestamp::infinite_past() ) { + DEBUG("Building " << out_file << " - Missing"); + } + else if( ts_result < this->get_timestamp(MRUSTC_PATH) /*|| ts_result < this->get_timestamp("bin/minicargo")*/ ) { + // Rebuild (older than mrustc/minicargo) + DEBUG("Building " << out_file << " - Older than mrustc ( " << ts_result << " < " << this->get_timestamp(MRUSTC_PATH) << ")"); + } + else + { + run_build_script = false; + } + if( run_build_script ) + { + // Compile and run build script + // - Load dependencies for the build script + // - TODO: Should this have already been done + // - Build the script itself + auto script_exe = this->build_build_script( manifest ); + if( script_exe == "" ) + return false; + auto script_exe_abs = ::helpers::path(script_exe).to_absolute(); + + auto output_dir_abs = m_output_dir.to_absolute(); + + // - Run the script and put output in the right dir + auto out_file = output_dir_abs / "build_" + manifest.name().c_str() + ".txt"; + // TODO: Environment variables (key-value list) + StringListKV env; + env.push_back("CARGO_MANIFEST_DIR", manifest.directory().to_absolute()); + //env.push_back("CARGO_MANIFEST_LINKS", manifest.m_links); + //for(const auto& feat : manifest.m_active_features) + //{ + // ::std::string fn = "CARGO_FEATURE_"; + // for(char c : feat) + // fn += c == '-' ? '_' : tolower(c); + // env.push_back(fn, manifest.m_links); + //} + //env.push_back("CARGO_CFG_RELEASE", ""); + env.push_back("OUT_DIR", output_dir_abs / "build_" + manifest.name().c_str()); + env.push_back("TARGET", TARGET); + env.push_back("HOST", TARGET); + env.push_back("NUM_JOBS", "1"); + env.push_back("OPT_LEVEL", "2"); + env.push_back("DEBUG", "0"); + env.push_back("PROFILE", "release"); + + #if _WIN32 + #else + auto fd_cwd = open(".", O_DIRECTORY); + chdir(manifest.directory().str().c_str()); + #endif + if( !this->spawn_process(script_exe_abs.str().c_str(), {}, env, out_file) ) + return false; + #if _WIN32 + #else + fchdir(fd_cwd); + #endif + } // - Load const_cast<PackageManifest&>(manifest).load_build_script( out_file.str() ); } @@ -345,11 +450,12 @@ bool Builder::build_library(const PackageManifest& manifest) const return this->build_target(manifest, manifest.get_library()); } -bool Builder::spawn_process_mrustc(const StringList& args, const ::helpers::path& logfile) const +bool Builder::spawn_process_mrustc(const StringList& args, StringListKV env, const ::helpers::path& logfile) const { - return spawn_process(MRUSTC_PATH, args, logfile); + env.push_back("MRUSTC_DEBUG", ""); + return spawn_process(MRUSTC_PATH, args, env, logfile); } -bool Builder::spawn_process(const char* exe_name, const StringList& args, const ::helpers::path& logfile) const +bool Builder::spawn_process(const char* exe_name, const StringList& args, const StringListKV& env, const ::helpers::path& logfile) const { #ifdef _WIN32 ::std::stringstream cmdline; @@ -358,6 +464,15 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const cmdline << " " << arg; auto cmdline_str = cmdline.str(); DEBUG("Calling " << cmdline_str); + + ::std::stringstream environ_str; + environ_str << "TEMP=" << getenv("TEMP") << '\0'; + environ_str << "TMP=" << getenv("TMP") << '\0'; + for(auto kv : env) + { + environ_str << kv.first << "=" << kv.second << '\0'; + } + environ_str << '\0'; CreateDirectory(static_cast<::std::string>(logfile.parent()).c_str(), NULL); @@ -412,15 +527,19 @@ bool Builder::spawn_process(const char* exe_name, const StringList& args, const argv.push_back(nullptr); // Generate `envp` - ::std::vector<const char*> envp; + StringList envp; extern char **environ; for(auto p = environ; *p; p++) { envp.push_back(*p); } + for(auto kv : env) + { + envp.push_back(::format(kv.first, "=", kv.second)); + } envp.push_back(nullptr); - if( posix_spawn(&pid, exe_name, &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.data()) != 0 ) + if( posix_spawn(&pid, exe_name, &fa, /*attr=*/nullptr, (char* const*)argv.data(), (char* const*)envp.get_vec().data()) != 0 ) { perror("posix_spawn"); DEBUG("Unable to spawn compiler"); diff --git a/tools/minicargo/build.h b/tools/minicargo/build.h index 950fd539..d81234ec 100644 --- a/tools/minicargo/build.h +++ b/tools/minicargo/build.h @@ -4,6 +4,7 @@ #include "path.h" class StringList; +class StringListKV; class Timestamp; class Builder @@ -25,8 +26,8 @@ public: ::std::string build_build_script(const PackageManifest& manifest) const; private: - bool spawn_process(const char* exe_name, const StringList& args, const ::helpers::path& logfile) const; - bool spawn_process_mrustc(const StringList& args, const ::helpers::path& logfile) const; + bool spawn_process_mrustc(const StringList& args, StringListKV env, const ::helpers::path& logfile) const; + bool spawn_process(const char* exe_name, const StringList& args, const StringListKV& env, const ::helpers::path& logfile) const; Timestamp get_timestamp(const ::helpers::path& path) const; diff --git a/tools/minicargo/helpers.h b/tools/minicargo/helpers.h index d913e3c2..9f97b5bb 100644 --- a/tools/minicargo/helpers.h +++ b/tools/minicargo/helpers.h @@ -24,6 +24,11 @@ public: return false; return s[m_len] == '\0'; } + + char operator[](size_t n) const { + return m_start[n]; + } + operator ::std::string() const { return ::std::string { m_start, m_start + m_len }; } diff --git a/tools/minicargo/manifest.cpp b/tools/minicargo/manifest.cpp index dd7d8d23..5f7ecdf0 100644 --- a/tools/minicargo/manifest.cpp +++ b/tools/minicargo/manifest.cpp @@ -510,20 +510,50 @@ void PackageManifest::load_build_script(const ::std::string& path) } // cargo:rustc-link-search=foo/bar/baz else if( key == "rustc-link-search" ) { - // TODO: Check for an = (otherwise default to dynamic) - throw ::std::runtime_error("TODO: rustc-link-search"); + // Check for an = (otherwise default to native) + ::std::string value_str = value; + auto pos = value_str.find_first_of('='); + const char* type = "native"; + ::std::string name; + if(pos == ::std::string::npos) { + name = ::std::move(value_str); + } + else { + name = value_str.substr(pos+1); + auto ty_str = value_str.substr(0, pos); + if( ty_str == "native" ) { + type = "native"; + } + else { + throw ::std::runtime_error(::format("TODO: rustc-link-search ", ty_str)); + } + } + rv.rustc_link_search.push_back(::std::make_pair(type, ::std::move(name))); } // cargo:rustc-link-lib=mysql else if( key == "rustc-link-lib" ) { - // TODO: Check for an = (otherwise default to dynamic) - ::std::string lazy = value; - auto pos = lazy.find_first_of('='); + // Check for an = (otherwise default to dynamic) + ::std::string value_str = value; + auto pos = value_str.find_first_of('='); + const char* type = "static"; + ::std::string name; if(pos == ::std::string::npos) { - rv.rustc_link_lib.push_back(::std::make_pair("static", lazy)); + name = ::std::move(value_str); } else { - throw ::std::runtime_error("TODO: rustc-link-lib"); + name = value_str.substr(pos+1); + auto ty_str = value_str.substr(0, pos); + if( ty_str == "static" ) { + type = "static"; + } + else if( ty_str == "dynamic" ) { + type = "dynamic"; + } + else { + throw ::std::runtime_error(::format("TODO: rustc-link-lib ", ty_str)); + } } + rv.rustc_link_lib.push_back(::std::make_pair(type, ::std::move(name))); } // cargo:rustc-cfg=foo else if( key == "rustc-cfg" ) { diff --git a/tools/minicargo/manifest.h b/tools/minicargo/manifest.h index a17db929..8baf766e 100644 --- a/tools/minicargo/manifest.h +++ b/tools/minicargo/manifest.h @@ -241,6 +241,9 @@ public: const PackageTarget& get_library() const; + const ::helpers::path directory() const { + return ::helpers::path(m_manifest_path).parent(); + } const ::std::string& manifest_path() const { return m_manifest_path; } diff --git a/tools/minicargo/path.cpp b/tools/minicargo/path.cpp index d0316548..93281e0f 100644 --- a/tools/minicargo/path.cpp +++ b/tools/minicargo/path.cpp @@ -1,6 +1,10 @@ /* */ #include "path.h" +#if _WIN32 +#else +# include <unistd.h> // getcwd/chdir +#endif helpers::path::path(const char* s): m_str(s) @@ -28,6 +32,36 @@ helpers::path::path(const char* s): } } +helpers::path helpers::path::to_absolute() const +{ + if(!this->is_valid()) + throw ::std::runtime_error("Calling to_absolute() on an invalid path"); + + if(this->m_str[0] == SEP) + return *this; + + #if _WIN32 + #else + char cwd[1024]; + if( !getcwd(cwd, sizeof(cwd)) ) + throw ::std::runtime_error("Calling getcwd() failed in path::to_absolute()"); + #endif + auto rv = path(cwd); + for(auto comp : *this) + { + if(comp == ".") + ; + else if( comp == ".." ) + rv.pop_component(); + else + rv /= comp; + } + #if _WIN32 + #else + #endif + return rv; +} + helpers::path helpers::path::normalise() const { path rv; @@ -154,4 +188,4 @@ void helpers::path::ComponentsIter::operator++() if(end == ::std::string::npos) end = p.m_str.size(); } -}
\ No newline at end of file +} diff --git a/tools/minicargo/path.h b/tools/minicargo/path.h index 54cb8f40..833fe90a 100644 --- a/tools/minicargo/path.h +++ b/tools/minicargo/path.h @@ -31,26 +31,45 @@ public: return m_str != ""; } - path operator/(const path& p) const + path& operator/=(const path& p) { - if(!this->is_valid()) - throw ::std::runtime_error("Appending to an invalid path"); if(!p.is_valid()) throw ::std::runtime_error("Appending from an invalid path"); - if(p.m_str[0] == '/') + + return *this /= p.m_str.c_str(); + } + path& operator/=(const char* o) + { + if(!this->is_valid()) + throw ::std::runtime_error("Appending to an invalid path"); + if(o[0] == '/') throw ::std::runtime_error("Appending an absolute path to another path"); - return *this / p.m_str.c_str(); + this->m_str.push_back(SEP); + this->m_str.append(o); + return *this; } - /// Append a relative path - path operator/(const char* o) const + path& operator/=(const string_view& o) { if(!this->is_valid()) throw ::std::runtime_error("Appending to an invalid path"); - if (o[0] == '/') + if(o[0] == '/') throw ::std::runtime_error("Appending an absolute path to another path"); + this->m_str.push_back(SEP); + this->m_str += o; + return *this; + } + + path operator/(const path& p) const + { auto rv = *this; - rv.m_str.push_back(SEP); - rv.m_str.append(o); + rv /= p; + return rv; + } + /// Append a relative path + path operator/(const char* o) const + { + auto rv = *this; + rv /= o; return rv; } /// Add an arbitary string to the final component @@ -65,6 +84,21 @@ public: return rv; } + bool pop_component() + { + if(!this->is_valid()) + throw ::std::runtime_error("Calling pop_component() on an invalid path"); + auto pos = m_str.find_last_of(SEP); + if(pos == ::std::string::npos || pos == 0) + { + return false; + } + else + { + this->m_str.resize(pos); + return true; + } + } path parent() const { if(!this->is_valid()) @@ -81,6 +115,7 @@ public: return rv; } } + path to_absolute() const; const ::std::string& str() const { |