119     assert(!binaryFilename.empty() && 
"binary filename cannot be blank");
 
  123         throw std::invalid_argument(
"Generated executable <" + binaryFilename + 
"> could not be found");
 
  130             ldPath += library + 
':';
 
  133         setenv(
"LD_LIBRARY_PATH", ldPath.c_str(), 1);
 
  139     exePath = 
"DYLD_LIBRARY_PATH=\"" + ldPath + 
"\" ";
 
  141     exePath += binaryFilename;
 
  143     int exitCode = system(exePath.c_str());
 
  146         remove(binaryFilename.c_str());
 
  147         remove((binaryFilename + 
".cpp").c_str());
 
  151     if (exitCode != EXIT_SUCCESS) {
 
  159 void compileToBinary(std::string compileCmd, 
const std::string& sourceFilename) {
 
  167         compileCmd += 
"-L" + path + 
' ';
 
  171         if (library.empty()) {
 
  174         compileCmd += 
"-l" + library + 
' ';
 
  177     compileCmd += sourceFilename;
 
  180     if (system(compileCmd.c_str()) != 0) {
 
  181         throw std::invalid_argument(
"failed to compile C++ source <" + sourceFilename + 
">");
 
  185 int main(
int argc, 
char** argv) {
 
  192         std::stringstream header;
 
  193         header << 
"============================================================================" << std::endl;
 
  194         header << 
"souffle -- A datalog engine." << std::endl;
 
  195         header << 
"Usage: souffle [OPTION] FILE." << std::endl;
 
  196         header << 
"----------------------------------------------------------------------------" << std::endl;
 
  197         header << 
"Options:" << std::endl;
 
  199         std::stringstream footer;
 
  200         footer << 
"----------------------------------------------------------------------------" << std::endl;
 
  202         footer << 
"----------------------------------------------------------------------------" << std::endl;
 
  203         footer << 
"Copyright (c) 2016-20 The Souffle Developers." << std::endl;
 
  204         footer << 
"Copyright (c) 2013-16 Oracle and/or its affiliates." << std::endl;
 
  205         footer << 
"All rights reserved." << std::endl;
 
  206         footer << 
"============================================================================" << std::endl;
 
  211         std::vector<MainOption> options{{
"", 0, 
"", 
"", 
false, 
""},
 
  212                 {
"fact-dir", 
'F', 
"DIR", 
".", 
false, 
"Specify directory for fact files."},
 
  213                 {
"include-dir", 
'I', 
"DIR", 
".", 
true, 
"Specify directory for include files."},
 
  214                 {
"output-dir", 
'D', 
"DIR", 
".", 
false,
 
  215                         "Specify directory for output files. If <DIR> is `-` then stdout is used."},
 
  216                 {
"jobs", 
'j', 
"N", 
"1", 
false,
 
  217                         "Run interpreter/compiler in parallel using N threads, N=auto for system " 
  219                 {
"compile", 
'c', 
"", 
"", 
false,
 
  220                         "Generate C++ source code, compile to a binary executable, then run this " 
  222                 {
"generate", 
'g', 
"FILE", 
"", 
false,
 
  223                         "Generate C++ source code for the given Datalog program and write it to " 
  224                         "<FILE>. If <FILE> is `-` then stdout is used."},
 
  225                 {
"swig", 
's', 
"LANG", 
"", 
false,
 
  226                         "Generate SWIG interface for given language. The values <LANG> accepts is java and " 
  228                 {
"library-dir", 
'L', 
"DIR", 
"", 
false, 
"Specify directory for library files."},
 
  229                 {
"libraries", 
'l', 
"FILE", 
"", 
false, 
"Specify libraries."},
 
  230                 {
"no-warn", 
'w', 
"", 
"", 
false, 
"Disable warnings."},
 
  231                 {
"magic-transform", 
'm', 
"RELATIONS", 
"", 
false,
 
  232                         "Enable magic set transformation changes on the given relations, use '*' " 
  234                 {
"macro", 
'M', 
"MACROS", 
"", 
false, 
"Set macro definitions for the pre-processor"},
 
  235                 {
"disable-transformers", 
'z', 
"TRANSFORMERS", 
"", 
false,
 
  236                         "Disable the given AST transformers."},
 
  237                 {
"dl-program", 
'o', 
"FILE", 
"", 
false,
 
  238                         "Generate C++ source code, written to <FILE>, and compile this to a " 
  239                         "binary executable (without executing it)."},
 
  240                 {
"live-profile", 
'\2', 
"", 
"", 
false, 
"Enable live profiling."},
 
  241                 {
"profile", 
'p', 
"FILE", 
"", 
false, 
"Enable profiling, and write profile data to <FILE>."},
 
  242                 {
"profile-use", 
'u', 
"FILE", 
"", 
false,
 
  243                         "Use profile log-file <FILE> for profile-guided optimization."},
 
  244                 {
"debug-report", 
'r', 
"FILE", 
"", 
false, 
"Write HTML debug report to <FILE>."},
 
  245                 {
"pragma", 
'P', 
"OPTIONS", 
"", 
false, 
"Set pragma options."},
 
  246                 {
"provenance", 
't', 
"[ none | explain | explore ]", 
"", 
false,
 
  247                         "Enable provenance instrumentation and interaction."},
 
  248                 {
"verbose", 
'v', 
"", 
"", 
false, 
"Verbose output."},
 
  249                 {
"version", 
'\3', 
"", 
"", 
false, 
"Version."},
 
  251                         "[ parse-errors | precedence-graph | scc-graph | transformed-datalog | " 
  252                         "transformed-ram | type-analysis ]",
 
  253                         "", 
false, 
"Print selected program information."},
 
  254                 {
"parse-errors", 
'\5', 
"", 
"", 
false, 
"Show parsing errors, if any, then exit."},
 
  255                 {
"help", 
'h', 
"", 
"", 
false, 
"Display this help message."},
 
  256                 {
"legacy", 
'\6', 
"", 
"", 
false, 
"Enable legacy support."}};
 
  264             for (
const std::string& option : configOptions) {
 
  265                 size_t splitPoint = option.find(
':');
 
  267                 std::string optionName = option.substr(0, splitPoint);
 
  268                 std::string optionValue = (splitPoint == std::string::npos)
 
  270                                                   : option.substr(splitPoint + 1, option.length());
 
  282             std::cout << std::endl;
 
  283             std::cout << 
"Copyright (c) 2016-19 The Souffle Developers." << std::endl;
 
  284             std::cout << 
"Copyright (c) 2013-16 Oracle and/or its affiliates." << std::endl;
 
  297             throw std::runtime_error(
"cannot open file " + std::string(
Global::config().
get(
"")));
 
  304                 throw std::runtime_error(
"-j/--jobs may only be set to 'auto' or an integer greater than 0.");
 
  308                 throw std::runtime_error(
"-j/--jobs may only be set to 'auto' or an integer greater than 0.");
 
  315             std::cerr << 
"\nThis installation of Souffle does not support concurrent jobs.\n";
 
  324             throw std::runtime_error(
 
  330             std::string currentInclude = 
"";
 
  331             std::string allIncludes = 
"";
 
  335                         throw std::runtime_error(
"include directory " + currentInclude + 
" does not exists");
 
  337                         allIncludes += 
" -I";
 
  338                         allIncludes += currentInclude;
 
  342                     currentInclude += ch;
 
  345             allIncludes += 
" -I" + currentInclude;
 
  351             std::string currentMacro = 
"";
 
  352             std::string allMacros = 
"";
 
  356                     allMacros += currentMacro;
 
  362             allMacros += 
" -D" + currentMacro;
 
  374     } 
catch (std::exception& 
e) {
 
  375         std::cerr << 
e.what() << std::endl;
 
  388     std::string souffleExecutable = 
which(argv[0]);
 
  390     if (souffleExecutable.empty()) {
 
  391         throw std::runtime_error(
"failed to determine souffle executable path");
 
  395     std::string cmd = 
::which(
"mcpp");
 
  398         throw std::runtime_error(
"failed to locate mcpp pre-processor");
 
  408     FILE* in = popen(cmd.c_str(), 
"r");
 
  417     DebugReport debugReport;
 
  418     Own<ast::TranslationUnit> astTranslationUnit =
 
  422     int preprocessor_status = pclose(in);
 
  423     if (preprocessor_status == -1) {
 
  425         throw std::runtime_error(
"failed to close pre-processor pipe");
 
  431         std::cout << 
"Parse Time: " << std::chrono::duration<double>(parser_end - parser_start).count()
 
  436         std::cout << astTranslationUnit->getErrorReport();
 
  437         return astTranslationUnit->getErrorReport().getNumErrors();
 
  441     astTranslationUnit->getErrorReport().exitIfErrors();
 
  446     (mk<ast::transform::PragmaChecker>())->apply(*astTranslationUnit);
 
  451     auto equivalencePipeline =
 
  452             mk<ast::transform::PipelineTransformer>(mk<ast::transform::NameUnnamedVariablesTransformer>(),
 
  453                     mk<ast::transform::FixpointTransformer>(mk<ast::transform::MinimiseProgramTransformer>()),
 
  454                     mk<ast::transform::ReplaceSingletonVariablesTransformer>(),
 
  455                     mk<ast::transform::RemoveRelationCopiesTransformer>(),
 
  456                     mk<ast::transform::RemoveEmptyRelationsTransformer>(),
 
  457                     mk<ast::transform::RemoveRedundantRelationsTransformer>());
 
  460     auto magicPipeline = mk<ast::transform::PipelineTransformer>(mk<ast::transform::MagicSetTransformer>(),
 
  461             mk<ast::transform::ResolveAliasesTransformer>(),
 
  462             mk<ast::transform::RemoveRelationCopiesTransformer>(),
 
  463             mk<ast::transform::RemoveEmptyRelationsTransformer>(),
 
  464             mk<ast::transform::RemoveRedundantRelationsTransformer>(), 
souffle::clone(equivalencePipeline));
 
  467     auto partitionPipeline =
 
  468             mk<ast::transform::PipelineTransformer>(mk<ast::transform::NameUnnamedVariablesTransformer>(),
 
  469                     mk<ast::transform::PartitionBodyLiteralsTransformer>(),
 
  470                     mk<ast::transform::ReplaceSingletonVariablesTransformer>());
 
  473     auto provenancePipeline = mk<ast::transform::ConditionalTransformer>(
 
  474             Global::config().has(
"provenance"), mk<ast::transform::ProvenanceTransformer>());
 
  477     auto pipeline = mk<ast::transform::PipelineTransformer>(mk<ast::transform::ComponentChecker>(),
 
  478             mk<ast::transform::ComponentInstantiationTransformer>(),
 
  479             mk<ast::transform::IODefaultsTransformer>(),
 
  480             mk<ast::transform::SimplifyAggregateTargetExpressionTransformer>(),
 
  481             mk<ast::transform::UniqueAggregationVariablesTransformer>(),
 
  482             mk<ast::transform::FixpointTransformer>(mk<ast::transform::PipelineTransformer>(
 
  483                     mk<ast::transform::ResolveAnonymousRecordAliasesTransformer>(),
 
  484                     mk<ast::transform::FoldAnonymousRecords>())),
 
  485             mk<ast::transform::SemanticChecker>(), mk<ast::transform::GroundWitnessesTransformer>(),
 
  486             mk<ast::transform::UniqueAggregationVariablesTransformer>(),
 
  487             mk<ast::transform::NormaliseMultiResultFunctorsTransformer>(),
 
  488             mk<ast::transform::MaterializeSingletonAggregationTransformer>(),
 
  489             mk<ast::transform::FixpointTransformer>(
 
  490                     mk<ast::transform::MaterializeAggregationQueriesTransformer>()),
 
  491             mk<ast::transform::ResolveAliasesTransformer>(),
 
  492             mk<ast::transform::RemoveBooleanConstraintsTransformer>(),
 
  493             mk<ast::transform::ResolveAliasesTransformer>(), mk<ast::transform::MinimiseProgramTransformer>(),
 
  494             mk<ast::transform::InlineRelationsTransformer>(), mk<ast::transform::GroundedTermsChecker>(),
 
  495             mk<ast::transform::ResolveAliasesTransformer>(),
 
  496             mk<ast::transform::RemoveRedundantRelationsTransformer>(),
 
  497             mk<ast::transform::RemoveRelationCopiesTransformer>(),
 
  498             mk<ast::transform::RemoveEmptyRelationsTransformer>(),
 
  499             mk<ast::transform::ReplaceSingletonVariablesTransformer>(),
 
  500             mk<ast::transform::FixpointTransformer>(mk<ast::transform::PipelineTransformer>(
 
  501                     mk<ast::transform::ReduceExistentialsTransformer>(),
 
  502                     mk<ast::transform::RemoveRedundantRelationsTransformer>())),
 
  503             mk<ast::transform::RemoveRelationCopiesTransformer>(), std::move(partitionPipeline),
 
  504             std::move(equivalencePipeline), mk<ast::transform::RemoveRelationCopiesTransformer>(),
 
  505             std::move(magicPipeline), mk<ast::transform::ReorderLiteralsTransformer>(),
 
  506             mk<ast::transform::RemoveRedundantSumsTransformer>(),
 
  507             mk<ast::transform::RemoveEmptyRelationsTransformer>(),
 
  508             mk<ast::transform::AddNullariesToAtomlessAggregatesTransformer>(),
 
  509             mk<ast::transform::ReorderLiteralsTransformer>(), mk<ast::transform::ExecutionPlanChecker>(),
 
  510             std::move(provenancePipeline), mk<ast::transform::IOAttributesTransformer>());
 
  514         std::vector<std::string> givenTransformers =
 
  516         pipeline->disableTransformers(
 
  517                 std::set<std::string>(givenTransformers.begin(), givenTransformers.end()));
 
  523         std::stringstream 
ss;
 
  527         ss << 
"Executed at ";
 
  528         ss << std::put_time(std::localtime(&
time), 
"%F %T") << 
"\n";
 
  533             out << 
"  \"" << arg.first << 
"\" -> \"" << arg.second << 
'"';
 
  537         debugReport.addSection(
"Configuration", 
"Configuration", 
ss.str());
 
  540         std::string runtimeStr =
 
  541                 "(" + std::to_string(std::chrono::duration<double>(parser_end - parser_start).
count()) + 
"s)";
 
  542         debugReport.addSection(
"Parsing", 
"Parsing " + runtimeStr, 
"");
 
  544         pipeline->setDebugReport();
 
  551     pipeline->apply(*astTranslationUnit);
 
  556             std::cout << astTranslationUnit->getProgram() << std::endl;
 
  562             astTranslationUnit->getAnalysis<ast::analysis::PrecedenceGraphAnalysis>()->print(std::cout);
 
  563             std::cout << std::endl;
 
  569             astTranslationUnit->getAnalysis<ast::analysis::SCCGraphAnalysis>()->print(std::cout);
 
  570             std::cout << std::endl;
 
  576             astTranslationUnit->getAnalysis<ast::analysis::TypeAnalysis>()->print(std::cout);
 
  577             std::cout << std::endl;
 
  584     debugReport.startSection();
 
  585     auto ramTranslationUnit = ast2ram::AstToRamTranslator().translateUnit(*astTranslationUnit);
 
  586     debugReport.endSection(
"ast-to-ram", 
"Translate AST to RAM");
 
  590         using namespace ram::transform;
 
  591         Own<Transformer> ramTransform = mk<TransformerSequence>(
 
  592                 mk<LoopTransformer>(mk<TransformerSequence>(mk<ExpandFilterTransformer>(),
 
  593                         mk<HoistConditionsTransformer>(), mk<MakeIndexTransformer>())),
 
  594                 mk<LoopTransformer>(mk<IndexedInequalityTransformer>()), mk<IfConversionTransformer>(),
 
  595                 mk<ChoiceConversionTransformer>(), mk<CollapseFiltersTransformer>(), mk<TupleIdTransformer>(),
 
  597                         mk<TransformerSequence>(mk<HoistAggregateTransformer>(), mk<TupleIdTransformer>())),
 
  598                 mk<ExpandFilterTransformer>(), mk<HoistConditionsTransformer>(),
 
  599                 mk<CollapseFiltersTransformer>(), mk<EliminateDuplicatesTransformer>(),
 
  600                 mk<ReorderConditionsTransformer>(), mk<LoopTransformer>(mk<ReorderFilterBreak>()),
 
  601                 mk<ConditionalTransformer>(
 
  604                         mk<ParallelTransformer>()),
 
  605                 mk<ReportIndexTransformer>());
 
  607         ramTransform->apply(*ramTranslationUnit);
 
  610     if (ramTranslationUnit->getErrorReport().getNumIssues() != 0) {
 
  611         std::cerr << ramTranslationUnit->getErrorReport();
 
  616         std::cout << ramTranslationUnit->getProgram();
 
  625             std::thread profiler;
 
  628                 profiler = std::thread([]() { profile::Tui().runProf(); });
 
  632             Own<interpreter::Engine> interpreter(mk<interpreter::Engine>(*ramTranslationUnit));
 
  633             interpreter->executeMain();
 
  635             if (profiler.joinable()) {
 
  640                 interpreter::ProgInterface interface(*interpreter);
 
  649             auto synthesiser = mk<synthesiser::Synthesiser>(*ramTranslationUnit);
 
  652             std::string baseFilename;
 
  659                 if (baseFilename.size() >= 4 && baseFilename.substr(baseFilename.size() - 4) == 
".cpp") {
 
  660                     baseFilename = baseFilename.substr(0, baseFilename.size() - 4);
 
  670             std::string sourceFilename = baseFilename + 
".cpp";
 
  672             bool withSharedLibrary;
 
  675                 synthesiser->generateCode(std::cout, baseIdentifier, withSharedLibrary);
 
  677                 std::ofstream os{sourceFilename};
 
  678                 synthesiser->generateCode(os, baseIdentifier, withSharedLibrary);
 
  681             if (withSharedLibrary) {
 
  690             auto findCompileCmd = [&] {
 
  691                 auto cmd = 
::findTool(
"souffle-compile", souffleExecutable, 
".");
 
  694                     throw std::runtime_error(
"failed to locate souffle-compile");
 
  700                 auto compileCmd = findCompileCmd() + 
" -s " + 
Global::config().get(
"swig") + 
" ";
 
  708                     std::cout << 
"Compilation Time: " << std::chrono::duration<double>(end - start).count()
 
  717     } 
catch (std::exception& 
e) {
 
  718         std::cerr << 
e.what() << std::endl;
 
  719         std::exit(EXIT_FAILURE);
 
  725         std::cout << 
"Total Time: " << std::chrono::duration<double>(souffle_end - souffle_start).count()
 
  734 int main(
int argc, 
char** argv) {