VirtualBox

source: kBuild/trunk/src/kmk/kbuild-read.c@ 2665

Last change on this file since 2665 was 2549, checked in by bird, 13 years ago

kmk: hacking on a new kmk/kBuild language extension...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.2 KB
Line 
1/* $Id: kbuild-read.c 2549 2011-11-09 01:22:04Z bird $ */
2/** @file
3 * kBuild specific make functionality related to read.c.
4 */
5
6/*
7 * Copyright (c) 2011 knut st. osmundsen <[email protected]>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/* No GNU coding style here! */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "make.h"
32#include "filedef.h"
33#include "variable.h"
34#include "dep.h"
35#include "debug.h"
36#include "kbuild.h"
37
38#include <assert.h>
39
40
41/*******************************************************************************
42* Defined Constants And Macros *
43*******************************************************************************/
44#define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \
45 ( (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0)
46
47
48/*******************************************************************************
49* Structures and Typedefs *
50*******************************************************************************/
51/** Indicate which kind of kBuild define we're working on. */
52enum kBuildDef
53{
54 kBuildDef_Invalid,
55 kBuildDef_Target,
56 kBuildDef_Template,
57 kBuildDef_Tool,
58 kBuildDef_Sdk,
59 kBuildDef_Unit
60};
61
62enum kBuildExtendBy
63{
64 kBuildExtendBy_NoParent,
65 kBuildExtendBy_Overriding,
66 kBuildExtendBy_Appending,
67 kBuildExtendBy_Prepending
68};
69
70
71/**
72 * The data we stack during eval.
73 */
74struct kbuild_eval_data
75{
76 /** The kind of define. */
77 enum kBuildDef enmKind;
78 /** The bare name of the define. */
79 char *pszName;
80 /** The file location where this define was declared. */
81 struct floc FileLoc;
82
83 /** Pointer to the next element in the global list. */
84 struct kbuild_eval_data *pGlobalNext;
85 /** Pointer to the element below us on the stack. */
86 struct kbuild_eval_data *pStackDown;
87
88 /** The variable set associated with this define. */
89 struct variable_set_list *pVariables;
90 /** The saved current variable set, for restoring in kBuild-endef. */
91 struct variable_set_list *pVariablesSaved;
92
93 /** The parent name, NULL if none. */
94 char *pszParent;
95 /** The inheritance method. */
96 enum kBuildExtendBy enmExtendBy;
97 /** Pointer to the parent. Resolved lazily, so it can be NULL even if we have
98 * a parent. */
99 struct kbuild_eval_data *pParent;
100
101 /** The template, NULL if none. Only applicable to targets. */
102 char *pszTemplate;
103 /** Pointer to the template. Resolved lazily, so it can be NULL even if we have
104 * a parent. */
105 struct kbuild_eval_data *pTemplate;
106
107 /** The variable prefix. */
108 char *pszVarPrefix;
109 /** The length of the variable prefix. */
110 size_t cchVarPrefix;
111};
112
113
114/*******************************************************************************
115* Header Files *
116*******************************************************************************/
117/** Linked list (LIFO) of kBuild defines.
118 * @todo use a hash! */
119struct kbuild_eval_data *g_pHeadKbDefs = NULL;
120/** Stack of kBuild defines. */
121struct kbuild_eval_data *g_pTopKbDef = NULL;
122
123
124struct variable_set *
125get_top_kbuild_variable_set(void)
126{
127 struct kbuild_eval_data *pTop = g_pTopKbDef;
128 assert(pTop != NULL);
129 return pTop->pVariables->set;
130}
131
132
133char *
134kbuild_prefix_variable(const char *pszName, unsigned int *pcchName)
135{
136 struct kbuild_eval_data *pTop = g_pTopKbDef;
137 char *pszPrefixed;
138 unsigned int cchPrefixed;
139
140 assert(pTop != NULL);
141
142 cchPrefixed = pTop->cchVarPrefix + *pcchName;
143 pszPrefixed = xmalloc(cchPrefixed + 1);
144 memcpy(pszPrefixed, pTop->pszVarPrefix, pTop->cchVarPrefix);
145 memcpy(&pszPrefixed[pTop->cchVarPrefix], pszName, *pcchName);
146 pszPrefixed[cchPrefixed] = '\0';
147 *pcchName = cchPrefixed;
148 return pszPrefixed;
149}
150
151
152static const char *
153eval_kbuild_kind_to_string(enum kBuildDef enmKind)
154{
155 switch (enmKind)
156 {
157 case kBuildDef_Target: return "target";
158 case kBuildDef_Template: return "template";
159 case kBuildDef_Tool: return "tool";
160 case kBuildDef_Sdk: return "sdk";
161 case kBuildDef_Unit: return "unit";
162 default:
163 case kBuildDef_Invalid: return "invalid";
164 }
165}
166
167static char *
168allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, unsigned int *pcchToken, int fStrip)
169{
170 unsigned int cchToken;
171 char *pszToken = find_next_token_eos(ppszCursor, pszEos, &cchToken);
172 if (pszToken)
173 {
174 pszToken = allocated_variable_expand_2(pszToken, cchToken, &cchToken);
175 if (pszToken)
176 {
177 if (fStrip)
178 {
179 unsigned int off = 0;
180 while (MY_IS_BLANK(pszToken[off]))
181 off++;
182 if (off)
183 {
184 cchToken -= off;
185 memmove(pszToken, &pszToken[off], cchToken + 1);
186 }
187
188 while (cchToken > 0 && MY_IS_BLANK(pszToken[cchToken - 1]))
189 pszToken[--cchToken] = '\0';
190 }
191
192 assert(cchToken == strlen(pszToken));
193 if (pcchToken)
194 *pcchToken = cchToken;
195 }
196 }
197 return pszToken;
198}
199
200static struct kbuild_eval_data *
201eval_kbuild_resolve_parent(struct kbuild_eval_data *pData)
202{
203 if ( !pData->pParent
204 && pData->pszParent)
205 {
206 struct kbuild_eval_data *pCur = g_pHeadKbDefs;
207 while (pCur)
208 {
209 if ( pCur->enmKind == pData->enmKind
210 && !strcmp(pCur->pszName, pData->pszParent))
211 {
212 if ( pCur->pszParent
213 && ( pCur->pParent == pData
214 || !strcmp(pCur->pszParent, pData->pszName)) )
215 fatal(&pData->FileLoc, _("'%s' and '%s' are both trying to be each other children..."),
216 pData->pszName, pCur->pszName);
217
218 pData->pParent = pCur;
219 pData->pVariables->next = pData->pVariables;
220 break;
221 }
222 pCur = pCur->pGlobalNext;
223 }
224 }
225 return pData->pParent;
226}
227
228static int
229eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
230 const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildDef enmKind)
231{
232 unsigned int cch;
233 unsigned int cchName;
234 char ch;
235 char *psz;
236 const char *pszPrefix;
237 struct kbuild_eval_data *pData;
238
239 if (fIgnoring)
240 return 0;
241
242 /*
243 * Create a new kBuild eval data item.
244 */
245 pData = xmalloc(sizeof(*pData));
246 pData->enmKind = enmKind;
247 pData->pszName = NULL;
248 pData->FileLoc = *pFileLoc;
249
250 pData->pGlobalNext = g_pHeadKbDefs;
251 g_pHeadKbDefs = pData;
252
253 pData->pStackDown = *ppData;
254 *ppData = g_pTopKbDef = pData;
255 pData->pVariables = create_new_variable_set();
256 pData->pVariablesSaved = NULL;
257
258 pData->pszParent = NULL;
259 pData->enmExtendBy = kBuildExtendBy_NoParent;
260 pData->pParent = NULL;
261
262 pData->pszTemplate = NULL;
263 pData->pTemplate = NULL;
264
265 pData->pszVarPrefix = NULL;
266 pData->cchVarPrefix = 0;
267
268 /*
269 * The first word is the name.
270 */
271 pData->pszName = allocate_expanded_next_token(&pszLine, pszEos, &cchName, 1 /*strip*/);
272 if (!pData->pszName || !*pData->pszName)
273 fatal(pFileLoc, _("The kBuild define requires a name"));
274
275 psz = pData->pszName;
276 while ((ch = *psz++) != '\0')
277 if (!isgraph(ch))
278 {
279 error(pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"),
280 eval_kbuild_kind_to_string(enmKind), pData->pszName);
281 break;
282 }
283
284 /*
285 * Parse subsequent words.
286 */
287 psz = find_next_token_eos(&pszLine, pszEos, &cch);
288 while (psz)
289 {
290 if (WORD_IS(psz, cch, "extending"))
291 {
292 /* Inheritance directive. */
293 if (pData->pszParent != NULL)
294 fatal(pFileLoc, _("'extending' can only occure once"));
295 pData->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &cch, 1 /*strip*/);
296 if (!pData->pszParent || !*pData->pszParent)
297 fatal(pFileLoc, _("'extending' requires a parent name"));
298
299 pData->enmExtendBy = kBuildExtendBy_Overriding;
300
301 /* optionally 'by overriding|prepending|appending' */
302 psz = find_next_token_eos(&pszLine, pszEos, &cch);
303 if (psz && WORD_IS(psz, cch, "by"))
304 {
305 cch = 0;
306 psz = find_next_token_eos(&pszLine, pszEos, &cch);
307 if (WORD_IS(psz, cch, "overriding"))
308 pData->enmExtendBy = kBuildExtendBy_Overriding;
309 else if (WORD_IS(psz, cch, "appending"))
310 pData->enmExtendBy = kBuildExtendBy_Appending;
311 else if (WORD_IS(psz, cch, "prepending"))
312 pData->enmExtendBy = kBuildExtendBy_Prepending;
313 else
314 fatal(pFileLoc, _("Unknown 'extending by' method '%.*s'"), (int)cch, psz);
315
316 /* next token */
317 psz = find_next_token_eos(&pszLine, pszEos, &cch);
318 }
319 }
320 else if (WORD_IS(psz, cch, "using"))
321 {
322 /* Template directive. */
323 if (enmKind != kBuildDef_Tool)
324 fatal(pFileLoc, _("'using <template>' can only be used with 'kBuild-define-target'"));
325 if (pData->pszTemplate != NULL)
326 fatal(pFileLoc, _("'using' can only occure once"));
327
328 pData->pszTemplate = allocate_expanded_next_token(&pszLine, pszEos, &cch, 1 /*fStrip*/);
329 if (!pData->pszTemplate || !*pData->pszTemplate)
330 fatal(pFileLoc, _("'using' requires a template name"));
331
332 /* next token */
333 psz = find_next_token_eos(&pszLine, pszEos, &cch);
334 }
335 else
336 fatal(pFileLoc, _("Don't know what '%.*s' means"), (int)cch, psz);
337 }
338
339 /*
340 * Calc the variable prefix.
341 */
342 switch (enmKind)
343 {
344 case kBuildDef_Target: pszPrefix = ""; break;
345 case kBuildDef_Template: pszPrefix = "TEMPLATE_"; break;
346 case kBuildDef_Tool: pszPrefix = "TOOL_"; break;
347 case kBuildDef_Sdk: pszPrefix = "SDK_"; break;
348 case kBuildDef_Unit: pszPrefix = "UNIT_"; break;
349 default:
350 fatal(pFileLoc, _("enmKind=%d"), enmKind);
351 return -1;
352 }
353 cch = strlen(pszPrefix);
354 pData->cchVarPrefix = cch + cchName;
355 pData->pszVarPrefix = xmalloc(pData->cchVarPrefix + 1);
356 memcpy(pData->pszVarPrefix, pszPrefix, cch);
357 memcpy(&pData->pszVarPrefix[cch], pData->pszName, cchName);
358
359 /*
360 * Try resolve the parent and change the current variable set.
361 */
362 eval_kbuild_resolve_parent(pData);
363 pData->pVariablesSaved = current_variable_set_list;
364 current_variable_set_list = pData->pVariables;
365
366 return 0;
367}
368
369static int
370eval_kbuild_endef_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
371 const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildDef enmKind)
372{
373 struct kbuild_eval_data *pData;
374 unsigned int cchName;
375 char *pszName;
376
377 if (fIgnoring)
378 return 0;
379
380 /*
381 * Is there something to pop?
382 */
383 pData = *ppData;
384 if (!pData)
385 {
386 error(pFileLoc, _("kBuild-endef-%s is missing kBuild-define-%s"),
387 eval_kbuild_kind_to_string(enmKind), eval_kbuild_kind_to_string(enmKind));
388 return 0;
389 }
390
391 /*
392 * ... and does it have a matching kind?
393 */
394 if (pData->enmKind != enmKind)
395 error(pFileLoc, _("'kBuild-endef-%s' does not match 'kBuild-define-%s %s'"),
396 eval_kbuild_kind_to_string(enmKind), eval_kbuild_kind_to_string(pData->enmKind), pData->pszName);
397
398 /*
399 * The endef-kbuild may optionally be followed by the target name.
400 * It should match the name given to the kBuild-define.
401 */
402 pszName = allocate_expanded_next_token(&pszLine, pszEos, &cchName, 1 /*fStrip*/);
403 if (pszName)
404 {
405 if (strcmp(pszName, pData->pszName))
406 error(pFileLoc, _("'kBuild-endef-%s %s' does not match 'kBuild-define-%s %s'"),
407 eval_kbuild_kind_to_string(enmKind), pszName,
408 eval_kbuild_kind_to_string(pData->enmKind), pData->pszName);
409 free(pszName);
410 }
411
412 /*
413 * Pop a define off the stack.
414 */
415 assert(pData == g_pTopKbDef);
416 *ppData = g_pTopKbDef = pData->pStackDown;
417 pData->pStackDown = NULL;
418 current_variable_set_list = pData->pVariablesSaved;
419 pData->pVariablesSaved = NULL;
420
421 return 0;
422}
423
424int eval_kbuild_define(struct kbuild_eval_data **kdata, const struct floc *flocp,
425 const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring)
426{
427 assert(memcmp(word, "kBuild-define", sizeof("kBuild-define") - 1) == 0);
428 word += sizeof("kBuild-define") - 1;
429 wlen -= sizeof("kBuild-define") - 1;
430 if ( wlen > 1
431 && word[0] == '-')
432 {
433 if (WORD_IS(word, wlen, "-target"))
434 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Target);
435 if (WORD_IS(word, wlen, "-template"))
436 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Template);
437 if (WORD_IS(word, wlen, "-tool"))
438 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Tool);
439 if (WORD_IS(word, wlen, "-sdk"))
440 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Sdk);
441 if (WORD_IS(word, wlen, "-unit"))
442 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Unit);
443 }
444
445 error(flocp, _("Unknown syntax 'kBuild-define%.*s'"), (int)wlen, word);
446 return 0;
447}
448
449int eval_kbuild_endef(struct kbuild_eval_data **kdata, const struct floc *flocp,
450 const char *word, unsigned int wlen, const char *line, const char *eos, int ignoring)
451{
452 assert(memcmp(word, "kBuild-endef", sizeof("kBuild-endef") - 1) == 0);
453 word += sizeof("kBuild-endef") - 1;
454 wlen -= sizeof("kBuild-endef") - 1;
455 if ( wlen > 1
456 && word[0] == '-')
457 {
458 if (WORD_IS(word, wlen, "-target"))
459 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Target);
460 if (WORD_IS(word, wlen, "-template"))
461 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Template);
462 if (WORD_IS(word, wlen, "-tool"))
463 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Tool);
464 if (WORD_IS(word, wlen, "-sdk"))
465 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Sdk);
466 if (WORD_IS(word, wlen, "-unit"))
467 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, kBuildDef_Unit);
468 }
469
470 error(flocp, _("Unknown syntax 'kBuild-endef%.*s'"), (int)wlen, word);
471 return 0;
472}
473
474void print_kbuild_data_base(void)
475{
476 struct kbuild_eval_data *pCur;
477
478 puts(_("\n# kBuild defines"));
479
480 for (pCur = g_pHeadKbDefs; pCur; pCur = pCur->pGlobalNext)
481 {
482 printf("\nkBuild-define-%s %s",
483 eval_kbuild_kind_to_string(pCur->enmKind), pCur->pszName);
484 if (pCur->pszParent)
485 {
486 printf(" extending %s", pCur->pszParent);
487 switch (pCur->enmExtendBy)
488 {
489 case kBuildExtendBy_Overriding: break;
490 case kBuildExtendBy_Appending: printf(" by appending"); break;
491 case kBuildExtendBy_Prepending: printf(" by prepending"); break;
492 default: printf(" by ?!?");
493 }
494 }
495 if (pCur->pszTemplate)
496 printf(" using %s", pCur->pszTemplate);
497 putchar('\n');
498
499 print_variable_set(pCur->pVariables->set, "");
500
501 printf("kBuild-endef-%s %s\n",
502 eval_kbuild_kind_to_string(pCur->enmKind), pCur->pszName);
503 }
504 /** @todo hash stats. */
505}
506
507void print_kbuild_define_stats(void)
508{
509 /* later when hashing stuff */
510}
511
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette