1 | /*
|
2 | * Souffle - A Datalog Compiler
|
3 | * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved
|
4 | * Licensed under the Universal Permissive License v 1.0 as shown at:
|
5 | * - https://opensource.org/licenses/UPL
|
6 | * - <souffle root>/licenses/SOUFFLE-UPL.txt
|
7 | */
|
8 |
|
9 | /************************************************************************
|
10 | *
|
11 | * @file CompiledOptions.h
|
12 | *
|
13 | * A header file offering command-line option support for compiled
|
14 | * RAM programs.
|
15 | *
|
16 | ***********************************************************************/
|
17 |
|
18 | #pragma once
|
19 |
|
20 | #include <cstdio>
|
21 | #include <cstdlib>
|
22 | #include <iostream>
|
23 | #include <string>
|
24 | #include <sys/stat.h>
|
25 |
|
26 | #ifdef USE_CUSTOM_GETOPTLONG
|
27 | #include "souffle/utility/GetOptLongImpl.h"
|
28 | #else
|
29 | #include <getopt.h>
|
30 | #endif
|
31 |
|
32 | namespace souffle {
|
33 |
|
34 | /**
|
35 | * A utility class for parsing command line arguments within generated
|
36 | * query programs.
|
37 | */
|
38 | class CmdOptions {
|
39 | protected:
|
40 | /**
|
41 | * source file
|
42 | */
|
43 | std::string src;
|
44 |
|
45 | /**
|
46 | * fact directory
|
47 | */
|
48 | std::string input_dir;
|
49 |
|
50 | /**
|
51 | * output directory
|
52 | */
|
53 | std::string output_dir;
|
54 |
|
55 | /**
|
56 | * profiling flag
|
57 | */
|
58 | bool profiling;
|
59 |
|
60 | /**
|
61 | * profile filename
|
62 | */
|
63 | std::string profile_name;
|
64 |
|
65 | /**
|
66 | * number of threads
|
67 | */
|
68 | std::size_t num_jobs;
|
69 |
|
70 | public:
|
71 | // all argument constructor
|
72 | CmdOptions(const char* s, const char* id, const char* od, bool pe, const char* pfn, std::size_t nj)
|
73 | : src(s), input_dir(id), output_dir(od), profiling(pe), profile_name(pfn), num_jobs(nj) {}
|
74 |
|
75 | /**
|
76 | * get source code name
|
77 | */
|
78 | const std::string& getSourceFileName() const {
|
79 | return src;
|
80 | }
|
81 |
|
82 | /**
|
83 | * get input directory
|
84 | */
|
85 | const std::string& getInputFileDir() const {
|
86 | return input_dir;
|
87 | }
|
88 |
|
89 | /**
|
90 | * get output directory
|
91 | */
|
92 | const std::string& getOutputFileDir() const {
|
93 | return output_dir;
|
94 | }
|
95 |
|
96 | /**
|
97 | * is profiling switched on
|
98 | */
|
99 | bool isProfiling() const {
|
100 | return profiling;
|
101 | }
|
102 |
|
103 | /**
|
104 | * get filename of profile
|
105 | */
|
106 | const std::string& getProfileName() const {
|
107 | return profile_name;
|
108 | }
|
109 |
|
110 | /**
|
111 | * get number of jobs
|
112 | */
|
113 | std::size_t getNumJobs() const {
|
114 | return num_jobs;
|
115 | }
|
116 |
|
117 | /**
|
118 | * Parses the given command line parameters, handles -h help requests or errors
|
119 | * and returns whether the parsing was successful or not.
|
120 | */
|
121 | bool parse(int argc, char** argv) {
|
122 | // get executable name
|
123 | std::string exec_name = "analysis";
|
124 | if (argc > 0) {
|
125 | exec_name = argv[0];
|
126 | }
|
127 |
|
128 | // local options
|
129 | std::string fact_dir = input_dir;
|
130 | std::string out_dir = output_dir;
|
131 |
|
132 | // long options
|
133 | option longOptions[] = {{"facts", true, nullptr, 'F'}, {"output", true, nullptr, 'D'},
|
134 | {"profile", true, nullptr, 'p'}, {"jobs", true, nullptr, 'j'}, {"index", true, nullptr, 'i'},
|
135 | // the terminal option -- needs to be null
|
136 | {nullptr, false, nullptr, 0}};
|
137 |
|
138 | // check whether all options are fine
|
139 | bool ok = true;
|
140 |
|
141 | int c; /* command-line arguments processing */
|
142 | while ((c = getopt_long(argc, argv, "D:F:hp:j:i:", longOptions, nullptr)) != EOF) {
|
143 | switch (c) {
|
144 | /* Fact directories */
|
145 | case 'F':
|
146 | if (!existDir(optarg)) {
|
147 | printf("Fact directory %s does not exists!\n", optarg);
|
148 | ok = false;
|
149 | }
|
150 | fact_dir = optarg;
|
151 | break;
|
152 | /* Output directory for resulting .csv files */
|
153 | case 'D':
|
154 | if (*optarg && !existDir(optarg) && !dirIsStdout(optarg)) {
|
155 | printf("Output directory %s does not exists!\n", optarg);
|
156 | ok = false;
|
157 | }
|
158 | out_dir = optarg;
|
159 | break;
|
160 | case 'p':
|
161 | if (!profiling) {
|
162 | std::cerr << "\nError: profiling was not enabled in compilation\n\n";
|
163 | printHelpPage(exec_name);
|
164 | exit(EXIT_FAILURE);
|
165 | }
|
166 | profile_name = optarg;
|
167 | break;
|
168 | case 'j':
|
169 | #ifdef _OPENMP
|
170 | if (std::string(optarg) == "auto") {
|
171 | num_jobs = 0;
|
172 | } else {
|
173 | int num = atoi(optarg);
|
174 | if (num > 0) {
|
175 | num_jobs = num;
|
176 | } else {
|
177 | std::cerr << "Invalid number of jobs [-j]: " << optarg << "\n";
|
178 | ok = false;
|
179 | }
|
180 | }
|
181 | #else
|
182 | std::cerr << "\nWarning: OpenMP was not enabled in compilation\n\n";
|
183 | #endif
|
184 | break;
|
185 | default: printHelpPage(exec_name); return false;
|
186 | }
|
187 | }
|
188 |
|
189 | // update member fields
|
190 | input_dir = fact_dir;
|
191 | output_dir = out_dir;
|
192 |
|
193 | // return success state
|
194 | return ok;
|
195 | }
|
196 |
|
197 | private:
|
198 | /**
|
199 | * Prints the help page if it has been requested or there was a typo in the command line arguments.
|
200 | */
|
201 | void printHelpPage(const std::string& exec_name) const {
|
202 | std::cerr << "====================================================================\n";
|
203 | std::cerr << " Datalog Program: " << src << "\n";
|
204 | std::cerr << " Usage: " << exec_name << " [OPTION]\n\n";
|
205 | std::cerr << " Options:\n";
|
206 | std::cerr << " -D <DIR>, --output=<DIR> -- Specify directory for output relations\n";
|
207 | std::cerr << " (default: " << output_dir << ")\n";
|
208 | std::cerr << " (suppress output with \"\")\n";
|
209 | std::cerr << " -F <DIR>, --facts=<DIR> -- Specify directory for fact files\n";
|
210 | std::cerr << " (default: " << input_dir << ")\n";
|
211 | if (profiling) {
|
212 | std::cerr << " -p <file>, --profile=<file> -- Specify filename for profiling\n";
|
213 | std::cerr << " (default: " << profile_name << ")\n";
|
214 | }
|
215 | #ifdef _OPENMP
|
216 | std::cerr << " -j <NUM>, --jobs=<NUM> -- Specify number of threads\n";
|
217 | if (num_jobs > 0) {
|
218 | std::cerr << " (default: " << num_jobs << ")\n";
|
219 | } else {
|
220 | std::cerr << " (default: auto)\n";
|
221 | }
|
222 | #endif
|
223 | std::cerr << " -h -- prints this help page.\n";
|
224 | std::cerr << "--------------------------------------------------------------------\n";
|
225 | #ifdef SOUFFLE_GENERATOR_VERSION
|
226 | std::cerr << " Version: " << SOUFFLE_GENERATOR_VERSION << std::endl;
|
227 | #endif
|
228 | std::cerr << " Word size: " << RAM_DOMAIN_SIZE << " bits" << std::endl;
|
229 | std::cerr << "--------------------------------------------------------------------\n";
|
230 | std::cerr << " Copyright (c) 2016-22 The Souffle Developers." << std::endl;
|
231 | std::cerr << " Copyright (c) 2013-16 Oracle and/or its affiliates." << std::endl;
|
232 | std::cerr << " All rights reserved.\n";
|
233 | std::cerr << "====================================================================\n";
|
234 | }
|
235 |
|
236 | /**
|
237 | * Check whether a file exists in the file system
|
238 | */
|
239 | inline bool existFile(const std::string& name) const {
|
240 | struct stat buffer;
|
241 | if (stat(name.c_str(), &buffer) == 0) {
|
242 | if ((buffer.st_mode & S_IFREG) != 0) {
|
243 | return true;
|
244 | }
|
245 | }
|
246 | return false;
|
247 | }
|
248 |
|
249 | /**
|
250 | * Check whether a directory exists in the file system
|
251 | */
|
252 | bool existDir(const std::string& name) const {
|
253 | struct stat buffer;
|
254 | if (stat(name.c_str(), &buffer) == 0) {
|
255 | if ((buffer.st_mode & S_IFDIR) != 0) {
|
256 | return true;
|
257 | }
|
258 | }
|
259 | return false;
|
260 | }
|
261 |
|
262 | /**
|
263 | * Check whether the output is "-", for which the output should be stdout
|
264 | */
|
265 | bool dirIsStdout(const std::string& name) const {
|
266 | return name == "-";
|
267 | }
|
268 | };
|
269 |
|
270 | } // end of namespace souffle
|