diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/configure.cc | 81 | ||||
| -rw-r--r-- | src/ctor.h | 1 | ||||
| -rw-r--r-- | src/deps.cc | 74 | ||||
| -rw-r--r-- | src/execute.cc | 248 | ||||
| -rw-r--r-- | src/rebuild.cc | 13 | ||||
| -rw-r--r-- | src/task_ar.cc | 2 | ||||
| -rw-r--r-- | src/task_cc.cc | 2 | ||||
| -rw-r--r-- | src/task_ld.cc | 24 | ||||
| -rw-r--r-- | src/task_so.cc | 2 | ||||
| -rw-r--r-- | src/tools.cc | 295 | ||||
| -rw-r--r-- | src/util.cc | 53 | 
11 files changed, 756 insertions, 39 deletions
| diff --git a/src/configure.cc b/src/configure.cc index a43152f..b52824e 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,7 +27,11 @@ 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}; @@ -44,6 +50,14 @@ const ctor::configuration& __attribute__((weak)) ctor::get_configuration()  	}  	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") +#endif  namespace ctor {  std::optional<std::string> includedir; @@ -100,11 +114,47 @@ std::string ctor::configuration::get(const std::string& key,  		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;  } @@ -162,6 +212,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; @@ -676,6 +729,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; @@ -906,6 +960,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 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 c050732..4ed274f 100644 --- a/src/execute.cc +++ b/src/execute.cc @@ -6,12 +6,24 @@  #include "ctor.h"  #include "pointerlist.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> +	extern char **environ; +#else +	#define WINDOWS_LEAN_AND_MEAN +	#include <windows.h> +	#undef max +	#include <thread> +#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/ @@ -23,7 +35,7 @@ https://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-  namespace  { - +#if !defined(_WIN32)  int parent_waitpid(pid_t pid)  {  	int status{}; @@ -61,9 +73,80 @@ int parent_waitpid(pid_t pid)  	// Should never happen...  	return 1;  } -} // namespace :: +#endif //_WIN32 + +#if defined(_WIN32) +std::string getLastErrorAsString() +{ +	DWORD errorMessageID = ::GetLastError(); +	if(errorMessageID == 0) +	{ +		return {}; +	} + +	LPSTR message_buffer{}; +	auto size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | +	                           FORMAT_MESSAGE_FROM_SYSTEM | +	                           FORMAT_MESSAGE_IGNORE_INSERTS, +	                           nullptr, +	                           errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), +	                           (LPSTR)&message_buffer, 0, nullptr); + +	std::string message(message_buffer, size); +	LocalFree(message_buffer); +	return message; +} + +int moveSelf(const ctor::settings& settings) +{ +	int cnt{0}; +	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); +		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; +			} -extern char **environ; // see 'man environ' +			cnt++; +			continue; // Increment and try again +		} +		else +		{ +			std::cerr << "Could not move file\n"; +			return err; +		} +	} +	return 0; +} +#endif // _WIN32 +} // namespace ::  int execute(const ctor::settings& settings,              const std::string& command, @@ -98,11 +181,13 @@ int execute(const ctor::settings& settings,  		std::cout << cmd << std::endl;  	} +#if !defined(_WIN32) +  #if 1  	auto pid = vfork();  	if(pid == 0)  	{ -		EnvMap envmap((const char**)environ); +		EnvMap envmap(environ);  		for(const auto& [key, value] : env)  		{  			envmap.insert(key + "=" + value); @@ -120,15 +205,16 @@ int execute(const ctor::settings& settings,  	}  	return parent_waitpid(pid);  #elif 0 -	pid_t pid; -	std::vector<std::string> venv; +	pid_t pid{}; +	EnvMap envmap(environ);  	for(const auto& [key, value] : env)  	{ -		venv.push_back(key + "=" + value); +		envmap.insert(key + "=" + value);  	} -	Env penv(venv); + +	auto [_, envv] = envmap.get();  	if(posix_spawn(&pid, command.data(), nullptr, nullptr, -	               (char**)argv.data(), penv.data())) +	               (char**)argv.data(), const_cast<char* const *>(envv)))  	{  		return 1;  	} @@ -138,5 +224,139 @@ int execute(const ctor::settings& settings,  	return system(cmd.data());  #endif +#else // _WIN32 +	if(terminate) +	{ +		auto ret = moveSelf(settings); +		if(ret != 0) +		{ +			return ret; +		} +	} + +	auto env_strings = GetEnvironmentStrings(); +	EnvMap envmap(env_strings); +	FreeEnvironmentStrings(env_strings); +	for(const auto& [key, value] : env) +	{ +		envmap.insert(key + "=" + value); +	} + +	// TODO: Use SetDllDirectory(...) to set DLL search directory? + +	SECURITY_ATTRIBUTES security_attr; +	// Set the bInheritHandle flag so pipe handles are inherited. +	security_attr.nLength = sizeof(SECURITY_ATTRIBUTES); +	security_attr.bInheritHandle = TRUE; +	security_attr.lpSecurityDescriptor = nullptr; + +	HANDLE stream_in_read{}; +	HANDLE stream_in_write{}; +	HANDLE stream_out_read{}; +	HANDLE stream_out_write{}; + +	if(!CreatePipe(&stream_out_read, &stream_out_write, &security_attr, 0)) +	{ +		std::cout << "Error CreatePipe (out): " << getLastErrorAsString() << "\n"; +	} + +	if(!SetHandleInformation(stream_out_read, HANDLE_FLAG_INHERIT, 0)) +	{ +		std::cout << "Error - SetHandleInformation (out): " << getLastErrorAsString() << "\n"; +	} + +	// Create a pipe for the child process's STDIN. +	if(!CreatePipe(&stream_in_read, &stream_in_write, &security_attr, 0)) +	{ +		std::cout << "Error CreatePipe (in): " << getLastErrorAsString() << "\n"; +	} + +	// Ensure the write handle to the pipe for STDIN is not inherited. +	if(!SetHandleInformation(stream_in_write, HANDLE_FLAG_INHERIT, 0)) +	{ +		std::cout << "Error - SetHandleInformation (in): " << getLastErrorAsString() << "\n"; +	} + +	STARTUPINFO si{}; +	si.hStdInput = GetStdHandle(((DWORD)-10));//STD_INPUT_HANDLE +	si.hStdOutput = stream_out_write; +	si.hStdError = stream_out_write; +	si.dwFlags |= STARTF_USESTDHANDLES; + +	PROCESS_INFORMATION pi{}; + +	si.cb = sizeof(si); + +	if(!CreateProcess(nullptr,           // lpApplicationName +	                  (char*)cmd.data(), // lpCommandLine +	                  nullptr,           // lpProcessAttributes +	                  nullptr,           // lpThreadAttributes +	                  TRUE,              // bInheritHandles +	                  INHERIT_PARENT_AFFINITY | +	                  0x00000200 | // CREATE_NEW_PROCESS_GROUP +	                  0,                 // dwCreationFlags +	                  envmap.stringify().data(),    // lpEnvironment +	                  nullptr,           // lpCurrentDirectory +	                  &si,               // lpStartupInfo +	                  &pi))              // lpProcessInformation +	{ +		std::cout << "Could not execute " << command << ": " << +			getLastErrorAsString() << "\n"; +		return 1; +	} + +	int ignore_lines{}; +	std::filesystem::path cmd_path{command}; +	if(cmd_path.filename() == "cl.exe") +	{ +		// Ignore first line, avoiding the annoying msvc compiler of printing the filename +		// of the file that is being compiled +		ignore_lines = 1; +	} + +	std::atomic<bool> running{true}; +	auto parent_waitpid = std::thread([&](){ +		WaitForSingleObject(pi.hProcess, INFINITE); +		CloseHandle(stream_out_write); +		CloseHandle(stream_in_read); +		running.store(false); +	}); + +	CHAR buf[1024]; +	while(running.load()) +	{ +		if(WaitForSingleObject(stream_out_read, 0) != WAIT_OBJECT_0) +		{ +			Sleep(1); +			continue; +		} +		DWORD read_bytes{}; +		auto res = ReadFile(stream_out_read, buf, sizeof(buf), &read_bytes, nullptr); +		if(res != TRUE || read_bytes == 0) +		{ +			break; +		} +		std::string str; +		str.append(buf, read_bytes); +		if(ignore_lines == 0) +		{ +			std::cout << str << std::flush; +		} +		if(str.find('\n') != std::string::npos) +		{ +			ignore_lines = std::max(0, ignore_lines - 1); +		} +	} + +	DWORD exit_code{}; +	GetExitCodeProcess(pi.hProcess, &exit_code); +	parent_waitpid.join(); + +	CloseHandle(pi.hProcess); +	CloseHandle(pi.hThread); + +	return exit_code; +#endif // _WIN32 +  	return 1;  } diff --git a/src/rebuild.cc b/src/rebuild.cc index a2b7ddd..9a3fca0 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  	{ @@ -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,9 +185,13 @@ 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::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_ar.cc b/src/task_ar.cc index 3b45cc2..0365d51 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()); diff --git a/src/task_cc.cc b/src/task_cc.cc index 9628455..b300cd6 100644 --- a/src/task_cc.cc +++ b/src/task_cc.cc @@ -305,12 +305,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 03745be..af71bbb 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); @@ -129,11 +130,28 @@ int TaskLD::runInner()  	auto tool = compiler();  	const auto& cfg = ctor::get_configuration(); -	auto ldflags = cfg.getenv("LDFLAGS"); -	if(!ldflags.empty()) +	if(toolchain == ctor::toolchain::gcc || +	   toolchain == ctor::toolchain::clang)  	{ -		append(args, ld_option(toolchain, ctor::ld_opt::custom, ldflags)); +		auto ldflags = cfg.getenv("LDFLAGS"); +		if(!ldflags.empty()) +		{ +			append(args, ld_option(toolchain, ctor::ld_opt::custom, ldflags)); +		}  	} +	else // msvc +	{ +		switch(outputSystem()) +		{ +		case ctor::output_system::host: +			tool = cfg.get(ctor::cfg::host_ld, "/usr/bin/ld"); +			break; +		case ctor::output_system::build: +			tool = cfg.get(ctor::cfg::build_ld, "/usr/bin/ld"); +			break; +		} +	} +  	auto res = execute(settings, tool, args, cfg.env, is_self);  	if(res != 0)  	{ diff --git a/src/task_so.cc b/src/task_so.cc index 92aeefe..db07c53 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()); diff --git a/src/tools.cc b/src/tools.cc index dfabdff..1a539be 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -6,6 +6,7 @@  #include <filesystem>  #include <iostream>  #include <sstream> +#include <algorithm>  #include <array>  #include <cassert> @@ -13,6 +14,11 @@  #include "util.h" +#if defined(_WIN32) +#define popen _popen +#define pclose _pclose +#endif +  std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt)  {  	// Adding to this enum should also imply adding to the unit-tests below @@ -129,6 +135,10 @@ ctor::toolchain getToolChain(const std::string& compiler)  	{  		return ctor::toolchain::gcc;  	} +	else if(to_lower(cc_cmd).find("cl") != std::string::npos) +	{ +		return ctor::toolchain::msvc; +	}  	std::cerr << "Unsupported output system.\n";  	return ctor::toolchain::gcc; @@ -154,12 +164,256 @@ 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) +{ +	return "windows"; +} + +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::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;  	std::string cmd; -  	const auto& c = ctor::get_configuration();  	switch(system)  	{ @@ -180,7 +434,6 @@ std::string get_arch(ctor::output_system system)  		return {};//ctor::arch::unknown;  	} -	std::string arch;  	while(!feof(pipe))  	{  		constexpr auto buffer_size{1024}; @@ -571,6 +824,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; @@ -586,6 +841,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; @@ -603,6 +860,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; @@ -636,6 +895,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; @@ -669,6 +930,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; @@ -702,6 +965,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; @@ -735,6 +1000,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; @@ -766,6 +1033,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; @@ -781,6 +1050,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; @@ -796,6 +1067,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; @@ -811,6 +1084,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; @@ -825,6 +1100,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; @@ -908,10 +1184,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;  }  } @@ -982,8 +1259,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 6fc650a..20dea71 100644 --- a/src/util.cc +++ b/src/util.cc @@ -8,10 +8,17 @@  #include <algorithm>  #include <sstream> +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;  } @@ -20,13 +27,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) @@ -71,7 +83,7 @@ namespace  {  bool isClean(char c)  { -	return c != '.' && c != '/'; +	return c != '.' && c != '/' && c != '\\';  }  } @@ -170,15 +182,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(); +				}  			}  		}  	} | 
