diff options
Diffstat (limited to 'src/task_cc.cc')
-rw-r--r-- | src/task_cc.cc | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/src/task_cc.cc b/src/task_cc.cc new file mode 100644 index 0000000..af9cf7a --- /dev/null +++ b/src/task_cc.cc @@ -0,0 +1,339 @@ +#include "task_cc.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> 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& sourceDir, const std::string& source) + : Task(config) + , config(config) + , settings(settings) + , sourceDir(sourceDir) +{ + sourceFile = sourceDir; + sourceFile /= source; + + std::filesystem::path base = settings.builddir; + base /= config.target; + base += "-"; + base += sourceFile.stem(); + + if(sourceFile.extension().string() == ".c") + { + base += "_c"; + } + else + { + base += "_cc"; + } + + targetFile = base; + targetFile += ".o"; + depsFile = base; + depsFile += ".d"; + flagsFile = base; + flagsFile += ".flags"; + + target_type = TargetType::Object; + if(sourceFile.extension().string() == ".c") + { + source_language = Language::C; + } + else + { + source_language = Language::Cpp; + } +} + +std::string TaskCC::name() const +{ + return target(); +} + +bool TaskCC::dirtyInner() +{ + 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::exists(flagsFile)) + { + //std::cout << "Missing flagsFile\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 lastFlags = readFile(flagsFile.string()); + if(flagsString() != lastFlags) + { + //std::cout << "The compiler flags changed\n"; + return true; + } + } + + auto depList = readDeps(depsFile.string()); + 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 TaskCC::runInner() +{ + if(!std::filesystem::exists(sourceFile)) + { + std::cout << "Missing source file: " << sourceFile.string() << "\n"; + return 1; + } + + auto args = getCompilerArgs(); + + { // Write flags to file. + std::ofstream flagsStream(flagsFile.string()); + flagsStream << flagsString(); + } + + if(settings.verbose == 0) + { + std::cout << compiler() << " " << + sourceFile.lexically_normal().string() << " => " << + targetFile.lexically_normal().string() << "\n"; + } + + return execute(compiler(), args, settings.verbose > 0); +} + +int TaskCC::clean() +{ + if(std::filesystem::exists(targetFile)) + { + std::cout << "Removing " << targetFile.string() << "\n"; + std::filesystem::remove(targetFile); + } + + if(std::filesystem::exists(depsFile)) + { + std::cout << "Removing " << depsFile.string() << "\n"; + std::filesystem::remove(depsFile); + } + + if(std::filesystem::exists(flagsFile)) + { + std::cout << "Removing " << flagsFile.string() << "\n"; + std::filesystem::remove(flagsFile); + } + + return 0; +} + +std::vector<std::string> TaskCC::depends() const +{ + return {}; +} + +std::string TaskCC::target() const +{ + return targetFile.string(); +} + +std::string TaskCC::toJSON() const +{ + std::string json; + json += "\t{\n"; + json += "\t\t\"directory\": \"" + sourceDir.string() + "\",\n"; + json += "\t\t\"file\": \"" + sourceFile.lexically_normal().string() + "\",\n"; + json += "\t\t\"output\": \"" + targetFile.string() + "\",\n"; + json += "\t\t\"arguments\": [ \"" + compiler() + "\""; + auto args = getCompilerArgs(); + for(const auto& arg : args) + { + json += ", \"" + arg + "\""; + } + json += " ]\n"; + json += "\t}"; + return json; +} + +std::vector<std::string> TaskCC::flags() const +{ + switch(sourceLanguage()) + { + case Language::C: + return config.cflags; + case Language::Cpp: + return config.cxxflags; + default: + std::cerr << "Unknown CC target type\n"; + exit(1); + break; + } +} + +std::string TaskCC::flagsString() const +{ + std::string flagsStr = compiler(); + for(const auto& flag : flags()) + { + flagsStr += " " + flag; + } + return flagsStr; +} + +std::vector<std::string> TaskCC::getCompilerArgs() const +{ + auto compiler_flags = flags(); + + std::vector<std::string> args; + args.push_back("-MMD"); + + if(std::filesystem::path(config.target).extension() == ".so") + { + // Add -fPIC arg to all contained object files + args.push_back("-fPIC"); + } + + args.push_back("-c"); + args.push_back(sourceFile.string()); + args.push_back("-o"); + args.push_back(targetFile.string()); + + for(const auto& flag : compiler_flags) + { + // Is arg an added include path? + if(flag.substr(0, 2) == "-I") + { + std::string include_path = flag.substr(2); + include_path.erase(0, include_path.find_first_not_of(' ')); + std::filesystem::path path(include_path); + + // Is it relative? + if(path.is_relative()) + { + path = (sourceDir / path).lexically_normal(); + std::string new_include_path = "-I" + path.string(); + args.push_back(new_include_path); + continue; + } + } + + args.push_back(flag); + } + + return args; +} |