11 #include "tm_target.h"
12 #include "tm_crypto.h"
13 #include "tm_update.h"
16 /* A list of targets that were updated during the current run */
17 target_list
*updated_targets
= NULL
;
20 /* Returns true if a file exists and is readable.
22 int file_exists(const char *filename
)
26 if ((fp
= fopen(filename
, "r"))) {
35 /* Used takes a Jim interpreter and a Jim error code.
36 * If there was an error, display an error message and exit.
37 * Otherwise, do nothing.
39 void wrap(Jim_Interp
*interp
, int error
)
41 if (error
== JIM_ERR
) {
42 Jim_MakeErrorMessage(interp
);
43 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
44 Jim_FreeInterp(interp
);
50 /* Update a target using the associated rule from tm_rules.
51 * Takes a SQLite database handle representing the sha1sum cache
52 * and the name of the TMakefile being evaluated, along with
53 * the name of the target to update.
55 int update(sqlite3
*db
, const char *tmfile
, const char *target
)
57 unsigned char digest
[CRYPTO_HASH_SIZE
];
58 char newhash
[CRYPTO_HASH_STRING_LENGTH
];
60 const char *fmt
= "INSERT OR REPLACE INTO TMCache (TMakefile, Target, Hash) VALUES (?, ?, ?)";
61 sqlite3_stmt
*stm
= NULL
;
65 rule
= find_rule(target
, tm_rules
);
71 updated_targets
= target_cons(rule
->target
, updated_targets
);
73 if (rule
->type
== TM_EXPLICIT
) {
74 TM_CRYPTO_HASH_DATA(rule
->recipe
, digest
);
75 } else if (rule
->type
== TM_FILENAME
) {
76 TM_CRYPTO_HASH_FILE(target
, digest
);
78 fprintf(stderr
, "WARNING: Unknown rule type %d\n"
79 " Don't know how to update cache for %s\n", rule
->type
, target
);
83 TM_CRYPTO_HASH_TO_STRING(digest
, newhash
);
85 sqlrc
= sqlite3_prepare(db
, fmt
, -1, &stm
, &stmtail
);
86 if (sqlrc
!= SQLITE_OK
) {
87 fprintf(stderr
, "WARNING: Unable to update cache for target %s\n", target
);
91 sqlite3_bind_text(stm
, 1, tmfile
, -1, SQLITE_TRANSIENT
);
92 sqlite3_bind_text(stm
, 2, target
, -1, SQLITE_TRANSIENT
);
93 sqlite3_bind_text(stm
, 3, newhash
, -1, SQLITE_TRANSIENT
);
94 sqlrc
= sqlite3_step(stm
);
95 if (sqlrc
!= SQLITE_DONE
) {
96 fprintf(stderr
, "WARNING: Error updating cache for target %s\n", target
);
97 sqlite3_finalize(stm
);
100 sqlite3_finalize(stm
);
102 Adding this return to squelch compilation warning.
103 Cory should review this code
109 /* Return 1 if target was updated, else return 0.
111 int was_updated(const char *target
)
113 return target_exists(target
, updated_targets
);
117 /* Return 1 if a given target is out of date, else return 0.
118 * Takes a SQLite database handle and the name of the TMakefile
119 * being evaluated along with the name of the target.
121 int needs_update(sqlite3
*db
, const char *tmfile
, const char *target
)
123 unsigned char digest
[CRYPTO_HASH_SIZE
];
124 const char *oldhash
= NULL
;
125 char newhash
[CRYPTO_HASH_STRING_LENGTH
];
126 target_list
*deps
= NULL
;
127 tm_rule
*rule
= NULL
;
128 const char *fmt
= "SELECT Hash FROM TMCache WHERE TMakefile = ? AND Target = ?";
129 const char *stmtail
= NULL
;
130 sqlite3_stmt
*stm
= NULL
;
133 rule
= find_rule(target
, tm_rules
);
139 if (rule
->always_oodate
) {
143 for (deps
= rule
->deps
; deps
; deps
= deps
->next
) {
144 if (was_updated(deps
->name
)) {
149 sqlrc
= sqlite3_prepare(db
, fmt
, -1, &stm
, &stmtail
);
150 if (sqlrc
!= SQLITE_OK
) {
151 fprintf(stderr
, "WARNING: Unable to prepare database statement.\n"
152 " Assuming %s needs update.\n", target
);
156 sqlite3_bind_text(stm
, 1, tmfile
, -1, SQLITE_TRANSIENT
);
157 sqlite3_bind_text(stm
, 2, target
, -1, SQLITE_TRANSIENT
);
158 sqlrc
= sqlite3_step(stm
);
159 if (sqlrc
!= SQLITE_ROW
) {
160 /* There was no row in the cache for this target, so update it */
164 oldhash
= (const char *)sqlite3_column_text(stm
, 0);
166 fprintf(stderr
, "WARNING: Error getting cache for target %s\n", target
);
170 if (rule
->type
== TM_EXPLICIT
) {
171 TM_CRYPTO_HASH_DATA(rule
->recipe
, digest
);
172 } else if (rule
->type
== TM_FILENAME
) {
173 TM_CRYPTO_HASH_FILE(target
, digest
);
175 fprintf(stderr
, "WARNING: Unexpected rule type %d\n"
176 " Assuming %s needs update.\n", rule
->type
, target
);
179 TM_CRYPTO_HASH_TO_STRING(digest
, newhash
);
181 if (strcmp(oldhash
, newhash
) == 0) {
188 sqlite3_finalize(stm
);
191 sqlite3_finalize(stm
);
195 /* Take a list of targets to check and return a sublist containing only
196 * the targets that are out of date.
197 * Takes a SQLite database handle and the name of the TMakefile being
198 * evaluated along with the list of targets.
200 target_list
*need_update(sqlite3
*db
, const char *tmfile
, target_list
*targets
)
202 target_list
*oodate
= NULL
;
204 for (; targets
; targets
= targets
->next
) {
205 if (needs_update(db
, tmfile
, targets
->name
)) {
206 oodate
= target_cons(targets
->name
, oodate
);
214 /* Update all the rules in sorted_rules that need updating.
215 * Takes a SQLite database handle, a Jim interpreter containing
216 * the recipe definitions, the name of the TMakefile that was
217 * evaluated in the interpreter, the rules to be updated if needed
218 * (in the order they are to be updated), whether or not to force
219 * updates regardless of out-of-date status, and whether or not
220 * we're running in silent mode.
222 void update_rules(sqlite3
*db
, Jim_Interp
*interp
,
224 tm_rule_list
*sorted_rules
,
233 for (; sorted_rules
; sorted_rules
= sorted_rules
->next
) {
234 tm_rule
*rule
= sorted_rules
->rule
;
235 if (rule
->type
== TM_EXPLICIT
) {
236 /* If the rule has a recipe and needs an update */
238 && (force
|| needs_update(db
, tmfile
, rule
->target
))) {
239 /* Execute the recipe for the current rule */
240 const char *fmt
= "recipe::%s {%s} {%s} {%s}";
243 const char *target
= rule
->target
;
244 char *inputs
= target_list_to_string(rule
->deps
);
245 target_list
*oodate_deps
= need_update(db
, tmfile
, rule
->deps
);
246 char *oodate
= target_list_to_string(oodate_deps
);
247 tm_rule_list
*oodate_rules
= find_rules(oodate_deps
, tm_rules
);
249 if (was_updated(target
)) {
253 update_rules(db
, interp
, tmfile
, oodate_rules
, force
, silence
);
256 printf("Making target %s:\n", rule
->target
);
258 len
= strlen(fmt
) + strlen(target
)*2 + strlen(inputs
) + strlen(oodate
) + 1;
260 sprintf(cmd
, fmt
, target
, target
, inputs
, oodate
);
261 wrap(interp
, Jim_Eval(interp
, cmd
));
263 update(db
, tmfile
, rule
->target
);
271 free_rule_list(oodate_rules
);
272 free_target_list(oodate_deps
);
274 rule
->type
= TM_UPDATED
;
276 } else if (rule
->type
== TM_FILENAME
) {
277 /* Check that the file actually exists */
278 if (!file_exists(rule
->target
)) {
279 fprintf(stderr
, "ERROR: Unable to find rule for target %s\n", rule
->target
);
282 if (force
|| needs_update(db
, tmfile
, rule
->target
)) {
283 update(db
, tmfile
, rule
->target
);
284 rule
->type
= TM_UPDATED
;