diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2021-07-10 21:17:49 +0200 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2021-07-10 23:43:37 +0200 | 
| commit | 23b150fd0dedc012e85b405ec92bc3adacfe9959 (patch) | |
| tree | 2f919e89b74906eb15c14ff89e2936dab2936b74 | |
| parent | bfbb506ff1a5e87401d4aa633f0707d1238082d0 (diff) | |
Individual target builds.
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | build.cc | 166 | ||||
| -rw-r--r-- | build.h | 18 | ||||
| -rw-r--r-- | libcppbuild.cc | 129 | ||||
| -rw-r--r-- | task.cc | 5 | ||||
| -rw-r--r-- | task.h | 2 | 
6 files changed, 233 insertions, 88 deletions
@@ -11,6 +11,7 @@ SRC = \  	configure.cc \  	rebuild.cc \  	tasks.cc \ +	build.cc \  OBJ = $(patsubst %.cc,%.o,$(SRC)) diff --git a/build.cc b/build.cc new file mode 100644 index 0000000..6302a18 --- /dev/null +++ b/build.cc @@ -0,0 +1,166 @@ +#include "build.h" + +#include <future> +#include <vector> +#include <iostream> +#include <chrono> +#include <set> + +#include "tasks.h" + +using namespace std::chrono_literals; + +int build(const Settings& settings, +          const std::string& name, +          const std::list<std::shared_ptr<Task>>& tasks, +          const std::list<std::shared_ptr<Task>>& all_tasks) +{ +	if(settings.verbose > 1) +	{ +		std::cout << "Building '" << name << "'\n"; +	} + +	std::list<std::shared_ptr<Task>> dirtyTasks; +	for(auto task : tasks) +	{ +		if(task->dirty()) +		{ +			dirtyTasks.push_back(task); +		} +	} + +	if(dirtyTasks.empty()) +	{ +		std::cout << "Nothing to be done for '"<< name << "'\n"; +		return 0; +	} + +	std::list<std::future<int>> processes; + +	// Start all tasks +	bool done{false}; +	while(!done) +	{ +		bool started_one{false}; +		while(processes.size() < settings.parallel_processes) +		{ +			if(dirtyTasks.empty()) +			{ +				done = true; +				break; +			} + +			auto task = getNextTask(all_tasks, dirtyTasks); +			if(task == nullptr) +			{ +				break; +			} + +			processes.emplace_back( +				std::async(std::launch::async, +				           [task]() +				           { +					           return task->run(); +				           })); +			started_one = true; +			std::this_thread::sleep_for(2ms); +		} + +		for(auto process = processes.begin(); +		    process != processes.end(); +		    ++process) +		{ +			if(process->valid()) +			{ +				if(process->get() != 0) +				{ +					// TODO: Wait for other processes to finish before returning +					return 1; +				} +				processes.erase(process); +				break; +			} +		} + +		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 1; +		} +	} + +	return 0; +} + +namespace +{ +std::set<std::shared_ptr<Task>> getDepTasks(std::shared_ptr<Task> task) +{ +	std::set<std::shared_ptr<Task>> tasks; +	tasks.insert(task); + +	auto deps = task->getDependsTasks(); +	for(const auto& dep : deps) +	{ +		auto depSet = getDepTasks(dep); +		for(const auto& dep : depSet) +		{ +			tasks.insert(dep); +		} +	} + +	return tasks; +} +} + +int build(const Settings& settings, +          const std::string& name, +          const std::list<std::shared_ptr<Task>>& all_tasks) +{ +	bool task_found{false}; +	for(auto task : all_tasks) +	{ +		if(task->name() == name || task->target() == name) +		{ +			std::cout << name << "\n"; +			task_found = true; + +			auto depSet = getDepTasks(task); +			std::list<std::shared_ptr<Task>> ts; +			for(const auto& task : depSet) +			{ +				ts.push_back(task); +			} +			auto ret = build(settings, name, ts, all_tasks); +			if(ret != 0) +			{ +				return ret; +			} + +			break; +		} +	} + +	if(!task_found) +	{ +		std::cerr << "*** No rule to make target '" << name << "'.  Stop.\n"; +		return 1; +	} + +	return 0; +} @@ -0,0 +1,18 @@ +// -*- c++ -*- +#pragma once + +#include <string> +#include <list> +#include <memory> + +#include "task.h" +#include "settings.h" + +int build(const Settings& settings, +          const std::string& name, +          const std::list<std::shared_ptr<Task>>& tasks, +          const std::list<std::shared_ptr<Task>>& all_tasks); + +int build(const Settings& settings, +          const std::string& name, +          const std::list<std::shared_ptr<Task>>& all_tasks); diff --git a/libcppbuild.cc b/libcppbuild.cc index 0bcbad5..1174421 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -4,7 +4,6 @@  #include <iostream>  #include <utility>  #include <list> -#include <chrono>  #include <thread>  #include <memory>  #include <algorithm> @@ -14,7 +13,6 @@  #include <fstream>  #include <cstdlib>  #include <set> -#include <future>  #include <getoptpp/getoptpp.hpp> @@ -23,9 +21,7 @@  #include "configure.h"  #include "rebuild.h"  #include "tasks.h" - -using namespace std::chrono_literals; - +#include "build.h"  int main(int argc, char* argv[])  {  	if(argc > 1 && std::string(argv[1]) == "configure") @@ -53,7 +49,7 @@ int main(int argc, char* argv[])  	int key{128};  	opt.add("jobs", required_argument, 'j', -	        "Number of parallel jobs. (default: cpucount * 2 - 1 )", +	        "Number of parallel jobs. (default: cpucount * 2 - 1)",  	        [&]() {  		        try  		        { @@ -135,7 +131,17 @@ int main(int argc, char* argv[])  	opt.add("help", no_argument, 'h',  	        "Print this help text.",  	        [&]() { -		        std::cout << "usage stuff\n"; +		        std::cout << "Usage: " << argv[0] << " [options] [target] ...\n"; +		        std::cout << +R"_( where target can be either: +   configure - run configuration step (cannot be used with other targets). +   clean     - clean all generated files. +   all       - build all targets (default) + or the name of a target which will be built along with its dependencies. + Use '-l' to see a list of possible target names. + +Options: +)_";  		        opt.help();  		        exit(0);  		        return 0; @@ -186,11 +192,11 @@ int main(int argc, char* argv[])  	std::filesystem::path builddir(settings.builddir);  	std::filesystem::create_directories(builddir); -	auto tasks = getTasks(settings); +	auto all_tasks = getTasks(settings);  	if(list_targets)  	{ -		for(const auto& task : tasks) +		for(const auto& task : all_tasks)  		{  			if(task->targetType() != TargetType::Object)  			{ @@ -205,7 +211,7 @@ int main(int argc, char* argv[])  		std::ofstream istr(compilation_database);  		istr << "[";  		bool first{true}; -		for(auto task : tasks) +		for(auto task : all_tasks)  		{  			auto s = task->toJSON();  			if(!s.empty()) @@ -241,118 +247,65 @@ int main(int argc, char* argv[])  		return 0;  	} -	for(auto task : tasks) +	for(auto task : all_tasks)  	{ -		if(task->registerDepTasks(tasks)) +		if(task->registerDepTasks(all_tasks))  		{  			return 1;  		}  	} -	std::list<std::shared_ptr<Task>> dirtyTasks; -	for(auto task : tasks) +	bool build_all{true}; +	for(auto const &arg : opt.arguments())  	{ -		if(task->dirty()) +		if(arg == "configure")  		{ -			dirtyTasks.push_back(task); +			std::cerr << "The 'configure' target must be the first argument.\n"; +			return 1;  		} -	} -	for(auto const &arg : opt.arguments()) -	{  		if(arg == "clean")  		{ +			build_all = false; +  			std::cout << "Cleaning\n"; -			for(auto& task : tasks) +			for(auto& task : all_tasks)  			{  				if(task->clean() != 0)  				{  					return 1;  				}  			} - -			return 0;  		} - -		if(arg == "configure") -		{ -			std::cerr << "The 'configure' target must be the first argument.\n"; -			return 1; -		} -	} - -	if(dirtyTasks.empty()) -	{ -		return 0; -	} - -	std::cout << "Building\n"; -	std::list<std::future<int>> processes; - -	// Start all tasks -	bool done{false}; -	while(!done) -	{ -		bool started_one{false}; -		while(processes.size() < settings.parallel_processes) +		else  		{ -			if(dirtyTasks.empty()) -			{ -				done = true; -				break; -			} +			build_all = false; -			auto task = getNextTask(tasks, dirtyTasks); -			if(task == nullptr) +			if(arg == "all")  			{ -				break; -				//return 1; +				auto ret = build(settings, "all", all_tasks, all_tasks); +				if(ret != 0) +				{ +					return ret; +				}  			} - -			processes.emplace_back( -				std::async(std::launch::async, -				           [task]() -				           { -					           return task->run(); -				           })); -			started_one = true; -			std::this_thread::sleep_for(2ms); -		} - -		for(auto process = processes.begin(); -		    process != processes.end(); -		    ++process) -		{ -			if(process->valid()) +			else  			{ -				if(process->get() != 0) +				auto ret = build(settings, arg, all_tasks); +				if(ret != 0)  				{ -					return 1; +					return ret;  				} -				processes.erase(process); -				break;  			}  		} - -		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) +	if(build_all)  	{ -		process->wait(); -		auto ret = process->get(); +		auto ret = build(settings, "all", all_tasks, all_tasks);  		if(ret != 0)  		{ -			return 1; +			return ret;  		}  	} @@ -139,3 +139,8 @@ std::string Task::compiler() const  		break;  	}  } + +std::list<std::shared_ptr<Task>> Task::getDependsTasks() +{ +	return dependsTasks; +} @@ -44,6 +44,8 @@ public:  	OutputSystem outputSystem() const;  	std::string compiler() const; +	std::list<std::shared_ptr<Task>> getDependsTasks(); +  protected:  	std::atomic<State> task_state{State::Unknown};  	virtual int runInner() { return 0; };  | 
