summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap.cc22
-rw-r--r--src/configure.cc215
-rw-r--r--src/execute.cc133
-rw-r--r--src/execute.h2
-rw-r--r--src/libctor.cc9
-rw-r--r--src/libctor.h1
-rw-r--r--src/rebuild.cc149
-rw-r--r--src/rebuild.h3
-rw-r--r--src/task.cc23
-rw-r--r--src/task.h1
-rw-r--r--src/task_ar.cc12
-rw-r--r--src/task_cc.cc31
-rw-r--r--src/task_fn.cc2
-rw-r--r--src/task_ld.cc12
-rw-r--r--src/task_so.cc3
-rw-r--r--src/tasks.cc7
-rw-r--r--src/tasks.h6
-rw-r--r--src/tools.cc63
-rw-r--r--src/tools.h1
-rw-r--r--src/unittest.cc3
-rw-r--r--src/unittest.h2
-rw-r--r--src/util.cc1
22 files changed, 618 insertions, 83 deletions
diff --git a/src/bootstrap.cc b/src/bootstrap.cc
index 9a3c321..97fe6fa 100644
--- a/src/bootstrap.cc
+++ b/src/bootstrap.cc
@@ -3,6 +3,7 @@
// See accompanying file LICENSE for details.
#include <iostream>
#include <array>
+#include <cstdlib>
#define BOOTSTRAP
@@ -17,6 +18,7 @@
#include "tasks.cc"
#include "build.cc"
#include "tools.cc"
+#include "../ctor.cc"
std::filesystem::path configurationFile("configuration.cc");
std::filesystem::path configHeaderFile("config.h");
@@ -35,6 +37,24 @@ bool hasConfiguration(const std::string& key)
const std::string& getConfiguration(const std::string& key,
const std::string& defaultValue)
{
+ if(key == cfg::host_cxx && std::getenv("CXX"))
+ {
+ static std::string s = std::getenv("CXX");
+ return s;
+ }
+
+ if(key == cfg::host_cc && std::getenv("CC"))
+ {
+ static std::string s = std::getenv("CC");
+ return s;
+ }
+
+ if(key == cfg::host_ar && std::getenv("AR"))
+ {
+ static std::string s = std::getenv("AR");
+ return s;
+ }
+
return defaultValue;
}
@@ -51,7 +71,7 @@ int main(int argc, char* argv[])
settings.builddir = getConfiguration(cfg::builddir, "build");
settings.parallel_processes =
- std::max(1u, std::thread::hardware_concurrency() * 2 - 1);
+ (std::max)(1u, std::thread::hardware_concurrency() * 2 - 1);
settings.verbose = 0;
auto all_tasks = getTasks(settings, {}, false);
for(auto task : all_tasks)
diff --git a/src/configure.cc b/src/configure.cc
index a81f8ad..bb94202 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -23,15 +23,73 @@ std::map<std::string, std::string> external_includedir;
std::map<std::string, std::string> external_libdir;
const Configuration default_configuration{};
+#if !defined(_WIN32)
const Configuration& __attribute__((weak)) configuration()
{
return default_configuration;
}
+#else
+//extern const char * pWeakValue;
+//extern const char * pDefaultWeakValue = NULL;
+//
+//#pragma comment(linker, "/alternatename:_pWeakValue=_pDefaultWeakValue")
+const Configuration& defConfiguration()
+{
+ return default_configuration;
+}
+#pragma comment(linker, "/alternatename:?configuration@@YAABUConfiguration@@XZ=?defConfiguration@@YAABUConfiguration@@XZ")
+//https://stackoverflow.com/questions/2290587/gcc-style-weak-linking-in-visual-studio
+//https://devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024
+
+//extern "C"
+//{
+//void default_error_log() { /* do nothing */ }
+//}
+//// For expository simplification: assume x86 cdecl
+//#pragma comment(linker, "/alternatename:_error_log=_default_error_log")
+
+
+#endif
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+void _copyAndRelaunch(int argc, char* argv[],
+ const std::string& copy_src,
+ const std::string& copy_tar,
+ const std::string& compilation_name)
+{
+#ifdef _WIN32
+ CopyFile(copy_src.data(), copy_tar.data(), false);
+ SetFileAttributes(copy_tar.data(), FILE_ATTRIBUTE_HIDDEN);
+ auto t = std::filesystem::last_write_time(copy_src);
+ std::filesystem::last_write_time(copy_tar, t);
+
+ STARTUPINFO si{};
+ PROCESS_INFORMATION pi{};
+ si.cb = sizeof(pi);
+
+ std::string args = copy_tar + " configure";
+ for(int i = 1; i < argc; ++i)
+ {
+ args += " ";
+ args += argv[i];
+ }
+ args += " --name ";
+ args += compilation_name;
+
+ CreateProcess(nullptr, args.data(), 0,0,0,0,0,0,&si,&pi);
+ exit(1);
+#endif // _WIN32
+}
namespace ctor
{
std::optional<std::string> includedir;
std::optional<std::string> libdir;
+std::map<std::string, std::string> conf_values;
}
bool hasConfiguration(const std::string& key)
@@ -46,6 +104,11 @@ bool hasConfiguration(const std::string& key)
return true;
}
+ if(ctor::conf_values.find(key) != ctor::conf_values.end())
+ {
+ return true;
+ }
+
const auto& c = configuration();
return c.tools.find(key) != c.tools.end();
}
@@ -63,6 +126,11 @@ const std::string& getConfiguration(const std::string& key,
return *ctor::libdir;
}
+ if(ctor::conf_values.find(key) != ctor::conf_values.end())
+ {
+ return ctor::conf_values[key];
+ }
+
const auto& c = configuration();
if(hasConfiguration(key))
{
@@ -88,11 +156,24 @@ std::string locate(const std::string& arch, const std::string& app)
{
std::stringstream ss(path_env);
std::string path;
- while (std::getline(ss, path, ':'))
+ while (std::getline(ss, path, ';'))
{
paths.push_back(path);
}
}
+ {
+ const auto& cfg = configuration();
+ auto it = cfg.env.find("ctorPATH");
+ if(it != cfg.env.end())
+ {
+ std::stringstream ss(it->second);
+ std::string path;
+ while (std::getline(ss, path, ';'))
+ {
+ paths.push_back(path);
+ }
+ }
+ }
for(const auto& path_str : paths)
{
std::filesystem::path path(path_str);
@@ -127,10 +208,10 @@ class Args
: public std::vector<char*>
{
public:
- Args(const std::vector<std::string>& args)
+ Args(const std::string& name, const std::vector<std::string>& args)
{
resize(args.size() + 1);
- (*this)[0] = strdup("./ctor");
+ (*this)[0] = strdup(name.data());
for(std::size_t i = 0; i < size() - 1; ++i)
{
(*this)[i + 1] = strdup(args[i].data());
@@ -146,15 +227,32 @@ public:
}
};
+std::string esc(const std::string& in)
+{
+ std::string out;
+ for(auto c : in)
+ {
+ switch(c)
+ {
+ case '\\': out += "\\\\"; break;
+ case '"': out += "\\\""; break;
+ default:
+ out += c;
+ break;
+ }
+ }
+ return out;
+}
+
// helper constant for the visitor
template<class> inline constexpr bool always_false_v = false;
-int regenerateCache(const Settings& default_settings,
+int regenerateCache(Settings& settings,
+ const std::string& name,
const std::vector<std::string>& args,
const std::map<std::string, std::string>& env)
{
- Settings settings{default_settings};
- Args vargs(args);
+ Args vargs(name, args);
dg::Options opt;
int key{128};
@@ -185,6 +283,13 @@ int regenerateCache(const Settings& default_settings,
return 0;
});
+ opt.add("name", required_argument, 'n',
+ "Set the output name of the ctor command to override the current one.",
+ [&]() {
+ settings.name = optarg;
+ return 0;
+ });
+
opt.add("cc", required_argument, key++,
"Use specified c-compiler instead of gcc.",
[&]() {
@@ -311,6 +416,24 @@ int regenerateCache(const Settings& default_settings,
opt.process(vargs.size(), vargs.data());
+ std::filesystem::path settings_file(settings.name);
+ std::filesystem::path argv0_file(vargs[0]);
+
+ if(settings_file.is_relative())
+ {
+ settings_file = std::filesystem::current_path() / settings_file;
+ }
+ if(argv0_file.is_relative())
+ {
+ argv0_file = std::filesystem::current_path() / argv0_file;
+ }
+
+ if(settings_file.string() == argv0_file.string())
+ {
+ _copyAndRelaunch(vargs.size(), vargs.data(), vargs[0], "ctor-configure-tmp.exe", settings.name);
+ exit(0);
+ }
+
if(host_arch.empty())
{
host_arch = build_arch;
@@ -376,6 +499,20 @@ int regenerateCache(const Settings& default_settings,
std::string build_ar = locate(build_arch, ar_prog);
std::string build_ld = locate(build_arch, ld_prog);
+ // Store current values for execution in this execution context.
+ if(!ctor_includedir.empty())
+ {
+ ctor::conf_values[cfg::ctor_includedir] = ctor_includedir;
+ }
+ if(!ctor_libdir.empty())
+ {
+ ctor::conf_values[cfg::ctor_libdir] = ctor_libdir;
+ }
+ ctor::conf_values[cfg::host_cxx] = host_cxx;
+ ctor::conf_values[cfg::build_cxx] = build_cxx;
+ ctor::conf_values[cfg::host_ld] = host_ld;
+ ctor::conf_values[cfg::build_ld] = build_ld;
+
std::cout << "Writing results to: " << configurationFile.string() << "\n";
{
std::ofstream istr(configurationFile);
@@ -387,34 +524,34 @@ int regenerateCache(const Settings& default_settings,
istr << " .args = {";
for(const auto& arg : args)
{
- istr << "\"" << arg << "\",";
+ istr << "\"" << esc(arg) << "\",";
}
istr << "},\n";
- istr << " .env = {";
+ istr << " .env = {\n";
for(const auto& e : env)
{
- istr << "{\"" << e.first << "\", \"" << e.second << "\"}, ";
+ istr << " {\"" << e.first << "\", \"" << esc(e.second) << "\"},\n";
}
- istr << "},\n";
+ istr << " },\n";
istr << " .tools = {\n";
- istr << " { \"" << cfg::builddir << "\", \"" << settings.builddir << "\" },\n";
- istr << " { \"" << cfg::host_cc << "\", \"" << host_cc << "\" },\n";
- istr << " { \"" << cfg::host_cxx << "\", \"" << host_cxx << "\" },\n";
- istr << " { \"" << cfg::host_ar << "\", \"" << host_ar << "\" },\n";
- istr << " { \"" << cfg::host_ld << "\", \"" << host_ld << "\" },\n";
- istr << " { \"" << cfg::build_cc << "\", \"" << build_cc << "\" },\n";
- istr << " { \"" << cfg::build_cxx << "\", \"" << build_cxx << "\" },\n";
- istr << " { \"" << cfg::build_ar << "\", \"" << build_ar << "\" },\n";
- istr << " { \"" << cfg::build_ld << "\", \"" << build_ld << "\" },\n";
+ istr << " { \"" << cfg::builddir << "\", \"" << esc(settings.builddir) << "\" },\n";
+ istr << " { \"" << cfg::host_cc << "\", \"" << esc(host_cc) << "\" },\n";
+ istr << " { \"" << cfg::host_cxx << "\", \"" << esc(host_cxx) << "\" },\n";
+ istr << " { \"" << cfg::host_ar << "\", \"" << esc(host_ar) << "\" },\n";
+ istr << " { \"" << cfg::host_ld << "\", \"" << esc(host_ld) << "\" },\n";
+ istr << " { \"" << cfg::build_cc << "\", \"" << esc(build_cc) << "\" },\n";
+ istr << " { \"" << cfg::build_cxx << "\", \"" << esc(build_cxx) << "\" },\n";
+ istr << " { \"" << cfg::build_ar << "\", \"" << esc(build_ar) << "\" },\n";
+ istr << " { \"" << cfg::build_ld << "\", \"" << esc(build_ld) << "\" },\n";
if(!ctor_includedir.empty())
{
- istr << " { \"" << cfg::ctor_includedir << "\", \"" << ctor_includedir << "\" },\n";
+ istr << " { \"" << cfg::ctor_includedir << "\", \"" << esc(ctor_includedir) << "\" },\n";
ctor::includedir = ctor_includedir;
}
if(!ctor_libdir.empty())
{
- istr << " { \"" << cfg::ctor_libdir << "\", \"" << ctor_libdir << "\" },\n";
+ istr << " { \"" << cfg::ctor_libdir << "\", \"" << esc(ctor_libdir) << "\" },\n";
ctor::libdir = ctor_libdir;
}
@@ -508,7 +645,7 @@ int configure(const Settings& global_settings, int argc, char* argv[])
args.push_back(argv[i]);
}
- std::map<std::string, std::string> env;
+ auto env = configuration().env;
auto cc_env = getenv("CC");
if(cc_env)
{
@@ -533,7 +670,32 @@ int configure(const Settings& global_settings, int argc, char* argv[])
env["LD"] = ld_env;
}
- auto ret = regenerateCache(settings, args, env);
+ // Env vars for msvc
+ auto cl_env = getenv("CL");
+ if(cl_env)
+ {
+ env["CL"] = cl_env;
+ }
+
+ auto lib_env = getenv("LIB");
+ if(lib_env)
+ {
+ env["LIB"] = lib_env;
+ }
+
+ auto link_env = getenv("LINK");
+ if(link_env)
+ {
+ env["LINK"] = link_env;
+ }
+
+ auto path_env = getenv("PATH");
+ if(path_env)
+ {
+ env["ctorPATH"] = path_env;
+ }
+
+ auto ret = regenerateCache(settings, argv[0], args, env);
if(ret != 0)
{
return ret;
@@ -544,8 +706,9 @@ int configure(const Settings& global_settings, int argc, char* argv[])
return 0;
}
-int reconfigure(const Settings& settings, int argc, char* argv[])
+int reconfigure(const Settings& global_settings, int argc, char* argv[])
{
+ Settings settings{global_settings};
bool no_rerun{false};
std::vector<std::string> args;
@@ -573,7 +736,7 @@ int reconfigure(const Settings& settings, int argc, char* argv[])
}
std::cout << "\n";
- auto ret = regenerateCache(settings, cfg.args, cfg.env);
+ auto ret = regenerateCache(settings, argv[0], cfg.args, cfg.env);
if(ret != 0)
{
return ret;
@@ -586,5 +749,5 @@ int reconfigure(const Settings& settings, int argc, char* argv[])
return 0; // this was originally invoked by configure, don't loop
}
- return execute(argv[0], args);
+ return execute(argv[0], args, {});
}
diff --git a/src/execute.cc b/src/execute.cc
index 610ccdd..5e59ff6 100644
--- a/src/execute.cc
+++ b/src/execute.cc
@@ -3,11 +3,17 @@
// See accompanying file LICENSE for details.
#include "execute.h"
-#include <unistd.h>
#include <cstring>
+#if !defined(_WIN32)
+#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <spawn.h>
+#else
+#include <processthreadsapi.h>
+#include <synchapi.h>
+#include <processenv.h>
+#endif
#include <iostream>
/*
@@ -18,6 +24,7 @@ https://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-
*/
+#if !defined(_WIN32)
namespace
{
int parent_waitpid(pid_t pid)
@@ -32,9 +39,11 @@ int parent_waitpid(pid_t pid)
return WEXITSTATUS(status);
}
} // namespace ::
+#endif
int execute(const std::string& command,
const std::vector<std::string>& args,
+ const std::map<std::string, std::string>& env,
bool verbose)
{
std::vector<const char*> argv;
@@ -45,46 +54,134 @@ int execute(const std::string& command,
}
argv.push_back(nullptr);
- if(verbose)
+ std::string cmd;
+ for(const auto& arg : argv)
{
- std::string cmd;
- for(const auto& arg : argv)
+ if(arg == nullptr)
{
- if(arg == nullptr)
- {
- break;
- }
- if(!cmd.empty())
- {
- cmd += " ";
- }
- cmd += arg;
+ break;
+ }
+ if(!cmd.empty())
+ {
+ cmd += " ";
}
+ cmd += arg;
+ }
+ if(verbose)
+ {
std::cout << cmd << "\n";
}
+#if !defined(_WIN32)
+
#if 1
auto pid = vfork();
if(pid == 0)
{
+ for(const auto& [key, value] : env)
+ {
+ setenv(key, value);
+ }
+ // TODO: use execvpe to set LD_LIBRARY_PATH
execv(command.data(), (char**)argv.data());
std::cout << "Could not execute " << command << ": " <<
strerror(errno) << "\n";
_exit(1); // execv only returns if an error occurred
}
- auto ret = parent_waitpid(pid);
+
+ return parent_waitpid(pid);
#elif 0
pid_t pid;
+ const char * envp[] = {nullptr}; // TODO: use this to set LD_LIBRARY_PATH
if(posix_spawn(&pid, command.data(), nullptr, nullptr,
- (char**)argv.data(), nullptr))
+ (char**)argv.data(), envp))
{
return 1;
}
- auto ret = parent_waitpid(pid);
+ return parent_waitpid(pid);
#else
- auto ret = system(cmd.data());
+ return system(cmd.data());
#endif
- return ret;
+#else
+ std::map<std::string, std::string> new_env;
+ auto env_strings = GetEnvironmentStrings();
+ const char* ptr = env_strings;
+ std::string key;
+ std::string value;
+ bool key_state{true};
+ while(true)
+ {
+ if(key_state) // searching for key
+ {
+ if(*ptr == '\0')
+ {
+ break;
+ }
+
+ if(*ptr != '=')
+ {
+ key += *ptr;
+ }
+ else
+ {
+ key_state = false;
+ }
+ }
+ else
+ {
+ if(*ptr != '\0')
+ {
+ value += *ptr;
+ }
+ else
+ {
+ new_env.insert({key, value});
+ key = {};
+ value = {};
+ key_state = true;
+ }
+ }
+ ++ptr;
+ }
+ FreeEnvironmentStrings(env_strings);
+
+ // add new env vars (if any)
+ for(const auto& [key, value] : env)
+ {
+ //if(key == "CL" || key == "LINK" || key == "LIB")
+ {
+ new_env[key] = value;
+ }
+ }
+
+ std::string env_str;
+ for(const auto& [k,v] : new_env)
+ {
+ env_str += k + "=" + v;
+ env_str += '\0';
+ }
+ env_str += '\0';
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&si,sizeof(si));
+ si.cb=sizeof(si);
+ ZeroMemory(&pi,sizeof(pi));
+ // TODO: Use SetDllDirectory(...) to set DLL search directory
+ if(!CreateProcess(nullptr, //"C:/WINDOWS/notepad.exe",
+ //"notepad.exe c:/readme.txt",0,0,0,0,0,0,&si,&pi))
+ (char*)cmd.data(),0,0,0,0,env_str.data(),0,&si,&pi))
+ {
+ return 1; // Could not start process;
+ }
+
+ // Now 'pi.hProcess' contains the process HANDLE, which you can use to
+ // wait for it like this:
+ const DWORD infinite = 0xFFFFFFFF;
+ WaitForSingleObject(pi.hProcess, infinite);
+ DWORD exitCode{0};
+ GetExitCodeProcess(pi.hProcess, &exitCode);
+ return exitCode;
+#endif
}
diff --git a/src/execute.h b/src/execute.h
index c750a83..2ad81d1 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -5,7 +5,9 @@
#include <string>
#include <vector>
+#include <map>
int execute(const std::string& command,
const std::vector<std::string>& args,
+ const std::map<std::string, std::string>& env,
bool verbose = true);
diff --git a/src/libctor.cc b/src/libctor.cc
index d188771..bfa09d6 100644
--- a/src/libctor.cc
+++ b/src/libctor.cc
@@ -33,6 +33,7 @@ int main(int argc, char* argv[])
settings.builddir = getConfiguration(cfg::builddir, settings.builddir);
settings.parallel_processes =
std::max(1u, std::thread::hardware_concurrency()) * 2 - 1;
+ settings.name = argv[0];
if(argc > 1 && std::string(argv[1]) == "configure")
{
@@ -96,6 +97,14 @@ int main(int argc, char* argv[])
return 0;
});
+ opt.add("name", required_argument, 'n',
+ "Set the output name of the ctor command to override the current one.",
+ [&]() {
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+ settings.name = optarg;
+ return 0;
+ });
+
opt.add("add", required_argument, 'a',
"Add specified file to the build configurations.",
[&]() {
diff --git a/src/libctor.h b/src/libctor.h
index 96e1115..e4ea7e7 100644
--- a/src/libctor.h
+++ b/src/libctor.h
@@ -69,6 +69,7 @@ struct Settings
std::string builddir{"build"};
std::size_t parallel_processes{1};
int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ...
+ std::string name;
};
struct BuildConfiguration;
diff --git a/src/rebuild.cc b/src/rebuild.cc
index 9ddf5ba..4b0c8e5 100644
--- a/src/rebuild.cc
+++ b/src/rebuild.cc
@@ -143,6 +143,92 @@ bool contains(const std::vector<Source>& sources, const std::string& file)
}
}
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+// From: http://www.catch22.net/tuts/win32/self-deleting-executables
+void DeleteSelf()
+{
+//#ifdef Windows NT/2000
+#if 1
+ char buf[MAX_PATH];
+ HMODULE module;
+
+ module = GetModuleHandle(0);
+ GetModuleFileName(module, buf, MAX_PATH);
+ CloseHandle((HANDLE)4);
+
+ __asm
+ {
+ lea eax, buf
+ push 0
+ push 0
+ push eax
+ push ExitProcess
+ push module
+ push DeleteFile
+ push UnmapViewOfFile
+ ret
+ }
+#endif
+//#elif Windows 95/98
+#if 0
+ char buf[MAX_PATH];
+ HMODULE module;
+
+ module = GetModuleHandle(0);
+ GetModuleFileName(module, buf, MAX_PATH);
+
+ __asm
+ {
+ lea eax, buf
+ push 0
+ push 0
+ push eax
+ push ExitProcess
+ push module
+ push DeleteFile
+ push FreeLibrary
+ ret
+ }
+#endif
+//endif
+}
+#endif // _WIN32
+
+void copyAndRelaunch(bool dirty_tasks, bool delete_me,
+ int argc, char* argv[],
+ const std::string& copy_src,
+ const std::string& copy_tar,
+ const std::string& compilation_name)
+{
+#ifdef _WIN32
+ if(dirty_tasks && !delete_me)
+ {
+ CopyFile(copy_src.data(), copy_tar.data(), false);
+ SetFileAttributes(copy_tar.data(), FILE_ATTRIBUTE_HIDDEN);
+ auto t = std::filesystem::last_write_time(copy_src);
+ std::filesystem::last_write_time(copy_tar, t);
+
+ STARTUPINFO si{};
+ PROCESS_INFORMATION pi{};
+ si.cb = sizeof(pi);
+ std::string args = copy_tar;
+ for(int i = 1; i < argc; ++i)
+ {
+ args += " ";
+ args += argv[i];
+ }
+ args += " --name ";
+ args += compilation_name;
+
+ CreateProcess(nullptr, args.data(), 0,0,0,0,0,0,&si,&pi);
+ exit(0);
+ }
+#endif // _WIN32
+}
+
bool recompileCheck(const Settings& global_settings, int argc, char* argv[],
bool relaunch_allowed)
{
@@ -152,40 +238,65 @@ bool recompileCheck(const Settings& global_settings, int argc, char* argv[],
{
std::cout << "Recompile check (" << numConfigFiles << "):\n";
}
+ std::filesystem::path settings_file(global_settings.name);
+ std::filesystem::path argv0_file(argv[0]);
+
+ if(settings_file.is_relative())
+ {
+ settings_file = std::filesystem::current_path() / settings_file;
+ }
+ if(argv0_file.is_relative())
+ {
+ argv0_file = std::filesystem::current_path() / argv0_file;
+ }
+
+ bool delete_me = settings_file.string() != argv0_file.string();
BuildConfiguration config;
+ config.type = TargetType::Executable;
config.name = "ctor";
config.system = OutputSystem::Build;
auto tool_chain = getToolChain(config.system);
append(config.flags.cxxflags,
- getOption(tool_chain, opt::optimization, "3"));
+ getOption(tool_chain, opt::optimization, "2"));
append(config.flags.cxxflags,
getOption(tool_chain, opt::cpp_std, "c++20"));
+ config.flags.cxxflags.push_back("/nologo");
if(hasConfiguration(cfg::ctor_includedir))
{
append(config.flags.cxxflags,
getOption(tool_chain, opt::include_path,
getConfiguration(cfg::ctor_includedir)));
}
+
if(hasConfiguration(cfg::ctor_libdir))
{
append(config.flags.ldflags,
getOption(tool_chain, opt::library_path,
getConfiguration(cfg::ctor_libdir)));
}
- append(config.flags.ldflags, getOption(tool_chain, opt::link, "ctor"));
+// append(config.flags.ldflags, getOption(tool_chain, opt::link, "ctor"));
+ config.flags.ldflags.push_back("build/libctor.lib");
append(config.flags.ldflags, getOption(tool_chain, opt::threads));
+ config.flags.ldflags.push_back("/nologo");
+ config.flags.ldflags.push_back("/SUBSYSTEM:CONSOLE");
+
Settings settings{global_settings};
- settings.verbose = -1; // Make check completely silent.
+ settings.parallel_processes = 1;
+ settings.verbose = 2;//-1; // Make check completely silent.
settings.builddir += "/ctor"; // override builddir to use ctor subdir
-
{
std::filesystem::path buildfile = settings.builddir;
- std::filesystem::path currentfile = argv[0];
+ std::filesystem::path currentfile = settings.name;
+
+ if(currentfile.is_relative())
+ {
+ currentfile = std::filesystem::current_path() / currentfile;
+ }
config.target = std::filesystem::relative(currentfile, buildfile).string();
}
@@ -247,35 +358,61 @@ bool recompileCheck(const Settings& global_settings, int argc, char* argv[],
}
auto dirty_tasks = build(settings, "ctor", tasks, true); // dryrun
+
+ copyAndRelaunch(dirty_tasks, delete_me, argc, argv,
+ settings.name/*argv[0]*/, "ctor-rebuild-tmp.exe", settings.name);
+
+ bool was_rebuilt{false};
if(dirty_tasks)
{
std::cout << "Rebuilding config.\n";
auto ret = build(settings, "ctor", tasks); // run for real
if(ret != 0)
{
+ if(delete_me)
+ {
+ DeleteSelf();
+ }
return ret;
}
+ was_rebuilt = true;
}
if(reconfigure)
{
+ copyAndRelaunch(true, delete_me, argc, argv,
+ settings.name,
+ "ctor-reconfigure-tmp.exe", settings.name);
std::vector<std::string> args;
args.push_back("reconfigure");
if(!relaunch_allowed)
{
args.push_back("--no-rerun");
}
+ if(delete_me)
+ {
+ args.push_back("--name " + settings.name);
+ }
for(int i = 1; i < argc; ++i)
{
args.push_back(argv[i]);
}
- auto ret = execute(argv[0], args);
+ auto ret = execute(settings.name, args, {});
//if(ret != 0)
{
+ if(delete_me)
+ {
+ DeleteSelf();
+ }
exit(ret);
}
}
+ if(delete_me)
+ {
+ DeleteSelf();
+ }
+
return dirty_tasks;
}
diff --git a/src/rebuild.h b/src/rebuild.h
index f1255c6..7b0ebb8 100644
--- a/src/rebuild.h
+++ b/src/rebuild.h
@@ -7,8 +7,7 @@
#include <array>
#include "libctor.h"
-
-class Settings;
+//class Settings;
struct BuildConfigurationEntry
{
diff --git a/src/task.cc b/src/task.cc
index fb50765..4736565 100644
--- a/src/task.cc
+++ b/src/task.cc
@@ -3,7 +3,7 @@
// See accompanying file LICENSE for details.
#include "task.h"
-#include <unistd.h>
+//#include <unistd.h>
#include <iostream>
Task::Task(const BuildConfiguration& config, const Settings& settings,
@@ -147,11 +147,24 @@ std::string Task::compiler() const
case OutputSystem::Build:
return getConfiguration(cfg::build_cxx, "/usr/bin/g++");
}
- default:
- std::cerr << "Unknown CC target type\n";
- exit(1);
- break;
}
+
+ std::cerr << "Unknown CC target type\n";
+ exit(1);
+}
+
+std::string Task::linker() const
+{
+ switch(outputSystem())
+ {
+ case OutputSystem::Host:
+ return getConfiguration(cfg::host_ld, "/usr/bin/ld");
+ case OutputSystem::Build:
+ return getConfiguration(cfg::build_ld, "/usr/bin/ld");
+ }
+
+ std::cerr << "Unknown CC target type\n";
+ exit(1);
}
std::set<std::shared_ptr<Task>> Task::getDependsTasks()
diff --git a/src/task.h b/src/task.h
index be3995f..0e2a9f7 100644
--- a/src/task.h
+++ b/src/task.h
@@ -64,6 +64,7 @@ public:
Language sourceLanguage() const;
OutputSystem outputSystem() const;
std::string compiler() const;
+ std::string linker() const;
std::set<std::shared_ptr<Task>> getDependsTasks();
diff --git a/src/task_ar.cc b/src/task_ar.cc
index 3e1746c..3fcfcf4 100644
--- a/src/task_ar.cc
+++ b/src/task_ar.cc
@@ -78,13 +78,16 @@ bool TaskAR::dirtyInner()
int TaskAR::runInner()
{
std::vector<std::string> args;
- args.push_back("rcs");
- args.push_back(targetFile().string());
+ //args.push_back("rcs");
for(const auto& task : getDependsTasks())
{
args.push_back(task->targetFile().string());
}
+ args.push_back("/nologo");
+ args.push_back("/SUBSYSTEM:CONSOLE");
+ args.push_back("/out:"+targetFile().string());
+
{ // Write flags to file.
std::ofstream flagsStream(flagsFile);
flagsStream << flagsString();
@@ -106,7 +109,8 @@ int TaskAR::runInner()
break;
}
- return execute(tool, args, settings.verbose > 0);
+ const auto& cfg = configuration();
+ return execute(tool, args, cfg.env, settings.verbose > 0);
}
int TaskAR::clean()
@@ -168,7 +172,7 @@ std::string TaskAR::flagsString() const
}
flagsStr += flag;
}
- flagsStr += "\n";
+ //flagsStr += "\n";
for(const auto& dep : config.depends)
{
diff --git a/src/task_cc.cc b/src/task_cc.cc
index c4343b6..e9ef590 100644
--- a/src/task_cc.cc
+++ b/src/task_cc.cc
@@ -24,7 +24,6 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,
sourceFile /= source.file;
std::filesystem::path base = sourceFile.parent_path();
- std::filesystem::create_directories(std::filesystem::path(settings.builddir) / base);
base /= cleanUp(config.target);
base += "-";
@@ -56,14 +55,17 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,
if(source.output.empty())
{
_targetFile = base;
- _targetFile += ".o";
+ _targetFile += ".obj";
}
else
{
_targetFile = source.output;
}
+
+ std::filesystem::create_directories(targetFile().parent_path());
+
depsFile = targetFile().parent_path() / targetFile().stem();
- depsFile += ".d";
+ depsFile += ".deps";
flagsFile = targetFile().parent_path() / targetFile().stem();
flagsFile += ".flags";
}
@@ -185,7 +187,8 @@ int TaskCC::runInner()
targetFile().lexically_normal().string() << "\n";
}
- return execute(compiler(), args, settings.verbose > 0);
+ const auto& cfg = configuration();
+ return execute(compiler(), args, cfg.env, settings.verbose > 0);
}
int TaskCC::clean()
@@ -285,8 +288,26 @@ std::vector<std::string> TaskCC::getCompilerArgs() const
auto compiler_flags = flags();
+ // cl.exe (compiler - gcc/g++)
+ // https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=msvc-170
+
+ // /c Compiles without linking.
+ // /Fo Object File Name (or path if .cc basename is re-used)
+ // /F Output-File
+ // /Fe (Name EXE File)
+ // /sourceDependencies <file> json file with dependenciy tree
+ // /I<dir> include path
+ // /LD Creates a dynamic-link library.
+ // /link <option> Passes the specified option to LINK.
+
+ // link.exe (exe and dll linker - ld)
+ // https://docs.microsoft.com/en-us/cpp/build/reference/linker-options?view=msvc-170
+
+ // lib.exe (lib linker - ar)
+ // https://docs.microsoft.com/en-us/cpp/build/reference/overview-of-lib?view=msvc-170
std::vector<std::string> args;
- append(args, getOption(tool_chain, opt::generate_dep_tree));
+ append(args, getOption(tool_chain, opt::generate_dep_tree, depsFile.string()));
+// args.push_back("-MMD"); // https://github.com/ninja-build/ninja/issues/1806
if(std::filesystem::path(config.target).extension() == ".so")
{
diff --git a/src/task_fn.cc b/src/task_fn.cc
index ab00fae..9ef8f96 100644
--- a/src/task_fn.cc
+++ b/src/task_fn.cc
@@ -97,7 +97,7 @@ std::vector<std::string> TaskFn::depends() const
std::string TaskFn::target() const
{
- return _targetFile;
+ return _targetFile.string();
}
std::filesystem::path TaskFn::targetFile() const
diff --git a/src/task_ld.cc b/src/task_ld.cc
index 20e823d..ba1eb1b 100644
--- a/src/task_ld.cc
+++ b/src/task_ld.cc
@@ -95,14 +95,15 @@ int TaskLD::runInner()
auto lib = depFile.stem().string().substr(3); // strip 'lib' prefix
append(args, getOption(tool_chain, opt::link, lib));
}
- else if(depFile.extension() == ".a" || depFile.extension() == ".o")
+ else if(depFile.extension() == ".lib" || depFile.extension() == ".obj")
{
args.push_back(depFile.string());
}
}
append(args, config.flags.ldflags);
- append(args, getOption(tool_chain, opt::output, targetFile().string()));
+// append(args, getOption(tool_chain, opt::output, targetFile().string()));
+ args.push_back("/out:"+targetFile().string());
{ // Write flags to file.
std::ofstream flagsStream(flagsFile);
@@ -114,8 +115,9 @@ int TaskLD::runInner()
std::cout << "LD => " << targetFile().string() << "\n";
}
- auto tool = compiler();
- return execute(tool, args, settings.verbose > 0);
+ auto tool = linker();
+ const auto& cfg = configuration();
+ return execute(tool, args, cfg.env, settings.verbose > 0);
}
int TaskLD::clean()
@@ -177,7 +179,7 @@ std::string TaskLD::flagsString() const
}
flagsStr += flag;
}
- flagsStr += "\n";
+ //flagsStr += "\n"; break on win32
for(const auto& dep : config.depends)
{
diff --git a/src/task_so.cc b/src/task_so.cc
index 8c6dbd4..98057ea 100644
--- a/src/task_so.cc
+++ b/src/task_so.cc
@@ -106,7 +106,8 @@ int TaskSO::runInner()
}
auto tool = compiler();
- return execute(tool, args, settings.verbose > 0);
+ const auto& cfg = configuration();
+ return execute(tool, args, cfg.env, settings.verbose > 0);
}
int TaskSO::clean()
diff --git a/src/tasks.cc b/src/tasks.cc
index 68b2476..d621cd9 100644
--- a/src/tasks.cc
+++ b/src/tasks.cc
@@ -92,15 +92,16 @@ std::set<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
{
target_type = TargetType::Function;
}
- else if(targetFile.extension() == ".a")
+ else if(targetFile.extension() == ".lib")
{
target_type = TargetType::StaticLibrary;
}
- else if(targetFile.extension() == ".so")
+ else if(targetFile.extension() == ".dll")
{
target_type = TargetType::DynamicLibrary;
}
- else if(targetFile.extension() == "")
+ else if(targetFile.extension() == "" ||
+ targetFile.extension() == ".exe")
{
target_type = TargetType::Executable;
}
diff --git a/src/tasks.h b/src/tasks.h
index c547432..d7634b7 100644
--- a/src/tasks.h
+++ b/src/tasks.h
@@ -9,9 +9,9 @@
#include <deque>
#include "task.h"
-
-class BuildConfiguration;
-class Settings;
+#include "libctor.h"
+//class BuildConfiguration;
+//class Settings;
struct Target
{
diff --git a/src/tools.cc b/src/tools.cc
index 7e8ac78..cd00f89 100644
--- a/src/tools.cc
+++ b/src/tools.cc
@@ -8,6 +8,14 @@
#include <cassert>
+/*
+https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically?view=msvc-170
+/TC Specifies all source files are C.
+/Tc Specifies a C source file.
+/TP Specifies all source files are C++.
+/Tp Specifies a C++ source file.
+*/
+
ToolChain getToolChain(OutputSystem system)
{
std::string compiler;
@@ -33,6 +41,11 @@ ToolChain getToolChain(OutputSystem system)
{
return ToolChain::gcc;
}
+ else if(cc_cmd.find("cl") != std::string::npos ||
+ cc_cmd.find("CL") != std::string::npos)
+ {
+ return ToolChain::msvc;
+ }
std::cerr << "Unsupported output system.\n";
return ToolChain::gcc;
@@ -55,7 +68,7 @@ std::vector<std::string> getOptionGcc(opt option, const std::string& arg)
case opt::warnings_as_errors:
return {"-Werror"};
case opt::generate_dep_tree:
- return {"-MMD"};
+ return {"-MMD", "-MF" + arg};
case opt::no_link:
return {"-c"};
case opt::include_path:
@@ -83,6 +96,50 @@ std::vector<std::string> getOptionGcc(opt option, const std::string& arg)
std::cerr << "Unsupported compiler option.\n";
return {};
}
+
+std::vector<std::string> getOptionMsvc(opt option, const std::string& arg)
+{
+ switch(option)
+ {
+ case opt::output:
+ return {"/Fo\""+arg+"\""};
+ case opt::debug:
+ return {"/DEBUG"};
+ case opt::strip:
+ return {};//{"-s"}; TODO
+ case opt::warn_all:
+ return {"/Wall"};
+ case opt::warnings_as_errors:
+ return {"/WX"};
+ case opt::generate_dep_tree:
+ return {"/sourceDependencies", arg};
+ case opt::no_link:
+ return {"/c"};
+ case opt::include_path:
+ return {"/I" + arg};
+ case opt::library_path:
+ return {"/LIBPATH:" + arg};
+ case opt::link:
+ return {}; //{"-l" + arg}; TODO
+ case opt::cpp_std:
+ return {"/std:" + arg};
+ case opt::build_shared:
+ return {};//{"-shared"}; TODO
+ case opt::threads:
+ return {};// {"-pthread"}; TODO
+ case opt::optimization:
+ return {"/O" + arg}; // TODO: max 2
+ case opt::position_independent_code:
+ return {};//{"-fPIC"}; TODO
+ case opt::position_independent_executable:
+ return {};//{"-fPIE"}; TODO
+ case opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
}
std::vector<std::string> getOption(ToolChain tool_chain,
@@ -94,6 +151,8 @@ std::vector<std::string> getOption(ToolChain tool_chain,
case ToolChain::gcc:
case ToolChain::clang:
return getOptionGcc(option, arg);
+ case ToolChain::msvc:
+ return getOptionMsvc(option, arg);
}
std::cerr << "Unsupported tool-chain.\n";
@@ -129,6 +188,8 @@ std::pair<opt, std::string> getOption(const std::string& flag,
case ToolChain::gcc:
case ToolChain::clang:
return getOptionGcc(flag);
+ case ToolChain::msvc:
+ break; // TODO
}
std::cerr << "Unsupported tool-chain.\n";
diff --git a/src/tools.h b/src/tools.h
index 39118d2..37282e1 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -12,6 +12,7 @@ enum class ToolChain
{
gcc,
clang,
+ msvc,
};
enum class opt
diff --git a/src/unittest.cc b/src/unittest.cc
index f18de47..5524ea5 100644
--- a/src/unittest.cc
+++ b/src/unittest.cc
@@ -7,6 +7,7 @@
#include "execute.h"
#include "task.h"
+#include "libctor.h"
int runUnitTests(std::set<std::shared_ptr<Task>>& tasks,
const Settings& settings)
@@ -24,7 +25,7 @@ int runUnitTests(std::set<std::shared_ptr<Task>>& tasks,
name = task->target();
}
std::cout << name << ": " << std::flush;
- auto ret = execute(task->targetFile(), {}, settings.verbose > 0);
+ auto ret = execute(task->targetFile().string(), {}, {}, settings.verbose > 0);
ok &= ret == 0;
if(ret == 0)
{
diff --git a/src/unittest.h b/src/unittest.h
index 8dee33c..5118689 100644
--- a/src/unittest.h
+++ b/src/unittest.h
@@ -7,7 +7,7 @@
#include <memory>
class Task;
-class Settings;
+struct Settings;
int runUnitTests(std::set<std::shared_ptr<Task>>& tasks,
const Settings& settings);
diff --git a/src/util.cc b/src/util.cc
index 92560b6..7aedad1 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -22,6 +22,7 @@ std::string readFile(const std::string& fileName)
std::vector<std::string> readDeps(const std::string& depFile)
{
+ return {};// TODO: parse json
if(!std::filesystem::exists(depFile))
{
return {};