diff options
-rw-r--r-- | libcppbuild.cc | 163 | ||||
-rw-r--r-- | libcppbuild.h | 39 | ||||
-rw-r--r-- | task.cc | 19 | ||||
-rw-r--r-- | task.h | 13 | ||||
-rw-r--r-- | task_ar.cc | 16 | ||||
-rw-r--r-- | task_cc.cc | 34 | ||||
-rw-r--r-- | task_ld.cc | 23 | ||||
-rw-r--r-- | task_so.cc | 21 |
8 files changed, 281 insertions, 47 deletions
diff --git a/libcppbuild.cc b/libcppbuild.cc index 927fe72..1fa1bc3 100644 --- a/libcppbuild.cc +++ b/libcppbuild.cc @@ -25,6 +25,35 @@ #include <unistd.h> + +namespace +{ +std::filesystem::path configurationFile("configuration.cc"); +const std::map<std::string, std::string> default_configuration{}; +} +const std::map<std::string, std::string>& __attribute__((weak)) configuration() +{ + return default_configuration; +} + +bool hasConfiguration(const std::string& key) +{ + const auto& c = configuration(); + return c.find(key) != c.end(); +} + +const std::string& getConfiguration(const std::string& key, + const std::string& defaultValue) +{ + const auto& c = configuration(); + if(hasConfiguration(key)) + { + return c.at(key); + } + + return defaultValue; +} + using namespace std::chrono_literals; std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config, @@ -151,6 +180,24 @@ void recompileCheck(const Settings& settings, int argc, char* argv[]) std::filesystem::path binFile("cppbuild"); + if(std::filesystem::exists(configurationFile)) + { + args.push_back(configurationFile.string()); + + if(std::filesystem::last_write_time(binFile) <= + std::filesystem::last_write_time(configurationFile)) + { + dirty = true; + } + + const auto& c = configuration(); + if(&c == &default_configuration) + { + // configuration.cc exists, but currently compiled with the default one. + dirty = true; + } + } + if(settings.verbose > 1) { std::cout << "Recompile check (" << numConfigFiles << "):\n"; @@ -183,10 +230,11 @@ void recompileCheck(const Settings& settings, int argc, char* argv[]) if(dirty) { std::cout << "Rebuilding config\n"; - auto ret = execute("/usr/bin/g++", args); + auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); + auto ret = execute(tool, args, settings.verbose > 0); if(ret != 0) { - std::cerr << "Failed.\n"; + std::cerr << "Failed: ." << ret << "\n"; exit(1); } else @@ -197,16 +245,87 @@ void recompileCheck(const Settings& settings, int argc, char* argv[]) { args.push_back(argv[i]); } - exit(execute(argv[0], args, settings.verbose)); + exit(execute(argv[0], args, settings.verbose > 0)); } } } +std::list<std::shared_ptr<Task>> getTasks(const Settings& settings) +{ + static std::deque<BuildConfiguration> build_configs; + std::list<std::shared_ptr<Task>> tasks; + for(int i = 0; i < numConfigFiles; ++i) + { + std::string path = + std::filesystem::path(configFiles[i].file).parent_path(); + if(settings.verbose > 1) + { + std::cout << configFiles[i].file << " in path " << path << "\n"; + } + auto configs = configFiles[i].cb(); + for(const auto& config : configs) + { + build_configs.push_back(config); + const auto& build_config = build_configs.back(); + std::vector<std::string> objects; + auto t = taskFactory(build_config, settings, path); + tasks.insert(tasks.end(), t.begin(), t.end()); + } + } + + return tasks; +} + +int configure(int argc, char* argv[],const Settings& settings) +{ + auto tasks = getTasks(settings); + + bool needs_cpp{false}; + bool needs_c{false}; + bool needs_ar{false}; + for(const auto& task :tasks) + { + switch(task->language()) + { + case Language::Auto: + std::cerr << "TargetLanguage not deduced!\n"; + exit(1); + break; + case Language::C: + needs_cpp = false; + break; + case Language::Cpp: + needs_c = true; + break; + } + } + std::ofstream istr(configurationFile); + istr << "#include \"libcppbuild.h\"\n\n"; + istr << "const std::map<std::string, std::string>& configuration()\n"; + istr << "{\n"; + istr << " static std::map<std::string, std::string> c =\n"; + istr << " {\n"; + istr << " { \"builddir\", \"build\" },\n"; + istr << " { \"host-cc\", \"/usr/bin/gcc\" },\n"; + istr << " { \"host-cpp\", \"/usr/bin/g++\" },\n"; + istr << " { \"host-ar\", \"/usr/bin/ar\" },\n"; + istr << " { \"host-ld\", \"/usr/bin/ld\" },\n"; + istr << " { \"target-cc\", \"/usr/bin/gcc\" },\n"; + istr << " { \"target-cpp\", \"/usr/bin/g++\" },\n"; + istr << " { \"target-ar\", \"/usr/bin/ar\" },\n"; + istr << " { \"target-ld\", \"/usr/bin/ld\" },\n"; + istr << " };\n"; + istr << " return c;\n"; + istr << "}\n"; + + return 0; +} + int main(int argc, char* argv[]) { Settings settings{}; - settings.builddir = "build/"; + settings.builddir = getConfiguration("builddir", "build"); settings.parallel_processes = std::max(1u, std::thread::hardware_concurrency() * 2 - 1); settings.verbose = 0; @@ -214,6 +333,11 @@ int main(int argc, char* argv[]) bool write_compilation_database{false}; std::string compilation_database; + if(argc > 1 && std::string(argv[1]) == "configure") + { + return configure(argc, argv, settings); + } + dg::Options opt; opt.add("jobs", required_argument, 'j', @@ -232,7 +356,8 @@ int main(int argc, char* argv[]) }); opt.add("build-dir", required_argument, 'b', - "Set output directory for build files (default: build).", + "Overload output directory for build files (default: '" + + settings.builddir + "').", [&]() { settings.builddir = optarg; return 0; @@ -269,26 +394,7 @@ int main(int argc, char* argv[]) std::filesystem::path builddir(settings.builddir); std::filesystem::create_directories(builddir); - std::deque<BuildConfiguration> build_configs; - std::list<std::shared_ptr<Task>> tasks; - for(int i = 0; i < numConfigFiles; ++i) - { - std::string path = - std::filesystem::path(configFiles[i].file).parent_path(); - if(settings.verbose > 1) - { - std::cout << configFiles[i].file << " in path " << path << "\n"; - } - auto configs = configFiles[i].cb(); - for(const auto& config : configs) - { - build_configs.push_back(config); - const auto& build_config = build_configs.back(); - std::vector<std::string> objects; - auto t = taskFactory(build_config, settings, path); - tasks.insert(tasks.end(), t.begin(), t.end()); - } - } + auto tasks = getTasks(settings); if(write_compilation_database) { @@ -337,7 +443,6 @@ int main(int argc, char* argv[]) if(arg == "clean") { std::cout << "Cleaning\n"; - //std::filesystem::remove_all(builddir); for(auto& task : tasks) { if(task->clean() != 0) @@ -348,6 +453,12 @@ int main(int argc, char* argv[]) return 0; } + + if(arg == "configure") + { + std::cerr << "The 'configure' target must be the first argument.\n"; + return 1; + } } if(dirtyTasks.empty()) diff --git a/libcppbuild.h b/libcppbuild.h index 2aba987..81e7a9e 100644 --- a/libcppbuild.h +++ b/libcppbuild.h @@ -3,25 +3,45 @@ #include <string> #include <vector> -//#include <source_location> +#include <map> enum class TargetType { - Auto, // Default - deduce from target name + Auto, // Default - deduce from target name and sources extensions + Executable, StaticLibrary, DynamicLibrary, + Object, +}; + +enum class Language +{ + Auto, // Default - deduce language from source extensions + + C, + Cpp, + Asm, +}; + +enum class OutputSystem +{ + Target, // Output for the target system + BuildHost, // Internal tool during cross-compilation }; struct BuildConfiguration { TargetType type{TargetType::Auto}; + Language language{Language::Auto}; + OutputSystem system{OutputSystem::Target}; std::string target; - std::vector<std::string> sources; - std::vector<std::string> depends; - std::vector<std::string> cxxflags; - std::vector<std::string> cflags; - std::vector<std::string> ldflags; + std::vector<std::string> sources; // source list + std::vector<std::string> depends; // internal dependencies + std::vector<std::string> cxxflags; // flags for c++ compiler + std::vector<std::string> cflags; // flags for c compiler + std::vector<std::string> ldflags; // flags for linker + std::vector<std::string> asmflags; // flags for asm translator }; using BuildConfigurations = std::vector<BuildConfiguration>; @@ -33,3 +53,8 @@ int reg(const char* location, BuildConfigurations (*cb)()); #define CONCAT_INNER(a, b) a ## b #define UNIQUE_NAME(base) CONCAT(base, __LINE__) #define REG(cb) namespace { int UNIQUE_NAME(unique) = reg(__FILE__, cb); } + +const std::map<std::string, std::string>& configuration(); +bool hasConfiguration(const std::string& key); +const std::string& getConfiguration(const std::string& key, + const std::string& defaultValue = {}); @@ -3,8 +3,10 @@ #include <unistd.h> #include <iostream> -Task::Task(const std::vector<std::string>& depends) +Task::Task(const BuildConfiguration& config, + const std::vector<std::string>& depends) : dependsStr(depends) + , config(config) { } @@ -84,3 +86,18 @@ State Task::state() const { return task_state.load(); } + +const BuildConfiguration& Task::buildConfig() const +{ + return config; +} + +TargetType Task::targetType() const +{ + return target_type; +} + +Language Task::language() const +{ + return _language; +} @@ -7,6 +7,8 @@ #include <list> #include <memory> +#include "libcppbuild.h" + enum class State { Unknown, @@ -19,7 +21,8 @@ enum class State class Task { public: - Task(const std::vector<std::string>& depends); + Task(const BuildConfiguration& config, + const std::vector<std::string>& depends = {}); int registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks); @@ -33,6 +36,11 @@ public: virtual std::string toJSON() const { return {}; }; + const BuildConfiguration& buildConfig() const; + + TargetType targetType() const; + Language language() const; + protected: std::atomic<State> task_state{State::Unknown}; virtual int runInner() { return 0; }; @@ -40,4 +48,7 @@ protected: std::vector<std::string> dependsStr; std::list<std::shared_ptr<Task>> dependsTasks; + const BuildConfiguration& config; + TargetType target_type{TargetType::Auto}; + Language _language{Language::Auto}; }; @@ -41,7 +41,7 @@ TaskAR::TaskAR(const BuildConfiguration& config, const Settings& settings, const std::string& target, const std::vector<std::string>& objects) - : Task(addPrefix(config.depends, settings)) + : Task(config, addPrefix(config.depends, settings)) , config(config) , settings(settings) { @@ -63,6 +63,17 @@ TaskAR::TaskAR(const BuildConfiguration& config, flagsFile = settings.builddir / targetFile.stem(); flagsFile += ".flags"; + + target_type = TargetType::StaticLibrary; + _language = Language::C; + for(const auto& source : config.sources) + { + std::filesystem::path sourceFile(source); + if(sourceFile.extension().string() != ".c") + { + _language = Language::Cpp; + } + } } bool TaskAR::dirtyInner() @@ -132,7 +143,8 @@ int TaskAR::runInner() std::cout << "AR => " << targetFile.string() << "\n"; } - return execute("/usr/bin/ar", args, settings.verbose > 0); + auto tool = getConfiguration("host-ar", "/usr/bin/ar"); + return execute(tool, args, settings.verbose > 0); } int TaskAR::clean() @@ -85,7 +85,7 @@ std::vector<std::string> readDeps(const std::string& depFile) TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, const std::string& sourceDir, const std::string& source) - : Task({}) + : Task(config) , config(config) , settings(settings) , sourceDir(sourceDir) @@ -101,6 +101,16 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings, flagsFile = settings.builddir / sourceFile.stem(); flagsFile += ".flags"; + + target_type = TargetType::Object; + if(sourceFile.extension().string() == ".c") + { + _language = Language::C; + } + else + { + _language = Language::Cpp; + } } bool TaskCC::dirtyInner() @@ -245,11 +255,17 @@ std::string TaskCC::toJSON() const std::vector<std::string> TaskCC::flags() const { - if(std::string(sourceFile.extension()) == ".c") + switch(language()) { + case Language::C: return config.cflags; + case Language::Cpp: + return config.cxxflags; + default: + std::cerr << "Unknown CC target type\n"; + exit(1); + break; } - return config.cxxflags; } std::string TaskCC::flagsString() const @@ -268,11 +284,17 @@ std::string TaskCC::flagsString() const std::string TaskCC::compiler() const { - if(std::string(sourceFile.extension()) == ".c") + switch(language()) { - return "/usr/bin/gcc"; + case Language::C: + return getConfiguration("host-cc"); + case Language::Cpp: + return getConfiguration("host-cpp"); + default: + std::cerr << "Unknown CC target type\n"; + exit(1); + break; } - return "/usr/bin/g++"; } std::vector<std::string> TaskCC::getCompilerArgs() const @@ -40,10 +40,12 @@ TaskLD::TaskLD(const BuildConfiguration& config, const Settings& settings, const std::string& target, const std::vector<std::string>& objects) - : Task(addPrefix(config.depends, settings)) + : Task(config, addPrefix(config.depends, settings)) , config(config) , settings(settings) { + target_type = TargetType::Executable; + targetFile = settings.builddir; targetFile /= target; for(const auto& object : objects) @@ -62,6 +64,17 @@ TaskLD::TaskLD(const BuildConfiguration& config, flagsFile = settings.builddir / targetFile.stem(); flagsFile += ".flags"; + + target_type = TargetType::Executable; + _language = Language::C; + for(const auto& source : config.sources) + { + std::filesystem::path sourceFile(source); + if(sourceFile.extension().string() != ".c") + { + _language = Language::Cpp; + } + } } bool TaskLD::dirtyInner() @@ -146,7 +159,13 @@ int TaskLD::runInner() std::cout << "LD => " << targetFile.string() << "\n"; } - return execute("/usr/bin/g++", args, settings.verbose > 0); + auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); + if(language() == Language::C) + { + tool = getConfiguration("host-cc", "/usr/bin/gcc"); + } + + return execute(tool, args, settings.verbose > 0); } int TaskLD::clean() @@ -40,7 +40,7 @@ TaskSO::TaskSO(const BuildConfiguration& config, const Settings& settings, const std::string& target, const std::vector<std::string>& objects) - : Task(addPrefix(config.depends, settings)) + : Task(config, addPrefix(config.depends, settings)) , config(config) , settings(settings) { @@ -62,6 +62,17 @@ TaskSO::TaskSO(const BuildConfiguration& config, flagsFile = settings.builddir / targetFile.stem(); flagsFile += ".flags"; + + target_type = TargetType::DynamicLibrary; + _language = Language::C; + for(const auto& source : config.sources) + { + std::filesystem::path sourceFile(source); + if(sourceFile.extension().string() != ".c") + { + _language = Language::Cpp; + } + } } bool TaskSO::dirtyInner() @@ -142,7 +153,13 @@ int TaskSO::runInner() std::cout << "LD => " << targetFile.string() << "\n"; } - return execute("/usr/bin/g++", args, settings.verbose > 0); + auto tool = getConfiguration("host-cpp", "/usr/bin/g++"); + if(language() == Language::C) + { + tool = getConfiguration("host-cc", "/usr/bin/gcc"); + } + + return execute(tool, args, settings.verbose > 0); } int TaskSO::clean() |