summaryrefslogtreecommitdiff
path: root/src/task_cc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/task_cc.cc')
-rw-r--r--src/task_cc.cc339
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;
+}