diff options
| -rw-r--r-- | Makefile | 9 | ||||
| -rw-r--r-- | libcppbuild.cc | 72 | ||||
| -rw-r--r-- | task.cc | 263 | ||||
| -rw-r--r-- | task.h | 30 | ||||
| -rw-r--r-- | task_cc.cc | 267 | ||||
| -rw-r--r-- | task_cc.h | 38 | ||||
| -rw-r--r-- | task_ld.cc | 89 | ||||
| -rw-r--r-- | task_ld.h | 38 | 
8 files changed, 464 insertions, 342 deletions
| @@ -1,12 +1,13 @@  all: libcppbuild.a cppbuild -libcppbuild.a: libcppbuild.cc task.cc libcppbuild.h +libcppbuild.a: libcppbuild.cc libcppbuild.h task_cc.cc task_cc.h task_ld.cc task_ld.h task.h  	g++ -g -std=c++17  libcppbuild.cc -c -o libcppbuild.o -	g++ -g -std=c++17  task.cc -c -o task.o -	ar rcs libcppbuild.a libcppbuild.o task.o +	g++ -g -std=c++17  task_cc.cc -c -o task_cc.o +	g++ -g -std=c++17  task_ld.cc -c -o task_ld.o +	ar rcs libcppbuild.a libcppbuild.o task_cc.o task_ld.o  cppbuild: cppbuild.cc  libcppbuild.h libcppbuild.a  	g++ -g -std=c++17 cppbuild.cc libcppbuild.a -pthread -o cppbuild  clean: -	rm -f cppbuild libcppbuild.o task.o libcppbuild.a +	rm -f cppbuild libcppbuild.o task_cc.o task_ld.o libcppbuild.a diff --git a/libcppbuild.cc b/libcppbuild.cc index 2167173..c75f43e 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -6,9 +6,11 @@  #include <list>  #include <chrono>  #include <thread> +#include <memory>  #include "libcppbuild.h" -#include "task.h" +#include "task_cc.h" +#include "task_ld.h"  #include "settings.h"  #include <unistd.h> @@ -29,31 +31,33 @@ int main(int argc, const char* argv[])  	std::filesystem::create_directories(builddir);  	auto config = configs(); -	std::string output = builddir / config.target; -	const auto& files = config.sources; -	std::vector<std::string> objects; - -	std::vector<Task> tasks; -	for(const auto& file : files) +	std::vector<std::string> objects; +	std::vector<std::unique_ptr<Task>> tasks; +	for(const auto& file : config.sources)  	{ -		tasks.emplace_back(config, settings, file); -		objects.push_back(tasks.back().target()); +		tasks.emplace_back(std::make_unique<TaskCC>(config, settings, file)); +		objects.push_back(tasks.back()->target());  	} +	TaskLD task_ld(config, settings, config.target, objects); +  	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) +			if(task->clean() != 0)  			{  				return 1;  			}  		} -		std::filesystem::remove(output); +		if(task_ld.clean() != 0) +		{ +			return 1; +		}  		return 0;  	} @@ -69,7 +73,7 @@ int main(int argc, const char* argv[])  		while(processes.size() < settings.parallel_processes &&  		      task != tasks.end())  		{ -			if(!task->dirty()) +			if(!(*task)->dirty())  			{  				++task;  				continue; @@ -77,9 +81,9 @@ int main(int argc, const char* argv[])  			processes.emplace_back(  				std::async(std::launch::async, -				           [task]() +				           [&t = *task]()  				           { -					           return task->run(); +					           return t->run();  				           }));  			++task;  			std::this_thread::sleep_for(2ms); @@ -108,49 +112,17 @@ int main(int argc, const char* argv[])  	    ++process)  	{  		process->wait(); -		if(process->get() != 0) +		auto ret = process->get(); +		if(ret != 0)  		{  			return 1;  		}  	}  	std::cout << "Linking\n"; -	bool dolink{false}; -	if(!std::filesystem::exists(output)) -	{ -		dolink = true; -	} -	else -	{ -		for(const auto& object : objects) -		{ -			if(std::filesystem::last_write_time(output) <= -			   std::filesystem::last_write_time(object)) -			{ -				dolink = true; -				break; -			} -		} -	} - -	if(!dolink) -	{ -		std::cout << "No linking needed\n"; -		return 0; -	} - -	std::string objectlist; -	for(const auto& object : objects) -	{ -		objectlist += object + " "; -	} -	std::string compiler = "g++ " + objectlist + " " + -		config.ldflags + " " + -		"-o " + output; -	std::cout << compiler << "\n"; -	if(system(compiler.data())) +	if(task_ld.dirty())  	{ -		return 1; +		return task_ld.run();  	}  	return 0; @@ -1,263 +0,0 @@ -#include "task.h" - -#include <iostream> -#include <fstream> -#include <unistd.h> -#include <cstring> -#include <sys/types.h> -#include <sys/wait.h> -#include <spawn.h> - -#include "libcppbuild.h" -#include "settings.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> readDeps(const std::string& depFile) -{ -	if(!std::filesystem::exists(depFile)) -	{ -		return {}; -	} - -	auto str = readFile(depFile); - -	std::vector<std::string> output; -	std::string tmp; -	bool start{false}; -	bool in_whitespace{false}; -	for(const auto& c : str) -	{ -		if(c == '\\' || c == '\n') -		{ -			continue; -		} - -		if(c == ':') -		{ -			start = true; -			continue; -		} - -		if(!start) -		{ -			continue; -		} - -		if(c == ' ' || c == '\t') -		{ -			if(in_whitespace) -			{ -				continue; -			} - -			if(!tmp.empty()) -			{ -				output.push_back(tmp); -			} -			tmp.clear(); -			in_whitespace = true; -		} -		else -		{ -			in_whitespace = false; -			tmp += c; -		} -	} - -	if(!tmp.empty()) -	{ -		output.push_back(tmp); -	} - -	return output; -} -} // namespace :: - -Task::Task(const BuildConfiguration& config, const Settings& settings, -           const std::string& source) -	: config(config) -	, settings(settings) -{ -	sourceFile = source; -	targetFile = settings.builddir / sourceFile.stem(); -	targetFile += ".o"; -	depsFile = settings.builddir / sourceFile.stem(); -	depsFile += ".d"; -} - -bool Task::dirty() -{ -	if(!std::filesystem::exists(sourceFile)) -	{ -		//std::cout << "Missing source file: " << std::string(sourceFile) << "\n"; -		return true; -	} - -	if(!std::filesystem::exists(targetFile)) -	{ -		//std::cout << "Missing targetFile\n"; -		return true; -	} - -	if(!std::filesystem::exists(depsFile)) -	{ -		//std::cout << "Missing depsFile\n"; -		return true; -	} - -	if(std::filesystem::last_write_time(sourceFile) > -	   std::filesystem::last_write_time(depsFile)) -	{ -		//std::cout << "The sourceFile newer than depsFile\n"; -		return true; -	} - -	auto depList = readDeps(depsFile); -	for(const auto& dep : depList) -	{ -		if(!std::filesystem::exists(dep) || -		   std::filesystem::last_write_time(targetFile) < -		   std::filesystem::last_write_time(dep)) -		{ -			//std::cout << "The targetFile older than " << std::string(dep) << "\n"; -			return true; -		} -	} - -	if(std::filesystem::last_write_time(sourceFile) > -	   std::filesystem::last_write_time(targetFile)) -	{ -		//std::cout << "The targetFile older than sourceFile\n"; -		return true; -	} - -	return false; -} - -int parent_waitpid(pid_t pid) -{ -	int status; - -	if(waitpid(pid, &status, 0) != pid) -	{ -		return 1; -	} - -	return status; -} -int Task::run() -{ -	if(!std::filesystem::exists(sourceFile)) -	{ -		std::cout << "Missing source file: " << std::string(sourceFile) << "\n"; -		return 1; -	} - -	std::string comp = "/usr/bin/g++"; -	auto flags = config.cxxflags; -	if(std::string(sourceFile.extension()) == ".c") -	{ -		comp = "/usr/bin/gcc"; -		flags = config.cflags; -	} - -	char source[256]; -	strcpy(source, std::string(sourceFile).data()); -	char target[256]; -	strcpy(target, std::string(targetFile).data()); -	char pwd[256]; -	strcpy(pwd, std::string(std::filesystem::current_path()).data()); -	std::vector<const char*> argv; -	//args.push_back("/bin/echo"); -	if(comp == "/usr/bin/gcc") -	{ -		argv.push_back("/usr/bin/gcc"); -	} -	else -	{ -		argv.push_back("/usr/bin/g++"); -	} - -	argv.push_back("-MMD"); -	argv.push_back("-c"); -	argv.push_back(source); -	argv.push_back("-o"); -	argv.push_back(target); - -	for(const auto& flag : flags) -	{ -		argv.push_back(flag.data()); -	} - -	std::string cmd; -	for(const auto& arg : argv) -	{ -		if(arg == nullptr) -		{ -			break; -		} -		if(!cmd.empty()) -		{ -			cmd += " "; -		} -		cmd += arg; -	} -	std::cout << cmd << "\n"; - -#if 0 -	auto pid = vfork(); -	if(pid == 0) -	{ -		execv(comp.data(), (char**)argv.data()); -	} -#else -	pid_t pid; -	if(posix_spawn(&pid, comp.data(), nullptr, nullptr, (char**)argv.data(), nullptr)) -	{ -		return 1;//exit(1); -	} -#endif - -	return parent_waitpid(pid); -} - -int Task::clean() -{ -	if(std::filesystem::exists(targetFile)) -	{ -		std::cout << "Removing " << std::string(targetFile) << "\n"; -		std::filesystem::remove(targetFile); -	} - -	if(std::filesystem::exists(depsFile)) -	{ -		std::cout << "Removing " << std::string(depsFile) << "\n"; -		std::filesystem::remove(depsFile); -	} - -	return 0; -} - -std::vector<std::string> Task::depends() const -{ -	return {}; -} - -std::string Task::target() const -{ -	return targetFile; -} @@ -3,33 +3,13 @@  #include <vector>  #include <string> -#include <future> -#include <filesystem> - -struct BuildConfiguration; -struct Settings;  class Task  {  public: -	Task(const BuildConfiguration& config, -	     const Settings& settings, -	     const std::string& source); - -	bool dirty(); - -	int run(); -	int clean(); - -	std::vector<std::string> depends() const; - -	std::string target() const; - -private: -	std::filesystem::path sourceFile; -	std::filesystem::path targetFile; -	std::filesystem::path depsFile; - -	const BuildConfiguration& config; -	const Settings& settings; +	virtual bool dirty() = 0; +	virtual int run() = 0; +	virtual int clean() = 0 ; +	virtual std::vector<std::string> depends() const = 0; +	virtual std::string target() const = 0;  }; diff --git a/task_cc.cc b/task_cc.cc new file mode 100644 index 0000000..2a65698 --- /dev/null +++ b/task_cc.cc @@ -0,0 +1,267 @@ +#include "task_cc.h" + +#include <iostream> +#include <fstream> +#include <unistd.h> +#include <cstring> +#include <sys/types.h> +#include <sys/wait.h> +#include <spawn.h> + +#include "libcppbuild.h" +#include "settings.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> readDeps(const std::string& depFile) +{ +	if(!std::filesystem::exists(depFile)) +	{ +		return {}; +	} + +	auto str = readFile(depFile); + +	std::vector<std::string> output; +	std::string tmp; +	bool start{false}; +	bool in_whitespace{false}; +	for(const auto& c : str) +	{ +		if(c == '\\' || c == '\n') +		{ +			continue; +		} + +		if(c == ':') +		{ +			start = true; +			continue; +		} + +		if(!start) +		{ +			continue; +		} + +		if(c == ' ' || c == '\t') +		{ +			if(in_whitespace) +			{ +				continue; +			} + +			if(!tmp.empty()) +			{ +				output.push_back(tmp); +			} +			tmp.clear(); +			in_whitespace = true; +		} +		else +		{ +			in_whitespace = false; +			tmp += c; +		} +	} + +	if(!tmp.empty()) +	{ +		output.push_back(tmp); +	} + +	return output; +} +} // namespace :: + +TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, +               const std::string& source) +	: config(config) +	, settings(settings) +{ +	sourceFile = source; +	targetFile = settings.builddir / sourceFile.stem(); +	targetFile += ".o"; +	depsFile = settings.builddir / sourceFile.stem(); +	depsFile += ".d"; +} + +bool TaskCC::dirty() +{ +	if(!std::filesystem::exists(sourceFile)) +	{ +		//std::cout << "Missing source file: " << std::string(sourceFile) << "\n"; +		return true; +	} + +	if(!std::filesystem::exists(targetFile)) +	{ +		//std::cout << "Missing targetFile\n"; +		return true; +	} + +	if(!std::filesystem::exists(depsFile)) +	{ +		//std::cout << "Missing depsFile\n"; +		return true; +	} + +	if(std::filesystem::last_write_time(sourceFile) > +	   std::filesystem::last_write_time(depsFile)) +	{ +		//std::cout << "The sourceFile newer than depsFile\n"; +		return true; +	} + +	auto depList = readDeps(depsFile); +	for(const auto& dep : depList) +	{ +		if(!std::filesystem::exists(dep) || +		   std::filesystem::last_write_time(targetFile) < +		   std::filesystem::last_write_time(dep)) +		{ +			//std::cout << "The targetFile older than " << std::string(dep) << "\n"; +			return true; +		} +	} + +	if(std::filesystem::last_write_time(sourceFile) > +	   std::filesystem::last_write_time(targetFile)) +	{ +		//std::cout << "The targetFile older than sourceFile\n"; +		return true; +	} + +	return false; +} + +int parent_waitpid(pid_t pid) +{ +	int status; + +	if(waitpid(pid, &status, 0) != pid) +	{ +		return 1; +	} + +	return status; +} +int TaskCC::run() +{ +	if(!std::filesystem::exists(sourceFile)) +	{ +		std::cout << "Missing source file: " << std::string(sourceFile) << "\n"; +		return 1; +	} + +	std::string comp = "/usr/bin/g++"; +	auto flags = config.cxxflags; +	if(std::string(sourceFile.extension()) == ".c") +	{ +		comp = "/usr/bin/gcc"; +		flags = config.cflags; +	} + +	char source[256]; +	strcpy(source, std::string(sourceFile).data()); +	char target[256]; +	strcpy(target, std::string(targetFile).data()); +	char pwd[256]; +	strcpy(pwd, std::string(std::filesystem::current_path()).data()); +	std::vector<const char*> argv; +	//args.push_back("/bin/echo"); +	if(comp == "/usr/bin/gcc") +	{ +		argv.push_back("/usr/bin/gcc"); +	} +	else +	{ +		argv.push_back("/usr/bin/g++"); +	} + +	argv.push_back("-MMD"); +	argv.push_back("-c"); +	argv.push_back(source); +	argv.push_back("-o"); +	argv.push_back(target); + +	for(const auto& flag : flags) +	{ +		argv.push_back(flag.data()); +	} + +	std::string cmd; +	for(const auto& arg : argv) +	{ +		if(arg == nullptr) +		{ +			break; +		} +		if(!cmd.empty()) +		{ +			cmd += " "; +		} +		cmd += arg; +	} +	std::cout << cmd << "\n"; + +#if 0 +	auto pid = vfork(); +	if(pid == 0) +	{ +		execv(comp.data(), (char**)argv.data()); +	} +	auto ret = parent_waitpid(pid); +#elif 0 +	pid_t pid; +	if(posix_spawn(&pid, comp.data(), nullptr, nullptr, (char**)argv.data(), nullptr)) +	{ +		return 1;//exit(1); +	} +	auto ret = parent_waitpid(pid); +#else +	auto ret = system(cmd.data()); +#endif + +	return ret; +} + +int TaskCC::clean() +{ +	if(std::filesystem::exists(targetFile)) +	{ +		std::cout << "Removing " << std::string(targetFile) << "\n"; +		std::filesystem::remove(targetFile); +	} + +	if(std::filesystem::exists(depsFile)) +	{ +		std::cout << "Removing " << std::string(depsFile) << "\n"; +		std::filesystem::remove(depsFile); +	} + +	return 0; +} + +std::vector<std::string> TaskCC::depends() const +{ +	return {}; +} + +std::string TaskCC::target() const +{ +	return targetFile; +} diff --git a/task_cc.h b/task_cc.h new file mode 100644 index 0000000..c73a1e5 --- /dev/null +++ b/task_cc.h @@ -0,0 +1,38 @@ +// -*- c++ -*- +#pragma once + +#include "task.h" + +#include <vector> +#include <string> +#include <future> +#include <filesystem> + +struct BuildConfiguration; +struct Settings; + +class TaskCC +	: public Task +{ +public: +	TaskCC(const BuildConfiguration& config, +	       const Settings& settings, +	       const std::string& source); + +	bool dirty() override; + +	int run() override; +	int clean() override; + +	std::vector<std::string> depends() const override; + +	std::string target() const override; + +private: +	std::filesystem::path sourceFile; +	std::filesystem::path targetFile; +	std::filesystem::path depsFile; + +	const BuildConfiguration& config; +	const Settings& settings; +}; diff --git a/task_ld.cc b/task_ld.cc new file mode 100644 index 0000000..235523f --- /dev/null +++ b/task_ld.cc @@ -0,0 +1,89 @@ +#include "task_ld.h" + +#include <iostream> +#include <fstream> +#include <unistd.h> +#include <cstring> +#include <sys/types.h> +#include <sys/wait.h> +#include <spawn.h> + +#include "libcppbuild.h" +#include "settings.h" + +TaskLD::TaskLD(const BuildConfiguration& config, +               const Settings& settings, +               const std::string& target, +               const std::vector<std::string>& objects) +	: config(config) +	, settings(settings) +{ +	targetFile = settings.builddir; +	targetFile /= target; +	for(const auto& object : objects) +	{ +		//std::filesystem::path objectFile = settings.builddir; +		//objectFile /= object; +		std::filesystem::path objectFile = object; +		objectFiles.push_back(objectFile); +	} +} + +bool TaskLD::dirty() +{ +	if(!std::filesystem::exists(targetFile)) +	{ +		return true; +	} + +	for(const auto& objectFile : objectFiles) +	{ +		if(std::filesystem::last_write_time(targetFile) <= +		   std::filesystem::last_write_time(objectFile)) +		{ +			return true; +		} +	} + +	return false; +} + +int TaskLD::run() +{ +	std::string objectlist; +	for(const auto& objectFile : objectFiles) +	{ +		if(!objectlist.empty()) +		{ +			objectlist += " "; +		} +		objectlist += std::string(objectFile); +	} + +	std::string compiler = "g++ " + objectlist + " " + +		config.ldflags + " " + +		"-o " + std::string(targetFile); +	std::cout << compiler << "\n"; +	if(system(compiler.data())) +	{ +		return 1; +	} +	return 0; +} + +int TaskLD::clean() +{ +	std::filesystem::remove(targetFile); +	return 0; +} + +std::vector<std::string> TaskLD::depends() const +{ +	return {}; +} + +std::string TaskLD::target() const +{ +	std::cout << "Removing " << std::string(targetFile) << "\n"; +	return std::string(targetFile); +} diff --git a/task_ld.h b/task_ld.h new file mode 100644 index 0000000..709f238 --- /dev/null +++ b/task_ld.h @@ -0,0 +1,38 @@ +// -*- c++ -*- +#pragma once + +#include "task.h" + +#include <vector> +#include <string> +#include <future> +#include <filesystem> + +struct BuildConfiguration; +struct Settings; + +class TaskLD +	: public Task +{ +public: +	TaskLD(const BuildConfiguration& config, +	       const Settings& settings, +	       const std::string& target, +	       const std::vector<std::string>& objects); + +	bool dirty() override; + +	int run() override; +	int clean() override; + +	std::vector<std::string> depends() const override; + +	std::string target() const override; + +private: +	std::vector<std::filesystem::path> objectFiles; +	std::filesystem::path targetFile; + +	const BuildConfiguration& config; +	const Settings& settings; +}; | 
