diff options
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | cppbuild.cc | 82 | ||||
| m--------- | getoptpp | 0 | ||||
| -rw-r--r-- | libcppbuild.cc | 184 | ||||
| -rw-r--r-- | libcppbuild.h | 1 | ||||
| -rw-r--r-- | settings.h | 1 | ||||
| -rw-r--r-- | task.cc | 70 | ||||
| -rw-r--r-- | task.h | 21 | ||||
| -rw-r--r-- | task_ar.cc | 188 | ||||
| -rw-r--r-- | task_ar.h | 42 | ||||
| -rw-r--r-- | task_cc.cc | 14 | ||||
| -rw-r--r-- | task_cc.h | 4 | ||||
| -rw-r--r-- | task_ld.cc | 54 | ||||
| -rw-r--r-- | task_ld.h | 5 | 
15 files changed, 565 insertions, 106 deletions
| diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1c313f3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "getoptpp"] +	path = getoptpp +	url = git://git.drumgizmo.org/getoptpp.git @@ -4,6 +4,8 @@ SRC = \  	libcppbuild.cc \  	task_cc.cc \  	task_ld.cc \ +	task_ar.cc \ +	task.cc \  	execute.cc \  OBJ = $(patsubst %.cc,%.o,$(SRC)) diff --git a/cppbuild.cc b/cppbuild.cc index 370e179..737ba83 100644 --- a/cppbuild.cc +++ b/cppbuild.cc @@ -23,11 +23,8 @@ std::vector<BuildConfiguration> configs()  	return  	{  		{ -			// target -			"plugingui", - -			// source files -			{ +			.target = "plugingui", +			.sources = {  				"drumgizmo/src/audiocache.cc",  				"drumgizmo/src/audiocacheeventhandler.cc",  				"drumgizmo/src/audiocachefile.cc", @@ -69,6 +66,50 @@ std::vector<BuildConfiguration> configs()  				"drumgizmo/src/velocityfilter.cc",  				"drumgizmo/src/versionstr.cc",  				"drumgizmo/src/zrwrapper.cc", +				"drumgizmo/zita-resampler/libs/cresampler.cc", +				"drumgizmo/zita-resampler/libs/resampler-table.cc", +				"drumgizmo/zita-resampler/libs/resampler.cc", +				"drumgizmo/zita-resampler/libs/vresampler.cc", +				"drumgizmo/hugin/hugin.c", +				"drumgizmo/pugixml/src/pugixml.cpp", +				"drumgizmo/plugingui/lodepng/lodepng.cpp", +			}, +			.depends = { +				"plugingui.a", +			}, +			.cxxflags = { +				"-DUI_X11", +				"-O3", +				"-g", +				"-Wall", +				"-Werror", +				"-std=c++11", +				"-Idrumgizmo/getoptpp", +				"-Idrumgizmo/", +				"-Idrumgizmo/hugin", +				"-Idrumgizmo/plugingui/", +				"-Idrumgizmo/src/", +				"-Idrumgizmo/zita-resampler/libs", +				"-Idrumgizmo/pugixml/src", +			}, +			.cflags = { +				"-g", +				//"-O3", +				"-Wall", +				"-Werror", +			}, +			.ldflags = { +				"-lm", +				"-lX11", +				"-lXext", +				"-lsndfile", +				"-pthread", +			} +		}, + +		{ +			.target = "plugingui.a", +			.sources = {  				"drumgizmo/plugingui/abouttab.cc",  				"drumgizmo/plugingui/bleedcontrolframecontent.cc",  				"drumgizmo/plugingui/button.cc", @@ -130,18 +171,11 @@ std::vector<BuildConfiguration> configs()  				"drumgizmo/plugingui/voicelimitframecontent.cc",  				"drumgizmo/plugingui/widget.cc",  				"drumgizmo/plugingui/window.cc", -				"drumgizmo/zita-resampler/libs/cresampler.cc", -				"drumgizmo/zita-resampler/libs/resampler-table.cc", -				"drumgizmo/zita-resampler/libs/resampler.cc", -				"drumgizmo/zita-resampler/libs/vresampler.cc", -				"drumgizmo/hugin/hugin.c", -				"drumgizmo/pugixml/src/pugixml.cpp", -				"drumgizmo/plugingui/lodepng/lodepng.cpp",  			}, - -			// cxx flags -			{ +			.depends = {}, +			.cxxflags = {  				"-DUI_X11", +				"-O3",  				"-g",  				"-Wall",  				"-Werror", @@ -154,22 +188,8 @@ std::vector<BuildConfiguration> configs()  				"-Idrumgizmo/zita-resampler/libs",  				"-Idrumgizmo/pugixml/src",  			}, - -			// c flags -			{ -				"-g", -				"-Wall", -				"-Werror", -			}, - -			// linker flags -			{ -				"-lm", -				"-lX11", -				"-lXext", -				"-pthread", -				"-lsndfile", -			} +			.cflags = {}, +			.ldflags = {}  		},  	};  } diff --git a/getoptpp b/getoptpp new file mode 160000 +Subproject 9ff20ef857429619267e3f156a4f81ad9e1eb8c diff --git a/libcppbuild.cc b/libcppbuild.cc index bf1a7fa..7f0a355 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -7,16 +7,67 @@  #include <chrono>  #include <thread>  #include <memory> +#include <algorithm> +#include <list>  #include "libcppbuild.h"  #include "task_cc.h"  #include "task_ld.h" +#include "task_ar.h"  #include "settings.h"  #include <unistd.h>  using namespace std::chrono_literals; +std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config, +                                             const Settings& settings) +{ +	std::vector<std::string> objects; +	std::list<std::shared_ptr<Task>> tasks; +	for(const auto& file : config.sources) +	{ +		tasks.emplace_back(std::make_shared<TaskCC>(config, settings, file)); +		objects.push_back(tasks.back()->target()); +	} + +	std::filesystem::path targetFile(config.target); +	if(targetFile.extension() == ".a") +	{ +		// static lib +		tasks.emplace_back(std::make_shared<TaskAR>(config, settings, config.target, +		                                            objects)); +	} +	else +	{ +		// binary +		tasks.emplace_back(std::make_shared<TaskLD>(config, settings, config.target, +		                                            objects)); + +	} + +	return tasks; +} + +std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks, +                                  std::list<std::shared_ptr<Task>>& dirtyTasks) +{ +	for(auto dirtyTask = dirtyTasks.begin(); +	    dirtyTask != dirtyTasks.end(); +	    ++dirtyTask) +	{ +		//std::cout << "Examining target " << (*dirtyTask)->target() << "\n"; +		if((*dirtyTask)->ready()) +		{ +			dirtyTasks.erase(dirtyTask); +			return *dirtyTask; +		} +	} + +	//std::cout << "No task ready ... \n"; +	return nullptr; +} +  int main(int argc, const char* argv[])  {  	Settings settings; @@ -27,84 +78,79 @@ int main(int argc, const char* argv[])  	settings.parallel_processes =  		std::max(1u, std::thread::hardware_concurrency() * 2 - 1); +	settings.verbose = 0; +  	std::filesystem::path builddir(settings.builddir);  	std::filesystem::create_directories(builddir);  	auto build_configs = configs(); +	std::list<std::shared_ptr<Task>> tasks;  	for(const auto& build_config : build_configs)  	{  		std::vector<std::string> objects; -		std::vector<std::unique_ptr<Task>> tasks; -		for(const auto& file : build_config.sources) -		{ -			tasks.emplace_back(std::make_unique<TaskCC>(build_config, settings, file)); -			objects.push_back(tasks.back()->target()); -		} +		auto t = taskFactory(build_config, settings); +		tasks.insert(tasks.end(), t.begin(), t.end()); +	} -		TaskLD task_ld(build_config, settings, build_config.target, objects); +	for(auto task : tasks) +	{ +		task->registerDepTasks(tasks); +	} -		if(argc == 2 && std::string(argv[1]) == "clean") +	std::list<std::shared_ptr<Task>> dirtyTasks; +	for(auto task : tasks) +	{ +		if(task->dirty())  		{ -			std::cout << "Cleaning\n"; -			//std::filesystem::remove_all(builddir); -			for(auto& task : tasks) -			{ -				if(task->clean() != 0) -				{ -					return 1; -				} -			} +			dirtyTasks.push_back(task); +		} +	} -			if(task_ld.clean() != 0) +	if(argc == 2 && std::string(argv[1]) == "clean") +	{ +		std::cout << "Cleaning\n"; +		//std::filesystem::remove_all(builddir); +		for(auto& task : tasks) +		{ +			if(task->clean() != 0)  			{  				return 1;  			} - -			return 0;  		} -		std::cout << "Building\n"; +		return 0; +	} -		std::list<std::future<int>> processes; +	std::cout << "Building\n"; +	std::list<std::future<int>> processes; -		// Start all tasks -		auto task = tasks.begin(); -		while(task != tasks.end()) +	// Start all tasks +	bool done{false}; +	while(!done) +	{ +		bool started_one{false}; +		while(processes.size() < settings.parallel_processes)  		{ -			while(processes.size() < settings.parallel_processes && -			      task != tasks.end()) +			if(dirtyTasks.empty())  			{ -				if(!(*task)->dirty()) -				{ -					++task; -					continue; -				} - -				processes.emplace_back( -					std::async(std::launch::async, -					           [&t = *task]() -					           { -						           return t->run(); -					           })); -				++task; -				std::this_thread::sleep_for(2ms); +				done = true; +				break;  			} -			for(auto process = processes.begin(); -			    process != processes.end(); -			    ++process) +			auto task = getNextTask(tasks, dirtyTasks); +			if(task == nullptr)  			{ -				if(process->valid()) -				{ -					if(process->get() != 0) -					{ -						return 1; -					} -					processes.erase(process); -					break; -				} +				break; +				//return 1;  			} +			processes.emplace_back( +				std::async(std::launch::async, +				           [task]() +				           { +					           return task->run(); +				           })); +			started_one = true;  			std::this_thread::sleep_for(2ms);  		} @@ -112,18 +158,36 @@ int main(int argc, const char* argv[])  		    process != processes.end();  		    ++process)  		{ -			process->wait(); -			auto ret = process->get(); -			if(ret != 0) +			if(process->valid())  			{ -				return 1; +				if(process->get() != 0) +				{ +					return 1; +				} +				processes.erase(process); +				break;  			}  		} -		std::cout << "Linking\n"; -		if(task_ld.dirty()) +		if(started_one) +		{ +			std::this_thread::sleep_for(2ms); +		} +		else +		{ +			std::this_thread::sleep_for(200ms); +		} +	} + +	for(auto process = processes.begin(); +	    process != processes.end(); +	    ++process) +	{ +		process->wait(); +		auto ret = process->get(); +		if(ret != 0)  		{ -			return task_ld.run(); +			return 1;  		}  	} diff --git a/libcppbuild.h b/libcppbuild.h index 6cc04ac..50b4459 100644 --- a/libcppbuild.h +++ b/libcppbuild.h @@ -8,6 +8,7 @@ struct BuildConfiguration  {  	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; @@ -7,4 +7,5 @@ struct Settings  {  	std::string builddir;  	std::size_t parallel_processes; +	int verbose{1};  }; @@ -0,0 +1,70 @@ +#include "task.h" + +#include <unistd.h> +#include <iostream> + +Task::Task(const std::vector<std::string>& depends) +	: dependsStr(depends) +{ +} + +void Task::registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks) +{ +	for(auto const& depStr : dependsStr) +	{ +		for(const auto& task : tasks) +		{ +			if(task->target() == depStr) +			{ +				dependsTasks.push_back(task); +			} +		} +	} +} + +bool Task::dirty() +{ +	for(const auto& task : dependsTasks) +	{ +		if(task->dirty()) +		{ +			return true; +		} +	} + +	return dirtyInner(); +} + +bool Task::ready() +{ +	for(const auto& task : dependsTasks) +	{ +		if(task->dirty() && !task->done()) +		{ +			return false; +		} +	} + +	return true; +} + +int Task::run() +{ +	if(is_done.load()) +	{ +		return 0; +	} + +	auto ret = runInner(); +	if(ret == 0) +	{ +		is_done.store(true); +	} + +	return ret; +} + +bool Task::done() const +{ +	return is_done.load(); +} @@ -3,13 +3,30 @@  #include <vector>  #include <string> +#include <atomic> +#include <list> +#include <memory>  class Task  {  public: -	virtual bool dirty() = 0; -	virtual int run() = 0; +	Task(const std::vector<std::string>& depends); + +	void registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks); + +	bool dirty(); +	bool ready(); +	int run(); +	bool done() const;  	virtual int clean() = 0 ;  	virtual std::vector<std::string> depends() const = 0;  	virtual std::string target() const = 0; + +protected: +	std::atomic<bool> is_done{false}; +	virtual int runInner() { return 0; }; +	virtual bool dirtyInner() { return false; } + +	std::vector<std::string> dependsStr; +	std::list<std::shared_ptr<Task>> dependsTasks;  }; diff --git a/task_ar.cc b/task_ar.cc new file mode 100644 index 0000000..c133875 --- /dev/null +++ b/task_ar.cc @@ -0,0 +1,188 @@ +#include "task_ar.h" + +#include <iostream> +#include <fstream> + +#include "libcppbuild.h" +#include "settings.h" +#include "execute.h" + +namespace +{ +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(); +	ifs.seekg(0, std::ios::beg); + +	std::vector<char> bytes(fileSize); +	ifs.read(bytes.data(), fileSize); + +	return std::string(bytes.data(), fileSize); +} + +std::vector<std::string> addPrefix(const std::vector<std::string>& lst, +                                   const Settings& settings) +{ +	std::vector<std::string> out; +	for(const auto& item : lst) +	{ +		std::filesystem::path file = settings.builddir; +		file /= item; +		out.push_back(file.string()); +	} +	return out; +} +} // namespace :: + +TaskAR::TaskAR(const BuildConfiguration& config, +               const Settings& settings, +               const std::string& target, +               const std::vector<std::string>& objects) +	: Task(addPrefix(config.depends, settings)) +	, config(config) +	, settings(settings) +{ +	targetFile = settings.builddir; +	targetFile /= target; +	for(const auto& object : objects) +	{ +		std::filesystem::path objectFile = object; +		objectFiles.push_back(objectFile); +		dependsStr.push_back(objectFile); +	} + +	for(const auto& dep : config.depends) +	{ +		std::filesystem::path depFile = settings.builddir; +		depFile /= dep; +		depFiles.push_back(depFile); +	} + +	flagsFile = settings.builddir / targetFile.stem(); +	flagsFile += ".flags"; +} + +bool TaskAR::dirtyInner() +{ +	if(!std::filesystem::exists(targetFile)) +	{ +		return true; +	} + +	if(!std::filesystem::exists(flagsFile)) +	{ +		return true; +	} + +	for(const auto& objectFile : objectFiles) +	{ +		if(std::filesystem::last_write_time(targetFile) <= +		   std::filesystem::last_write_time(objectFile)) +		{ +			return true; +		} +	} + +	{ +		auto lastFlags = readFile(flagsFile); +		if(flagsString() != lastFlags) +		{ +			//std::cout << "The compiler flags changed\n"; +			return true; +		} +	} + +	return false; +} + +int TaskAR::runInner() +{ +	std::string objectlist; +	for(const auto& objectFile : objectFiles) +	{ +		if(!objectlist.empty()) +		{ +			objectlist += " "; +		} +		objectlist += std::string(objectFile); +	} + +	std::vector<std::string> args; +	args.push_back("rcs"); +	args.push_back(std::string(targetFile)); +	for(const auto& objectFile : objectFiles) +	{ +		args.push_back(std::string(objectFile)); +	} +	for(const auto& flag : config.ldflags) +	{ +		args.push_back(flag); +	} + +	{ // Write flags to file. +		std::ofstream flagsStream(flagsFile); +		flagsStream << flagsString(); +	} + +	if(settings.verbose == 0) +	{ +		std::cout << "AR => " << targetFile.string() << "\n"; +	} + +	return execute("/usr/bin/ar", args, settings.verbose > 0); +} + +int TaskAR::clean() +{ +	if(std::filesystem::exists(targetFile)) +	{ +		std::cout << "Removing " << std::string(targetFile) << "\n"; +		std::filesystem::remove(targetFile); +	} + +	if(std::filesystem::exists(flagsFile)) +	{ +		std::cout << "Removing " << std::string(flagsFile) << "\n"; +		std::filesystem::remove(flagsFile); +	} + +	return 0; +} + +std::vector<std::string> TaskAR::depends() const +{ +	std::vector<std::string> deps; +	for(const auto& objectFile : objectFiles) +	{ +		deps.push_back(objectFile.string()); +	} + +	for(const auto& depFile : depFiles) +	{ +		deps.push_back(depFile.string()); +	} + +	return deps; +} + +std::string TaskAR::target() const +{ +	return targetFile.string(); +} + +std::string TaskAR::flagsString() const +{ +	std::string flagsStr; +	for(const auto& flag : config.ldflags) +	{ +		if(!flagsStr.empty()) +		{ +			flagsStr += " "; +		} +		flagsStr += flag; +	} +	return flagsStr; +} diff --git a/task_ar.h b/task_ar.h new file mode 100644 index 0000000..bfa21a2 --- /dev/null +++ b/task_ar.h @@ -0,0 +1,42 @@ +// -*- c++ -*- +#pragma once + +#include "task.h" + +#include <vector> +#include <string> +#include <future> +#include <filesystem> + +struct BuildConfiguration; +struct Settings; + +class TaskAR +	: public Task +{ +public: +	TaskAR(const BuildConfiguration& config, +	       const Settings& settings, +	       const std::string& target, +	       const std::vector<std::string>& objects); + +	bool dirtyInner() override; + +	int runInner() override; +	int clean() override; + +	std::vector<std::string> depends() const override; + +	std::string target() const override; + +private: +	std::string flagsString() const; + +	std::vector<std::filesystem::path> objectFiles; +	std::vector<std::filesystem::path> depFiles; +	std::filesystem::path targetFile; +	std::filesystem::path flagsFile; + +	const BuildConfiguration& config; +	const Settings& settings; +}; @@ -85,7 +85,8 @@ std::vector<std::string> readDeps(const std::string& depFile)  TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,                 const std::string& source) -	: config(config) +	: Task({}) +	, config(config)  	, settings(settings)  {  	sourceFile = source; @@ -100,7 +101,7 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,  	flagsFile += ".flags";  } -bool TaskCC::dirty() +bool TaskCC::dirtyInner()  {  	if(!std::filesystem::exists(sourceFile))  	{ @@ -164,7 +165,7 @@ bool TaskCC::dirty()  	return false;  } -int TaskCC::run() +int TaskCC::runInner()  {  	if(!std::filesystem::exists(sourceFile))  	{ @@ -192,7 +193,12 @@ int TaskCC::run()  		flagsStream << flagsString();  	} -	return execute(comp, args); +	if(settings.verbose == 0) +	{ +		std::cout << compiler() << " " << sourceFile.string() << " => " << +			targetFile.string() << "\n"; +	} +	return execute(comp, args, settings.verbose > 0);  }  int TaskCC::clean() @@ -19,9 +19,9 @@ public:  	       const Settings& settings,  	       const std::string& source); -	bool dirty() override; +	bool dirtyInner() override; -	int run() override; +	int runInner() override;  	int clean() override;  	std::vector<std::string> depends() const override; @@ -21,13 +21,27 @@ std::string readFile(const std::string &fileName)  	return std::string(bytes.data(), fileSize);  } + +std::vector<std::string> addPrefix(const std::vector<std::string>& lst, +                                   const Settings& settings) +{ +	std::vector<std::string> out; +	for(const auto& item : lst) +	{ +		std::filesystem::path file = settings.builddir; +		file /= item; +		out.push_back(file.string()); +	} +	return out; +}  } // namespace ::  TaskLD::TaskLD(const BuildConfiguration& config,                 const Settings& settings,                 const std::string& target,                 const std::vector<std::string>& objects) -	: config(config) +	: Task(addPrefix(config.depends, settings)) +	, config(config)  	, settings(settings)  {  	targetFile = settings.builddir; @@ -36,13 +50,21 @@ TaskLD::TaskLD(const BuildConfiguration& config,  	{  		std::filesystem::path objectFile = object;  		objectFiles.push_back(objectFile); +		dependsStr.push_back(objectFile); +	} + +	for(const auto& dep : config.depends) +	{ +		std::filesystem::path depFile = settings.builddir; +		depFile /= dep; +		depFiles.push_back(depFile);  	}  	flagsFile = settings.builddir / targetFile.stem();  	flagsFile += ".flags";  } -bool TaskLD::dirty() +bool TaskLD::dirtyInner()  {  	if(!std::filesystem::exists(targetFile))  	{ @@ -75,7 +97,7 @@ bool TaskLD::dirty()  	return false;  } -int TaskLD::run() +int TaskLD::runInner()  {  	std::string objectlist;  	for(const auto& objectFile : objectFiles) @@ -92,6 +114,12 @@ int TaskLD::run()  	{  		args.push_back(std::string(objectFile));  	} + +	for(const auto& depFile : depFiles) +	{ +		args.push_back(depFile.string()); +	} +  	for(const auto& flag : config.ldflags)  	{  		args.push_back(flag); @@ -104,7 +132,12 @@ int TaskLD::run()  		flagsStream << flagsString();  	} -	return execute("/usr/bin/g++", args); +	if(settings.verbose == 0) +	{ +		std::cout << "LD => " << targetFile.string() << "\n"; +	} + +	return execute("/usr/bin/g++", args, settings.verbose > 0);  }  int TaskLD::clean() @@ -126,7 +159,18 @@ int TaskLD::clean()  std::vector<std::string> TaskLD::depends() const  { -	return {}; +	std::vector<std::string> deps; +	for(const auto& objectFile : objectFiles) +	{ +		deps.push_back(objectFile.string()); +	} + +	for(const auto& depFile : depFiles) +	{ +		deps.push_back(depFile.string()); +	} + +	return deps;  }  std::string TaskLD::target() const @@ -20,9 +20,9 @@ public:  	       const std::string& target,  	       const std::vector<std::string>& objects); -	bool dirty() override; +	bool dirtyInner() override; -	int run() override; +	int runInner() override;  	int clean() override;  	std::vector<std::string> depends() const override; @@ -33,6 +33,7 @@ private:  	std::string flagsString() const;  	std::vector<std::filesystem::path> objectFiles; +	std::vector<std::filesystem::path> depFiles;  	std::filesystem::path targetFile;  	std::filesystem::path flagsFile; | 
