diff --git a/modcc/modcc.cpp b/modcc/modcc.cpp index 975d35e36a680f3b7ba027af5784dd4a52467f9d..6036ac166d6e670f4e8e70da4a355cae97f20803 100644 --- a/modcc/modcc.cpp +++ b/modcc/modcc.cpp @@ -22,19 +22,20 @@ #include <fmt/format.h> -using std::cout; -using std::cerr; +#include <filesystem> + +namespace fs = std::filesystem; // Options and option parsing: int report_error(const std::string& message) { - cerr << red("error trace:\n") << message << "\n"; + std::cerr << red("error trace:\n") << message << "\n"; return 1; } int report_ice(const std::string& message) { - cerr << red("internal compiler error:\n") << message << "\n" - << "\nPlease report this error to the modcc developers.\n"; + std::cerr << red("internal compiler error:\n") << message << "\n" + << "\nPlease report this error to the modcc developers.\n"; return 1; } @@ -99,22 +100,19 @@ std::ostream& operator<<(std::ostream& out, const Options& opt) { targets += " "+key_by_value(targetKindMap, t); } - for (const auto& f: opt.modfiles) { - out << table_prefix{"file"} << f << line_end; - } - out << table_prefix{"output"} << (opt.outprefix.empty()? "-": opt.outprefix) << line_end << - table_prefix{"verbose"} << noyes[opt.verbose] << line_end << - table_prefix{"targets"} << targets << line_end << - table_prefix{"analysis"} << noyes[opt.analysis] << line_end; + for (const auto& f: opt.modfiles) out << table_prefix{"file"} << f << line_end; + out << table_prefix{"output"} << (opt.outprefix.empty() ? "-" : opt.outprefix) << line_end + << table_prefix{"verbose"} << noyes[opt.verbose] << line_end + << table_prefix{"targets"} << targets << line_end + << table_prefix{"analysis"} << noyes[opt.analysis] << line_end; return out; } std::ostream& operator<<(std::ostream& out, const printer_options& popt) { static const std::string line_end = cyan(" |") + "\n"; - - return out << - table_prefix{"namespace"} << popt.cpp_namespace << line_end << - table_prefix{"simd"} << popt.simd << line_end; + out << table_prefix{"namespace"} << popt.cpp_namespace << line_end + << table_prefix{"simd"} << popt.simd << line_end; + return out; } std::istream& operator>> (std::istream& i, simd_spec& spec) { @@ -146,8 +144,6 @@ const char* usage_str = "<filenames> [Files to be compiled]\n"; int main(int argc, char **argv) { - using namespace to; - Options opt; printer_options popt; try { @@ -188,99 +184,96 @@ int main(int argc, char **argv) { if (!opt.catalogue.empty()) popt.cpp_namespace += "::" + opt.catalogue + "_catalogue"; - std::vector<std::string> modules; + std::vector<std::pair<std::string, std::string>> modules; + - for (const auto& modfile: opt.modfiles) { + auto outdir = fs::path(opt.outprefix); + + for (const auto& input: opt.modfiles) { + auto modfile = fs::path(input); try { auto emit_header = [&opt](const char* h) { if (opt.verbose) { - cout << green("[") << h << green("]") << "\n"; + std::cout << green("[") << h << green("]") << "\n"; } }; if (opt.verbose) { static const std::string tableline = cyan("."+std::string(60, '-')+".")+"\n"; - cout << tableline; - cout << opt; - cout << popt; - cout << tableline; + std::cout << tableline + << opt + << popt + << tableline; } // Load module file and initialize Module object. Module m(io::read_all(modfile), modfile); - if (m.empty()) { - return report_error("empty file: "+modfile); - } + if (m.empty()) return report_error(fmt::format("Input file is empty: {}", modfile.string())); // Perform parsing and semantic analysis passes. - emit_header("parsing"); Parser p(m, false); - if (!p.parse()) { - // Parser::parse() writes its own errors to stderr. - return 1; - } + if (!p.parse()) return 1; emit_header("semantic analysis"); m.semantic(); if (m.has_warning()) { - cerr << yellow("Warnings:\n"); - cerr << m.warning_string() << "\n"; - } - if (m.has_error()) { - return report_error(m.error_string()); + std::cerr << yellow("Warnings:\n") + << m.warning_string() << "\n"; } - // Generate backend-specific sources for each backend provided. + if (m.has_error()) return report_error(m.error_string()); + // Generate backend-specific sources for each backend provided. emit_header("code generation"); - std::string prefix = m.module_name(); - if (!opt.outprefix.empty()) { - if (opt.outprefix.back() != '/') opt.outprefix += "/"; - prefix = opt.outprefix + prefix; - } + std::string mod = m.module_name(); bool have_cpu = opt.targets.find(targetKind::cpu) != opt.targets.end(); bool have_gpu = opt.targets.find(targetKind::gpu) != opt.targets.end(); - io::write_all(build_info_header(m, popt, have_cpu, have_gpu), prefix+".hpp"); + auto prefix = modfile.filename().replace_extension("").string(); + + io::write_all(build_info_header(m, popt, have_cpu, have_gpu), outdir / (mod + ".hpp")); for (targetKind target: opt.targets) { - std::string outfile = prefix; switch (target) { - case targetKind::gpu: - io::write_all(emit_gpu_cpp_source(m, popt), outfile+"_gpu.cpp"); - io::write_all(emit_gpu_cu_source(m, popt), outfile+"_gpu.cu"); + case targetKind::gpu: { + fs::path fn = outdir / (mod + "_gpu.cpp"); + io::write_all(emit_gpu_cpp_source(m, popt), fn.string()); + fn.replace_extension(".cu"); + io::write_all(emit_gpu_cu_source(m, popt), fn.string()); break; - case targetKind::cpu: - io::write_all(emit_cpp_source(m, popt), outfile+"_cpu.cpp"); + } + case targetKind::cpu: { + fs::path fn = outdir / (mod + "_cpu"); + fn.replace_extension(".cpp"); + io::write_all(emit_cpp_source(m, popt), fn.string()); break; + } } } // Optional analysis report. - if (opt.analysis) { - cout << green("performance analysis\n"); + std::cout << green("performance analysis\n"); for (auto &symbol: m.symbols()) { if (auto method = symbol.second->is_api_method()) { - cout << white("-------------------------\n"); - cout << yellow("method " + method->name()) << "\n"; - cout << white("-------------------------\n"); - FlopVisitor flops; method->accept(&flops); - cout << white("FLOPS\n") << flops.print() << "\n"; - MemOpVisitor memops; method->accept(&memops); - cout << white("MEMOPS\n") << memops.print() << "\n"; + + std::cout << white("-------------------------\n") + << yellow("method " + method->name()) << "\n" + << white("-------------------------\n") + << white("FLOPS\n") << flops.print() << "\n" + << white("MEMOPS\n") << memops.print() << "\n"; } } } - modules.push_back(m.module_name()); + modules.push_back({mod, prefix}); } catch (io::bulkio_error& e) { return report_error(e.what()); @@ -297,45 +290,43 @@ int main(int argc, char **argv) { } if (!opt.catalogue.empty()) { - const auto prefix = std::regex_replace(popt.cpp_namespace, std::regex{"::"}, "_"); + const auto ns = std::regex_replace(popt.cpp_namespace, std::regex{"::"}, "_"); { - std::ofstream out(opt.outprefix + opt.catalogue + "_catalogue.cpp"); + std::ofstream out(outdir / (opt.catalogue + "_catalogue.cpp")); out << "// Automatically generated by modcc\n" - "\n" - "#include <arbor/mechanism_abi.h>\n" - "\n"; + "\n" + "#include <arbor/mechanism_abi.h>\n" + "\n"; - for (const auto& mod: modules) { - out << fmt::format("#include \"{}.hpp\"\n", mod); - } + for (const auto& [mod, prefix]: modules) out << fmt::format("#include \"{}.hpp\"\n", mod); out << "\n" - "#ifdef STANDALONE\n" - "extern \"C\" {\n" - " [[gnu::visibility(\"default\")]] const void* get_catalogue(int* n) {\n"; - out << fmt::format(" *n = {0};\n" + "#ifdef STANDALONE\n" + "extern \"C\" {\n" + " [[gnu::visibility(\"default\")]] const void* get_catalogue(int* n) {\n" + << fmt::format(" *n = {0};\n" " static arb_mechanism cat[{0}] = {{\n", opt.modfiles.size()); - for (const auto& mod: modules) { - out << fmt::format(" make_{}_{}(),\n", prefix, mod); + for (const auto& [mod, prefix]: modules) { + out << fmt::format(" make_{}_{}(),\n", ns, mod); } out << " };\n" - " return (void*)cat;\n" - " }\n" - "}\n" - "\n" - "#else\n" - "\n" - "#include <arbor/mechanism.hpp>\n" - "#include <arbor/assert.hpp>\n" - "\n"; - out << fmt::format("#include \"{0}_catalogue.hpp\"\n" + " return (void*)cat;\n" + " }\n" + "}\n" + "\n" + "#else\n" + "\n" + "#include <arbor/mechanism.hpp>\n" + "#include <arbor/assert.hpp>\n" + "\n" + << fmt::format("#include \"{0}_catalogue.hpp\"\n" "\n" "namespace arb {{\n" "mechanism_catalogue build_{0}_catalogue() {{\n" " mechanism_catalogue cat;\n", opt.catalogue); - for (const auto& mod: modules) { + for (const auto& [mod, prefix]: modules) { out << fmt::format(" {{\n" " auto mech = make_{}_{}();\n" " auto ty = mech.type();\n" @@ -347,22 +338,21 @@ int main(int argc, char **argv) { " if (ic) cat.register_implementation(nm, std::make_unique<arb::mechanism>(ty, *ic));\n" " if (ig) cat.register_implementation(nm, std::make_unique<arb::mechanism>(ty, *ig));\n" " }}\n", - prefix, mod); + ns, mod); } - out << " return cat;\n" - "}\n" - "\n"; - out << fmt::format("ARB_ARBOR_API const mechanism_catalogue& global_{0}_catalogue() {{\n" + "}\n" + "\n" + << fmt::format("ARB_ARBOR_API const mechanism_catalogue& global_{0}_catalogue() {{\n" " static mechanism_catalogue cat = build_{0}_catalogue();\n" " return cat;\n" "}}\n", - opt.catalogue); - out << "} // namespace arb\n" - "#endif\n"; + opt.catalogue) + << "} // namespace arb\n" + "#endif\n"; } { - std::ofstream out(opt.outprefix + opt.catalogue + "_catalogue.hpp"); + std::ofstream out(outdir / (opt.catalogue + "_catalogue.hpp")); out << fmt::format("#pragma once\n" "\n" "#include <arbor/mechcat.hpp>\n" diff --git a/modcc/printer/infoprinter.cpp b/modcc/printer/infoprinter.cpp index 596b7b80d01ded90e81b6d4d1a25541ba61816dd..f59f52f544513f3d56dbcc82d9fdbd3c45f060a4 100644 --- a/modcc/printer/infoprinter.cpp +++ b/modcc/printer/infoprinter.cpp @@ -1,5 +1,4 @@ #include <ostream> -#include <set> #include <string> #include <regex> @@ -15,8 +14,6 @@ #include "io/ostream_wrappers.hpp" #include "io/prefixbuf.hpp" -using io::quote; - ARB_LIBMODCC_API std::string build_info_header(const Module& m, const printer_options& opt, bool cpu, bool gpu) { using io::indent; using io::popindent;