]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * Copyright 1993, 2000 Christopher Seiwald. | |
3 | * | |
4 | * This file is part of Jam - see jam.c for Copyright information. | |
5 | */ | |
6 | ||
7 | /* This file is ALSO: | |
8 | * Copyright 2001-2004 David Abrahams. | |
9 | * Distributed under the Boost Software License, Version 1.0. | |
10 | * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) | |
11 | */ | |
12 | ||
13 | /* | |
14 | * compile.c - compile parsed jam statements | |
15 | * | |
16 | * External routines: | |
17 | * evaluate_rule() - execute a rule invocation | |
18 | * | |
19 | * Internal routines: | |
20 | * debug_compile() - printf with indent to show rule expansion | |
21 | */ | |
22 | ||
23 | #include "jam.h" | |
24 | #include "compile.h" | |
25 | ||
26 | #include "builtins.h" | |
27 | #include "class.h" | |
28 | #include "constants.h" | |
29 | #include "hash.h" | |
30 | #include "hdrmacro.h" | |
31 | #include "make.h" | |
32 | #include "modules.h" | |
33 | #include "parse.h" | |
34 | #include "rules.h" | |
35 | #include "search.h" | |
36 | #include "strings.h" | |
37 | #include "variable.h" | |
38 | #include "output.h" | |
39 | ||
40 | #include <assert.h> | |
41 | #include <stdarg.h> | |
42 | #include <string.h> | |
43 | ||
44 | ||
45 | static void debug_compile( int which, char const * s, FRAME * ); | |
46 | ||
47 | /* Internal functions from builtins.c */ | |
48 | void backtrace( FRAME * ); | |
49 | void backtrace_line( FRAME * ); | |
50 | void print_source_line( FRAME * ); | |
51 | void unknown_rule( FRAME *, char const * key, module_t *, OBJECT * rule_name ); | |
52 | ||
53 | ||
54 | /* | |
55 | * evaluate_rule() - execute a rule invocation | |
56 | */ | |
57 | ||
58 | LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * frame ) | |
59 | { | |
60 | LIST * result = L0; | |
61 | profile_frame prof[ 1 ]; | |
62 | module_t * prev_module = frame->module; | |
63 | ||
64 | if ( DEBUG_COMPILE ) | |
65 | { | |
66 | /* Try hard to indicate in which module the rule is going to execute. */ | |
67 | char buf[ 256 ] = ""; | |
68 | if ( rule->module->name ) | |
69 | { | |
70 | strncat( buf, object_str( rule->module->name ), sizeof( buf ) - | |
71 | 1 ); | |
72 | strncat( buf, ".", sizeof( buf ) - 1 ); | |
73 | if ( strncmp( buf, object_str( rule->name ), strlen( buf ) ) == 0 ) | |
74 | { | |
75 | buf[ 0 ] = 0; | |
76 | } | |
77 | } | |
78 | strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 ); | |
79 | debug_compile( 1, buf, frame ); | |
80 | ||
81 | lol_print( frame->args ); | |
82 | out_printf( "\n" ); | |
83 | } | |
84 | ||
85 | if ( rule->procedure && rule->module != prev_module ) | |
86 | { | |
87 | /* Propagate current module to nested rule invocations. */ | |
88 | frame->module = rule->module; | |
89 | } | |
90 | ||
91 | /* Record current rule name in frame. */ | |
92 | if ( rule->procedure ) | |
93 | { | |
94 | frame->rulename = object_str( rulename ); | |
95 | /* And enter record profile info. */ | |
96 | if ( DEBUG_PROFILE ) | |
97 | profile_enter( function_rulename( rule->procedure ), prof ); | |
98 | } | |
99 | ||
100 | /* Check traditional targets $(<) and sources $(>). */ | |
101 | if ( !rule->actions && !rule->procedure ) | |
11fdf7f2 | 102 | unknown_rule( frame, NULL, frame->module, rulename ); |
7c673cae FG |
103 | |
104 | /* If this rule will be executed for updating the targets then construct the | |
105 | * action for make(). | |
106 | */ | |
107 | if ( rule->actions ) | |
108 | { | |
109 | TARGETS * t; | |
110 | ||
111 | /* The action is associated with this instance of this rule. */ | |
112 | ACTION * const action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) ); | |
113 | memset( (char *)action, '\0', sizeof( *action ) ); | |
114 | ||
115 | action->rule = rule; | |
116 | action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); | |
117 | action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); | |
118 | action->refs = 1; | |
119 | ||
120 | /* If we have a group of targets all being built using the same action | |
121 | * and any of these targets is updated, then we have to consider them | |
122 | * all to be out-dated. We do this by adding a REBUILDS in both directions | |
123 | * between the first target and all the other targets. | |
124 | */ | |
125 | if ( action->targets ) | |
126 | { | |
127 | TARGET * const t0 = action->targets->target; | |
128 | for ( t = action->targets->next; t; t = t->next ) | |
129 | { | |
130 | t->target->rebuilds = targetentry( t->target->rebuilds, t0 ); | |
131 | t0->rebuilds = targetentry( t0->rebuilds, t->target ); | |
132 | } | |
133 | } | |
134 | ||
135 | /* Append this action to the actions of each target. */ | |
136 | for ( t = action->targets; t; t = t->next ) | |
137 | t->target->actions = actionlist( t->target->actions, action ); | |
138 | ||
139 | action_free( action ); | |
140 | } | |
141 | ||
142 | /* Now recursively compile any parse tree associated with this rule. | |
143 | * function_refer()/function_free() call pair added to ensure the rule does | |
144 | * not get freed while in use. | |
145 | */ | |
146 | if ( rule->procedure ) | |
147 | { | |
148 | FUNCTION * const function = rule->procedure; | |
149 | function_refer( function ); | |
150 | result = function_run( function, frame, stack_global() ); | |
151 | function_free( function ); | |
152 | } | |
153 | ||
154 | if ( DEBUG_PROFILE && rule->procedure ) | |
155 | profile_exit( prof ); | |
156 | ||
157 | if ( DEBUG_COMPILE ) | |
158 | debug_compile( -1, 0, frame ); | |
159 | ||
160 | return result; | |
161 | } | |
162 | ||
163 | ||
164 | /* | |
165 | * Call the given rule with the specified parameters. The parameters should be | |
166 | * of type LIST* and end with a NULL pointer. This differs from 'evaluate_rule' | |
167 | * in that frame for the called rule is prepared inside 'call_rule'. | |
168 | * | |
169 | * This function is useful when a builtin rule (in C) wants to call another rule | |
170 | * which might be implemented in Jam. | |
171 | */ | |
172 | ||
173 | LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... ) | |
174 | { | |
175 | va_list va; | |
176 | LIST * result; | |
177 | ||
178 | FRAME inner[ 1 ]; | |
179 | frame_init( inner ); | |
180 | inner->prev = caller_frame; | |
181 | inner->prev_user = caller_frame->module->user_module | |
182 | ? caller_frame | |
183 | : caller_frame->prev_user; | |
184 | inner->module = caller_frame->module; | |
185 | ||
186 | va_start( va, caller_frame ); | |
187 | for ( ; ; ) | |
188 | { | |
189 | LIST * const l = va_arg( va, LIST * ); | |
190 | if ( !l ) | |
191 | break; | |
192 | lol_add( inner->args, l ); | |
193 | } | |
194 | va_end( va ); | |
195 | ||
196 | result = evaluate_rule( bindrule( rulename, inner->module ), rulename, inner ); | |
197 | ||
198 | frame_free( inner ); | |
199 | ||
200 | return result; | |
201 | } | |
202 | ||
203 | ||
204 | /* | |
205 | * debug_compile() - printf with indent to show rule expansion | |
206 | */ | |
207 | ||
208 | static void debug_compile( int which, char const * s, FRAME * frame ) | |
209 | { | |
210 | static int level = 0; | |
211 | static char indent[ 36 ] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|"; | |
212 | ||
213 | if ( which >= 0 ) | |
214 | { | |
215 | int i; | |
216 | ||
217 | print_source_line( frame ); | |
218 | ||
219 | i = ( level + 1 ) * 2; | |
220 | while ( i > 35 ) | |
221 | { | |
222 | out_puts( indent ); | |
223 | i -= 35; | |
224 | } | |
225 | ||
226 | out_printf( "%*.*s ", i, i, indent ); | |
227 | } | |
228 | ||
229 | if ( s ) | |
230 | out_printf( "%s ", s ); | |
231 | ||
232 | level += which; | |
233 | } |