diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bootstrap.cc | 22 | ||||
-rw-r--r-- | src/configure.cc | 215 | ||||
-rw-r--r-- | src/execute.cc | 133 | ||||
-rw-r--r-- | src/execute.h | 2 | ||||
-rw-r--r-- | src/libctor.cc | 9 | ||||
-rw-r--r-- | src/libctor.h | 1 | ||||
-rw-r--r-- | src/rebuild.cc | 149 | ||||
-rw-r--r-- | src/rebuild.h | 3 | ||||
-rw-r--r-- | src/task.cc | 23 | ||||
-rw-r--r-- | src/task.h | 1 | ||||
-rw-r--r-- | src/task_ar.cc | 12 | ||||
-rw-r--r-- | src/task_cc.cc | 31 | ||||
-rw-r--r-- | src/task_fn.cc | 2 | ||||
-rw-r--r-- | src/task_ld.cc | 12 | ||||
-rw-r--r-- | src/task_so.cc | 3 | ||||
-rw-r--r-- | src/tasks.cc | 7 | ||||
-rw-r--r-- | src/tasks.h | 6 | ||||
-rw-r--r-- | src/tools.cc | 63 | ||||
-rw-r--r-- | src/tools.h | 1 | ||||
-rw-r--r-- | src/unittest.cc | 3 | ||||
-rw-r--r-- | src/unittest.h | 2 | ||||
-rw-r--r-- | src/util.cc | 1 |
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() @@ -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 {}; |