#include "task_cc.h" #include #include #include "libctor.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 bytes(fileSize); ifs.read(bytes.data(), fileSize); return std::string(bytes.data(), fileSize); } std::vector readDeps(const std::string& depFile) { if(!std::filesystem::exists(depFile)) { return {}; } auto str = readFile(depFile); std::vector 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 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 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 TaskCC::getCompilerArgs() const { auto compiler_flags = flags(); std::vector 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; }