diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bootstrap.cc | 2 | ||||
| -rw-r--r-- | src/configure.cc | 108 | ||||
| -rw-r--r-- | src/ctor.h | 13 | ||||
| -rw-r--r-- | src/deps.cc | 74 | ||||
| -rw-r--r-- | src/execute.cc | 227 | ||||
| -rw-r--r-- | src/libctor.cc | 3 | ||||
| -rw-r--r-- | src/rebuild.cc | 15 | ||||
| -rw-r--r-- | src/task.cc | 9 | ||||
| -rw-r--r-- | src/task_ar.cc | 3 | ||||
| -rw-r--r-- | src/task_cc.cc | 2 | ||||
| -rw-r--r-- | src/task_ld.cc | 23 | ||||
| -rw-r--r-- | src/task_so.cc | 3 | ||||
| -rw-r--r-- | src/tools.cc | 409 | ||||
| -rw-r--r-- | src/util.cc | 51 | 
14 files changed, 897 insertions, 45 deletions
diff --git a/src/bootstrap.cc b/src/bootstrap.cc index aa50561..9d895ba 100644 --- a/src/bootstrap.cc +++ b/src/bootstrap.cc @@ -41,7 +41,7 @@ bool ctor::configuration::has(const std::string& key) const  	return false;  } -const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const +std::string ctor::configuration::get(const std::string& key, const std::string& default_value) const  {  	auto cxx_env = std::getenv("CXX");  	if(key == ctor::cfg::build_cxx && cxx_env) diff --git a/src/configure.cc b/src/configure.cc index 995e340..d2c1053 100644 --- a/src/configure.cc +++ b/src/configure.cc @@ -8,6 +8,8 @@  #include <fstream>  #include <optional>  #include <span> +#include <vector> +#include <deque>  #include <getoptpp/getoptpp.hpp> @@ -25,17 +27,49 @@ const std::filesystem::path configHeaderFile("config.h");  std::map<std::string, std::string> external_includedir;  std::map<std::string, std::string> external_libdir; +#if !defined(_WIN32)  const ctor::configuration& __attribute__((weak)) ctor::get_configuration() +#else +const ctor::configuration& default_get_configuration() +#endif  {  	static ctor::configuration cfg;  	static bool initialised{false};  	if(!initialised)  	{ -		cfg.build_toolchain = getToolChain(cfg.get(ctor::cfg::build_cxx, "/usr/bin/g++")); +		std::string cxx_prog{"g++"}; +		auto cxx_env = getenv("CXX"); +		if(cxx_env) +		{ +			cxx_prog = cxx_env; +		} + +		cfg.build_toolchain = getToolChain(cfg.get(ctor::cfg::build_cxx, cxx_prog));  		initialised = true;  	}  	return cfg;  } +#if defined(_WIN32) +// Hack to make ctor::get_configuration "weak" linked +// See: +//   https://stackoverflow.com/questions/2290587/gcc-style-weak-linking-in-visual-studio +// and +//   https://stackoverflow.com/questions/11849853/how-to-list-functions-present-in-object-file +#pragma comment(linker, "/alternatename:?get_configuration@ctor@@YAABUconfiguration@1@XZ=?default_get_configuration@@YAABUconfiguration@ctor@@XZ") + +/* + +?get_configuration@ctor@@YAABUconfiguration@1@XZ +??__Fcfg@?1??get_configuration@ctor@@YAABUconfiguration@1@XZ@YAXXZ + += + +?default_get_configuration@@YAABUconfiguration@ctor@@XZ +??__Fcfg@?1??default_get_configuration@@YAABUconfiguration@ctor@@XZ@YAXXZ + +*/ +//#pragma comment(linker, "/alternatename:??__Fcfg@?1??get_configuration@ctor@@YAABUconfiguration@1@XZ@YAXXZ=??__Fcfg@?1??default_get_configuration@@YAABUconfiguration@ctor@@XZ@YAXXZ") +#endif  namespace ctor {  std::optional<std::string> includedir; @@ -69,7 +103,7 @@ bool ctor::configuration::has(const std::string& key) const  	return tools.find(key) != tools.end();  } -const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const +std::string ctor::configuration::get(const std::string& key, const std::string& default_value) const  {  	if(key == ctor::cfg::ctor_includedir && ctor::includedir)  	{ @@ -91,11 +125,47 @@ const std::string& ctor::configuration::get(const std::string& key, const std::s  		return ctor::conf_values[key];  	} -	if(has(key)) +	if(tools.find(key) != tools.end())  	{  		return tools.at(key);  	} +	if(key == ctor::cfg::build_cxx) +	{ +		auto e = std::getenv("CXX"); +		if(e) +		{ +			return e; +		} +	} + +	if(key == ctor::cfg::build_cc) +	{ +		auto e = std::getenv("CC"); +		if(e) +		{ +			return e; +		} +	} + +	if(key == ctor::cfg::build_ld) +	{ +		auto e = std::getenv("LD"); +		if(e) +		{ +			return e; +		} +	} + +	if(key == ctor::cfg::build_ar) +	{ +		auto e = std::getenv("AR"); +		if(e) +		{ +			return e; +		} +	} +  	return default_value;  } @@ -136,6 +206,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)  	case ctor::toolchain::gcc:  		stream << "ctor::toolchain::gcc";  		break; +	case ctor::toolchain::msvc: +		stream << "ctor::toolchain::msvc"; +		break;  	case ctor::toolchain::clang:  		stream << "ctor::toolchain::clang";  		break; @@ -358,13 +431,12 @@ int regenerateCache(ctor::settings& settings,  	opt.add("help", no_argument, 'h',  	        "Print this help text.", -	        [&]() { +	        [&]() -> int {  		        std::cout << "Configure how to build with " << name << "\n";  		        std::cout << "Usage: " << name << " configure [options]\n\n";  		        std::cout << "Options:\n";  		        opt.help();  		        exit(0); -		        return 0;  	        });  	opt.process(static_cast<int>(vargs.size()), vargs.data()); @@ -651,6 +723,7 @@ int regenerateCache(ctor::settings& settings,  	{  		ctor::conf_values[ctor::cfg::builddir] = builddir;  	} +  	ctor::conf_values[ctor::cfg::host_cxx] = host_cxx;  	ctor::conf_values[ctor::cfg::build_cxx] = build_cxx; @@ -863,6 +936,31 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[])  		env["PATH"] = path_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 include_env = getenv("INCLUDE"); +	if(include_env) +	{ +		env["INCLUDE"] = include_env; +	} +  	auto ret = regenerateCache(settings, args_span[0], args, env);  	if(ret != 0)  	{ @@ -59,6 +59,7 @@ enum class toolchain  	none,  	gcc,  	clang, +	msvc,  };  struct source @@ -90,6 +91,9 @@ enum class cxx_opt  	output,                          //  -o  	debug,                           //  -g  	warn_all,                        //  -Wall +	warn_conversion,                 //  -Wconversion +	warn_shadow,                     //  -Wshadow +	warn_extra,                      //  -Wextra  	warnings_as_errors,              //  -Werror  	generate_dep_tree,               //  -MMD  	no_link,                         //  -c @@ -108,6 +112,9 @@ enum class c_opt  	output,                          //  -o  	debug,                           //  -g  	warn_all,                        //  -Wall +	warn_conversion,                 //  -Wconversion +	warn_shadow,                     //  -Wshadow +	warn_extra,                      //  -Wextra  	warnings_as_errors,              //  -Werror  	generate_dep_tree,               //  -MMD  	no_link,                         //  -c @@ -261,12 +268,12 @@ namespace cfg  constexpr auto builddir = "builddir";  constexpr auto host_cc = "host-cc"; -constexpr auto host_cxx = "host-cpp"; +constexpr auto host_cxx = "host-cxx";  constexpr auto host_ar = "host-ar";  constexpr auto host_ld = "host-ld";  constexpr auto build_cc = "build-cc"; -constexpr auto build_cxx = "build-cpp"; +constexpr auto build_cxx = "build-cxx";  constexpr auto build_ar = "build-ar";  constexpr auto build_ld = "build-ld"; @@ -277,7 +284,7 @@ constexpr auto ctor_libdir = "ctor-libdir";  struct configuration  {  	bool has(const std::string& key) const; -	const std::string& get(const std::string& key, const std::string& default_value = {}) const; +	std::string get(const std::string& key, const std::string& default_value = {}) const;  	ctor::toolchain host_toolchain{ctor::toolchain::none};  	ctor::arch host_arch{ctor::arch::unknown}; diff --git a/src/deps.cc b/src/deps.cc index 9400b35..599be8c 100644 --- a/src/deps.cc +++ b/src/deps.cc @@ -5,6 +5,8 @@  #include "util.h" +#include <nlohmann/json.hpp> +  #include <fstream>  namespace { @@ -94,6 +96,74 @@ std::vector<std::string> readDepsMake(const std::string& dep_file)  	return output;  } + +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html +// https://devblogs.microsoft.com/cppblog/introducing-source-dependency-reporting-with-msvc-in-visual-studio-2019-version-16-7/ +/* Format examples: +{ +    "Version": "1.1", +    "Data": { +        "Source": "z:\\home\\deva\\docs\\c\\ctor\\src\\libctor.cc", +        "ProvidedModule": "", +        "Includes": [ +            "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\vector", +            "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\yvals_core.h", +            "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\vcruntime.h", +. +. +. +            "z:\\home\\deva\\docs\\c\\ctor\\src\\unittest.h" +        ], +        "ImportedModules": [], +        "ImportedHeaderUnits": [] +    } +} +*/ +/* +{ +    "Version": "1.2", +    "Data": { +        "Source": "c:\\jenkins\\workspace\\ctor-linux64\\src\\build.cc", +        "ProvidedModule": "", +        "Includes": [ +            "c:\\jenkins\\workspace\\ctor-linux64\\src\\build.h", +            "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\string", +            "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\yvals_core.h", +. +. +. +            "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\iostream" +        ], +        "ImportedModules": [], +        "ImportedHeaderUnits": [] +    } +} +*/ + +std::vector<std::string> readDepsJson(const std::string& dep_file) +{ +	std::ifstream stream(dep_file); +	auto json = nlohmann::json::parse(stream); +	for(const auto& [key, value] : json.items()) +	{ +		if(key == "Data" && value.is_object()) +		{ +			for(const auto& [inner_key, inner_value] : value.items()) +			{ +				if(inner_key == "Includes" && inner_value.is_array()) +				{ +					std::vector<std::string> deps; +					for(const auto& dep : inner_value) +					{ +						deps.emplace_back(dep); +					} +					return deps; +				} +			} +		} +	} +	return {}; +}  }  std::vector<std::string> readDeps(const std::string& dep_file, @@ -110,6 +180,10 @@ std::vector<std::string> readDeps(const std::string& dep_file,  	case ctor::toolchain::none:  		return {}; +	// json based: +	case ctor::toolchain::msvc: +		return readDepsJson(dep_file); +  	// makefile .d file based:  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang: diff --git a/src/execute.cc b/src/execute.cc index cbae899..58e0051 100644 --- a/src/execute.cc +++ b/src/execute.cc @@ -5,12 +5,22 @@  #include "ctor.h" -#include <unistd.h> -#include <cstring> -#include <sys/types.h> -#include <sys/wait.h> -#include <spawn.h> +#if !defined(_WIN32) +	#include <unistd.h> +	#include <sys/types.h> +	#include <sys/wait.h> +	#include <spawn.h> +#else +	#define WINDOWS_LEAN_AND_MEAN +	#include <windows.h> +	#undef max +#endif +  #include <iostream> +#include <cstring> +#include <vector> +#include <deque> +#include <filesystem>  /*  https://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/ @@ -30,7 +40,11 @@ public:  	{  		for(const auto& arg : args)  		{ +#if !defined(_WIN32)  			push_back(strdup(arg.data())); +#else +			push_back(_strdup(arg.data())); +#endif  		}  		push_back(nullptr);  	} @@ -44,6 +58,7 @@ public:  	}  }; +#if !defined(_WIN32)  int parent_waitpid(pid_t pid)  {  	int status{}; @@ -55,9 +70,44 @@ int parent_waitpid(pid_t pid)  	return WEXITSTATUS(status);  } +#endif //_WIN32  } // namespace :: +#if !defined(_WIN32)  extern char **environ; // see 'man environ' +#endif + +#if defined(_WIN32) +//Returns the last Win32 error, in string format. Returns an empty string if there is no error. +std::string GetLastErrorAsString() +{ +	//Get the error message ID, if any. +	DWORD errorMessageID = ::GetLastError(); +	if(errorMessageID == 0) +	{ +		return std::string(); //No error message has been recorded +	} + +	LPSTR messageBuffer = nullptr; + +	//Ask Win32 to give us the string version of that message ID. +	//The parameters we pass in, tell Win32 to create the buffer that holds the message for us +	// (because we don't yet know how long the message string will be). +	size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | +	                             FORMAT_MESSAGE_FROM_SYSTEM | +	                             FORMAT_MESSAGE_IGNORE_INSERTS, +	                             NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), +	                             (LPSTR)&messageBuffer, 0, NULL); + +	//Copy the error message into a std::string. +	std::string message(messageBuffer, size); + +	//Free the Win32's string's buffer. +	LocalFree(messageBuffer); + +	return message; +} +#endif // _WIN32  int execute(const ctor::settings& settings,              const std::string& command, @@ -92,6 +142,8 @@ int execute(const ctor::settings& settings,  		std::cout << cmd << std::endl;  	} +#if !defined(_WIN32) +  #if 1  	auto pid = vfork();  	if(pid == 0) @@ -133,5 +185,170 @@ int execute(const ctor::settings& settings,  	return system(cmd.data());  #endif +#else // _WIN32 +	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'; + +//	std::cout <<"#### Length of new env: " << env_str.size() << "\n"; + +	STARTUPINFO si{}; +//	si.hStdInput = GetStdHandle(((DWORD)-10)/*STD_INPUT_HANDLE*/); +//	si.hStdOutput = GetStdHandle(((DWORD)-11)/*STD_OUTPUT_HANDLE*/); +//	si.hStdError = GetStdHandle(((DWORD)-12)/*STD_ERROR_HANDLE*/); +//	si.dwFlags = /*STARTF_USESTDHANDLES*/0x00000100; + +	PROCESS_INFORMATION pi{}; + +	si.cb = sizeof(si); + +	// TODO: Use SetDllDirectory(...) to set DLL search directory + +	if(terminate) +	{ +		char tmpdir[MAX_PATH+1]; +		int cnt{0}; + +		// The returned string ends with a backslash +		if(GetTempPathA(sizeof(tmpdir), tmpdir) == 0) +		{ +			std::cerr << "Could not read TMP folder\n"; +			return GetLastError(); +		} + +		char source[MAX_PATH]; +		HMODULE module = GetModuleHandle(0); +		GetModuleFileNameA(module, source, MAX_PATH); + +		while(true) +		{ +			if(cnt > 10) // If we need to try more than 10 times something is wrong +			{ +				return 1; +			} + +			std::filesystem::path tmp_file = settings.builddir; +			tmp_file /= "tmp"; +			std::string target = tmp_file.string() + "-" + std::to_string(cnt); +			std::cout << "move " << source << " => " << target <<std::endl; +			if(MoveFileA(source, target.data())) +			{ +				break; // success +			} + +			auto err = GetLastError(); +			if(err == ERROR_ALREADY_EXISTS) +			{ +				if(DeleteFileA(target.data())) +				{ +					continue; // Try again +				} + +				err = GetLastError(); +				if(err != ERROR_ACCESS_DENIED) +				{ +					std::cerr << "Could not delete file\n"; +					return err; +				} + +				cnt++; +				continue; // Increment and try again +			} +			else +			{ +				std::cerr << "Could not move file\n"; +				return err; +			} +		} +	} + +	if(!CreateProcess(nullptr,           // lpApplicationName +	                  (char*)cmd.data(), // lpCommandLine +	                  nullptr,           // lpProcessAttributes +	                  nullptr,           // lpThreadAttributes +	                  TRUE,              // bInheritHandles +	                  INHERIT_PARENT_AFFINITY | +	                  //DETACHED_PROCESS | +	                  ///*DEBUG_PROCESS*/ 0x00000001 | +	                  ///*CREATE_NO_WINDOW*/ 0x08000000 | +	                  ///*CREATE_BREAKAWAY_FROM_JOB*/ 0x01000000 | +	                  /*CREATE_NEW_PROCESS_GROUP*/ 0x00000200 | +	                  0,                 // dwCreationFlags +	                  env_str.data(),    // lpEnvironment +	                  nullptr,           // lpCurrentDirectory +	                  &si,               // lpStartupInfo +	                  &pi))              // lpProcessInformation +	{ +		std::cout << "Could not execute " << command << ": " << +			GetLastErrorAsString() << "\n"; +		return 1;//_exit(1); // execve only returns if an error occurred +	} + +	// 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 // _WIN32 +  	return 1;  } diff --git a/src/libctor.cc b/src/libctor.cc index b1fbaea..aaf17c9 100644 --- a/src/libctor.cc +++ b/src/libctor.cc @@ -159,7 +159,7 @@ int main(int argc, char* argv[])  	opt.add("help", no_argument, 'h',  	        "Print this help text.", -	        [&]() { +	        [&]() -> int {  		        std::cout << "Usage: " << args[0] << " [options] [target] ...\n";  		        std::cout <<  R"_( where target can be either: @@ -174,7 +174,6 @@ Options:  )_";  		        opt.help();  		        exit(0); -		        return 0;  	        });  	opt.process(argc, argv); diff --git a/src/rebuild.cc b/src/rebuild.cc index 4ca1809..865a45b 100644 --- a/src/rebuild.cc +++ b/src/rebuild.cc @@ -38,7 +38,10 @@ int reg(ctor::build_configurations (*cb)(const ctor::settings&),  	{  		auto pwd = std::filesystem::current_path();  		auto rel = std::filesystem::relative(loc, pwd); -		configFiles[numConfigFiles].file = strdup(rel.string().data()); // NOTE: This intentionally leaks memory +		auto str = rel.string(); +		auto file = new char[str.size() + 1]; +		strncpy(file, str.data(), str.size() + 1); +		configFiles[numConfigFiles].file = file; // NOTE: This intentionally leaks memory  	}  	else  	{ @@ -71,7 +74,7 @@ int reg(const char* location)  int unreg(const char* location)  { -	std::size_t found{0}; +	int found{0};  	for(std::size_t i = 0; i < numConfigFiles;)  	{  		if(std::string(location) == configFiles[i].file) @@ -169,6 +172,8 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[  	config.flags.cxxflags.emplace_back(ctor::cxx_opt::optimization, "3");  	config.flags.cxxflags.emplace_back(ctor::cxx_opt::cpp_std, "c++20"); +	config.flags.cxxflags.push_back({ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"}); +  	const auto& c = ctor::get_configuration();  	if(c.has(ctor::cfg::ctor_includedir))  	{ @@ -180,10 +185,14 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[  		config.flags.ldflags.emplace_back(ctor::ld_opt::library_path,  		                                  c.get(ctor::cfg::ctor_libdir));  	} -	config.flags.ldflags.emplace_back(ctor::ld_opt::link, "ctor"); +	config.flags.ldflags.emplace_back(ctor::toolchain::msvc, ctor::ld_opt::link, "libctor.lib"); +	config.flags.ldflags.emplace_back(ctor::toolchain::gcc, ctor::ld_opt::link, "ctor"); +	config.flags.ldflags.emplace_back(ctor::toolchain::clang, ctor::ld_opt::link, "ctor");  	config.flags.ldflags.emplace_back(ctor::ld_opt::strip);  	config.flags.ldflags.emplace_back(ctor::ld_opt::threads); +	config.flags.ldflags.push_back({ctor::toolchain::msvc, ctor::ld_opt::custom, "/subsystem:console"}); +  	ctor::settings settings{global_settings};  	settings.verbose = -1; // Make check completely silent. diff --git a/src/task.cc b/src/task.cc index cd03fce..ef7731b 100644 --- a/src/task.cc +++ b/src/task.cc @@ -48,10 +48,11 @@ bool Task::operator==(const std::string& depStr)  	std::filesystem::path generated_output = sourceDir;  	generated_output /= target();  	return -		name() == depStr || -		target() == depStr || -		generated_output  == depStr || -		targetFile().string() == depStr +		(!derived() && name() == depStr) || // compare to name +		(!derived() && config.target == depStr) || // compare to stated target (ex. foo.a) +		target() == depStr || // compare to derived (derived to foo.lib on msvc) +		generated_output  == depStr || // not sure what this is for?! +		targetFile().string() == depStr // compare to target output file  		;  } diff --git a/src/task_ar.cc b/src/task_ar.cc index 09403bb..25ab7c0 100644 --- a/src/task_ar.cc +++ b/src/task_ar.cc @@ -93,6 +93,8 @@ int TaskAR::runInner()  	append(args, ar_option(toolchain, ctor::ar_opt::add_index));  	append(args, ar_option(toolchain, ctor::ar_opt::create));  	append(args, ar_option(toolchain, ctor::ar_opt::output, targetFile().string())); +	append(args, to_strings(toolchain, {ctor::toolchain::msvc, ctor::ar_opt::custom, "/nologo"})); +  	for(const auto& task : getDependsTasks())  	{  		args.push_back(task->targetFile().string()); @@ -189,7 +191,6 @@ std::string TaskAR::flagsString() const  			flagsStr += str;  		}  	} -	flagsStr += "\n";  	for(const auto& dep : config.depends)  	{ diff --git a/src/task_cc.cc b/src/task_cc.cc index 9de2657..2e15555 100644 --- a/src/task_cc.cc +++ b/src/task_cc.cc @@ -278,12 +278,14 @@ std::vector<std::string> TaskCC::flags() const  		{  			append(flags, to_strings(toolchain, flag));  		} +		append(flags, to_strings(toolchain, {ctor::toolchain::msvc, ctor::c_opt::custom, "/nologo"}));  		return flags;  	case ctor::language::cpp:  		for(const auto& flag : config.flags.cxxflags)  		{  			append(flags, to_strings(toolchain, flag));  		} +		append(flags, to_strings(toolchain, {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/nologo"}));  		return flags;  	default:  		std::cerr << "Unknown CC target type\n"; diff --git a/src/task_ld.cc b/src/task_ld.cc index 31ee8c0..9dcbb3a 100644 --- a/src/task_ld.cc +++ b/src/task_ld.cc @@ -115,6 +115,7 @@ int TaskLD::runInner()  	}  	append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string())); +	append(args, to_strings(toolchain, {ctor::toolchain::msvc, ctor::ld_opt::custom, "/nologo"}));  	{ // Write flags to file.  		std::ofstream flagsStream(flagsFile); @@ -127,8 +128,27 @@ int TaskLD::runInner()  		std::cout << output << std::flush;  	} -	auto tool = compiler(); +	std::string tool;  	const auto& c = ctor::get_configuration(); + +	if(toolchain == ctor::toolchain::gcc || +	   toolchain == ctor::toolchain::clang) +	{ +		tool = compiler(); +	} +	else // msvc +	{ +		switch(outputSystem()) +		{ +		case ctor::output_system::host: +			tool = c.get(ctor::cfg::host_ld, "/usr/bin/ld"); +			break; +		case ctor::output_system::build: +			tool = c.get(ctor::cfg::build_ld, "/usr/bin/ld"); +			break; +		} +	} +  	return execute(settings, tool, args, c.env, is_self);  } @@ -197,7 +217,6 @@ std::string TaskLD::flagsString() const  			flagsStr += str;  		}  	} -	flagsStr += "\n";  	for(const auto& dep : config.depends)  	{ diff --git a/src/task_so.cc b/src/task_so.cc index eecd7aa..f61fa17 100644 --- a/src/task_so.cc +++ b/src/task_so.cc @@ -93,6 +93,8 @@ int TaskSO::runInner()  	append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string())); +	append(args, to_strings(toolchain, {ctor::toolchain::msvc, ctor::ld_opt::custom, "/nologo"})); +  	for(const auto& task : getDependsTasks())  	{  		args.push_back(task->targetFile().string()); @@ -184,7 +186,6 @@ std::string TaskSO::flagsString() const  			flagsStr += str;  		}  	} -	flagsStr += "\n";  	for(const auto& dep : config.depends)  	{ diff --git a/src/tools.cc b/src/tools.cc index eb98265..7f16a0e 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -6,6 +6,7 @@  #include <filesystem>  #include <iostream>  #include <sstream> +#include <algorithm>  #include <cassert>  #include <cstdio> @@ -20,6 +21,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt)  	case ctor::c_opt::output: stream << "ctor::c_opt::output"; break;  	case ctor::c_opt::debug: stream << "ctor::c_opt::debug"; break;  	case ctor::c_opt::warn_all: stream << "ctor::c_opt::warn_all"; break; +	case ctor::c_opt::warn_conversion: stream << "ctor::c_opt::warn_conversion"; break; +	case ctor::c_opt::warn_shadow: stream << "ctor::c_opt::warn_shadow"; break; +	case ctor::c_opt::warn_extra: stream << "ctor::c_opt::warn_extra"; break;  	case ctor::c_opt::warnings_as_errors: stream << "ctor::c_opt::warnings_as_errors"; break;  	case ctor::c_opt::generate_dep_tree: stream << "ctor::c_opt::generate_dep_tree"; break;  	case ctor::c_opt::no_link: stream << "ctor::c_opt::no_link"; break; @@ -43,6 +47,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::cxx_opt& opt)  	case ctor::cxx_opt::output: stream << "ctor::cxx_opt::output"; break;  	case ctor::cxx_opt::debug: stream << "ctor::cxx_opt::debug"; break;  	case ctor::cxx_opt::warn_all: stream << "ctor::cxx_opt::warn_all"; break; +	case ctor::cxx_opt::warn_conversion: stream << "ctor::cxx_opt::warn_conversion"; break; +	case ctor::cxx_opt::warn_shadow: stream << "ctor::cxx_opt::warn_shadow"; break; +	case ctor::cxx_opt::warn_extra: stream << "ctor::cxx_opt::warn_extra"; break;  	case ctor::cxx_opt::warnings_as_errors: stream << "ctor::cxx_opt::warnings_as_errors"; break;  	case ctor::cxx_opt::generate_dep_tree: stream << "ctor::cxx_opt::generate_dep_tree"; break;  	case ctor::cxx_opt::no_link: stream << "ctor::cxx_opt::no_link"; break; @@ -111,18 +118,27 @@ ctor::toolchain getToolChain(const std::string& compiler)  	std::filesystem::path cc(compiler);  	auto cc_cmd = cc.stem().string(); +	std::cout << "getToolChain: [" << cc_cmd << "] => "; +  	// Note: "g++" is a substring of "clang++" so "clang++" must be tested first.  	if(cc_cmd.find("clang++") != std::string::npos ||  	   cc_cmd.find("clang") != std::string::npos)  	{ +		std::cout << "clang" << std::endl;  		return ctor::toolchain::clang;  	}  	else if(cc_cmd.find("g++") != std::string::npos ||  	        cc_cmd.find("gcc") != std::string::npos ||  	        cc_cmd.find("mingw") != std::string::npos)  	{ +		std::cout << "gcc" << std::endl;  		return ctor::toolchain::gcc;  	} +	else if(to_lower(cc_cmd).find("cl") != std::string::npos) +	{ +		std::cout << "msvc" << std::endl; +		return ctor::toolchain::msvc; +	}  	std::cerr << "Unsupported output system.\n";  	return ctor::toolchain::gcc; @@ -148,12 +164,262 @@ ctor::toolchain getToolChain(ctor::output_system system)  		return getToolChain(cfg.get(ctor::cfg::build_cxx, "g++"));  	}  } +namespace msvc { +std::string get_arch([[maybe_unused]] ctor::output_system system) +{ +	std::string arch; +	// TODO +	return arch; +} + +ctor::arch get_arch([[maybe_unused]] const std::string& str) +{ +	return ctor::arch::windows; +} + +ctor::c_flag c_option(const std::string& flag) +{ +	if(flag.starts_with("/I")) +	{ +		std::string path = flag.substr(2); +		path.erase(0, path.find_first_not_of(' ')); +		return { ctor::c_opt::include_path, path }; +	} + +	return { ctor::c_opt::custom, flag }; +} + +ctor::cxx_flag cxx_option(const std::string& flag) +{ +	if(flag.starts_with("/I")) +	{ +		std::string path = flag.substr(2); +		path.erase(0, path.find_first_not_of(' ')); +		return { ctor::cxx_opt::include_path, path }; +	} + +	return { ctor::cxx_opt::custom, flag }; +} + +ctor::ld_flag ld_option(const std::string& flag) +{ +	if(flag.starts_with("/L")) +	{ +		std::string path = flag.substr(2); +		path.erase(0, path.find_first_not_of(' ')); +		return { ctor::ld_opt::library_path, path }; +	} + +	return { ctor::ld_opt::custom, flag }; +} + +ctor::ar_flag ar_option(const std::string& flag) +{ +	return { ctor::ar_opt::custom, flag }; +} + +std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg, +                                    const std::string& arg2) +{ +	switch(opt) +	{ +	case ctor::cxx_opt::output: +		return {"/Fo\"" + arg + "\""}; +	case ctor::cxx_opt::debug: +		return {"/DEBUG"}; +	case ctor::cxx_opt::warn_all: +		return {"/W4"}; +	case ctor::cxx_opt::warn_conversion: +		return {"/W4"}; // TODO: This is incorrect +	case ctor::cxx_opt::warn_shadow: +		return {"/W4"}; // TODO: This is incorrect +	case ctor::cxx_opt::warn_extra: +		return {"/W4"}; // TODO: This is incorrect +	case ctor::cxx_opt::warnings_as_errors: +		return {"/WX"}; +	case ctor::cxx_opt::generate_dep_tree: +		return {"/sourceDependencies", arg}; +	case ctor::cxx_opt::no_link: +		return {"/c"}; +	case ctor::cxx_opt::include_path: +		return {"/I" + arg}; +	case ctor::cxx_opt::cpp_std: +		return {"/std:" + arg}; +	case ctor::cxx_opt::optimization: +		{ +			int o{0}; +			try +			{ +				o = std::stoi(arg); +				o = std::clamp(o, 0, 2); +			} +			catch(...) +			{ +				// bad number? +			} +			return {"/O" + std::to_string(o)}; +		} +	case ctor::cxx_opt::position_independent_code: +		return {}; // TODO? +	case ctor::cxx_opt::position_independent_executable: +		return {}; // TODO? +	case ctor::cxx_opt::define: +		if(!arg2.empty()) +		{ +			return {"/D" + arg + "=" + esc(arg2)}; +		} +		else +		{ +			return {"/D" + arg}; +		} +	case ctor::cxx_opt::custom: +		return {arg}; +	} + +	std::cerr << "Unsupported compiler option.\n"; +	return {}; +} + +std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg, +                                  const std::string& arg2) +{ +	switch(opt) +	{ +	case ctor::c_opt::output: +		return {"/Fo\"" + arg + "\""}; +	case ctor::c_opt::debug: +		return {"/DEBUG"}; +	case ctor::c_opt::warn_all: +		return {"/W4"}; +	case ctor::c_opt::warn_conversion: +		return {"/W4"}; // TODO: This is incorrect +	case ctor::c_opt::warn_shadow: +		return {"/W4"}; // TODO: This is incorrect +	case ctor::c_opt::warn_extra: +		return {"/W4"}; // TODO: This is incorrect +	case ctor::c_opt::warnings_as_errors: +		return {"/WX"}; +	case ctor::c_opt::generate_dep_tree: +		return {"/sourceDependencies", arg}; +	case ctor::c_opt::no_link: +		return {"/c"}; +	case ctor::c_opt::include_path: +		return {"/I" + arg}; +	case ctor::c_opt::c_std: +		return {"/std:" + arg}; +	case ctor::c_opt::optimization: +		{ +			int o{0}; +			try +			{ +				o = std::stoi(arg); +				o = std::clamp(o, 0, 2); +			} +			catch(...) +			{ +				// bad number? +			} +			return {"/O" + std::to_string(o)}; +		} +	case ctor::c_opt::position_independent_code: +		return {}; // TODO? +	case ctor::c_opt::position_independent_executable: +		return {}; // TODO? +	case ctor::c_opt::define: +		if(!arg2.empty()) +		{ +			return {"/D" + arg + "=" + esc(arg2)}; +		} +		else +		{ +			return {"/D" + arg}; +		} +	case ctor::c_opt::custom: +		return {arg}; +	} + +	std::cerr << "Unsupported compiler option.\n"; +	return {}; +} + +std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg, +                                   [[maybe_unused]]const std::string& arg2) +{ +	switch(opt) +	{ +	case ctor::ld_opt::output: +		return {"/out:" + arg + ""}; +	case ctor::ld_opt::strip: +		return {}; // TODO? +	case ctor::ld_opt::warn_all: +		return {"/Wall"}; +	case ctor::ld_opt::warnings_as_errors: +		return {"/WX"}; +	case ctor::ld_opt::library_path: +		return {"/LIBPATH:\""+arg+"\""}; +	case ctor::ld_opt::link: +		return {arg}; // TODO? +	case ctor::ld_opt::cpp_std: +		return {"/std:" + arg}; +	case ctor::ld_opt::build_shared: +		return {}; // TODO? +	case ctor::ld_opt::threads: +		return {}; // TODO? +	case ctor::ld_opt::position_independent_code: +		return {}; // TODO? +	case ctor::ld_opt::position_independent_executable: +		return {}; // TODO? +	case ctor::ld_opt::custom: +		return {arg}; +	} + +	std::cerr << "Unsupported compiler option.\n"; +	return {}; +} + +std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg, +                                   [[maybe_unused]]const std::string& arg2) +{ +	switch(opt) +	{ +	case ctor::ar_opt::replace: +		return {}; +	case ctor::ar_opt::add_index: +		return {}; +	case ctor::ar_opt::create: +		return {}; +	case ctor::ar_opt::output: +		return {"/out:" + arg}; +	case ctor::ar_opt::custom: +		return {arg}; +	} + +	std::cerr << "Unsupported compiler option.\n"; +	return {}; +} + +std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg, +                                    [[maybe_unused]]const std::string& arg2) +{ +	switch(opt) +	{ +	case ctor::asm_opt::custom: +		return {arg}; +	} + +	std::cerr << "Unsupported compiler option.\n"; +	return {}; +} +} // msvc:: +  namespace gcc { -std::string get_arch(ctor::output_system system) +std::string get_arch([[maybe_unused]] ctor::output_system system)  { +	std::string arch; +	// TODO popen on windows +#if !defined(_WIN32)  	std::string cmd; -  	const auto& c = ctor::get_configuration();  	switch(system)  	{ @@ -174,7 +440,6 @@ std::string get_arch(ctor::output_system system)  		return {};//ctor::arch::unknown;  	} -	std::string arch;  	while(!feof(pipe))  	{  		constexpr auto buffer_size{1024}; @@ -200,6 +465,7 @@ std::string get_arch(ctor::output_system system)  	// Remove 'Target: ' prefix  	constexpr auto prefix_length{8};  	arch = arch.substr(prefix_length); +#endif // _WIN32  	return arch;  } @@ -247,6 +513,48 @@ ctor::c_flag c_option(const std::string& flag)  		return { ctor::c_opt::include_path, path };  	} +	if(flag.starts_with("-std=")) +	{ +		std::string std = flag.substr(5); +		return { ctor::c_opt::c_std, std }; +	} + +	if(flag.starts_with("-O")) +	{ +		std::string opt = flag.substr(2, 1); +		return { ctor::c_opt::optimization, opt }; +	} + +	if(flag.starts_with("-Wall")) +	{ +		return { ctor::c_opt::warn_all }; +	} + +	if(flag.starts_with("-Wconversion")) +	{ +		return { ctor::c_opt::warn_conversion}; +	} + +	if(flag.starts_with("-Wshadow")) +	{ +		return { ctor::c_opt::warn_shadow}; +	} + +	if(flag.starts_with("-Wextra")) +	{ +		return { ctor::c_opt::warn_extra}; +	} + +	if(flag.starts_with("-Werror")) +	{ +		return { ctor::c_opt::warnings_as_errors }; +	} + +	if(flag.starts_with("-g")) +	{ +		return { ctor::c_opt::debug }; +	} +  	if(flag.starts_with("-D"))  	{  		std::string def = flag.substr(2); @@ -272,6 +580,48 @@ ctor::cxx_flag cxx_option(const std::string& flag)  		return { ctor::cxx_opt::include_path, path };  	} +	if(flag.starts_with("-std=")) +	{ +		std::string std = flag.substr(5); +		return { ctor::cxx_opt::cpp_std, std }; +	} + +	if(flag.starts_with("-O")) +	{ +		std::string opt = flag.substr(2, 1); +		return { ctor::cxx_opt::optimization, opt }; +	} + +	if(flag.starts_with("-Wall")) +	{ +		return { ctor::cxx_opt::warn_all }; +	} + +	if(flag.starts_with("-Werror")) +	{ +		return { ctor::cxx_opt::warnings_as_errors }; +	} + +	if(flag.starts_with("-Wconversion")) +	{ +		return { ctor::cxx_opt::warn_conversion}; +	} + +	if(flag.starts_with("-Wshadow")) +	{ +		return { ctor::cxx_opt::warn_shadow}; +	} + +	if(flag.starts_with("-Wextra")) +	{ +		return { ctor::cxx_opt::warn_extra}; +	} + +	if(flag.starts_with("-g")) +	{ +		return { ctor::cxx_opt::debug }; +	} +  	if(flag.starts_with("-D"))  	{  		std::string def = flag.substr(2); @@ -298,6 +648,11 @@ ctor::ld_flag ld_option(const std::string& flag)  		return { ctor::ld_opt::library_path, path };  	} +	if(flag.starts_with("-pthread")) +	{ +		return { ctor::ld_opt::threads }; +	} +  	return { ctor::ld_opt::custom, flag };  } @@ -317,6 +672,12 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,  		return {"-g"};  	case ctor::cxx_opt::warn_all:  		return {"-Wall"}; +	case ctor::cxx_opt::warn_conversion: +		return {"-Wconversion"}; +	case ctor::cxx_opt::warn_shadow: +		return {"-Wshadow"}; +	case ctor::cxx_opt::warn_extra: +		return {"-Wextra"};  	case ctor::cxx_opt::warnings_as_errors:  		return {"-Werror"};  	case ctor::cxx_opt::generate_dep_tree: @@ -358,6 +719,12 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,  		return {"-g"};  	case ctor::c_opt::warn_all:  		return {"-Wall"}; +	case ctor::c_opt::warn_conversion: +		return {"-Wconversion"}; +	case ctor::c_opt::warn_shadow: +		return {"-Wshadow"}; +	case ctor::c_opt::warn_extra: +		return {"-Wextra"};  	case ctor::c_opt::warnings_as_errors:  		return {"-Werror"};  	case ctor::c_opt::generate_dep_tree: @@ -466,6 +833,8 @@ std::string get_arch(ctor::output_system system)  	case ctor::toolchain::clang:  	case ctor::toolchain::gcc:  		return gcc::get_arch(system); +	case ctor::toolchain::msvc: +		return msvc::get_arch(system);  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -481,6 +850,8 @@ ctor::arch get_arch(ctor::output_system system, const std::string& str)  	case ctor::toolchain::clang:  	case ctor::toolchain::gcc:  		return gcc::get_arch(str); +	case ctor::toolchain::msvc: +		return msvc::get_arch(str);  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -498,6 +869,8 @@ std::vector<std::string> c_option(ctor::toolchain toolchain,  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::c_option(opt, arg, arg2); +	case ctor::toolchain::msvc: +		return msvc::c_option(opt, arg, arg2);  	case ctor::toolchain::any:  		{  			std::ostringstream ss; @@ -531,6 +904,8 @@ std::vector<std::string> cxx_option(ctor::toolchain toolchain,  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::cxx_option(opt, arg, arg2); +	case ctor::toolchain::msvc: +		return msvc::cxx_option(opt, arg, arg2);  	case ctor::toolchain::any:  		{  			std::ostringstream ss; @@ -564,6 +939,8 @@ std::vector<std::string> ld_option(ctor::toolchain toolchain,  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::ld_option(opt, arg, arg2); +	case ctor::toolchain::msvc: +		return msvc::ld_option(opt, arg, arg2);  	case ctor::toolchain::any:  		{  			std::ostringstream ss; @@ -597,6 +974,8 @@ std::vector<std::string> ar_option(ctor::toolchain toolchain,  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::ar_option(opt, arg, arg2); +	case ctor::toolchain::msvc: +		return msvc::ar_option(opt, arg, arg2);  	case ctor::toolchain::any:  		{  			std::ostringstream ss; @@ -630,6 +1009,8 @@ std::vector<std::string> asm_option(ctor::toolchain toolchain,  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::asm_option(opt, arg, arg2); +	case ctor::toolchain::msvc: +		return msvc::asm_option(opt, arg, arg2);  	case ctor::toolchain::any:  		{  			std::ostringstream ss; @@ -661,6 +1042,8 @@ ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain)  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::c_option(flag); +	case ctor::toolchain::msvc: +		return msvc::c_option(flag);  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -676,6 +1059,8 @@ ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain)  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::cxx_option(flag); +	case ctor::toolchain::msvc: +		return msvc::cxx_option(flag);  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -691,6 +1076,8 @@ ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain)  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::ld_option(flag); +	case ctor::toolchain::msvc: +		return msvc::ld_option(flag);  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -706,6 +1093,8 @@ ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain)  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang:  		return gcc::ar_option(flag); +	case ctor::toolchain::msvc: +		return msvc::ar_option(flag);  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -720,6 +1109,7 @@ ctor::asm_flag asm_option(const std::string& flag, ctor::toolchain toolchain)  	{  	case ctor::toolchain::gcc:  	case ctor::toolchain::clang: +	case ctor::toolchain::msvc:  	case ctor::toolchain::any:  	case ctor::toolchain::none:  		break; @@ -803,10 +1193,11 @@ ctor::toolchain guess_toolchain(const std::string& opt)  		return ctor::toolchain::gcc;  	} -	//if(opt[0] == '/') -	//{ -	//	return ctor::toolchain::msvc; -	//} +	if(opt[0] == '/') +	{ +		return ctor::toolchain::msvc; +	} +  	return ctor::toolchain::any;  }  } @@ -877,8 +1268,8 @@ ctor::target_type target_type_from_extension(ctor::toolchain toolchain,  		}  	} -	if(toolchain == ctor::toolchain::any// || -	   //toolchain == ctor::toolchain::msvc || +	if(toolchain == ctor::toolchain::any || +	   toolchain == ctor::toolchain::msvc// ||  	   //toolchain == ctor::toolchain::mingw ||  		)  	{ diff --git a/src/util.cc b/src/util.cc index dbd4c3c..f13a4a4 100644 --- a/src/util.cc +++ b/src/util.cc @@ -7,10 +7,17 @@  #include <fstream>  #include <algorithm> +namespace { +char to_lower_c(char ch) +{ +	return static_cast<char>(::tolower(ch)); +} +} +  std::string to_lower(const std::string& str)  {  	std::string out{str}; -	std::transform(out.begin(), out.end(), out.begin(), ::tolower); +	std::transform(out.begin(), out.end(), out.begin(), to_lower_c);  	return out;  } @@ -19,13 +26,18 @@ std::string readFile(const std::string& fileName)  	std::ifstream ifs(fileName.c_str(),  	                  std::ios::in | std::ios::binary | std::ios::ate); -	std::ifstream::pos_type fileSize = ifs.tellg(); +	auto tell = ifs.tellg(); +	if(tell < 0) +	{ +		return {}; +	} +	auto fileSize = static_cast<std::size_t>(tell);  	ifs.seekg(0, std::ios::beg); -	std::vector<char> bytes(static_cast<std::size_t>(fileSize)); -	ifs.read(bytes.data(), fileSize); +	std::vector<char> bytes(fileSize); +	ifs.read(bytes.data(), static_cast<long>(bytes.size())); -	return {bytes.data(), static_cast<std::size_t>(fileSize)}; +	return { bytes.data(), bytes.size() };  }  ctor::language languageFromExtension(const std::filesystem::path& file) @@ -169,15 +181,36 @@ std::string locate(const std::string& prog,  		}  	} +	if(std::filesystem::exists(program + ".exe")) +	{ +		if(check_executable(program + ".exe")) +		{ +			return program + ".exe"; +		} +	} +  	for(const auto& path_str : paths)  	{  		std::filesystem::path path(path_str); -		auto prog_path = path / program; -		if(std::filesystem::exists(prog_path))  		{ -			if(check_executable(prog_path)) +			auto prog_path = path / program; +			if(std::filesystem::exists(prog_path)) +			{ +				if(check_executable(prog_path)) +				{ +					return prog_path.string(); +				} +			} +		} + +		{ +			auto prog_path = path / (program + ".exe"); +			if(std::filesystem::exists(prog_path))  			{ -				return prog_path.string(); +				if(check_executable(prog_path)) +				{ +					return prog_path.string(); +				}  			}  		}  	}  | 
