Fix formatting
[tmk.git] / tmake.c
blobce30d87df87759ed5956ee2b8423c0bf68cfcc56
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #include <sqlite3.h>
7 #define JIM_EMBEDDED
8 #include <jim.h>
10 #include "tmake.h"
11 #include "tm_target.h"
12 #include "tm_update.h"
13 #include "tm_core_cmds.h"
14 #include "tm_ext_cmds.h"
17 /* The default paths to search of include files */
18 const char *DEFAULT_INC_PATH[] = {
19 ".",
20 TM_PREFIX "/lib/tmk/include",
21 NULL
24 /* The default path to search for package files */
25 const char *DEFAULT_PKG_PATH[] = {
26 ".",
27 TM_PREFIX "/lib/tmk/packages",
28 NULL
31 /* Display usage and exit.
33 static void usage(const char *progname)
35 printf("usage: %s [options] [target]\n", progname);
36 printf("\n");
37 printf("options:\n");
38 printf(" -f <TMakefile> Process <TMakefile> instead of the default.\n");
39 printf(" -n Display commands that would be executed without\n"
40 " actually executing any commands.\n");
41 printf(" -I <path> Add <path> to the list of directories to search\n"
42 " for include files.\n");
43 printf(" -P <path> Add <path> to the list of directories to search\n"
44 " for TMake packages.\n");
45 printf(" -D <param> Define <param> for the execution of TMakefile\n");
46 printf(" -V <var> Display the value of variable <var> without\n"
47 " executing any commands.\n");
48 printf(" -e Initialize the values of parameters from corresponding\n"
49 " environment variables.\n");
50 printf(" -u Force update of target even if it is not out of date.\n");
51 printf(" -s Only output errors, if anything at all.\n");
52 printf(" PARAM=VALUE Set the parameter PARAM to VALUE.\n");
53 exit(1);
56 /* Takes a pointer to the current argv index, argc, and argv.
57 * Checks if the flag is separated from its argument with a space.
58 * If it is, increments the argv index, or else has no effect on
59 * the index. Returns the argument to the flag if it is available,
60 * or else displays usage and exits.
62 * e.g., -D NO_BUILD_JIMTCL and -DNO_BUILD_JIMTCL will both yield
63 * "NO_BUILD_JIMTCL" here.
65 static char *get(int *arg, int argc, char **argv)
67 if (strlen(argv[*arg]) > 2) {
68 return &(argv[*arg][2]);
71 if ((*arg + 1) < argc) {
72 *arg = *arg + 1;
73 return argv[*arg];
76 usage(argv[0]);
77 return NULL;
80 /* Register the include paths (specified in more_inc) and package paths
81 * (specified in more_pkg) with the Jim interpreter and the include command
82 * (defined in tm_core_cmds.c).
84 static int register_search_paths(Jim_Interp *interp, target_list *more_inc, target_list *more_pkg)
86 Jim_Obj *inc, *pkg;
87 int i;
89 inc = Jim_NewListObj(interp, NULL, 0);
90 pkg = Jim_NewListObj(interp, NULL, 0);
92 for (; more_inc; more_inc = more_inc->next) {
93 Jim_Obj *elem = Jim_NewStringObj(interp, more_inc->name, strlen(more_inc->name));
94 Jim_ListAppendElement(interp, inc, elem);
97 for (; more_pkg; more_pkg = more_pkg->next) {
98 Jim_Obj *elem = Jim_NewStringObj(interp, more_pkg->name, strlen(more_pkg->name));
99 Jim_ListAppendElement(interp, pkg, elem);
102 for (i = 0; DEFAULT_INC_PATH[i]; i++) {
103 Jim_Obj *elem = NULL;
104 elem = Jim_NewStringObj(interp, DEFAULT_INC_PATH[i], strlen(DEFAULT_INC_PATH[i]));
105 Jim_ListAppendElement(interp, inc, elem);
108 for (i = 0; DEFAULT_PKG_PATH[i]; i++) {
109 Jim_Obj *elem = NULL;
110 elem = Jim_NewStringObj(interp, DEFAULT_PKG_PATH[i], strlen(DEFAULT_PKG_PATH[i]));
111 Jim_ListAppendElement(interp, inc, elem);
114 Jim_SetGlobalVariableStr(interp, TM_INCLUDE_PATH, inc);
115 Jim_SetGlobalVariableStr(interp, JIM_LIBPATH, pkg);
117 return JIM_OK;
121 /* Orchestrate everything! */
122 int main(int argc, char **argv)
124 const char *filename = DEFAULT_FILE;
125 const char *goal = NULL;
126 int silent = 0;
127 int force_update = 0;
128 int no_execute = 0;
129 int env_lookup = 0;
130 target_list *also_include = NULL;
131 target_list *also_package = NULL;
132 target_list *parameters = NULL;
133 target_list *defines = NULL;
134 target_list *display_vars = NULL;
136 int retval = EXIT_SUCCESS;
137 tm_rule_list *sorted_rules = NULL;
139 Jim_Interp *interp = NULL;
140 sqlite3 *db = NULL;
141 int sqlrc = 0;
142 char *sqlerr = NULL;
144 target_list *node = NULL;
146 int i;
148 for (i = 1; i < argc; i++) {
149 if (argv[i][0] == '-') {
150 switch (argv[i][1]) {
151 case 'f':
152 if (strcmp(filename, DEFAULT_FILE) == 0) {
153 filename = get(&i, argc, argv);
154 } else {
155 usage(argv[0]);
157 break;
158 case 's':
159 silent = 1;
160 break;
161 case 'n':
162 no_execute = 1;
163 break;
164 case 'u':
165 force_update = 1;
166 break;
167 case 'e':
168 env_lookup = 1;
169 break;
170 case 'I':
171 also_include = target_cons(get(&i, argc, argv), also_include);
172 break;
173 case 'P':
174 also_package = target_cons(get(&i, argc, argv), also_package);
175 break;
176 case 'D':
177 defines = target_cons(get(&i, argc, argv), defines);
178 break;
179 case 'V':
180 display_vars = target_cons(get(&i, argc, argv), display_vars);
181 break;
182 default:
183 usage(argv[0]);
184 break;
186 } else if (strstr(argv[i], "=")) {
187 parameters = target_cons(argv[i], parameters);
188 } else if (goal == NULL) {
189 goal = argv[i];
190 } else {
191 usage(argv[0]);
195 /* Create a Tcl interpreter */
196 interp = Jim_CreateInterp();
197 if (interp == NULL) {
198 fprintf(stderr, "ERROR: Unable to create Tcl interpreter\n");
199 return (EXIT_FAILURE);
202 /* Register the core Tcl commands */ Jim_RegisterCoreCommands(interp);
203 tm_RegisterCoreCommands(interp);
205 /* Initialize any static extensions */
206 Jim_InitStaticExtensions(interp);
208 /* Initialize the Tcl TMake commands */
209 wrap(interp, Jim_Eval(interp, "set TM_OPSYS " TM_OPSYS));
210 wrap(interp, Jim_Eval(interp, "set TM_MACHINE_ARCH " TM_MACHINE_ARCH));
211 wrap(interp, Jim_tm_ext_cmdsInit(interp));
213 register_search_paths(interp, also_include, also_package);
214 free_target_list(also_include);
215 free_target_list(also_package);
217 /* Initialize commandline parameters */
218 for (node = parameters; node; node = node->next) {
219 char *var = strtok(node->name, "=");
220 char *val = strtok(NULL, "\0");
222 const char *fmt = "set {TM_PARAM(%s)} {%s}";
223 int len = strlen(var) + strlen(val) + strlen(fmt) + 1;
224 char *cmd = malloc(len);
226 sprintf(cmd, fmt, var, val);
227 wrap(interp, Jim_Eval(interp, cmd));
229 free(cmd);
231 free_target_list(parameters);
233 for (node = defines; node; node = node->next) {
234 const char *fmt = "set {%s} 1";
235 int len = strlen(node->name) + strlen(fmt) + 1;
236 char *cmd = malloc(len);
238 sprintf(cmd, fmt, node->name);
239 wrap(interp, Jim_Eval(interp, cmd));
241 free(cmd);
243 free_target_list(defines);
245 if (env_lookup) {
246 wrap(interp, Jim_Eval(interp, "set TM_ENV_LOOKUP 1"));
249 if (no_execute) {
250 wrap(interp, Jim_Eval(interp, "set TM_NO_EXECUTE 1"));
253 if (silent) {
254 wrap(interp, Jim_Eval(interp, "set TM_SILENT_MODE 1"));
257 goal = goal ? goal : tm_goal;
259 if (goal) {
260 char *fmt = "set TM_CURRENT_GOAL %s";
261 char *cmd = NULL;
263 cmd = malloc(strlen(fmt) + strlen(goal) + 1);
264 sprintf(cmd, fmt, goal);
265 wrap(interp, Jim_Eval(interp, cmd));
268 /* TMakefile evaluation */
269 if (file_exists(filename)) {
270 wrap(interp, Jim_EvalFile(interp, filename));
271 } else {
272 fprintf(stderr, "ERROR: Could not open %s for reading\n", filename);
273 retval = EXIT_FAILURE;
276 if (display_vars) {
277 target_list *node;
278 target_list *rev = target_list_reverse(display_vars);
279 free_target_list(display_vars);
281 for (node = rev; node; node = node->next) {
282 Jim_Obj *val = Jim_GetGlobalVariableStr(interp, node->name, JIM_NONE);
284 if (val) {
285 const char *sval = Jim_String(val);
286 printf("%s=%s\n", node->name, sval);
287 } else {
288 printf("%s is not defined\n", node->name);
292 free_target_list(rev);
293 if (tm_goal) free(tm_goal);
294 free_rule_list(tm_rules);
295 Jim_FreeInterp(interp);
296 exit(EXIT_SUCCESS);
299 goal = goal ? goal : tm_goal;
301 if (!find_rule(goal, tm_rules)) {
302 fprintf(stderr, "ERROR: No rule for goal %s\n", goal);
303 exit(EXIT_FAILURE);
306 find_files(&tm_rules);
308 sorted_rules = topsort(goal, tm_rules);
310 if (!sorted_rules) {
311 fprintf(stderr, "ERROR: Could not find rule to make %s\n", goal);
312 exit(EXIT_FAILURE);
315 sqlrc = sqlite3_open(TM_CACHE, &db);
316 if (sqlrc != SQLITE_OK) {
317 fprintf(stderr, "ERROR: Unable to open " TM_CACHE " database\n");
318 exit(EXIT_FAILURE);
321 sqlrc = sqlite3_exec(db,
322 "CREATE TABLE IF NOT EXISTS TMCache ("
323 "TMakefile TEXT,"
324 "Target TEXT,"
325 "Hash TEXT,"
326 "CONSTRAINT OneFileTarget UNIQUE (TMakefile, Target) ON CONFLICT REPLACE"
327 ")",
328 NULL, NULL, &sqlerr
331 if (sqlrc != SQLITE_OK) {
332 fprintf(stderr, "ERROR: Unable to create database schema: %s", sqlerr);
333 sqlite3_free(sqlerr);
334 exit(EXIT_FAILURE);
337 update_rules(db, interp, filename, sorted_rules, force_update, silent);
339 if (!updated_targets && !silent) {
340 printf("Target %s is up to date\n", goal);
343 free_rule_list(sorted_rules);
344 free_rule_list(tm_rules);
345 if (tm_goal) free(tm_goal);
347 sqlrc = sqlite3_close(db);
348 if (sqlrc != SQLITE_OK) {
349 fprintf(stderr, "WARNING: Exiting while " TM_CACHE " database is busy\n");
352 /* Free the Tcl interpreter */
353 Jim_FreeInterp(interp);
355 return retval;