std::shared_ptr<Toolset>
DefaultTools::checkAndAddArchiver( Scope &s, const std::map<std::string, std::string> &exelist )
{
	std::shared_ptr<Toolset> cTools = std::make_shared<Toolset>( "system_ar" );
	cTools->setTag( "archive" );

	for ( const auto &e: exelist )
	{
		const std::string &name = e.first;
		const std::string &exe = e.second;
		if ( name == "ar" )
		{
			std::string rmTool;
			bool haveRM = File::findExecutable( rmTool, "rm" );

			std::shared_ptr<Tool> t = std::make_shared<Tool>( "static_lib", name );
			t->myExtensions = { ".c", ".cpp" };
			t->myExeName = exe;
			t->myInputTools = { "cc" };
			t->myOutputPrefix = "lib";
			t->myOutputs = { ".a" };
			t->myFlagPrefixes = theVarPrefixes;
			if ( haveRM )
				t->myCommand = { rmTool, "-f", "$out", "&&", "$exe", "rcs", "$out", "$in"};
			else
				t->myCommand = { "$exe", "rcs", "$out", "$in"};

			t->myDescription = " AR $out_short";

			s.addTool( t );
			cTools->addTool( t );

			t = std::make_shared<Tool>( "static_lib_cxx", name );
			t->myExeName = exe;
			t->myInputTools = { "cc", "cxx", "objcxx" };
			t->myOutputPrefix = "lib";
			t->myOutputs = { ".a" };
			t->myFlagPrefixes = theVarPrefixes;
			if ( haveRM )
				t->myCommand = { rmTool, "-f", "$out", "&&", "$exe", "rcs", "$out", "$in"};
			else
				t->myCommand = { "$exe", "rcs", "$out", "$in"};
			t->myDescription = " AR $out_short";
			s.addTool( t );
			cTools->addTool( t );
		}
	}
	if ( cTools->empty() )
		cTools.reset();
	else
		s.addToolSet( cTools );

	return cTools;
}
void
DefaultTools::addSelfGenerator( Scope &s )
{
	std::string selfTool;
	bool haveSelf = File::findExecutable( selfTool, File::getArgv0() );
	if ( ! haveSelf )
		selfTool = File::getArgv0();

	std::shared_ptr<Tool> t = std::make_shared<Tool>( "codegen_binary_cstring", "codegen_binary_cstring" );
	t->myExeName = selfTool;
	t->myCommand = { selfTool, "-embed_binary_cstring", "$out", "$codegen_info", "$in"};
	t->myDescription = "BLOB $out";
	s.addTool( t );
}
std::shared_ptr<Toolset>
DefaultTools::checkAndAddGCC( Scope &s, const std::map<std::string, std::string> &exelist )
{
	std::shared_ptr<Toolset> cTools = std::make_shared<Toolset>( "gcc" );
	cTools->setTag( "compile" );

	static Tool::OptionSet commonWarnings{
		{ "none", { "-w" } },
		{ "default", {} },
		{ "some", { "-Wall" } },
		{ "most", { "-Wall", "-Wextra" } },
		{ "strict", { "-Wall", "-Wextra" } },
		{ "error", { "-Wall", "-Werror"  } } };

	for ( const auto &e: exelist )
	{
		const std::string &name = e.first;
		const std::string &exe = e.second;
		std::shared_ptr<Tool> t;
		if ( name == "gcc" )
		{
			// TODO: Add version check for gcc to optionally enable features
			t = std::make_shared<Tool>( "cc", name );
			t->myExtensions = { ".c" };
			t->myOutputs = { ".o" };
			t->myExeName = exe;
			t->myOptions = theCommonOptions;
			t->myOptions["optimization"]["optdebug"] = { "-g", "-Og" };
			t->myOptions["warnings"] = commonWarnings;
			t->myOptions["warnings"]["most"] =
				{ "-Wall", "-Wextra", "-Wno-unused-parameter", "-Winit-self", "-Wcomment", "-Wcast-align", "-Wswitch", "-Wformat", "-Wmultichar", "-Wmissing-braces", "-Wparentheses", "-Wpointer-arith", "-Wsign-compare", "-Wreturn-type", "-Wwrite-strings", "-Wcast-align", "-Wno-unused" };
			t->myOptions["language"] = theCLanguages;
			t->myOptionDefaults = theCDefaults;
			t->myImplDepName = "$out.d";
			t->myImplDepStyle = "gcc";
			t->myImplDepCmd = { "-MMD", "-MF", "$out.d" };
			t->myFlagPrefixes = theVarPrefixes;
			t->myDescription = " CC $out_short";
			t->myCommand = theCompileCmd;

			s.addTool( t );
			cTools->addTool( t );

			t = std::make_shared<Tool>( "ld", "gcc_linker" );
			t->myExeName = exe;
			t->myInputTools = theCLinkInputTools;
			t->myOptions = theCommonOptions;
			t->myOptions["optimization"]["optdebug"] = { "-g", "-Og" };
			t->myOptions["language"] = theCLanguages;
			t->myOptionDefaults = theCDefaults;
			t->myFlagPrefixes = theVarPrefixes;
			t->myDescription = " LD $out_short";
			t->myCommand = theLinkCmd;
			s.addTool( t );
			cTools->addTool( t );
		}
		else if ( name == "g++" )
		{
			t = std::make_shared<Tool>( "cxx", name );
			t->myExtensions = { ".cpp", ".cc" };
			t->myAltExtensions = { ".c", ".C" };
			t->myOutputs = { ".o" };
			t->myExeName = exe;
			t->myOptions = theCommonOptions;
			t->myOptions["optimization"]["optdebug"] = { "-g", "-Og" };
			t->myOptions["warnings"] = commonWarnings;
			t->myOptions["warnings"]["most"] = { "-Wall", "-Wextra", "-Wno-unused-parameter", "-Winit-self", "-Wcomment", "-Wcast-align", "-Wswitch", "-Wformat", "-Wmultichar", "-Wmissing-braces", "-Wparentheses", "-Wpointer-arith", "-Wsign-compare", "-Wreturn-type", "-Wwrite-strings", "-Wcast-align", "-Wunused", "-Woverloaded-virtual", "-Wno-ctor-dtor-privacy", "-Wnon-virtual-dtor", "-Wpmf-conversions", "-Wsign-promo", "-Wmissing-field-initializers" };
			t->myOptions["language"] = theCPPLanguages;
			t->myOptionDefaults = theCPPDefaults;
			t->myImplDepName = "$out.d";
			t->myImplDepStyle = "gcc";
			t->myImplDepCmd = { "-MMD", "-MF", "$out.d" };
			t->myDescription = "CXX $out_short";
			t->myFlagPrefixes = theVarPrefixes;
			t->myCommand = theCompileCmd;
			s.addTool( t );
			cTools->addTool( t );

			t = std::make_shared<Tool>( "ld_cxx", "g++_linker" );
			t->myExeName = exe;
			t->myInputTools = theCPPLinkInputTools;
			t->myOptions = theCommonOptions;
			t->myOptions["optimization"]["optdebug"] = { "-g", "-Og" };
			t->myOptions["language"] = theCPPLinkLanguages;
			t->myOptionDefaults = theCPPDefaults;
			t->myFlagPrefixes = theVarPrefixes;
			t->myDescription = " LD $out_short";
			t->myCommand = theLinkCmd;

			s.addTool( t );
			cTools->addTool( t );
		}
	}

	if ( cTools->empty() )
		cTools.reset();
	else
		s.addToolSet( cTools );
	return cTools;
}
std::shared_ptr<Toolset>
DefaultTools::checkAndAddClang( Scope &s, const std::map<std::string, std::string> &exelist )
{
	std::shared_ptr<Toolset> cTools = std::make_shared<Toolset>( "clang" );
	cTools->setTag( "compile" );

	static Tool::OptionSet commonWarnings{
		{ "none", { "-w" } },
		{ "default", {} },
		{ "some", { "-Wall" } },
		{ "strict", { "-Weverything", } },
		{ "most", { "-Weverything", } },
		{ "error", { "-Wall", "-Werror"  } } };

	for ( const auto &e: exelist )
	{
		const std::string &name = e.first;
		const std::string &exe = e.second;
		std::shared_ptr<Tool> t;
		if ( name == "clang" )
		{
			t = std::make_shared<Tool>( "cc", name );
			t->myExtensions = { ".c" };
			t->myOutputs = { ".o" };
			t->myExeName = exe;
			t->myOptions = theCommonOptions;
			t->myOptions["warnings"] = commonWarnings;
			t->myOptions["language"] = theCLanguages;
			t->myOptionDefaults = theCDefaults;
			t->myImplDepName = "$out.d";
			t->myImplDepStyle = "gcc";
			t->myImplDepCmd = { "-MMD", "-MF", "$out.d" };
			t->myFlagPrefixes = theVarPrefixes;
			t->myDescription = " CC $out_short";
			t->myCommand = theCompileCmd;

			s.addTool( t );
			cTools->addTool( t );

			t = std::make_shared<Tool>( "ld", "clang_linker" );
			t->myExeName = exe;
			t->myInputTools = theCLinkInputTools;
			t->myOptions = theCommonOptions;
			t->myOptions["language"] = theCLanguages;
			t->myOptionDefaults = theCDefaults;
			t->myFlagPrefixes = theVarPrefixes;
			t->myDescription = " LD $out_short";
			t->myCommand = theLinkCmd;
			s.addTool( t );
			cTools->addTool( t );
		}
		else if ( name == "clang++" )
		{
			t = std::make_shared<Tool>( "cxx", name );
			t->myExtensions = { ".cpp", ".cc" };
			t->myAltExtensions = { ".c", ".C" };
			t->myOutputs = { ".o" };
			t->myExeName = exe;
			t->myOptions = theCommonOptions;
			t->myOptions["warnings"] = commonWarnings;
			t->myOptions["warnings"]["most"] = { "-Weverything", "-Wno-padded", "-Wno-global-constructors", "-Wno-documentation-unknown-command", "-Wno-mismatched-tags", "-Wno-exit-time-destructors" };
			t->myOptions["language"] = theCPPLanguages;
			t->myOptions["language"]["c++11"] = { "-x", "c++", "-std=c++11", "-Wno-c++98-compat", "-Wno-c++98-compat-pedantic" };
			t->myOptions["language"]["c++14"] = { "-x", "c++", "-std=c++14", "-Wno-c++98-compat", "-Wno-c++98-compat-pedantic" };
			t->myOptionDefaults = theCPPDefaults;
			t->myImplDepName = "$out.d";
			t->myImplDepStyle = "gcc";
			t->myImplDepCmd = { "-MMD", "-MF", "$out.d" };
			t->myDescription = "CXX $out_short";
			t->myFlagPrefixes = theVarPrefixes;
			t->myCommand = theCompileCmd;

			s.addTool( t );
			cTools->addTool( t );

			t = std::make_shared<Tool>( "objcxx", name );
			t->myExtensions = { ".mm" };
			t->myAltExtensions = { ".MM" };
			t->myOutputs = { ".o" };
			t->myExeName = exe;
			t->myOptions = theCommonOptions;
			t->myOptions["warnings"] = commonWarnings;
			t->myOptions["warnings"]["most"] = { "-Weverything", "-Wno-padded", "-Wno-global-constructors", "-Wno-documentation-unknown-command", "-Wno-mismatched-tags", "-Wno-exit-time-destructors" };
			t->myOptions["language"]["c++"] = { "-ObjC++" };
			t->myOptions["language"]["c++11"] = { "-ObjC++", "-std=c++11", "-Wno-c++98-compat", "-Wno-c++98-compat-pedantic" };
			t->myOptions["language"]["c++14"] = { "-ObjC++", "-std=c++14", "-Wno-c++98-compat", "-Wno-c++98-compat-pedantic" };
			t->myOptionDefaults = theCPPDefaults;
			t->myImplDepName = "$out.d";
			t->myImplDepStyle = "gcc";
			t->myImplDepCmd = { "-MMD", "-MF", "$out.d" };
			t->myDescription = "OBJCXX $out_short";
			t->myFlagPrefixes = theVarPrefixes;
			t->myCommand = theCompileCmd;

			s.addTool( t );
			cTools->addTool( t );

			t = std::make_shared<Tool>( "ld_cxx", "clang++_linker" );
			t->myExeName = exe;
			t->myInputTools = theCPPLinkInputTools;
			t->myInputTools.push_back( "objcxx" );
			t->myOptions = theCommonOptions;
			t->myOptionDefaults = theCPPDefaults;
			t->myFlagPrefixes = theVarPrefixes;
			t->myDescription = " LD $out_short";
			t->myCommand = theLinkCmd;
			s.addTool( t );
			cTools->addTool( t );
		}
	}

	if ( cTools->empty() )
		cTools.reset();
	else
		s.addToolSet( cTools );

	return cTools;
}