summaryrefslogtreecommitdiff
path: root/tools/minicargo/build.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/minicargo/build.cpp')
-rw-r--r--tools/minicargo/build.cpp230
1 files changed, 222 insertions, 8 deletions
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;
}