diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 59a3c5ad5af..734242835f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOUFFLE_SOURCES FunctorOps.cpp Global.cpp + MainDriver.cpp ast/Aggregator.cpp ast/IntrinsicAggregator.cpp ast/UserDefinedAggregator.cpp @@ -220,7 +221,10 @@ target_compile_features(libsouffle PUBLIC cxx_std_17) target_compile_features(compiled PUBLIC cxx_std_17) set_target_properties(libsouffle PROPERTIES CXX_EXTENSIONS OFF) +set_target_properties(libsouffle PROPERTIES POSITION_INDEPENDENT_CODE ON) + set_target_properties(compiled PROPERTIES CXX_EXTENSIONS OFF) +set_target_properties(compiled PROPERTIES POSITION_INDEPENDENT_CODE ON) if (NOT MSVC) target_compile_options(libsouffle PUBLIC -Wall -Wextra -Werror -fwrapv) @@ -315,7 +319,7 @@ set_target_properties(libsouffle PROPERTIES OUTPUT_NAME "souffle") # Souffle binary # -------------------------------------------------- add_executable(souffle - main.cpp) + souffle.cpp) target_link_libraries(souffle libsouffle) install(TARGETS souffle DESTINATION bin) diff --git a/src/main.cpp b/src/MainDriver.cpp similarity index 77% rename from src/main.cpp rename to src/MainDriver.cpp index eba0866f888..0f60cf8da8b 100644 --- a/src/main.cpp +++ b/src/MainDriver.cpp @@ -8,12 +8,13 @@ /************************************************************************ * - * @file main.cpp + * @file MainDriver.cpp * * Main driver for Souffle * ***********************************************************************/ +#include "MainDriver.h" #include "Global.h" #include "ast/Clause.h" #include "ast/Node.h" @@ -103,6 +104,7 @@ #include "souffle/utility/SubProcess.h" #include "synthesiser/GenDb.h" #include "synthesiser/Synthesiser.h" + #include #include #include @@ -183,6 +185,10 @@ void compileToBinary( argv.push_back(glb.config().get("swig")); } + if (glb.config().has("verbose")) { + argv.push_back("-v"); + } + for (auto&& path : glb.config().getMany("library-dir")) { // The first entry may be blank if (path.empty()) { @@ -395,134 +401,300 @@ static WarnSet process_warn_opts(const Global& glb) { return warns; } -int main(Global& glb, int argc, char** argv) { - /* Time taking for overall runtime */ - auto souffle_start = std::chrono::high_resolution_clock::now(); +Own astTransformationPipeline(Global& glb) { + // clang-format off + // Equivalence pipeline + auto equivalencePipeline = + mk(mk(), + mk(mk()), + mk(), + mk(), + mk(), + mk()); - std::string versionFooter; + // Magic-Set pipeline + auto magicPipeline = mk( + mk( + glb.config().has("magic-transform"), mk()), + mk(), mk(), + mk(), + mk(), + mk(), clone(equivalencePipeline)); - /* have all to do with command line arguments in its own scope, as these are accessible through the global - * configuration only */ + // Partitioning pipeline + auto partitionPipeline = + mk(mk(), + mk(), + mk()); + + // Provenance pipeline + auto provenancePipeline = mk(glb.config().has("provenance"), + mk(mk(), + mk())); + + // Main pipeline + auto pipeline = mk(mk(), + mk(), + mk(), + mk(), + mk(), + mk(mk( + mk(), + mk())), + mk(), mk(), + mk(), + mk(), + mk(), + mk( + mk()), + mk(), + mk(), + mk(), + mk(), + mk(), mk(), + mk(), + mk(), mk(), + mk(), + mk(), + mk(), + mk(), + mk(), + mk(mk( + mk(), + mk())), + mk(), std::move(partitionPipeline), + std::move(equivalencePipeline), mk(), + std::move(magicPipeline), mk(), + mk(), + mk(), std::move(provenancePipeline), + mk()); + // clang-format on + + return pipeline; +} + +Own getUnitTranslator(Global& glb) { + auto translationStrategy = + glb.config().has("provenance") + ? mk() + : mk(); + auto unitTranslator = Own(translationStrategy->createUnitTranslator()); + + return unitTranslator; +} + +Own ramTransformerSequence(Global& glb) { + using namespace ram::transform; + // clang-format off + Own ramTransform = mk( + mk(mk(mk(), + mk(), mk())), + mk(), mk(), + mk(), mk(), + mk( + mk(mk(), mk())), + mk(), mk(), + mk(), mk(), + mk(), mk(mk()), + mk( + // job count of 0 means all cores are used. + [&]() -> bool { return std::stoi(glb.config().get("jobs")) != 1; }, + mk()), + mk()); + // clang-format on + + return ramTransform; +} + +bool interpretTranslationUnit(Global& glb, ram::TranslationUnit& ramTranslationUnit) { try { - std::stringstream header; - header << "============================================================================" << std::endl; - header << "souffle -- A datalog engine." << std::endl; - header << "Usage: souffle [OPTION] FILE." << std::endl; - header << "----------------------------------------------------------------------------" << std::endl; - header << "Options:" << std::endl; - - std::stringstream footer; - footer << "----------------------------------------------------------------------------" << std::endl; - footer << "Version: " << PACKAGE_VERSION << std::endl; - footer << "Word size: " << RAM_DOMAIN_SIZE << " bits" << std::endl; - footer << "Options enabled:"; + std::thread profiler; + // Start up profiler if needed + if (glb.config().has("live-profile")) { +#ifdef _MSC_VER + throw("No live-profile on Windows\n."); +#else + profiler = std::thread([]() { profile::Tui().runProf(); }); +#endif + } + + // configure and execute interpreter + const std::size_t numThreadsOrZero = std::stoi(glb.config().get("jobs")); + Own interpreter(mk(ramTranslationUnit, numThreadsOrZero)); + interpreter->executeMain(); + // If the profiler was started, join back here once it exits. + if (profiler.joinable()) { + profiler.join(); + } + if (glb.config().has("provenance")) { +#ifdef _MSC_VER + throw("No explain/explore provenance on Windows\n."); +#else + // only run explain interface if interpreted + interpreter::ProgInterface interface(*interpreter); + if (glb.config().get("provenance") == "explain") { + explain(interface, false); + } else if (glb.config().get("provenance") == "explore") { + explain(interface, true); + } +#endif + } + return true; + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + return false; + } +} + +const char* packageVersion() { + return PACKAGE_VERSION; +} + +std::size_t ramDomainSizeInBits() { + return RAM_DOMAIN_SIZE; +} + +std::string versionFooter() { + std::stringstream footer; + footer << "----------------------------------------------------------------------------" << std::endl; + footer << "Version: " << packageVersion() << std::endl; + footer << "Word size: " << ramDomainSizeInBits() << " bits" << std::endl; + footer << "Options enabled:"; #ifdef USE_LIBFFI - footer << " ffi"; + footer << " ffi"; #endif #ifdef _OPENMP - footer << " openmp"; + footer << " openmp"; #endif #ifdef USE_NCURSES - footer << " ncurses"; + footer << " ncurses"; #endif #ifdef USE_SQLITE - footer << " sqlite"; + footer << " sqlite"; #endif #ifdef USE_LIBZ - footer << " zlib"; + footer << " zlib"; #endif - footer << std::endl; - footer << "----------------------------------------------------------------------------" << std::endl; - footer << "Copyright (c) 2016-22 The Souffle Developers." << std::endl; - footer << "Copyright (c) 2013-16 Oracle and/or its affiliates." << std::endl; - footer << "All rights reserved." << std::endl; - footer << "============================================================================" << std::endl; - - versionFooter = footer.str(); - - // command line options, the environment will be filled with the arguments passed to them, or - // the empty string if they take none - // main option, the datalog program itself, has an empty key - std::vector options{{"", 0, "", "", false, ""}, - {"auto-schedule", 'a', "FILE", "", false, - "Use profile auto-schedule for auto-scheduling."}, - {"fact-dir", 'F', "DIR", ".", false, "Specify directory for fact files."}, - {"include-dir", 'I', "DIR", ".", true, "Specify directory for include files."}, - {"output-dir", 'D', "DIR", ".", false, - "Specify directory for output files. If is `-` then stdout is used."}, - {"jobs", 'j', "N", "1", false, - "Run interpreter/compiler in parallel using N threads, N=auto for system " - "default."}, - {"compile", 'c', "", "", false, - "Generate C++ source code, compile to a binary executable, then run this " - "executable."}, - {"compile-many", 'C', "", "", false, - "Generate C++ source code in multiple files, compile to a binary executable, then " - "run this " - "executable."}, - {"generate", 'g', "FILE", "", false, - "Generate C++ source code for the given Datalog program and write it to " - ". If is `-` then stdout is used."}, - {"generate-many", 'G', "DIR", "", false, - "Generate C++ source code in multiple files for the given Datalog program " - "and write it to ."}, - {"inline-exclude", '\x7', "RELATIONS", "", false, - "Prevent the given relations from being inlined. Overrides any `inline` qualifiers."}, - {"swig", 's', "LANG", "", false, - "Generate SWIG interface for given language. The values accepts is java and " - "python. "}, - {"library-dir", 'L', "DIR", "", true, "Specify directory for library files."}, - {"libraries", 'l', "FILE", "", true, "Specify libraries."}, - {"no-warn", 'w', "", "", false, "Disable warnings."}, - {"warn", 'W', "WARN", "all", true, "Enable a warning."}, - {"wno", '\xb', "WARN", "none", true, "Disable a specific warning."}, - // TODO(lb): - // {"Werror", '\xc', "WARN", "none", false, "Turn a warning into an error."}, - {"magic-transform", 'm', "RELATIONS", "", false, - "Enable magic set transformation changes on the given relations, use '*' " - "for all."}, - {"magic-transform-exclude", '\x8', "RELATIONS", "", false, - "Disable magic set transformation changes on the given relations. Overrides " - "`magic-transform`. Implies `inline-exclude` for the given relations."}, - {"macro", 'M', "MACROS", "", false, "Set macro definitions for the pre-processor"}, - {"disable-transformers", 'z', "TRANSFORMERS", "", false, - "Disable the given AST transformers."}, - {"dl-program", 'o', "FILE", "", false, - "Generate C++ source code, written to , and compile this to a " - "binary executable (without executing it)."}, - {"emit-statistics", '\x9', "", "", false, - "Enable collection of statistics for auto-scheduling"}, - {"live-profile", '\1', "", "", false, "Enable live profiling."}, - {"profile", 'p', "FILE", "", false, "Enable profiling, and write profile data to ."}, - {"profile-frequency", '\2', "", "", false, "Enable the frequency counter in the profiler."}, - {"debug-report", 'r', "FILE", "", false, "Write HTML debug report to ."}, - {"pragma", 'P', "OPTIONS", "", true, "Set pragma options."}, - {"provenance", 't', "[ none | explain | explore ]", "", false, - "Enable provenance instrumentation and interaction."}, - {"verbose", 'v', "", "", false, "Verbose output."}, - {"version", '\3', "", "", false, "Version."}, - {"show", '\4', "[ ]", "", true, - "Print selected program information.\n" - "Modes:\n" - "\tinitial-ast\n" - "\tinitial-ram\n" - "\tparse-errors\n" - "\tprecedence-graph\n" - "\tprecedence-graph-text\n" - "\tscc-graph\n" - "\tscc-graph-text\n" - "\ttransformed-ast\n" - "\ttransformed-ram\n" - "\ttype-analysis"}, - {"parse-errors", '\5', "", "", false, "Show parsing errors, if any, then exit."}, - {"help", 'h', "", "", false, "Display this help message."}, - {"legacy", '\6', "", "", false, "Enable legacy support."}, - {"preprocessor", '\7', "CMD", "", false, "C preprocessor to use."}, - {"no-preprocessor", 10, "", "", false, "Do not use a C preprocessor."}}; - glb.config().processArgs(argc, argv, header.str(), versionFooter, options); - - // ------ command line arguments ------------- + footer << std::endl; + footer << "----------------------------------------------------------------------------" << std::endl; + footer << "Copyright (c) 2016-22 The Souffle Developers." << std::endl; + footer << "Copyright (c) 2013-16 Oracle and/or its affiliates." << std::endl; + footer << "All rights reserved." << std::endl; + footer << "============================================================================" << std::endl; + + return footer.str(); +} +std::vector getMainOptions() { + char nextOptChar = 1; + // clang-format off + std::vector options{ + {"", 0, "", "", false, ""}, + {"auto-schedule", 'a', "FILE", "", false, + "Use profile auto-schedule for auto-scheduling."}, + {"compile", 'c', "", "", false, + "Generate C++ source code, compile to a binary executable, then run this " + "executable."}, + {"compile-many", 'C', "", "", false, + "Generate C++ source code in multiple files, compile to a binary executable, then " + "run this " + "executable."}, + {"debug-report", 'r', "FILE", "", false, + "Write HTML debug report to ."}, + {"disable-transformers", 'z', "TRANSFORMERS", "", false, + "Disable the given AST transformers."}, + {"dl-program", 'o', "FILE", "", false, + "Generate C++ source code, written to , and compile this to a " + "binary executable (without executing it)."}, + {"emit-statistics", nextOptChar++, "", "", false, + "Enable collection of statistics for auto-scheduling"}, + {"fact-dir", 'F', "DIR", ".", false, + "Specify directory for fact files."}, + {"generate", 'g', "FILE", "", false, + "Generate C++ source code for the given Datalog program and write it to " + ". If is `-` then stdout is used."}, + {"generate-many", 'G', "DIR", "", false, + "Generate C++ source code in multiple files for the given Datalog program " + "and write it to ."}, + {"help", 'h', "", "", false, + "Display this help message."}, + {"include-dir", 'I', "DIR", ".", true, + "Specify directory for include files."}, + {"inline-exclude", nextOptChar++, "RELATIONS", "", false, + "Prevent the given relations from being inlined. Overrides any `inline` qualifiers."}, + {"jobs", 'j', "N", "1", false, + "Run interpreter/compiler in parallel using N threads, N=auto for system " + "default."}, + {"legacy", nextOptChar++, "", "", false, + "Enable legacy support."}, + {"libraries", 'l', "FILE", "", true, + "Specify libraries."}, + {"library-dir", 'L', "DIR", "", true, + "Specify directory for library files."}, + {"live-profile", nextOptChar++, "", "", false, + "Enable live profiling."}, + {"macro", 'M', "MACROS", "", false, + "Set macro definitions for the pre-processor"}, + {"magic-transform", 'm', "RELATIONS", "", false, + "Enable magic set transformation changes on the given relations, use '*' " + "for all."}, + {"magic-transform-exclude", nextOptChar++, "RELATIONS", "", false, + "Disable magic set transformation changes on the given relations. Overrides " + "`magic-transform`. Implies `inline-exclude` for the given relations."}, + {"no-preprocessor", nextOptChar++, "", "", false, + "Do not use a C preprocessor."}, + {"no-warn", 'w', "", "", false, + "Disable warnings."}, + {"output-dir", 'D', "DIR", ".", false, + "Specify directory for output files. If is `-` then stdout is used."}, + {"parse-errors", nextOptChar++, "", "", false, + "Show parsing errors, if any, then exit."}, + {"pragma", 'P', "OPTIONS", "", true, + "Set pragma options."}, + {"preprocessor", nextOptChar++, "CMD", "", false, + "C preprocessor to use."}, + {"profile", 'p', "FILE", "", false, + "Enable profiling, and write profile data to ."}, + {"profile-frequency", nextOptChar++, "", "", false, + "Enable the frequency counter in the profiler."}, + {"provenance", 't', "[ none | explain | explore ]", "", false, + "Enable provenance instrumentation and interaction."}, + {"show", nextOptChar++, "[ ]", "", true, + "Print selected program information.\n" + "Modes:\n" + "\tinitial-ast\n" + "\tinitial-ram\n" + "\tparse-errors\n" + "\tprecedence-graph\n" + "\tprecedence-graph-text\n" + "\tscc-graph\n" + "\tscc-graph-text\n" + "\ttransformed-ast\n" + "\ttransformed-ram\n" + "\ttype-analysis"}, + {"swig", 's', "LANG", "", false, + "Generate SWIG interface for given language. The values accepts is java and " + "python. "}, + {"verbose", 'v', "", "", false, + "Verbose output."}, + {"version", nextOptChar++, "", "", false, + "Version."}, + {"warn", 'W', "WARN", "all", true, + "Enable a warning."}, + {"wno", nextOptChar++, "WARN", "none", true, + "Disable a specific warning."}, + // TODO(lb): + // {"Werror", '\xc', "WARN", "none", false, "Turn a warning into an error."}, + }; + // clang-format off + return options; +} + +int main(Global& glb, const char* souffle_executable) { + /* Time taking for overall runtime */ + auto souffle_start = std::chrono::high_resolution_clock::now(); + + try { // Take in pragma options from the command line if (glb.config().has("pragma")) { ast::transform::PragmaChecker::Merger merger(glb); @@ -542,10 +714,10 @@ int main(Global& glb, int argc, char** argv) { /* for the version option, if given print the version text then exit */ if (glb.config().has("version")) { - std::cout << versionFooter << std::endl; + std::cout << versionFooter() << std::endl; return 0; } - glb.config().set("version", PACKAGE_VERSION); + glb.config().set("version", packageVersion()); /* for the help option, if given simply print the help text then exit */ if (glb.config().has("help")) { @@ -638,7 +810,7 @@ int main(Global& glb, int argc, char** argv) { // ------ start souffle ------------- - const std::string souffleExecutable = which(argv[0]); + const std::string souffleExecutable = which(souffle_executable); if (souffleExecutable.empty()) { throw std::runtime_error("failed to determine souffle executable path"); @@ -676,7 +848,7 @@ int main(Global& glb, int argc, char** argv) { // parse file ErrorReport errReport(process_warn_opts(glb)); - DebugReport debugReport; + DebugReport debugReport(glb); Own astTranslationUnit = ParserDriver::parseTranslationUnit( glb, InputPath.string(), Input->getInputStream(), errReport, debugReport); Input->endInput(); @@ -716,72 +888,7 @@ int main(Global& glb, int argc, char** argv) { } /* construct the transformation pipeline */ - - // Equivalence pipeline - auto equivalencePipeline = - mk(mk(), - mk(mk()), - mk(), - mk(), - mk(), - mk()); - - // Magic-Set pipeline - auto magicPipeline = mk( - mk( - glb.config().has("magic-transform"), mk()), - mk(), mk(), - mk(), - mk(), - mk(), clone(equivalencePipeline)); - - // Partitioning pipeline - auto partitionPipeline = - mk(mk(), - mk(), - mk()); - - // Provenance pipeline - auto provenancePipeline = mk(glb.config().has("provenance"), - mk(mk(), - mk())); - - // Main pipeline - auto pipeline = mk(mk(), - mk(), - mk(), - mk(), - mk(), - mk(mk( - mk(), - mk())), - mk(), mk(), - mk(), - mk(), - mk(), - mk( - mk()), - mk(), - mk(), - mk(), - mk(), - mk(), mk(), - mk(), - mk(), mk(), - mk(), - mk(), - mk(), - mk(), - mk(), - mk(mk( - mk(), - mk())), - mk(), std::move(partitionPipeline), - std::move(equivalencePipeline), mk(), - std::move(magicPipeline), mk(), - mk(), - mk(), std::move(provenancePipeline), - mk()); + auto pipeline = astTransformationPipeline(glb); // Disable unwanted transformations if (glb.config().has("disable-transformers")) { @@ -865,11 +972,7 @@ int main(Global& glb, int argc, char** argv) { // ------- execution ------------- /* translate AST to RAM */ debugReport.startSection(); - auto translationStrategy = - glb.config().has("provenance") - ? mk() - : mk(); - auto unitTranslator = Own(translationStrategy->createUnitTranslator()); + auto unitTranslator = getUnitTranslator(glb); auto ramTranslationUnit = unitTranslator->translateUnit(*astTranslationUnit); debugReport.endSection("ast-to-ram", "Translate AST to RAM"); @@ -881,23 +984,7 @@ int main(Global& glb, int argc, char** argv) { // Apply RAM transforms { - using namespace ram::transform; - Own ramTransform = mk( - mk(mk(mk(), - mk(), mk())), - mk(), mk(), - mk(), mk(), - mk( - mk(mk(), mk())), - mk(), mk(), - mk(), mk(), - mk(), mk(mk()), - mk( - // job count of 0 means all cores are used. - [&]() -> bool { return std::stoi(glb.config().get("jobs")) != 1; }, - mk()), - mk()); - + auto ramTransform = ramTransformerSequence(glb); ramTransform->apply(*ramTranslationUnit); } @@ -924,45 +1011,13 @@ int main(Global& glb, int argc, char** argv) { try { if (must_interpret) { // ------- interpreter ------------- - - std::thread profiler; - // Start up profiler if needed - if (glb.config().has("live-profile")) { -#ifdef _MSC_VER - throw("No live-profile on Windows\n."); -#else - profiler = std::thread([]() { profile::Tui().runProf(); }); -#endif - } - - // configure and execute interpreter - const std::size_t numThreadsOrZero = std::stoi(glb.config().get("jobs")); - Own interpreter( - mk(*ramTranslationUnit, numThreadsOrZero)); - interpreter->executeMain(); - // If the profiler was started, join back here once it exits. - if (profiler.joinable()) { - profiler.join(); - } - if (glb.config().has("provenance")) { -#ifdef _MSC_VER - throw("No explain/explore provenance on Windows\n."); -#else - // only run explain interface if interpreted - interpreter::ProgInterface interface(*interpreter); - if (glb.config().get("provenance") == "explain") { - explain(interface, false); - } else if (glb.config().get("provenance") == "explore") { - explain(interface, true); - } -#endif + const bool success = interpretTranslationUnit(glb, *ramTranslationUnit); + if (!success) { + std::exit(EXIT_FAILURE); } } else { // ------- compiler ------------- - // int jobs = std::stoi(glb.config().get("jobs")); - // jobs = (jobs <= 0 ? MAX_THREADS : jobs); - auto synthesiser = - mk(/*static_cast(jobs),*/ *ramTranslationUnit); + auto synthesiser = mk(*ramTranslationUnit); // Find the base filename for code generation and execution std::string baseFilename; @@ -1070,7 +1125,3 @@ int main(Global& glb, int argc, char** argv) { } // end of namespace souffle -int main(int argc, char** argv) { - souffle::Global glb; - return souffle::main(glb, argc, argv); -} diff --git a/src/MainDriver.h b/src/MainDriver.h new file mode 100644 index 00000000000..6f529c63e64 --- /dev/null +++ b/src/MainDriver.h @@ -0,0 +1,56 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2022, The Souffle Developers. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/** + * @file MainDriver.h + * + * Main driver interface for Souffle + */ +#pragma once + +#include "Global.h" +#include "ast/transform/Pipeline.h" +#include "ast2ram/UnitTranslator.h" +#include "ast2ram/utility/TranslatorContext.h" +#include "include/souffle/utility/Types.h" +#include "ram/Program.h" +#include "ram/transform/Transformer.h" + +#include +#include + +namespace souffle { + +/** Return the package version string. */ +const char* packageVersion(); + +/** Return the size in bits of the RamDomain type. */ +std::size_t ramDomainSizeInBits(); + +/** Return the copyright and version footer banner string. */ +std::string versionFooter(); + +/** Return the command-line options that can be passed to `MainConfig::processArgs()`. */ +std::vector getMainOptions(); + +/** Execute entire Souffle driver. */ +int main(Global& glb, const char* souffle_executable); + +/** Construct and return an AST transformer pipeline. */ +Own astTransformationPipeline(Global& glb); + +/** Construct and return an AST to RAM unit translator. */ +Own getUnitTranslator(Global& glb); + +/** Construct and return a RAM transformer pipeline */ +Own ramTransformerSequence(Global& glb); + +/** Interpret the RAM translation unit using Souffle's interpreter engine. */ +bool interpretTranslationUnit(Global& glb, ram::TranslationUnit& ramTranslationUnit); + +} // namespace souffle diff --git a/src/souffle.cpp b/src/souffle.cpp new file mode 100644 index 00000000000..a95bddc908d --- /dev/null +++ b/src/souffle.cpp @@ -0,0 +1,48 @@ +/* + * Souffle - A Datalog Compiler + * Copyright (c) 2022, The Souffle Developers. All rights reserved + * Licensed under the Universal Permissive License v 1.0 as shown at: + * - https://opensource.org/licenses/UPL + * - /licenses/SOUFFLE-UPL.txt + */ + +/** + * @file The souffle executable + */ + +#include "MainDriver.h" + +#include +#include + +namespace { + +bool processArgs(souffle::Global& glb, int argc, char** argv) { + /* have all to do with command line arguments in its own scope, as these are accessible through the global + * configuration only */ + std::stringstream header; + + header << "============================================================================" << std::endl; + header << "souffle -- A datalog engine." << std::endl; + header << "Usage: souffle [OPTION] FILE." << std::endl; + header << "----------------------------------------------------------------------------" << std::endl; + header << "Options:" << std::endl; + + // command line options, the environment will be filled with the arguments passed to them, or + // the empty string if they take none + // main option, the datalog program itself, has an empty key + const std::vector options = souffle::getMainOptions(); + glb.config().processArgs(argc, argv, header.str(), souffle::versionFooter(), options); + + return true; +} + +} // namespace + +int main(int argc, char** argv) { + souffle::Global glb; + + processArgs(glb, argc, argv); + + return souffle::main(glb, argv[0]); +}