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
[] = {
20 TM_PREFIX
"/lib/tmk/include",
24 /* The default path to search for package files */
25 const char *DEFAULT_PKG_PATH
[] = {
27 TM_PREFIX
"/lib/tmk/packages",
31 /* Display usage and exit.
33 static void usage(const char *progname
)
35 printf("usage: %s [options] [target]\n", progname
);
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");
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
) {
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
)
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
);
121 /* Orchestrate everything! */
122 int main(int argc
, char **argv
)
124 const char *filename
= DEFAULT_FILE
;
125 const char *goal
= NULL
;
127 int force_update
= 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
;
144 target_list
*node
= NULL
;
148 for (i
= 1; i
< argc
; i
++) {
149 if (argv
[i
][0] == '-') {
150 switch (argv
[i
][1]) {
152 if (strcmp(filename
, DEFAULT_FILE
) == 0) {
153 filename
= get(&i
, argc
, argv
);
171 also_include
= target_cons(get(&i
, argc
, argv
), also_include
);
174 also_package
= target_cons(get(&i
, argc
, argv
), also_package
);
177 defines
= target_cons(get(&i
, argc
, argv
), defines
);
180 display_vars
= target_cons(get(&i
, argc
, argv
), display_vars
);
186 } else if (strstr(argv
[i
], "=")) {
187 parameters
= target_cons(argv
[i
], parameters
);
188 } else if (goal
== NULL
) {
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
));
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
));
243 free_target_list(defines
);
246 wrap(interp
, Jim_Eval(interp
, "set TM_ENV_LOOKUP 1"));
250 wrap(interp
, Jim_Eval(interp
, "set TM_NO_EXECUTE 1"));
254 wrap(interp
, Jim_Eval(interp
, "set TM_SILENT_MODE 1"));
257 goal
= goal
? goal
: tm_goal
;
260 char *fmt
= "set TM_CURRENT_GOAL %s";
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
));
272 fprintf(stderr
, "ERROR: Could not open %s for reading\n", filename
);
273 retval
= EXIT_FAILURE
;
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
);
285 const char *sval
= Jim_String(val
);
286 printf("%s=%s\n", node
->name
, sval
);
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
);
299 goal
= goal
? goal
: tm_goal
;
301 if (!find_rule(goal
, tm_rules
)) {
302 fprintf(stderr
, "ERROR: No rule for goal %s\n", goal
);
306 find_files(&tm_rules
);
308 sorted_rules
= topsort(goal
, tm_rules
);
311 fprintf(stderr
, "ERROR: Could not find rule to make %s\n", goal
);
315 sqlrc
= sqlite3_open(TM_CACHE
, &db
);
316 if (sqlrc
!= SQLITE_OK
) {
317 fprintf(stderr
, "ERROR: Unable to open " TM_CACHE
" database\n");
321 sqlrc
= sqlite3_exec(db
,
322 "CREATE TABLE IF NOT EXISTS TMCache ("
326 "CONSTRAINT OneFileTarget UNIQUE (TMakefile, Target) ON CONFLICT REPLACE"
331 if (sqlrc
!= SQLITE_OK
) {
332 fprintf(stderr
, "ERROR: Unable to create database schema: %s", sqlerr
);
333 sqlite3_free(sqlerr
);
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
);