diff options
40 files changed, 692 insertions, 331 deletions
diff --git a/Jenkinsfile b/Jenkinsfile index c95b0eb..290f412 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,56 +1,48 @@ pipeline { - agent { label 'c++20' } - + agent any stages { - stage('Clean') { + //////////////////////////////////////////////////// + stage('Linux gcc') { + agent { label 'linux && gcc && c++20' } steps { echo 'Cleaning workspace ...' - sh 'rm -Rf build*' - } - } - stage('Build-gcc') { - steps { + sh 'git clean -d -x -f' echo 'Building (gcc) ...' - sh 'BUILDDIR=build-gcc CXX=g++ ./bootstrap.sh' - } - } - stage('Test-gcc') { - steps { + sh 'CXX=g++ ./bootstrap.sh' echo 'Testing (gcc) ...' sh './ctor check' - } - } - stage('Test-suite-gcc') { - steps { echo 'Testing suite (gcc) ...' - sh '(cd test/suite; CTORDIR=../../build-gcc CXX=g++ ./test.sh)' + sh '(cd test/suite; CTORDIR=../../build CXX=g++ ./test.sh)' } - } - stage('Build-clang') { - steps { - echo 'Building (clang) ...' - sh 'BUILDDIR=build-clang CXX=clang++ ./bootstrap.sh' + post { + always { + xunit(thresholds: [ skipped(failureThreshold: '0'), + failed(failureThreshold: '0') ], + tools: [ CppUnit(pattern: 'build/test/*.xml') ]) + } } } - stage('Test-clang') { + //////////////////////////////////////////////////// + stage('Linux clang') { + agent { label 'linux && clang && c++20' } steps { + echo 'Cleaning workspace ...' + sh 'git clean -d -x -f' + echo 'Building (clang) ...' + sh 'CXX=clang++ ./bootstrap.sh' echo 'Testing (clang) ...' sh './ctor check' - } - } - stage('Test-suite-clang') { - steps { echo 'Testing suite (clang) ...' - sh '(cd test/suite; CTORDIR=../../build-clang CXX=clang++ ./test.sh)' + sh '(cd test/suite; CTORDIR=../../build CXX=clang++ ./test.sh)' + } + post { + always { + xunit(thresholds: [ skipped(failureThreshold: '0'), + failed(failureThreshold: '0') ], + tools: [ CppUnit(pattern: 'build/test/*.xml') ]) + } } } - } - - post { - always { - xunit(thresholds: [ skipped(failureThreshold: '0'), - failed(failureThreshold: '0') ], - tools: [ CppUnit(pattern: 'build-*/test/*.xml') ]) - } + //////////////////////////////////////////////////// } } @@ -15,6 +15,7 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) .sources = { "src/build.cc", "src/configure.cc", + "src/deps.cc", "src/execute.cc", "src/externals_manual.cc", "src/libctor.cc", @@ -37,6 +38,10 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) "-g", "-Wall", "-Werror", + "-Wextra", + "-Wshadow", + "-Wconversion", +// "-Wnrvo", "-Isrc", }, }, diff --git a/src/bootstrap.cc b/src/bootstrap.cc index 55bd3e0..aa50561 100644 --- a/src/bootstrap.cc +++ b/src/bootstrap.cc @@ -4,6 +4,7 @@ #include <iostream> #include <array> #include <cstdlib> +#include <span> #define BOOTSTRAP @@ -19,8 +20,8 @@ #include "build.cc" #include "tools.cc" -std::filesystem::path configurationFile("configuration.cc"); -std::filesystem::path configHeaderFile("config.h"); +const std::filesystem::path configurationFile("configuration.cc"); +const std::filesystem::path configHeaderFile("config.h"); const ctor::configuration& ctor::get_configuration() { @@ -42,44 +43,56 @@ bool ctor::configuration::has(const std::string& key) const const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const { - if(key == ctor::cfg::build_cxx && std::getenv("CXX")) + auto cxx_env = std::getenv("CXX"); + if(key == ctor::cfg::build_cxx && cxx_env) { - static std::string s = std::getenv("CXX"); + static std::string s = cxx_env; return s; } - if(key == ctor::cfg::build_cc && std::getenv("CC")) + auto cc_env = std::getenv("CC"); + if(key == ctor::cfg::build_cc && cc_env) { - static std::string s = std::getenv("CC"); + static std::string s = cc_env; return s; } - if(key == ctor::cfg::build_ld && std::getenv("LD")) + auto ld_env = std::getenv("LD"); + if(key == ctor::cfg::build_ld && ld_env) { - static std::string s = std::getenv("LD"); + static std::string s = ld_env; return s; } - if(key == ctor::cfg::build_ar && std::getenv("AR")) + auto ar_env = std::getenv("AR"); + if(key == ctor::cfg::build_ar && ar_env) { - static std::string s = std::getenv("AR"); + static std::string s = ar_env; return s; } - if(key == ctor::cfg::builddir && std::getenv("BUILDDIR")) + auto builddir_env = std::getenv("BUILDDIR"); + if(key == ctor::cfg::builddir && builddir_env) { - static std::string s = std::getenv("BUILDDIR"); + static std::string s = builddir_env; return s; } return default_value; } +std::vector<std::string> readDeps(const std::string& depFile, + ctor::toolchain toolchain) +{ + return {}; +} + int main(int argc, char* argv[]) { - if(argc > 1) + auto args = std::span(argv, static_cast<std::size_t>(argc)); + if(args.size() > 1) { - std::cerr << "This is a minimal bootstrap version of " << argv[0] << + std::cerr << "This is a minimal bootstrap version of " << args[0] << " which doesn't support any arguments\n"; return 1; } diff --git a/src/build.cc b/src/build.cc index ea65656..906c3ea 100644 --- a/src/build.cc +++ b/src/build.cc @@ -38,7 +38,7 @@ int build(const ctor::settings& settings, // Dry-run returns number of dirty tasks but otherwise does nothing. if(dryrun) { - return dirtyTasks.size(); + return static_cast<int>(dirtyTasks.size()); } if(dirtyTasks.empty()) @@ -114,17 +114,15 @@ int build(const ctor::settings& settings, } } - for(auto process = processes.begin(); - process != processes.end(); - ++process) + for(auto& process : processes) { - if(process->valid() == false) + if(process.valid() == false) { continue; } - process->wait(); - auto ret = process->get(); - if(ret != 0) + process.wait(); + auto ret = process.get(); + if (ret != 0) { return ret; } @@ -144,11 +142,11 @@ std::vector<std::shared_ptr<Task>> getDepTasks(std::shared_ptr<Task> task) for(const auto& dep : deps) { auto depSet = getDepTasks(dep); - for(const auto& dep : depSet) + for(const auto& dep_inner : depSet) { - if(std::find(tasks.begin(), tasks.end(), dep) == tasks.end()) + if(std::find(tasks.begin(), tasks.end(), dep_inner) == tasks.end()) { - tasks.push_back(dep); + tasks.push_back(dep_inner); } } } @@ -171,11 +169,11 @@ int build(const ctor::settings& settings, auto depSet = getDepTasks(task); std::vector<std::shared_ptr<Task>> ts; - for(const auto& task : depSet) + for(const auto& task_inner : depSet) { - if(std::find(ts.begin(), ts.end(), task) == ts.end()) + if(std::find(ts.begin(), ts.end(), task_inner) == ts.end()) { - ts.push_back(task); + ts.push_back(task_inner); } } @@ -217,11 +215,11 @@ int build(const ctor::settings& settings, task_found = true; auto depSet = getDepTasks(task); - for(const auto& task : depSet) + for(const auto& task_inner : depSet) { - if(std::find(ts.begin(), ts.end(), task) == ts.end()) + if(std::find(ts.begin(), ts.end(), task_inner) == ts.end()) { - ts.push_back(task); + ts.push_back(task_inner); } } } diff --git a/src/configure.cc b/src/configure.cc index c08ed88..995e340 100644 --- a/src/configure.cc +++ b/src/configure.cc @@ -7,6 +7,7 @@ #include <filesystem> #include <fstream> #include <optional> +#include <span> #include <getoptpp/getoptpp.hpp> @@ -18,8 +19,8 @@ #include "tools.h" #include "util.h" -std::filesystem::path configurationFile("configuration.cc"); -std::filesystem::path configHeaderFile("config.h"); +const std::filesystem::path configurationFile("configuration.cc"); +const std::filesystem::path configHeaderFile("config.h"); std::map<std::string, std::string> external_includedir; std::map<std::string, std::string> external_libdir; @@ -321,19 +322,19 @@ int regenerateCache(ctor::settings& settings, } auto add_path_args = - [&](const std::string& name) + [&](const std::string& arg_name) { - opt.add(name + "-includedir", required_argument, key++, - "Set path to " + name + " header file.", + opt.add(arg_name + "-includedir", required_argument, key++, + "Set path to " + arg_name + " header file.", [&]() { - external_includedir[name] = optarg; + external_includedir[arg_name] = optarg; return 0; }); - opt.add(name + "-libdir", required_argument, key++, - "Set path to " + name + " libraries.", + opt.add(arg_name + "-libdir", required_argument, key++, + "Set path to " + arg_name + " libraries.", [&]() { - external_libdir[name] = optarg; + external_libdir[arg_name] = optarg; return 0; }); }; @@ -366,7 +367,7 @@ int regenerateCache(ctor::settings& settings, return 0; }); - opt.process(vargs.size(), vargs.data()); + opt.process(static_cast<int>(vargs.size()), vargs.data()); if(host_arch_prefix.empty()) { @@ -821,12 +822,14 @@ int regenerateCache(ctor::settings& settings, int configure(const ctor::settings& global_settings, int argc, char* argv[]) { + auto args_span = std::span(argv, static_cast<std::size_t>(argc)); + ctor::settings settings{global_settings}; std::vector<std::string> args; - for(int i = 2; i < argc; ++i) // skip command and the first 'configure' arg + for(std::size_t i = 2; i < args_span.size(); ++i) // skip command and the first 'configure' arg { - args.push_back(argv[i]); + args.emplace_back(args_span[i]); } std::map<std::string, std::string> env; @@ -860,7 +863,7 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[]) env["PATH"] = path_env; } - auto ret = regenerateCache(settings, argv[0], args, env); + auto ret = regenerateCache(settings, args_span[0], args, env); if(ret != 0) { return ret; @@ -873,19 +876,21 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[]) int reconfigure(const ctor::settings& global_settings, int argc, char* argv[]) { + auto args_span = std::span(argv, static_cast<std::size_t>(argc)); + ctor::settings settings{global_settings}; bool no_rerun{false}; std::vector<std::string> args; - for(int i = 2; i < argc; ++i) // skip executable name and 'reconfigure' arg + for(std::size_t i = 2; i < args_span.size(); ++i) // skip executable name and 'reconfigure' arg { - if(i == 2 && std::string(argv[i]) == "--no-rerun") + if(i == 2 && std::string(args_span[i]) == "--no-rerun") { no_rerun = true; continue; } - args.push_back(argv[i]); + args.emplace_back(args_span[i]); } const auto& cfg = ctor::get_configuration(); @@ -895,14 +900,14 @@ int reconfigure(const ctor::settings& global_settings, int argc, char* argv[]) { std::cout << e.first << "=\"" << e.second << "\" "; } - std::cout << argv[0] << " configure "; + std::cout << args_span[0] << " configure "; for(const auto& arg : cfg.args) { std::cout << arg << " "; } std::cout << "\n"; - auto ret = regenerateCache(settings, argv[0], cfg.args, cfg.env); + auto ret = regenerateCache(settings, args_span[0], cfg.args, cfg.env); if(ret != 0) { return ret; @@ -915,5 +920,5 @@ int reconfigure(const ctor::settings& global_settings, int argc, char* argv[]) return 0; // this was originally invoked by configure, don't loop } - return execute(argv[0], args); + return execute(settings, args_span[0], args); } diff --git a/src/configure.h b/src/configure.h index ac8d721..5344646 100644 --- a/src/configure.h +++ b/src/configure.h @@ -12,8 +12,8 @@ namespace ctor { struct settings; } // namespace ctor:: -extern std::filesystem::path configurationFile;; -extern std::filesystem::path configHeaderFile; +extern const std::filesystem::path configurationFile; +extern const std::filesystem::path configHeaderFile; int configure(const ctor::settings& settings, int argc, char* argv[]); int reconfigure(const ctor::settings& settings, int argc, char* argv[]); @@ -10,6 +10,7 @@ #include <variant> #include <cstddef> #include <functional> +#include <string_view> namespace ctor { @@ -52,31 +53,37 @@ enum class arch unknown, //!< Target platform architecture has not yet detected or was not possible to detect }; +enum class toolchain +{ + any, + none, + gcc, + clang, +}; + struct source { - source(const char* file) : file(file) {} - source(const std::string& file) : file(file) {} - source(const char* file, ctor::language lang) : file(file), language(lang) {} - source(const std::string& file, ctor::language lang) : file(file), language(lang) {} + source(const char* file_) : file(file_) {} // convenience ctor + + source(std::string_view file_) : source(file_, ctor::language::automatic) {} + source(std::string_view file_, ctor::language lang_) : file(file_), language(lang_) {} + + source(std::string_view file_, std::string_view output_) : file(file_), output(output_) {} + source(std::string_view file_, ctor::language lang_, std::string_view output_) : file(file_), language(lang_), output(output_) {} + + source(ctor::toolchain toolchain_, std::string_view file_) : file(file_), toolchain(toolchain_) {} + source(ctor::toolchain toolchain_, std::string_view file_, ctor::language lang_) : file(file_), toolchain(toolchain_), language(lang_) {} - source(const char* file, const char* output) : file(file), output(output) {} - source(const std::string& file, const std::string& output) : file(file), output(output) {} - source(const char* file, ctor::language lang, const char* output) : file(file), language(lang), output(output) {} - source(const std::string& file, ctor::language lang, const std::string& output) : file(file), language(lang), output(output) {} + source(ctor::toolchain toolchain_, std::string_view file_, std::string_view output_) : file(file_), toolchain(toolchain_), output(output_) {} + + source(ctor::toolchain toolchain_, std::string_view file_, ctor::language lang_, std::string_view output_) : file(file_), toolchain(toolchain_), language(lang_), output(output_) {} std::string file; + ctor::toolchain toolchain{ctor::toolchain::any}; ctor::language language{ctor::language::automatic}; std::string output{}; }; -enum class toolchain -{ - any, - none, - gcc, - clang, -}; - enum class cxx_opt { // gcc/clang @@ -91,6 +98,7 @@ enum class cxx_opt optimization, // -O<arg> position_independent_code, // -fPIC position_independent_executable, // -fPIE + define, // -D<arg>[=<arg2>] custom, // entire option taken verbatim from <arg> }; @@ -108,6 +116,7 @@ enum class c_opt optimization, // -O<arg> position_independent_code, // -fPIC position_independent_executable, // -fPIE + define, // -D<arg>[=<arg2>] custom, // entire option taken verbatim from <arg> }; @@ -149,18 +158,24 @@ template<typename T> class flag { public: - flag(const std::string& str); + flag(std::string_view str); flag(const char* str); - flag(T opt) : opt(opt) {} - flag(T opt, const std::string& arg) : opt(opt), arg(arg) {} - flag(T opt, const char* arg) : opt(opt), arg(arg) {} - flag(ctor::toolchain toolchain, T opt) : toolchain(toolchain), opt(opt) {} - flag(ctor::toolchain toolchain, T opt, const char* arg) : toolchain(toolchain), opt(opt), arg(arg) {} - flag(ctor::toolchain toolchain, T opt, const std::string& arg) : toolchain(toolchain), opt(opt), arg(arg) {} + flag(T opt_) : opt(opt_) {} + flag(T opt_, std::string_view arg_, std::string_view arg2_ = "") + : opt(opt_), arg(arg_), arg2(arg2_) {} + flag(T opt_, const char* arg_, const char* arg2_ = "") + : opt(opt_), arg(arg_), arg2(arg2_) {} + flag(ctor::toolchain toolchain_, T opt_) + : toolchain(toolchain_), opt(opt_) {} + flag(ctor::toolchain toolchain_, T opt_, const char* arg_, const char* arg2_ = "") + : toolchain(toolchain_), opt(opt_), arg(arg_), arg2(arg2_) {} + flag(ctor::toolchain toolchain_, T opt_, std::string_view arg_, std::string_view arg2_ = "") + : toolchain(toolchain_), opt(opt_), arg(arg_), arg2(arg2_) {} ctor::toolchain toolchain{ctor::toolchain::any}; - T opt; + T opt{}; std::string arg; + std::string arg2; }; using c_flag = ctor::flag<ctor::c_opt>; diff --git a/src/deps.cc b/src/deps.cc new file mode 100644 index 0000000..9400b35 --- /dev/null +++ b/src/deps.cc @@ -0,0 +1,120 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include "deps.h" + +#include "util.h" + +#include <fstream> + +namespace { +/* Format example: +build/src/libctor_a-libctor_cc.o: src/libctor.cc \ + src/getoptpp/getoptpp.hpp src/ctor.h src/configure.h src/rebuild.h \ + src/A\ B\ C.h src/task.h src/build.h src/unittest.h + */ +std::vector<std::string> readDepsMake(const std::string& dep_file) +{ + auto str = readFile(dep_file); + + std::vector<std::string> output; + std::string tmp; + + enum class State + { + pre_colon, + post_colon, + in_escape, + } state{State::pre_colon}; + + auto old_state{state}; + for(const auto& c : str) + { + if(c == '\r') + { + // just always ignore windows extra newline char + continue; + } + + switch(state) + { + case State::pre_colon: + if(c == ':') // ignore everything until the colon + { + state = State::post_colon; + continue; + } + continue; + + case State::post_colon: + if(c == '\n') + { + // done + if(!tmp.empty()) + { + output.emplace_back(tmp); + } + return output; + } + if(c == '\\') + { + old_state = state; + state = State::in_escape; + continue; + } + if(c == '\t' || c == ' ') // new token + { + if(!tmp.empty()) + { + output.emplace_back(tmp); + } + tmp.clear(); + continue; + } + break; + + case State::in_escape: + if(c == '\n') + { + // linewrap + state = old_state; + continue; + } + state = old_state; + break; + } + + tmp += c; + } + + if(!tmp.empty()) + { + output.emplace_back(tmp); + } + + return output; +} +} + +std::vector<std::string> readDeps(const std::string& dep_file, + ctor::toolchain toolchain) +{ + if(!std::filesystem::exists(dep_file)) + { + return {}; + } + + switch(toolchain) + { + case ctor::toolchain::any: + case ctor::toolchain::none: + return {}; + + // makefile .d file based: + case ctor::toolchain::gcc: + case ctor::toolchain::clang: + return readDepsMake(dep_file); + } + + return {}; +} diff --git a/src/deps.h b/src/deps.h new file mode 100644 index 0000000..be0dfb2 --- /dev/null +++ b/src/deps.h @@ -0,0 +1,12 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#pragma once + +#include "ctor.h" + +#include <vector> +#include <string> + +std::vector<std::string> readDeps(const std::string& dep_file, + ctor::toolchain toolchain); diff --git a/src/execute.cc b/src/execute.cc index b4013d0..cbae899 100644 --- a/src/execute.cc +++ b/src/execute.cc @@ -3,6 +3,8 @@ // See accompanying file LICENSE for details. #include "execute.h" +#include "ctor.h" + #include <unistd.h> #include <cstring> #include <sys/types.h> @@ -44,7 +46,7 @@ public: int parent_waitpid(pid_t pid) { - int status; + int status{}; if(waitpid(pid, &status, 0) != pid) { @@ -57,10 +59,11 @@ int parent_waitpid(pid_t pid) extern char **environ; // see 'man environ' -int execute(const std::string& command, +int execute(const ctor::settings& settings, + const std::string& command, const std::vector<std::string>& args, const std::map<std::string, std::string>& env, - bool verbose) + [[maybe_unused]] bool terminate) { std::vector<const char*> argv; argv.push_back(command.data()); @@ -84,7 +87,7 @@ int execute(const std::string& command, cmd += arg; } - if(verbose) + if(settings.verbose) { std::cout << cmd << std::endl; } @@ -101,7 +104,7 @@ int execute(const std::string& command, for(auto current = environ; *current; ++current) { - venv.push_back(*current); + venv.emplace_back(*current); } Env penv(venv); diff --git a/src/execute.h b/src/execute.h index 336c3ef..4288bb7 100644 --- a/src/execute.h +++ b/src/execute.h @@ -7,7 +7,12 @@ #include <vector> #include <map> -int execute(const std::string& command, +namespace ctor { +struct settings; +}//ctor:: + +int execute(const ctor::settings& settings, + const std::string& command, const std::vector<std::string>& args = {}, const std::map<std::string, std::string>& env = {}, - bool verbose = true); + bool terminate = false); diff --git a/src/externals_manual.cc b/src/externals_manual.cc index 3b96263..0563a5e 100644 --- a/src/externals_manual.cc +++ b/src/externals_manual.cc @@ -13,7 +13,7 @@ extern std::map<std::string, std::string> external_includedir; extern std::map<std::string, std::string> external_libdir; -int resolv(const ctor::settings& settings, const ctor::external_configuration& config, +int resolv([[maybe_unused]]const ctor::settings& settings, const ctor::external_configuration& config, const ctor::external_manual& ext, ctor::flags& flags) { flags = ext.flags; @@ -21,14 +21,14 @@ int resolv(const ctor::settings& settings, const ctor::external_configuration& c auto inc = external_includedir.find(config.name); if(inc != external_includedir.end()) { - flags.cflags.push_back({ctor::c_opt::include_path, inc->second}); - flags.cxxflags.push_back({ctor::cxx_opt::include_path, inc->second}); + flags.cflags.emplace_back(ctor::c_opt::include_path, inc->second); + flags.cxxflags.emplace_back(ctor::cxx_opt::include_path, inc->second); } auto lib = external_libdir.find(config.name); if(lib != external_libdir.end()) { - flags.ldflags.push_back({ctor::ld_opt::library_path, lib->second}); + flags.ldflags.emplace_back(ctor::ld_opt::library_path, lib->second); } return 0; diff --git a/src/getoptpp b/src/getoptpp -Subproject 9ff20ef857429619267e3f156a4f81ad9e1eb8c +Subproject 5aba94355ec638c6f8612f86be309ed684979ae diff --git a/src/libctor.cc b/src/libctor.cc index 3eb6c6f..b1fbaea 100644 --- a/src/libctor.cc +++ b/src/libctor.cc @@ -15,6 +15,7 @@ #include <deque> #include <fstream> #include <cstdlib> +#include <span> #include <getoptpp/getoptpp.hpp> @@ -27,6 +28,8 @@ int main(int argc, char* argv[]) { + auto args = std::span(argv, static_cast<std::size_t>(argc)); + ctor::settings settings{}; const auto& c = ctor::get_configuration(); @@ -34,12 +37,12 @@ int main(int argc, char* argv[]) settings.parallel_processes = std::max(1u, std::thread::hardware_concurrency()) * 2 - 1; - if(argc > 1 && std::string(argv[1]) == "configure") + if(args.size() > 1 && std::string(args[1]) == "configure") { return configure(settings, argc, argv); } - if(argc > 1 && std::string(argv[1]) == "reconfigure") + if(args.size() > 1 && std::string(args[1]) == "reconfigure") { return reconfigure(settings, argc, argv); } @@ -64,7 +67,8 @@ int main(int argc, char* argv[]) [&]() { try { - settings.parallel_processes = std::stoi(optarg); + settings.parallel_processes = + static_cast<std::size_t>(std::stoi(optarg)); } catch(...) { @@ -100,7 +104,7 @@ int main(int argc, char* argv[]) "Add specified file to the build configurations.", [&]() { no_relaunch = true; - add_files.push_back(optarg); + add_files.emplace_back(optarg); return 0; }); @@ -108,7 +112,7 @@ int main(int argc, char* argv[]) "Remove specified file from the build configurations.", [&]() { no_relaunch = true; - remove_files.push_back(optarg); + remove_files.emplace_back(optarg); return 0; }); @@ -156,7 +160,7 @@ int main(int argc, char* argv[]) opt.add("help", no_argument, 'h', "Print this help text.", [&]() { - std::cout << "Usage: " << argv[0] << " [options] [target] ...\n"; + std::cout << "Usage: " << args[0] << " [options] [target] ...\n"; std::cout << R"_( where target can be either: configure - run configuration step (cannot be used with other targets). @@ -187,12 +191,12 @@ Options: std::vector<std::string> files; for(std::size_t i = 0; i < numConfigFiles; ++i) { - files.push_back(configFiles[i].file); + files.emplace_back(configFiles[i].file); } for(std::size_t i = 0; i < numExternalConfigFiles; ++i) { - files.push_back(externalConfigFiles[i].file); + files.emplace_back(externalConfigFiles[i].file); } std::sort(files.begin(), files.end()); @@ -270,7 +274,6 @@ Options: if(print_configure_db) { no_default_build = true; - const auto& c = ctor::get_configuration(); for(const auto& config : c.tools) { std::cout << config.first << ": " << config.second << "\n"; diff --git a/src/rebuild.cc b/src/rebuild.cc index f0d52d9..4ca1809 100644 --- a/src/rebuild.cc +++ b/src/rebuild.cc @@ -8,6 +8,7 @@ #include <algorithm> #include <source_location> #include <cstring> +#include <span> #include "configure.h" #include "ctor.h" @@ -105,7 +106,7 @@ int unreg(const char* location) } } - return found; + return static_cast<int>(found); } std::array<ExternalConfigurationEntry, 1024> externalConfigFiles; @@ -150,6 +151,8 @@ bool contains(const std::vector<ctor::source>& sources, const std::string& file) bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[], bool relaunch_allowed) { + auto args_span = std::span(argv, static_cast<std::size_t>(argc)); + using namespace std::string_literals; if(global_settings.verbose > 1) @@ -163,36 +166,40 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[ config.name = "ctor"; config.system = ctor::output_system::build; - config.flags.cxxflags.push_back({ctor::cxx_opt::optimization, "3"}); - config.flags.cxxflags.push_back({ctor::cxx_opt::cpp_std, "c++20"}); + config.flags.cxxflags.emplace_back(ctor::cxx_opt::optimization, "3"); + config.flags.cxxflags.emplace_back(ctor::cxx_opt::cpp_std, "c++20"); const auto& c = ctor::get_configuration(); if(c.has(ctor::cfg::ctor_includedir)) { - config.flags.cxxflags.push_back({ctor::cxx_opt::include_path, - c.get(ctor::cfg::ctor_includedir)}); + config.flags.cxxflags.emplace_back(ctor::cxx_opt::include_path, + c.get(ctor::cfg::ctor_includedir)); } if(c.has(ctor::cfg::ctor_libdir)) { - config.flags.ldflags.push_back({ctor::ld_opt::library_path, c.get(ctor::cfg::ctor_libdir)}); + config.flags.ldflags.emplace_back(ctor::ld_opt::library_path, + c.get(ctor::cfg::ctor_libdir)); } - config.flags.ldflags.push_back({ctor::ld_opt::link, "ctor"}); - config.flags.ldflags.push_back({ctor::ld_opt::strip}); - config.flags.ldflags.push_back({ctor::ld_opt::threads}); + config.flags.ldflags.emplace_back(ctor::ld_opt::link, "ctor"); + config.flags.ldflags.emplace_back(ctor::ld_opt::strip); + config.flags.ldflags.emplace_back(ctor::ld_opt::threads); ctor::settings settings{global_settings}; settings.verbose = -1; // Make check completely silent. - settings.builddir += "/ctor"; // override builddir to use ctor subdir + + // override builddir to use ctor subdir + auto ctor_builddir = std::filesystem::path(settings.builddir) / "ctor"; + settings.builddir = ctor_builddir.string(); { std::filesystem::path buildfile = settings.builddir; - std::filesystem::path currentfile = argv[0]; + std::filesystem::path currentfile = args_span[0]; config.target = std::filesystem::relative(currentfile, buildfile).string(); } if(std::filesystem::exists(configurationFile)) { - config.sources.push_back(configurationFile.string()); + config.sources.emplace_back(configurationFile.string()); } for(std::size_t i = 0; i < numConfigFiles; ++i) @@ -206,7 +213,7 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[ // Ensure that files containing multiple configurations are only added once. if(!contains(config.sources, location)) { - config.sources.push_back(location); + config.sources.emplace_back(location); } } @@ -221,11 +228,11 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[ // Ensure that files containing multiple configurations are only added once. if(!contains(config.sources, location)) { - config.sources.push_back(location); + config.sources.emplace_back(location); } } - auto tasks = taskFactory({config}, settings, {}); + auto tasks = taskFactory({config}, settings, {}, true); for(auto task : tasks) { @@ -261,16 +268,17 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[ if(reconfigure) { std::vector<std::string> args; - args.push_back("reconfigure"); + args.emplace_back("reconfigure"); if(!relaunch_allowed) { - args.push_back("--no-rerun"); + args.emplace_back("--no-rerun"); } - for(int i = 1; i < argc; ++i) + for(std::size_t i = 1; i < args_span.size(); ++i) { - args.push_back(argv[i]); + args.emplace_back(args_span[i]); } - auto ret = execute(argv[0], args); + + auto ret = execute(settings, args_span[0], args); //if(ret != 0) { exit(ret); diff --git a/src/task.cc b/src/task.cc index 7813235..cd03fce 100644 --- a/src/task.cc +++ b/src/task.cc @@ -3,16 +3,16 @@ // See accompanying file LICENSE for details. #include "task.h" -#include <unistd.h> #include <iostream> #include <algorithm> +#include <utility> -Task::Task(const ctor::build_configuration& config, const ctor::settings& settings, - const std::string& sourceDir) - : config(config) +Task::Task(const ctor::build_configuration& config_, const ctor::settings& settings_, + std::string sourceDir_) + : config(config_) , output_system(config.system) - , settings(settings) - , sourceDir(sourceDir) + , settings(settings_) + , sourceDir(std::move(sourceDir_)) { } @@ -45,10 +45,12 @@ int Task::registerDepTasks(const std::vector<std::shared_ptr<Task>>& tasks) bool Task::operator==(const std::string& depStr) { + std::filesystem::path generated_output = sourceDir; + generated_output /= target(); return name() == depStr || target() == depStr || - sourceDir + "/" + target() == depStr || + generated_output == depStr || targetFile().string() == depStr ; } @@ -144,6 +146,7 @@ std::string Task::compiler() const case ctor::output_system::build: return c.get(ctor::cfg::build_cc, "/usr/bin/gcc"); } + break; case ctor::language::cpp: switch(outputSystem()) { @@ -152,11 +155,15 @@ std::string Task::compiler() const case ctor::output_system::build: return c.get(ctor::cfg::build_cxx, "/usr/bin/g++"); } + break; default: std::cerr << "Unknown CC target type\n"; exit(1); break; } + + std::cerr << "Unhandled compiler!\n"; + exit(1); } std::vector<std::shared_ptr<Task>> Task::getDependsTasks() @@ -24,11 +24,11 @@ class Task { public: Task(const ctor::build_configuration& config, const ctor::settings& settings, - const std::string& sourceDir); + std::string sourceDir); virtual ~Task() = default; int registerDepTasks(const std::vector<std::shared_ptr<Task>>& tasks); - virtual int registerDepTasksInner(const std::vector<std::shared_ptr<Task>>& tasks) { return 0; } + virtual int registerDepTasksInner([[maybe_unused]]const std::vector<std::shared_ptr<Task>>& tasks) { return 0; } bool operator==(const std::string& dep); diff --git a/src/task_ar.cc b/src/task_ar.cc index 19a65ae..09403bb 100644 --- a/src/task_ar.cc +++ b/src/task_ar.cc @@ -11,20 +11,20 @@ #include "util.h" #include "tools.h" -TaskAR::TaskAR(const ctor::build_configuration& config, - const ctor::settings& settings, +TaskAR::TaskAR(const ctor::build_configuration& config_, + const ctor::settings& settings_, const std::string& target, const std::vector<std::string>& objects, - const std::string& sourceDir) - : Task(config, settings, sourceDir) - , config(config) - , settings(settings) - , sourceDir(sourceDir) + const std::string& sourceDir_) + : Task(config_, settings_, sourceDir_) + , _targetFile(target) + , config(config_) + , settings(settings_) + , sourceDir(sourceDir_) { target_type = ctor::target_type::static_library; output_system = config.system; - _targetFile = target; auto toolchain = getToolChain(config.system); _targetFile = extension(toolchain, target_type, config.system, _targetFile); for(const auto& object : objects) @@ -36,7 +36,7 @@ TaskAR::TaskAR(const ctor::build_configuration& config, for(const auto& dep : config.depends) { - depFiles.push_back(dep); + depFiles.emplace_back(dep); } flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem(); @@ -105,7 +105,8 @@ int TaskAR::runInner() if(settings.verbose == 0) { - std::cout << "AR => " << targetFile().string() << std::endl; + std::string output = "AR => " + targetFile().string() + '\n'; + std::cout << output << std::flush; } const auto& c = ctor::get_configuration(); @@ -120,7 +121,7 @@ int TaskAR::runInner() break; } - return execute(tool, args, {}, settings.verbose > 0); + return execute(settings, tool, args, c.env); } int TaskAR::clean() diff --git a/src/task_cc.cc b/src/task_cc.cc index 4eb07ae..9de2657 100644 --- a/src/task_cc.cc +++ b/src/task_cc.cc @@ -12,16 +12,17 @@ #include "execute.h" #include "util.h" #include "tools.h" - -TaskCC::TaskCC(const ctor::build_configuration& config, const ctor::settings& settings, - const std::string& sourceDir, const ctor::source& source) - : Task(config, settings, sourceDir) - , config(config) - , settings(settings) - , sourceDir(sourceDir) +#include "deps.h" + +TaskCC::TaskCC(const ctor::build_configuration& config_, const ctor::settings& settings_, + const std::string& sourceDir_, const ctor::source& source) + : Task(config_, settings_, sourceDir_) + , sourceFile(sourceDir_) + , config(config_) + , settings(settings_) + , sourceDir(sourceDir_) , _source(source) { - sourceFile = sourceDir; sourceFile /= source.file; std::filesystem::path base = sourceFile.parent_path(); @@ -136,7 +137,8 @@ bool TaskCC::dirtyInner() } } - auto depList = readDeps(depsFile.string()); + auto toolchain = getToolChain(config.system); + auto depList = readDeps(depsFile.string(), toolchain); for(const auto& dep : depList) { if(!std::filesystem::exists(dep) || @@ -175,25 +177,27 @@ int TaskCC::runInner() if(settings.verbose == 0) { + std::string output; switch(sourceLanguage()) { case ctor::language::c: - std::cout << "CC "; + output = "CC "; break; case ctor::language::cpp: - std::cout << "CXX "; + output = "CXX "; break; case ctor::language::automatic: case ctor::language::assembler: // Only c/c++ handled by this task type. break; } - std::cout << - sourceFile.lexically_normal().string() << " => " << - targetFile().lexically_normal().string() << std::endl; + output += sourceFile.lexically_normal().string() + " => " + + targetFile().lexically_normal().string() + '\n'; + std::cout << output << std::flush; } - return execute(compiler(), args, {}, settings.verbose > 0); + const auto& cfg = ctor::get_configuration(); + return execute(settings, compiler(), args, cfg.env); } int TaskCC::clean() @@ -286,6 +290,7 @@ std::vector<std::string> TaskCC::flags() const exit(1); break; } + } std::string TaskCC::flagsString() const @@ -309,7 +314,7 @@ std::vector<std::string> TaskCC::getCompilerArgs() const { case ctor::language::c: { - append(args, c_option(toolchain, ctor::c_opt::generate_dep_tree)); + append(args, c_option(toolchain, ctor::c_opt::generate_dep_tree, depsFile.string())); if(std::filesystem::path(config.target).extension() == ".so") { @@ -351,7 +356,7 @@ std::vector<std::string> TaskCC::getCompilerArgs() const case ctor::language::cpp: { - append(args, cxx_option(toolchain, ctor::cxx_opt::generate_dep_tree)); + append(args, cxx_option(toolchain, ctor::cxx_opt::generate_dep_tree, depsFile.string())); if(std::filesystem::path(config.target).extension() == ".so") { diff --git a/src/task_fn.cc b/src/task_fn.cc index b11ff15..1ff72f9 100644 --- a/src/task_fn.cc +++ b/src/task_fn.cc @@ -11,13 +11,13 @@ #include "execute.h" #include "util.h" -TaskFn::TaskFn(const ctor::build_configuration& config, const ctor::settings& settings, - const std::string& sourceDir, const ctor::source& source) - : Task(config, settings, sourceDir) - , config(config) - , settings(settings) +TaskFn::TaskFn(const ctor::build_configuration& config_, const ctor::settings& settings_, + const std::string& sourceDir_, const ctor::source& source) + : Task(config_, settings_, sourceDir_) + , sourceFile(sourceDir_) + , config(config_) + , settings(settings_) { - sourceFile = sourceDir; sourceFile /= source.file; std::filesystem::create_directories(std::filesystem::path(settings.builddir) / sourceFile.parent_path()); @@ -68,9 +68,10 @@ int TaskFn::runInner() if(settings.verbose >= 0) { - std::cout << "Fn" << " " << - sourceFile.lexically_normal().string() << " => " << - targetFile().lexically_normal().string() << std::endl; + std::string output = "Fn " + + sourceFile.lexically_normal().string() + " => " + + targetFile().lexically_normal().string() + '\n'; + std::cout << output << std::flush; } return config.function(sourceFile.string(), @@ -97,7 +98,7 @@ std::vector<std::string> TaskFn::depends() const std::string TaskFn::target() const { - return _targetFile; + return _targetFile.string(); } std::filesystem::path TaskFn::targetFile() const diff --git a/src/task_ld.cc b/src/task_ld.cc index b0aa4ae..31ee8c0 100644 --- a/src/task_ld.cc +++ b/src/task_ld.cc @@ -11,15 +11,17 @@ #include "util.h" #include "tools.h" -TaskLD::TaskLD(const ctor::build_configuration& config, - const ctor::settings& settings, +TaskLD::TaskLD(const ctor::build_configuration& config_, + const ctor::settings& settings_, const std::string& target, const std::vector<std::string>& objects, - const std::string& sourceDir) - : Task(config, settings, sourceDir) - , config(config) - , settings(settings) - , sourceDir(sourceDir) + const std::string& sourceDir_, + bool is_self_) + : Task(config_, settings_, sourceDir_) + , config(config_) + , settings(settings_) + , sourceDir(sourceDir_) + , is_self(is_self_) { target_type = config.type; output_system = config.system; @@ -41,7 +43,7 @@ TaskLD::TaskLD(const ctor::build_configuration& config, for(const auto& dep : config.depends) { - depFiles.push_back(dep); + depFiles.emplace_back(dep); } flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem(); @@ -121,11 +123,13 @@ int TaskLD::runInner() if(settings.verbose == 0) { - std::cout << "LD => " << targetFile().string() << std::endl; + std::string output = "LD => " + targetFile().string() + '\n'; + std::cout << output << std::flush; } auto tool = compiler(); - return execute(tool, args, {}, settings.verbose > 0); + const auto& c = ctor::get_configuration(); + return execute(settings, tool, args, c.env, is_self); } int TaskLD::clean() diff --git a/src/task_ld.h b/src/task_ld.h index dbe7db1..c0e3ebb 100644 --- a/src/task_ld.h +++ b/src/task_ld.h @@ -18,7 +18,8 @@ public: const ctor::settings& settings, const std::string& target, const std::vector<std::string>& objects, - const std::string& _sourceDir); + const std::string& _sourceDir, + bool is_self); virtual ~TaskLD() = default; bool dirtyInner() override; @@ -44,4 +45,5 @@ private: const ctor::build_configuration& config; const ctor::settings& settings; std::string sourceDir; + bool is_self; }; diff --git a/src/task_so.cc b/src/task_so.cc index ba96388..eecd7aa 100644 --- a/src/task_so.cc +++ b/src/task_so.cc @@ -11,15 +11,15 @@ #include "util.h" #include "tools.h" -TaskSO::TaskSO(const ctor::build_configuration& config, - const ctor::settings& settings, +TaskSO::TaskSO(const ctor::build_configuration& config_, + const ctor::settings& settings_, const std::string& target, const std::vector<std::string>& objects, - const std::string& sourceDir) - : Task(config, settings, sourceDir) - , config(config) - , settings(settings) - , sourceDir(sourceDir) + const std::string& sourceDir_) + : Task(config_, settings_, sourceDir_) + , config(config_) + , settings(settings_) + , sourceDir(sourceDir_) { std::filesystem::path base = sourceDir; @@ -38,7 +38,7 @@ TaskSO::TaskSO(const ctor::build_configuration& config, for(const auto& dep : config.depends) { - depFiles.push_back(dep); + depFiles.emplace_back(dep); } flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem(); @@ -110,11 +110,13 @@ int TaskSO::runInner() if(settings.verbose == 0) { - std::cout << "LD => " << targetFile().string() << std::endl; + std::string output = "LD => " + targetFile().string() + '\n'; + std::cout << output << std::flush; } auto tool = compiler(); - return execute(tool, args, {}, settings.verbose > 0); + const auto& cfg = ctor::get_configuration(); + return execute(settings, tool, args, cfg.env); } int TaskSO::clean() diff --git a/src/tasks.cc b/src/tasks.cc index 61c130b..2f9e47a 100644 --- a/src/tasks.cc +++ b/src/tasks.cc @@ -8,6 +8,7 @@ #include <list> #include <iostream> #include <algorithm> +#include <span> #include "ctor.h" #include "task.h" @@ -24,20 +25,22 @@ const std::deque<Target>& getTargets(const ctor::settings& settings, bool resolve_externals) { + auto config_files = std::span(configFiles).subspan(0, numConfigFiles); + static bool initialised{false}; static std::deque<Target> targets; if(!initialised) { const auto& externals = ctor::get_configuration().externals; - for(std::size_t i = 0; i < numConfigFiles; ++i) + for(const auto& config_file : config_files) { std::string path = - std::filesystem::path(configFiles[i].file).parent_path().string(); + std::filesystem::path(config_file.file).parent_path().string(); if(settings.verbose > 1) { - std::cout << configFiles[i].file << " in path " << path << "\n"; + std::cout << config_file.file << " in path " << path << "\n"; } - auto configs = configFiles[i].cb(settings); + auto configs = config_file.cb(settings); for(auto& config : configs) { if(resolve_externals) @@ -72,7 +75,8 @@ const std::deque<Target>& getTargets(const ctor::settings& settings, std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& config, const ctor::settings& settings, - const std::string& sourceDir) + const std::string& sourceDir, + bool is_self) { std::vector<std::shared_ptr<Task>> tasks; @@ -91,14 +95,20 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& } } + const auto& c = ctor::get_configuration(); std::vector<std::string> objects; if(target_type != ctor::target_type::function) { - for(const auto& file : config.sources) + for(const auto& source : config.sources) { - auto task = std::make_shared<TaskCC>(config, settings, sourceDir, file); - tasks.push_back(task); - objects.push_back(task->targetFile().string()); + if(source.toolchain == ctor::toolchain::any || + (config.system == ctor::output_system::build && source.toolchain == c.build_toolchain) || + (config.system == ctor::output_system::host && source.toolchain == c.host_toolchain)) + { + auto task = std::make_shared<TaskCC>(config, settings, sourceDir, source); + tasks.push_back(task); + objects.push_back(task->targetFile().string()); + } } } #ifndef BOOTSTRAP @@ -145,7 +155,7 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& case ctor::target_type::executable: case ctor::target_type::unit_test: tasks.push_back(std::make_shared<TaskLD>(config, settings, config.target, - objects, sourceDir)); + objects, sourceDir, is_self)); break; case ctor::target_type::object: @@ -160,7 +170,7 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& return tasks; } -std::shared_ptr<Task> getNextTask(const std::vector<std::shared_ptr<Task>>& allTasks, +std::shared_ptr<Task> getNextTask([[maybe_unused]]const std::vector<std::shared_ptr<Task>>& allTasks, std::vector<std::shared_ptr<Task>>& dirtyTasks) { for(auto dirtyTask = dirtyTasks.begin(); @@ -192,7 +202,7 @@ std::vector<std::shared_ptr<Task>> getTasks(const ctor::settings& settings, std::find(std::begin(names), std::end(names), target.config.target) != std::end(names)) { std::vector<std::string> objects; - auto t = taskFactory(target.config, settings, target.path); + auto t = taskFactory(target.config, settings, target.path, false); tasks.insert(tasks.end(), t.begin(), t.end()); } } diff --git a/src/tasks.h b/src/tasks.h index cc34f56..6573784 100644 --- a/src/tasks.h +++ b/src/tasks.h @@ -36,4 +36,5 @@ std::vector<std::shared_ptr<Task>> getTasks(const ctor::settings& settings, //! link target and all its objects files (if any). std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& config, const ctor::settings& settings, - const std::string& sourceDir); + const std::string& sourceDir, + bool is_self); diff --git a/src/tools.cc b/src/tools.cc index be94794..eb98265 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -28,6 +28,7 @@ std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt) case ctor::c_opt::optimization: stream << "ctor::c_opt::optimization"; break; case ctor::c_opt::position_independent_code: stream << "ctor::c_opt::position_independent_code"; break; case ctor::c_opt::position_independent_executable: stream << "ctor::c_opt::position_independent_executable"; break; + case ctor::c_opt::define: stream << "ctor::c_opt::define"; break; case ctor::c_opt::custom: stream << "ctor::c_opt::custom"; break; } @@ -50,6 +51,7 @@ std::ostream& operator<<(std::ostream& stream, const ctor::cxx_opt& opt) case ctor::cxx_opt::optimization: stream << "ctor::cxx_opt::optimization"; break; case ctor::cxx_opt::position_independent_code: stream << "ctor::cxx_opt::position_independent_code"; break; case ctor::cxx_opt::position_independent_executable: stream << "ctor::cxx_opt::position_independent_executable"; break; + case ctor::cxx_opt::define: stream << "ctor::cxx_opt::define"; break; case ctor::cxx_opt::custom: stream << "ctor::cxx_opt::custom"; break; } @@ -175,10 +177,11 @@ std::string get_arch(ctor::output_system system) std::string arch; while(!feof(pipe)) { - char buf[1024]; - if(fgets(buf, sizeof(buf), pipe) != nullptr) + constexpr auto buffer_size{1024}; + std::array<char, buffer_size> buf{}; + if(fgets(buf.data(), buf.size(), pipe) != nullptr) { - arch = buf; + arch = buf.data(); if(arch.starts_with("Target:")) { break; @@ -195,7 +198,8 @@ std::string get_arch(ctor::output_system system) } // Remove 'Target: ' prefix - arch = arch.substr(8); + constexpr auto prefix_length{8}; + arch = arch.substr(prefix_length); return arch; } @@ -243,6 +247,19 @@ ctor::c_flag c_option(const std::string& flag) return { ctor::c_opt::include_path, path }; } + if(flag.starts_with("-D")) + { + std::string def = flag.substr(2); + auto pos = def.find('='); + if(pos != def.npos) + { + return { ctor::c_opt::define, def.substr(0, pos), def.substr(pos + 1) }; + } + else + { + return { ctor::c_opt::define, def }; + } + } return { ctor::c_opt::custom, flag }; } @@ -255,6 +272,20 @@ ctor::cxx_flag cxx_option(const std::string& flag) return { ctor::cxx_opt::include_path, path }; } + if(flag.starts_with("-D")) + { + std::string def = flag.substr(2); + auto pos = def.find('='); + if(pos != def.npos) + { + return { ctor::cxx_opt::define, def.substr(0, pos), def.substr(pos + 1) }; + } + else + { + return { ctor::cxx_opt::define, def }; + } + } + return { ctor::cxx_opt::custom, flag }; } @@ -275,7 +306,8 @@ ctor::ar_flag ar_option(const std::string& flag) return { ctor::ar_opt::custom, flag }; } -std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg) +std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg, + const std::string& arg2) { switch(opt) { @@ -301,6 +333,12 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg) return {"-fPIC"}; case ctor::cxx_opt::position_independent_executable: return {"-fPIE"}; + case ctor::cxx_opt::define: + if(!arg2.empty()) + { + return {"-D" + arg + "=" + arg2}; + } + return {"-D" + arg}; case ctor::cxx_opt::custom: return {arg}; } @@ -309,7 +347,8 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg) return {}; } -std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg) +std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg, + const std::string& arg2) { switch(opt) { @@ -335,6 +374,12 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg) return {"-fPIC"}; case ctor::c_opt::position_independent_executable: return {"-fPIE"}; + case ctor::c_opt::define: + if(!arg2.empty()) + { + return {"-D" + arg + "=" + arg2}; + } + return {"-D" + arg}; case ctor::c_opt::custom: return {arg}; } @@ -343,7 +388,8 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg) return {}; } -std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg) +std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg, + [[maybe_unused]]const std::string& arg2) { switch(opt) { @@ -377,7 +423,8 @@ std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg) return {}; } -std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg) +std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg, + [[maybe_unused]]const std::string& arg2) { switch(opt) { @@ -397,7 +444,8 @@ std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg) return {}; } -std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg) +std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg, + [[maybe_unused]]const std::string& arg2) { switch(opt) { @@ -442,13 +490,14 @@ ctor::arch get_arch(ctor::output_system system, const std::string& str) std::vector<std::string> c_option(ctor::toolchain toolchain, ctor::c_opt opt, - const std::string& arg) + const std::string& arg, + const std::string& arg2) { switch(toolchain) { case ctor::toolchain::gcc: case ctor::toolchain::clang: - return gcc::c_option(opt, arg); + return gcc::c_option(opt, arg, arg2); case ctor::toolchain::any: { std::ostringstream ss; @@ -457,6 +506,10 @@ std::vector<std::string> c_option(ctor::toolchain toolchain, { ss << ", \"" << arg << "\""; } + if(!arg2.empty()) + { + ss << ", \"" << arg2 << "\""; + } ss << "}"; return { ss.str() }; } @@ -470,13 +523,14 @@ std::vector<std::string> c_option(ctor::toolchain toolchain, std::vector<std::string> cxx_option(ctor::toolchain toolchain, ctor::cxx_opt opt, - const std::string& arg) + const std::string& arg, + const std::string& arg2) { switch(toolchain) { case ctor::toolchain::gcc: case ctor::toolchain::clang: - return gcc::cxx_option(opt, arg); + return gcc::cxx_option(opt, arg, arg2); case ctor::toolchain::any: { std::ostringstream ss; @@ -485,6 +539,10 @@ std::vector<std::string> cxx_option(ctor::toolchain toolchain, { ss << ", \"" << arg << "\""; } + if(!arg2.empty()) + { + ss << ", \"" << arg2 << "\""; + } ss << "}"; return { ss.str() }; } @@ -498,13 +556,14 @@ std::vector<std::string> cxx_option(ctor::toolchain toolchain, std::vector<std::string> ld_option(ctor::toolchain toolchain, ctor::ld_opt opt, - const std::string& arg) + const std::string& arg, + const std::string& arg2) { switch(toolchain) { case ctor::toolchain::gcc: case ctor::toolchain::clang: - return gcc::ld_option(opt, arg); + return gcc::ld_option(opt, arg, arg2); case ctor::toolchain::any: { std::ostringstream ss; @@ -513,6 +572,10 @@ std::vector<std::string> ld_option(ctor::toolchain toolchain, { ss << ", \"" << arg << "\""; } + if(!arg2.empty()) + { + ss << ", \"" << arg2 << "\""; + } ss << "}"; return { ss.str() }; } @@ -526,13 +589,14 @@ std::vector<std::string> ld_option(ctor::toolchain toolchain, std::vector<std::string> ar_option(ctor::toolchain toolchain, ctor::ar_opt opt, - const std::string& arg) + const std::string& arg, + const std::string& arg2) { switch(toolchain) { case ctor::toolchain::gcc: case ctor::toolchain::clang: - return gcc::ar_option(opt, arg); + return gcc::ar_option(opt, arg, arg2); case ctor::toolchain::any: { std::ostringstream ss; @@ -541,6 +605,10 @@ std::vector<std::string> ar_option(ctor::toolchain toolchain, { ss << ", \"" << arg << "\""; } + if(!arg2.empty()) + { + ss << ", \"" << arg2 << "\""; + } ss << "}"; return { ss.str() }; } @@ -554,13 +622,14 @@ std::vector<std::string> ar_option(ctor::toolchain toolchain, std::vector<std::string> asm_option(ctor::toolchain toolchain, ctor::asm_opt opt, - const std::string& arg) + const std::string& arg, + const std::string& arg2) { switch(toolchain) { case ctor::toolchain::gcc: case ctor::toolchain::clang: - return gcc::asm_option(opt, arg); + return gcc::asm_option(opt, arg, arg2); case ctor::toolchain::any: { std::ostringstream ss; @@ -569,6 +638,10 @@ std::vector<std::string> asm_option(ctor::toolchain toolchain, { ss << ", \"" << arg << "\""; } + if(!arg2.empty()) + { + ss << ", \"" << arg2 << "\""; + } ss << "}"; return { ss.str() }; } @@ -663,7 +736,7 @@ std::vector<std::string> to_strings(ctor::toolchain toolchain, if(flag.toolchain == ctor::toolchain::any || flag.toolchain == toolchain) { - return c_option(toolchain, flag.opt, flag.arg); + return c_option(toolchain, flag.opt, flag.arg, flag.arg2); } return {}; @@ -675,7 +748,7 @@ std::vector<std::string> to_strings(ctor::toolchain toolchain, if(flag.toolchain == ctor::toolchain::any || flag.toolchain == toolchain) { - return cxx_option(toolchain, flag.opt, flag.arg); + return cxx_option(toolchain, flag.opt, flag.arg, flag.arg2); } return {}; @@ -687,7 +760,7 @@ std::vector<std::string> to_strings(ctor::toolchain toolchain, if(flag.toolchain == ctor::toolchain::any || flag.toolchain == toolchain) { - return ld_option(toolchain, flag.opt, flag.arg); + return ld_option(toolchain, flag.opt, flag.arg, flag.arg2); } return {}; @@ -699,7 +772,7 @@ std::vector<std::string> to_strings(ctor::toolchain toolchain, if(flag.toolchain == ctor::toolchain::any || flag.toolchain == toolchain) { - return ar_option(toolchain, flag.opt, flag.arg); + return ar_option(toolchain, flag.opt, flag.arg, flag.arg2); } return {}; @@ -711,7 +784,7 @@ std::vector<std::string> to_strings(ctor::toolchain toolchain, if(flag.toolchain == ctor::toolchain::any || flag.toolchain == toolchain) { - return asm_option(toolchain, flag.opt, flag.arg); + return asm_option(toolchain, flag.opt, flag.arg, flag.arg2); } return {}; diff --git a/src/tools.h b/src/tools.h index 188d49f..0e7fc15 100644 --- a/src/tools.h +++ b/src/tools.h @@ -32,31 +32,36 @@ ctor::toolchain getToolChain(ctor::output_system system); //! tool-chain std::vector<std::string> c_option(ctor::toolchain toolchain, ctor::c_opt option, - const std::string& arg = {}); + const std::string& arg = {}, + const std::string& arg2 = {}); //! Get tool argument(s) for specific option type matching the supplied //! tool-chain std::vector<std::string> cxx_option(ctor::toolchain toolchain, ctor::cxx_opt option, - const std::string& arg = {}); + const std::string& arg = {}, + const std::string& arg2 = {}); //! Get tool argument(s) for specific option type matching the supplied //! tool-chain std::vector<std::string> ld_option(ctor::toolchain toolchain, ctor::ld_opt option, - const std::string& arg = {}); + const std::string& arg = {}, + const std::string& arg2 = {}); //! Get tool argument(s) for specific option type matching the supplied //! tool-chain std::vector<std::string> ar_option(ctor::toolchain toolchain, ctor::ar_opt option, - const std::string& arg = {}); + const std::string& arg = {}, + const std::string& arg2 = {}); //! Get tool argument(s) for specific option type matching the supplied //! tool-chain std::vector<std::string> asm_option(ctor::toolchain toolchain, ctor::asm_opt option, - const std::string& arg = {}); + const std::string& arg = {}, + const std::string& arg2 = {}); diff --git a/src/unittest.cc b/src/unittest.cc index 9e85187..b95a931 100644 --- a/src/unittest.cc +++ b/src/unittest.cc @@ -24,7 +24,7 @@ int runUnitTests(std::vector<std::shared_ptr<Task>>& tasks, name = task->target(); } std::cout << name << ": " << std::flush; - auto ret = execute(task->targetFile(), {}, {}, settings.verbose > 0); + auto ret = execute(settings, task->targetFile().string(), {}, {}); ok &= ret == 0; if(ret == 0) { diff --git a/src/util.cc b/src/util.cc index 76d380b..dbd4c3c 100644 --- a/src/util.cc +++ b/src/util.cc @@ -22,70 +22,10 @@ std::string readFile(const std::string& fileName) std::ifstream::pos_type fileSize = ifs.tellg(); ifs.seekg(0, std::ios::beg); - std::vector<char> bytes(fileSize); + std::vector<char> bytes(static_cast<std::size_t>(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; + return {bytes.data(), static_cast<std::size_t>(fileSize)}; } ctor::language languageFromExtension(const std::filesystem::path& file) @@ -12,7 +12,6 @@ std::string to_lower(const std::string& str); std::string readFile(const std::string& fileName); -std::vector<std::string> readDeps(const std::string& depFile); ctor::language languageFromExtension(const std::filesystem::path& file); std::string cleanUp(const std::string& path); diff --git a/test/ctor.cc b/test/ctor.cc index ccf1c31..1951a30 100644 --- a/test/ctor.cc +++ b/test/ctor.cc @@ -12,6 +12,25 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings) { .type = ctor::target_type::unit_test, .system = ctor::output_system::build, + .target = "deps_test", + .sources = { + "deps_test.cc", + "testmain.cc", + "../src/deps.cc", + "../src/util.cc", + }, + .depends = { "testprog", }, + .flags = { + .cxxflags = { + "-std=c++20", "-O3", "-Wall", "-Werror", + "-I../src", "-Iuunit", + "-DOUTPUT=\"deps\"", + }, + }, + }, + { + .type = ctor::target_type::unit_test, + .system = ctor::output_system::build, .target = "testprog", .sources = { "testprog.cc", @@ -104,6 +123,7 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings) .sources = { "../src/build.cc", "../src/configure.cc", + "../src/deps.cc", "../src/execute.cc", "../src/rebuild.cc", "../src/tasks.cc", diff --git a/test/deps_test.cc b/test/deps_test.cc new file mode 100644 index 0000000..762b0e5 --- /dev/null +++ b/test/deps_test.cc @@ -0,0 +1,97 @@ +#include <uunit.h> + +#include <fstream> +#include <map> +#include <vector> + +#include <deps.h> +#include <algorithm> + +#include "paths.h" +#include "tmpfile.h" + +class DepsTest + : public uUnit +{ +public: + DepsTest() + { + uTEST(DepsTest::parser_test); + } + + void parser_test() + { + using namespace std::string_literals; + + auto test_data = paths::top_srcdir / "test" / "deps_test_data"; + + auto empty = test_data / "empty.d"; + auto trivial = test_data / "trivial.d"; + auto no_newline = test_data / "no_newline.d"; + auto no_deps = test_data / "no_deps.d"; + auto trailing_whitespace = test_data / "trailing_whitespace.d"; + auto spaces = test_data / "spaces.d"; + auto multiline = test_data / "multiline.d"; + auto no_such_file = test_data / "no_such_file.d"; // doesn't exist + auto missing_colon = test_data / "missing_colon.d"; + + { + auto res = readDeps(empty.string(), ctor::toolchain::gcc); + uASSERT(res.empty()); + } + + { + auto res = readDeps(trivial.string(), ctor::toolchain::gcc); + uASSERT_EQUAL(1u, res.size()); + uASSERT_EQUAL("x.cc"s, res[0]); + } + + { + auto res = readDeps(no_newline.string(), ctor::toolchain::gcc); + uASSERT_EQUAL(1u, res.size()); + uASSERT_EQUAL("x.cc"s, res[0]); + } + + { + auto res = readDeps(no_deps.string(), ctor::toolchain::gcc); + uASSERT_EQUAL(0u, res.size()); + } + + { + auto res = readDeps(spaces.string(), ctor::toolchain::gcc); + uASSERT_EQUAL(2u, res.size()); + uASSERT_EQUAL("x y.cc"s, res[0]); + uASSERT_EQUAL("x y.h"s, res[1]); + } + + { + auto res = readDeps(multiline.string(), ctor::toolchain::gcc); + uASSERT_EQUAL(12u, res.size()); + uASSERT_EQUAL("src/configure.cc"s, res[0]); + uASSERT_EQUAL("src/configure.h"s, res[1]); + uASSERT_EQUAL("src/getoptpp/getoptpp.hpp"s, res[2]); + uASSERT_EQUAL("src/execute.h"s, res[3]); + uASSERT_EQUAL("src/ctor.h"s, res[4]); + uASSERT_EQUAL("src/tasks.h"s, res[5]); + uASSERT_EQUAL("src/task.h"s, res[6]); + uASSERT_EQUAL("src/rebuild.h"s, res[7]); + uASSERT_EQUAL("src/externals.h"s, res[8]); + uASSERT_EQUAL("src/externals_manual.h"s, res[9]); + uASSERT_EQUAL("src/tools.h"s, res[10]); + uASSERT_EQUAL("src/util.h"s, res[11]); + } + + { + auto res = readDeps(no_such_file.string(), ctor::toolchain::gcc); + uASSERT(res.empty()); + } + + { + auto res = readDeps(missing_colon.string(), ctor::toolchain::gcc); + uASSERT(res.empty()); + } + } +}; + +// Registers the fixture into the 'registry' +static DepsTest test; diff --git a/test/deps_test_data/empty.d b/test/deps_test_data/empty.d new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/deps_test_data/empty.d diff --git a/test/deps_test_data/missing_colon.d b/test/deps_test_data/missing_colon.d new file mode 100644 index 0000000..e46996c --- /dev/null +++ b/test/deps_test_data/missing_colon.d @@ -0,0 +1 @@ +x.cc x.h diff --git a/test/deps_test_data/multiline.d b/test/deps_test_data/multiline.d new file mode 100644 index 0000000..8862ab0 --- /dev/null +++ b/test/deps_test_data/multiline.d @@ -0,0 +1,4 @@ +build/src/libctor_a-configure_cc.o: src/configure.cc src/configure.h \ + src/getoptpp/getoptpp.hpp src/execute.h src/ctor.h src/tasks.h \ + src/task.h src/rebuild.h src/externals.h src/externals_manual.h \ + src/tools.h src/util.h diff --git a/test/deps_test_data/no_deps.d b/test/deps_test_data/no_deps.d new file mode 100644 index 0000000..e7cccf6 --- /dev/null +++ b/test/deps_test_data/no_deps.d @@ -0,0 +1 @@ +x.o: diff --git a/test/deps_test_data/no_newline.d b/test/deps_test_data/no_newline.d new file mode 100644 index 0000000..88829ea --- /dev/null +++ b/test/deps_test_data/no_newline.d @@ -0,0 +1 @@ +x.o: x.cc
\ No newline at end of file diff --git a/test/deps_test_data/spaces.d b/test/deps_test_data/spaces.d new file mode 100644 index 0000000..c53fd64 --- /dev/null +++ b/test/deps_test_data/spaces.d @@ -0,0 +1 @@ +x\ y.o: x\ y.cc x\ y.h diff --git a/test/deps_test_data/trivial.d b/test/deps_test_data/trivial.d new file mode 100644 index 0000000..15a0c29 --- /dev/null +++ b/test/deps_test_data/trivial.d @@ -0,0 +1 @@ +x.o: x.cc diff --git a/test/execute_test.cc b/test/execute_test.cc index d5d40c9..4c686bf 100644 --- a/test/execute_test.cc +++ b/test/execute_test.cc @@ -23,20 +23,25 @@ public: void return_value() { + ctor::settings s; auto cur_path = std::filesystem::path(paths::argv_0).parent_path(); std::vector<std::string> paths{{cur_path.string()}}; auto cmd = locate("testprog", paths); uASSERT(!cmd.empty()); - uASSERT_EQUAL(0, execute(cmd, {"retval", "0"}, {}, false)); - uASSERT_EQUAL(1, execute(cmd, {"retval", "1"}, {}, false)); - uASSERT_EQUAL(1, execute("no-such-binary", {}, {}, false)); + auto value = execute(s, cmd, {"retval", "0"}, {}, false); + uASSERT_EQUAL(0, value); + value = execute(s, cmd, {"retval", "1"}, {}, false); + uASSERT_EQUAL(1, value); + value = execute(s, "no-such-binary", {}, {}, false); + uASSERT_EQUAL(1, value); } void env() { using namespace std::string_literals; + ctor::settings s; auto cur_path = std::filesystem::path(paths::argv_0).parent_path(); std::vector<std::string> paths{{cur_path.string()}}; auto cmd = locate("testprog", paths); @@ -53,7 +58,8 @@ public: // Overwrite the exiting LANG var env["LANG"] = "foo"; - uASSERT_EQUAL(0, execute(cmd, {"envdump", tmp.get()}, env, false)); + auto value = execute(s, cmd, {"envdump", tmp.get()}, env, false); + uASSERT_EQUAL(0, value); std::vector<std::string> vars; { |