diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2021-06-20 20:21:58 +0200 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2021-06-20 20:21:58 +0200 | 
| commit | c53e622b648635539e4870fd0c9159c5d8c3be4a (patch) | |
| tree | a154de97d62e2aad99ccb5498ca7c297ee93623e | |
| parent | 4bc1ac3fe2fe3ae96ba0e5aa4d19fa4885a16c83 (diff) | |
Introduction of configuration generation for controlling tool-chain.
| -rw-r--r-- | libcppbuild.cc | 163 | ||||
| -rw-r--r-- | libcppbuild.h | 39 | ||||
| -rw-r--r-- | task.cc | 19 | ||||
| -rw-r--r-- | task.h | 13 | ||||
| -rw-r--r-- | task_ar.cc | 16 | ||||
| -rw-r--r-- | task_cc.cc | 34 | ||||
| -rw-r--r-- | task_ld.cc | 23 | ||||
| -rw-r--r-- | task_so.cc | 21 | 
8 files changed, 281 insertions, 47 deletions
diff --git a/libcppbuild.cc b/libcppbuild.cc index 927fe72..1fa1bc3 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -25,6 +25,35 @@  #include <unistd.h> + +namespace +{ +std::filesystem::path configurationFile("configuration.cc"); +const std::map<std::string, std::string> default_configuration{}; +} +const std::map<std::string, std::string>& __attribute__((weak)) configuration() +{ +	return default_configuration; +} + +bool hasConfiguration(const std::string& key) +{ +	const auto& c = configuration(); +	return c.find(key) != c.end(); +} + +const std::string& getConfiguration(const std::string& key, +                                    const std::string& defaultValue) +{ +	const auto& c = configuration(); +	if(hasConfiguration(key)) +	{ +		return c.at(key); +	} + +	return defaultValue; +} +  using namespace std::chrono_literals;  std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config, @@ -151,6 +180,24 @@ void recompileCheck(const Settings& settings, int argc, char* argv[])  	std::filesystem::path binFile("cppbuild"); +	if(std::filesystem::exists(configurationFile)) +	{ +		args.push_back(configurationFile.string()); + +		if(std::filesystem::last_write_time(binFile) <= +		   std::filesystem::last_write_time(configurationFile)) +		{ +			dirty = true; +		} + +		const auto& c = configuration(); +		if(&c == &default_configuration) +		{ +			// configuration.cc exists, but currently compiled with the default one. +			dirty = true; +		} +	} +  	if(settings.verbose > 1)  	{  		std::cout << "Recompile check (" << numConfigFiles << "):\n"; @@ -183,10 +230,11 @@ void recompileCheck(const Settings& settings, int argc, char* argv[])  	if(dirty)  	{  		std::cout << "Rebuilding config\n"; -		auto ret = execute("/usr/bin/g++", args); +		auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); +		auto ret = execute(tool, args, settings.verbose > 0);  		if(ret != 0)  		{ -			std::cerr << "Failed.\n"; +			std::cerr << "Failed: ." << ret << "\n";  			exit(1);  		}  		else @@ -197,16 +245,87 @@ void recompileCheck(const Settings& settings, int argc, char* argv[])  			{  				args.push_back(argv[i]);  			} -			exit(execute(argv[0], args, settings.verbose)); +			exit(execute(argv[0], args, settings.verbose > 0));  		}  	}  } +std::list<std::shared_ptr<Task>> getTasks(const Settings& settings) +{ +	static std::deque<BuildConfiguration> build_configs; +	std::list<std::shared_ptr<Task>> tasks; +	for(int i = 0; i < numConfigFiles; ++i) +	{ +		std::string path = +			std::filesystem::path(configFiles[i].file).parent_path(); +		if(settings.verbose > 1) +		{ +			std::cout << configFiles[i].file << " in path " << path << "\n"; +		} +		auto configs = configFiles[i].cb(); +		for(const auto& config : configs) +		{ +			build_configs.push_back(config); +			const auto& build_config = build_configs.back(); +			std::vector<std::string> objects; +			auto t = taskFactory(build_config, settings, path); +			tasks.insert(tasks.end(), t.begin(), t.end()); +		} +	} + +	return tasks; +} + +int configure(int argc, char* argv[],const Settings& settings) +{ +	auto tasks = getTasks(settings); + +	bool needs_cpp{false}; +	bool needs_c{false}; +	bool needs_ar{false}; +	for(const auto& task :tasks) +	{ +		switch(task->language()) +		{ +		case Language::Auto: +			std::cerr << "TargetLanguage not deduced!\n"; +			exit(1); +			break; +		case Language::C: +			needs_cpp = false; +			break; +		case Language::Cpp: +			needs_c = true; +			break; +		} +	} +	std::ofstream istr(configurationFile); +	istr << "#include \"libcppbuild.h\"\n\n"; +	istr << "const std::map<std::string, std::string>& configuration()\n"; +	istr << "{\n"; +	istr << "	static std::map<std::string, std::string> c =\n"; +	istr << "	{\n"; +	istr << "		{ \"builddir\", \"build\" },\n"; +	istr << "		{ \"host-cc\", \"/usr/bin/gcc\" },\n"; +	istr << "		{ \"host-cpp\", \"/usr/bin/g++\" },\n"; +	istr << "		{ \"host-ar\", \"/usr/bin/ar\" },\n"; +	istr << "		{ \"host-ld\", \"/usr/bin/ld\" },\n"; +	istr << "		{ \"target-cc\", \"/usr/bin/gcc\" },\n"; +	istr << "		{ \"target-cpp\", \"/usr/bin/g++\" },\n"; +	istr << "		{ \"target-ar\", \"/usr/bin/ar\" },\n"; +	istr << "		{ \"target-ld\", \"/usr/bin/ld\" },\n"; +	istr << "	};\n"; +	istr << "	return c;\n"; +	istr << "}\n"; + +	return 0; +} +  int main(int argc, char* argv[])  {  	Settings settings{}; -	settings.builddir = "build/"; +	settings.builddir = getConfiguration("builddir", "build");  	settings.parallel_processes =  		std::max(1u, std::thread::hardware_concurrency() * 2 - 1);  	settings.verbose = 0; @@ -214,6 +333,11 @@ int main(int argc, char* argv[])  	bool write_compilation_database{false};  	std::string compilation_database; +	if(argc > 1 && std::string(argv[1]) == "configure") +	{ +		return configure(argc, argv, settings); +	} +  	dg::Options opt;  	opt.add("jobs", required_argument, 'j', @@ -232,7 +356,8 @@ int main(int argc, char* argv[])  	        });  	opt.add("build-dir", required_argument, 'b', -	        "Set output directory for build files (default: build).", +	        "Overload output directory for build files (default: '" + +	        settings.builddir + "').",  	        [&]() {  		        settings.builddir = optarg;  		        return 0; @@ -269,26 +394,7 @@ int main(int argc, char* argv[])  	std::filesystem::path builddir(settings.builddir);  	std::filesystem::create_directories(builddir); -	std::deque<BuildConfiguration> build_configs; -	std::list<std::shared_ptr<Task>> tasks; -	for(int i = 0; i < numConfigFiles; ++i) -	{ -		std::string path = -			std::filesystem::path(configFiles[i].file).parent_path(); -		if(settings.verbose > 1) -		{ -			std::cout << configFiles[i].file << " in path " << path << "\n"; -		} -		auto configs = configFiles[i].cb(); -		for(const auto& config : configs) -		{ -			build_configs.push_back(config); -			const auto& build_config = build_configs.back(); -			std::vector<std::string> objects; -			auto t = taskFactory(build_config, settings, path); -			tasks.insert(tasks.end(), t.begin(), t.end()); -		} -	} +	auto tasks = getTasks(settings);  	if(write_compilation_database)  	{ @@ -337,7 +443,6 @@ int main(int argc, char* argv[])  		if(arg == "clean")  		{  			std::cout << "Cleaning\n"; -			//std::filesystem::remove_all(builddir);  			for(auto& task : tasks)  			{  				if(task->clean() != 0) @@ -348,6 +453,12 @@ int main(int argc, char* argv[])  			return 0;  		} + +		if(arg == "configure") +		{ +			std::cerr << "The 'configure' target must be the first argument.\n"; +			return 1; +		}  	}  	if(dirtyTasks.empty()) diff --git a/libcppbuild.h b/libcppbuild.h index 2aba987..81e7a9e 100644 --- a/libcppbuild.h +++ b/libcppbuild.h @@ -3,25 +3,45 @@  #include <string>  #include <vector> -//#include <source_location> +#include <map>  enum class TargetType  { -	Auto, // Default - deduce from target name +	Auto, // Default - deduce from target name and sources extensions +  	Executable,  	StaticLibrary,  	DynamicLibrary, +	Object, +}; + +enum class Language +{ +	Auto, // Default - deduce language from source extensions + +	C, +	Cpp, +	Asm, +}; + +enum class OutputSystem +{ +	Target, // Output for the target system +	BuildHost, // Internal tool during cross-compilation  };  struct BuildConfiguration  {  	TargetType type{TargetType::Auto}; +	Language language{Language::Auto}; +	OutputSystem system{OutputSystem::Target};  	std::string target; -	std::vector<std::string> sources; -	std::vector<std::string> depends; -	std::vector<std::string> cxxflags; -	std::vector<std::string> cflags; -	std::vector<std::string> ldflags; +	std::vector<std::string> sources; // source list +	std::vector<std::string> depends; // internal dependencies +	std::vector<std::string> cxxflags; // flags for c++ compiler +	std::vector<std::string> cflags; // flags for c compiler +	std::vector<std::string> ldflags; // flags for linker +	std::vector<std::string> asmflags; // flags for asm translator  };  using BuildConfigurations = std::vector<BuildConfiguration>; @@ -33,3 +53,8 @@ int reg(const char* location, BuildConfigurations (*cb)());  #define CONCAT_INNER(a, b) a ## b  #define UNIQUE_NAME(base) CONCAT(base, __LINE__)  #define REG(cb) namespace { int UNIQUE_NAME(unique) = reg(__FILE__, cb); } + +const std::map<std::string, std::string>& configuration(); +bool hasConfiguration(const std::string& key); +const std::string& getConfiguration(const std::string& key, +                                    const std::string& defaultValue = {}); @@ -3,8 +3,10 @@  #include <unistd.h>  #include <iostream> -Task::Task(const std::vector<std::string>& depends) +Task::Task(const BuildConfiguration& config, +           const std::vector<std::string>& depends)  	: dependsStr(depends) +	, config(config)  {  } @@ -84,3 +86,18 @@ State Task::state() const  {  	return task_state.load();  } + +const BuildConfiguration& Task::buildConfig() const +{ +	return config; +} + +TargetType Task::targetType() const +{ +	return target_type; +} + +Language Task::language() const +{ +	return _language; +} @@ -7,6 +7,8 @@  #include <list>  #include <memory> +#include "libcppbuild.h" +  enum class State  {  	Unknown, @@ -19,7 +21,8 @@ enum class State  class Task  {  public: -	Task(const std::vector<std::string>& depends); +	Task(const BuildConfiguration& config, +	     const std::vector<std::string>& depends = {});  	int registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks); @@ -33,6 +36,11 @@ public:  	virtual std::string toJSON() const { return {}; }; +	const BuildConfiguration& buildConfig() const; + +	TargetType targetType() const; +	Language language() const; +  protected:  	std::atomic<State> task_state{State::Unknown};  	virtual int runInner() { return 0; }; @@ -40,4 +48,7 @@ protected:  	std::vector<std::string> dependsStr;  	std::list<std::shared_ptr<Task>> dependsTasks; +	const BuildConfiguration& config; +	TargetType target_type{TargetType::Auto}; +	Language _language{Language::Auto};  }; @@ -41,7 +41,7 @@ TaskAR::TaskAR(const BuildConfiguration& config,                 const Settings& settings,                 const std::string& target,                 const std::vector<std::string>& objects) -	: Task(addPrefix(config.depends, settings)) +	: Task(config, addPrefix(config.depends, settings))  	, config(config)  	, settings(settings)  { @@ -63,6 +63,17 @@ TaskAR::TaskAR(const BuildConfiguration& config,  	flagsFile = settings.builddir / targetFile.stem();  	flagsFile += ".flags"; + +	target_type = TargetType::StaticLibrary; +	_language = Language::C; +	for(const auto& source : config.sources) +	{ +		std::filesystem::path sourceFile(source); +		if(sourceFile.extension().string() != ".c") +		{ +			_language = Language::Cpp; +		} +	}  }  bool TaskAR::dirtyInner() @@ -132,7 +143,8 @@ int TaskAR::runInner()  		std::cout << "AR => " << targetFile.string() << "\n";  	} -	return execute("/usr/bin/ar", args, settings.verbose > 0); +	auto tool = getConfiguration("host-ar", "/usr/bin/ar"); +	return execute(tool, args, settings.verbose > 0);  }  int TaskAR::clean() @@ -85,7 +85,7 @@ std::vector<std::string> readDeps(const std::string& depFile)  TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,                 const std::string& sourceDir, const std::string& source) -	: Task({}) +	: Task(config)  	, config(config)  	, settings(settings)  	, sourceDir(sourceDir) @@ -101,6 +101,16 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,  	flagsFile = settings.builddir / sourceFile.stem();  	flagsFile += ".flags"; + +	target_type = TargetType::Object; +	if(sourceFile.extension().string() == ".c") +	{ +		_language = Language::C; +	} +	else +	{ +		_language = Language::Cpp; +	}  }  bool TaskCC::dirtyInner() @@ -245,11 +255,17 @@ std::string TaskCC::toJSON() const  std::vector<std::string> TaskCC::flags() const  { -	if(std::string(sourceFile.extension()) == ".c") +	switch(language())  	{ +	case Language::C:  		return config.cflags; +	case Language::Cpp: +		return config.cxxflags; +	default: +		std::cerr << "Unknown CC target type\n"; +		exit(1); +		break;  	} -	return config.cxxflags;  }  std::string TaskCC::flagsString() const @@ -268,11 +284,17 @@ std::string TaskCC::flagsString() const  std::string TaskCC::compiler() const  { -	if(std::string(sourceFile.extension()) == ".c") +	switch(language())  	{ -		return "/usr/bin/gcc"; +	case Language::C: +		return getConfiguration("host-cc"); +	case Language::Cpp: +		return getConfiguration("host-cpp"); +	default: +		std::cerr << "Unknown CC target type\n"; +		exit(1); +		break;  	} -	return "/usr/bin/g++";  }  std::vector<std::string> TaskCC::getCompilerArgs() const @@ -40,10 +40,12 @@ TaskLD::TaskLD(const BuildConfiguration& config,                 const Settings& settings,                 const std::string& target,                 const std::vector<std::string>& objects) -	: Task(addPrefix(config.depends, settings)) +	: Task(config, addPrefix(config.depends, settings))  	, config(config)  	, settings(settings)  { +	target_type = TargetType::Executable; +  	targetFile = settings.builddir;  	targetFile /= target;  	for(const auto& object : objects) @@ -62,6 +64,17 @@ TaskLD::TaskLD(const BuildConfiguration& config,  	flagsFile = settings.builddir / targetFile.stem();  	flagsFile += ".flags"; + +	target_type = TargetType::Executable; +	_language = Language::C; +	for(const auto& source : config.sources) +	{ +		std::filesystem::path sourceFile(source); +		if(sourceFile.extension().string() != ".c") +		{ +			_language = Language::Cpp; +		} +	}  }  bool TaskLD::dirtyInner() @@ -146,7 +159,13 @@ int TaskLD::runInner()  		std::cout << "LD => " << targetFile.string() << "\n";  	} -	return execute("/usr/bin/g++", args, settings.verbose > 0); +	auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); +	if(language() == Language::C) +	{ +		tool = getConfiguration("host-cc", "/usr/bin/gcc"); +	} + +	return execute(tool, args, settings.verbose > 0);  }  int TaskLD::clean() @@ -40,7 +40,7 @@ TaskSO::TaskSO(const BuildConfiguration& config,                 const Settings& settings,                 const std::string& target,                 const std::vector<std::string>& objects) -	: Task(addPrefix(config.depends, settings)) +	: Task(config, addPrefix(config.depends, settings))  	, config(config)  	, settings(settings)  { @@ -62,6 +62,17 @@ TaskSO::TaskSO(const BuildConfiguration& config,  	flagsFile = settings.builddir / targetFile.stem();  	flagsFile += ".flags"; + +	target_type = TargetType::DynamicLibrary; +	_language = Language::C; +	for(const auto& source : config.sources) +	{ +		std::filesystem::path sourceFile(source); +		if(sourceFile.extension().string() != ".c") +		{ +			_language = Language::Cpp; +		} +	}  }  bool TaskSO::dirtyInner() @@ -142,7 +153,13 @@ int TaskSO::runInner()  		std::cout << "LD => " << targetFile.string() << "\n";  	} -	return execute("/usr/bin/g++", args, settings.verbose > 0); +	auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); +	if(language() == Language::C) +	{ +		tool = getConfiguration("host-cc", "/usr/bin/gcc"); +	} + +	return execute(tool, args, settings.verbose > 0);  }  int TaskSO::clean()  | 
