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