VirtualBox

source: kBuild/trunk/src/kmk/kbuild-object.c@ 2752

Last change on this file since 2752 was 2720, checked in by bird, 11 years ago

kBuild objects: Implemented the special variable accessor [@super] and [@self].

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 50.0 KB
Line 
1/* $Id: kbuild-object.c 2720 2014-01-01 22:59:50Z bird $ */
2/** @file
3 * kBuild objects.
4 */
5
6/*
7 * Copyright (c) 2011-2014 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#include <stdarg.h>
40
41
42/*******************************************************************************
43* Defined Constants And Macros *
44*******************************************************************************/
45#define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \
46 ( (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0)
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/** kBuild object type. */
53enum kBuildType
54{
55 kBuildType_Invalid,
56 kBuildType_Target,
57 kBuildType_Template,
58 kBuildType_Tool,
59 kBuildType_Sdk,
60 kBuildType_Unit
61};
62
63enum kBuildSeverity
64{
65 kBuildSeverity_Warning,
66 kBuildSeverity_Error,
67 kBuildSeverity_Fatal
68};
69
70
71/**
72 * kBuild object data.
73 */
74struct kbuild_object
75{
76 /** The object type. */
77 enum kBuildType enmType;
78 /** Object name length. */
79 size_t cchName;
80 /** The bare name of the define. */
81 char *pszName;
82 /** The file location where this define was declared. */
83 struct floc FileLoc;
84
85 /** Pointer to the next element in the global list. */
86 struct kbuild_object *pGlobalNext;
87
88 /** The variable set associated with this define. */
89 struct variable_set_list *pVariables;
90
91 /** The parent name, NULL if none. */
92 char *pszParent;
93 /** The length of the parent name. */
94 size_t cchParent;
95 /** Pointer to the parent. Resolved lazily, so it can be NULL even if we
96 * have a parent. */
97 struct kbuild_object *pParent;
98
99 /** The template, NULL if none. Only applicable to targets. Only covers the
100 * primary template, not target or type specific templates.
101 * @todo not sure if this is really necessary. */
102 char const *pszTemplate;
103
104 /** The variable prefix. */
105 char *pszVarPrefix;
106 /** The length of the variable prefix. */
107 size_t cchVarPrefix;
108};
109
110
111/**
112 * The data we stack during eval.
113 */
114struct kbuild_eval_data
115{
116 /** Pointer to the element below us on the stack. */
117 struct kbuild_eval_data *pStackDown;
118 /** Pointer to the object. */
119 struct kbuild_object *pObj;
120 /** The saved current variable set, for restoring in kBuild-endef. */
121 struct variable_set_list *pVariablesSaved;
122};
123
124
125
126/*******************************************************************************
127* Global Variables *
128*******************************************************************************/
129/** Linked list (LIFO) of kBuild defines.
130 * @todo use a hash! */
131static struct kbuild_object *g_pHeadKbObjs = NULL;
132/** Stack of kBuild evalutation contexts.
133 * This is for dealing with potential recursive kBuild object definition,
134 * generally believed to only happen via $(eval ) or include similar. */
135struct kbuild_eval_data *g_pTopKbEvalData = NULL;
136
137/** Cached variable name '_TEMPLATE'. */
138static const char *g_pszVarNmTemplate = NULL;
139
140/** Zero if compatibility mode is disabled, non-zero if enabled.
141 * If explicitily enabled, the value will be greater than 1. */
142int g_fKbObjCompMode = 1;
143
144
145/*******************************************************************************
146* Internal Functions *
147*******************************************************************************/
148static struct kbuild_object *
149resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet);
150static struct kbuild_object *
151get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity);
152
153static struct kbuild_object *
154parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
155 enum kBuildSeverity enmSeverity, const struct floc *pFileLoc,
156 const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType);
157
158
159/**
160 * Initializes the kBuild object stuff.
161 *
162 * Requires the variable_cache to be initialized.
163 */
164void init_kbuild_object(void)
165{
166 g_pszVarNmTemplate = strcache2_add(&variable_strcache, STRING_SIZE_TUPLE("_TEMPLATE"));
167}
168
169
170/**
171 * Reports a problem with dynamic severity level.
172 *
173 * @param enmSeverity The severity level.
174 * @param pFileLoc The file location.
175 * @param pszFormat The format string.
176 * @param ... Arguments for the format string.
177 */
178static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const struct floc *pFileLoc,
179 const char *pszFormat, ...)
180{
181 char szBuf[8192];
182 va_list va;
183
184 va_start(va, pszFormat);
185#ifdef _MSC_VER
186 _vsnprintf(szBuf, sizeof(szBuf), pszFormat, va);
187#else
188 vsnprintf(szBuf, sizeof(szBuf), pszFormat, va);
189#endif
190 va_end(va);
191
192 switch (enmSeverity)
193 {
194 case kBuildSeverity_Warning:
195 message(0, "%s", szBuf);
196 break;
197 case kBuildSeverity_Error:
198 error(pFileLoc, "%s", szBuf);
199 break;
200 default:
201 case kBuildSeverity_Fatal:
202 fatal(pFileLoc, "%s", szBuf);
203 break;
204 }
205}
206
207
208static const char *
209eval_kbuild_type_to_string(enum kBuildType enmType)
210{
211 switch (enmType)
212 {
213 case kBuildType_Target: return "target";
214 case kBuildType_Template: return "template";
215 case kBuildType_Tool: return "tool";
216 case kBuildType_Sdk: return "sdk";
217 case kBuildType_Unit: return "unit";
218 default:
219 case kBuildType_Invalid: return "invalid";
220 }
221}
222
223/**
224 * Gets the length of the string representation of the given type.
225 *
226 * @returns The string length.
227 * @param enmType The kBuild object type in question.
228 */
229static unsigned
230eval_kbuild_type_to_string_length(enum kBuildType enmType)
231{
232 switch (enmType)
233 {
234 case kBuildType_Target: return sizeof("target") - 1;
235 case kBuildType_Template: return sizeof("template") - 1;
236 case kBuildType_Tool: return sizeof("tool") - 1;
237 case kBuildType_Sdk: return sizeof("sdk") - 1;
238 case kBuildType_Unit: return sizeof("unit") - 1;
239 default:
240 case kBuildType_Invalid: return sizeof("invalid") - 1;
241 }
242}
243
244/**
245 * Converts a string into an kBuild object type.
246 *
247 * @returns The type on success, kBuildType_Invalid on failure.
248 * @param pchWord The pchWord. Not necessarily zero terminated.
249 * @param cchWord The length of the word.
250 */
251static enum kBuildType
252eval_kbuild_type_from_string(const char *pchWord, size_t cchWord)
253{
254 if (cchWord >= 3)
255 {
256 if (*pchWord == 't')
257 {
258 if (WORD_IS(pchWord, cchWord, "target"))
259 return kBuildType_Target;
260 if (WORD_IS(pchWord, cchWord, "template"))
261 return kBuildType_Template;
262 if (WORD_IS(pchWord, cchWord, "tool"))
263 return kBuildType_Tool;
264 }
265 else
266 {
267 if (WORD_IS(pchWord, cchWord, "sdk"))
268 return kBuildType_Sdk;
269 if (WORD_IS(pchWord, cchWord, "unit"))
270 return kBuildType_Unit;
271 }
272 }
273
274 return kBuildType_Invalid;
275}
276
277
278
279/**
280 * Helper function for caching variable name strings.
281 *
282 * @returns The string cache variable name.
283 * @param pszName The variable name.
284 * @param ppszCache Cache variable, static or global. Initialize to
285 * NULL.
286 */
287static const char *
288kbuild_variable_name(const char *pszName, const char **ppszCache)
289{
290 const char *pszRet = *ppszCache;
291 if (!pszRet)
292 *ppszCache = pszRet = strcache2_add(&variable_strcache, pszName, strlen(pszName));
293 return pszRet;
294}
295
296static struct kbuild_object *
297lookup_kbuild_object(enum kBuildType enmType, const char *pchName, size_t cchName)
298{
299 /* Linear lookup for now. */
300 struct kbuild_object *pCur = g_pHeadKbObjs;
301 while (pCur)
302 {
303 if ( pCur->enmType == enmType
304 && pCur->cchName == cchName
305 && !memcmp(pCur->pszName, pchName, cchName))
306 return pCur;
307 pCur = pCur->pGlobalNext;
308 }
309 return NULL;
310}
311
312
313/** @name Defining and modifying variables
314 * @{
315 */
316
317/**
318 * Checks if the variable name is valid.
319 *
320 * @returns 1 if valid, 0 if not.
321 * @param pchName The variable name.
322 * @param cchName The length of the variable name.
323 */
324static int
325is_valid_kbuild_object_variable_name(const char *pchName, size_t cchName)
326{
327 if (cchName > 0)
328 {
329 if (!memchr(pchName, '[', cchName))
330 {
331 /** @todo more? */
332 return 1;
333 }
334 }
335 return 0;
336}
337
338static const char *
339kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue,
340 const struct floc *pFileLoc)
341{
342 size_t cchValue = *pcchValue;
343 size_t cbAllocated = *pfDuplicateValue ? 0 : cchValue + 1;
344
345 /*
346 * Loop thru each potential special accessor occurance in the string.
347 *
348 * Unfortunately, we don't have a strnstr function in the C library, so
349 * we'll using memchr and doing a few more rounds in this loop.
350 */
351 size_t cchLeft = cchValue;
352 char *pchLeft = (char *)pchValue;
353 for (;;)
354 {
355 int fSuper;
356 char *pch = (char *)memchr(pchLeft, '$', cchLeft);
357 if (!pch)
358 break;
359
360 pch++;
361 cchLeft -= pch - pchLeft;
362 pchLeft = pch;
363
364 /* [@self] is the shorter, quit if there isn't enough room for even it. */
365 if (cchLeft < sizeof("([@self]") - 1)
366 break;
367
368 /* We don't care how many dollars there are in front of a special accessor. */
369 if (*pchLeft == '$')
370 {
371 do
372 {
373 cchLeft--;
374 pchLeft++;
375 } while (cchLeft >= sizeof("([@self]") - 1 && *pchLeft == '$');
376 if (cchLeft < sizeof("([@self]") - 1)
377 break;
378 }
379
380 /* Is it a special accessor? */
381 if ( pchLeft[2] != '@'
382 || pchLeft[1] != '['
383 || pchLeft[0] != '(')
384 continue;
385 pchLeft += 2;
386 cchLeft -= 2;
387 if (!memcmp(pchLeft, STRING_SIZE_TUPLE("@self]")))
388 fSuper = 0;
389 else if ( cchLeft >= sizeof("@super]")
390 && !memcmp(pchLeft, STRING_SIZE_TUPLE("@super]")))
391 fSuper = 1;
392 else
393 continue;
394
395 /*
396 * We've got something to replace. First figure what with and then
397 * resize the value buffer.
398 */
399 if (g_pTopKbEvalData)
400 {
401 struct kbuild_object *pObj = g_pTopKbEvalData->pObj;
402 size_t const cchSpecial = fSuper ? sizeof("@super") - 1 : sizeof("@self") - 1;
403 size_t cchName;
404 size_t cchType;
405 long cchDelta;
406 const char *pszName;
407
408 if (fSuper)
409 {
410 pObj = get_kbuild_object_parent(pObj, kBuildSeverity_Error);
411 if (!pObj)
412 continue;
413 }
414 pszName = pObj->pszName;
415 cchName = pObj->cchName;
416 cchType = eval_kbuild_type_to_string_length(pObj->enmType);
417 cchDelta = cchType + 1 + cchName - cchSpecial;
418
419 if (cchValue + cchDelta >= cbAllocated)
420 {
421 size_t offLeft = pchLeft - pchValue;
422 char *pszNewValue;
423
424 cbAllocated = cchValue + cchDelta + 1;
425 if (cchValue < 1024)
426 cbAllocated = (cbAllocated + 31) & ~(size_t)31;
427 else
428 cbAllocated = (cbAllocated + 255) & ~(size_t)255;
429 pszNewValue = (char *)xmalloc(cbAllocated);
430
431 memcpy(pszNewValue, pchValue, offLeft);
432 memcpy(pszNewValue + offLeft + cchSpecial + cchDelta,
433 pchLeft + cchSpecial,
434 cchLeft - cchSpecial + 1);
435
436 if (*pfDuplicateValue == 0)
437 free((char *)pchValue);
438 else
439 *pfDuplicateValue = 0;
440
441 pchValue = pszNewValue;
442 pchLeft = pszNewValue + offLeft;
443 }
444 else
445 {
446 assert(*pfDuplicateValue == 0);
447 memmove(pchLeft + cchSpecial + cchDelta,
448 pchLeft + cchSpecial,
449 cchLeft - cchSpecial + 1);
450 }
451
452 cchLeft += cchDelta;
453 cchValue += cchDelta;
454 *pcchValue = cchValue;
455
456 memcpy(pchLeft, eval_kbuild_type_to_string(pObj->enmType), cchType);
457 pchLeft += cchType;
458 *pchLeft++ = '@';
459 memcpy(pchLeft, pszName, cchName);
460 pchLeft += cchName;
461 cchLeft -= cchType + 1 + cchName;
462 }
463 else
464 error(pFileLoc, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"),
465 MAX(cchLeft, 20), pchLeft);
466 }
467
468 return pchValue;
469}
470
471static struct variable *
472define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName,
473 const char *pchValue, size_t cchValue,
474 int fDuplicateValue, enum variable_origin enmOrigin,
475 int fRecursive, int fNoSpecialAccessors, const struct floc *pFileLoc)
476{
477 struct variable *pVar;
478 size_t cchName = strcache2_get_len(&variable_strcache, pszName);
479
480 if (fRecursive && !fNoSpecialAccessors)
481 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc);
482
483 pVar = define_variable_in_set(pszName, cchName,
484 pchValue, cchValue, fDuplicateValue,
485 enmOrigin, fRecursive,
486 pObj->pVariables->set,
487 pFileLoc);
488
489 /* Single underscore prefixed variables gets a global alias. */
490 if ( pszName[0] == '_'
491 && pszName[1] != '_'
492 && g_fKbObjCompMode)
493 {
494 struct variable *pAlias;
495 size_t cchPrefixed = pObj->cchVarPrefix + cchName;
496 char *pszPrefixed = xmalloc(cchPrefixed + 1);
497 memcpy(pszPrefixed, pObj->pszVarPrefix, pObj->cchVarPrefix);
498 memcpy(&pszPrefixed[pObj->cchVarPrefix], pszName, cchName);
499 pszPrefixed[cchPrefixed] = '\0';
500
501 pAlias = define_variable_alias_in_set(pszPrefixed, cchPrefixed, pVar, enmOrigin,
502 &global_variable_set, pFileLoc);
503 if (!pAlias->alias)
504 error(pFileLoc, _("Error defining alias '%s'"), pszPrefixed);
505 }
506
507 return pVar;
508}
509
510#if 0
511struct variable *
512define_kbuild_object_variable(struct kbuild_object *pObj, const char *pchName, size_t cchName,
513 const char *pchValue, size_t cchValue,
514 int fDuplicateValue, enum variable_origin enmOrigin,
515 int fRecursive, const struct floc *pFileLoc)
516{
517 return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchName, cchName),
518 pchValue, cchValue,
519 fDuplicateValue, enmOrigin,
520 fRecursive, pFileLoc);
521}
522#endif
523
524/**
525 * Try define a kBuild object variable via a possible accessor
526 * ([type@object]var).
527 *
528 * @returns Pointer to the defined variable on success.
529 * @retval VAR_NOT_KBUILD_ACCESSOR if it isn't an accessor.
530 *
531 * @param pchName The variable name, not cached.
532 * @param cchName The variable name length. This will not be ~0U.
533 * @param pszValue The variable value. If @a fDuplicateValue is clear,
534 * this should be assigned as the actual variable
535 * value, otherwise it will be duplicated. In the
536 * latter case it might not be properly null
537 * terminated.
538 * @param cchValue The value length.
539 * @param fDuplicateValue Whether @a pszValue need to be duplicated on the
540 * heap or is already there.
541 * @param enmOrigin The variable origin.
542 * @param fRecursive Whether it's a recursive variable.
543 * @param pFileLoc The location of the variable definition.
544 */
545struct variable *
546try_define_kbuild_object_variable_via_accessor(const char *pchName, size_t cchName,
547 const char *pszValue, size_t cchValue, int fDuplicateValue,
548 enum variable_origin enmOrigin, int fRecursive,
549 struct floc const *pFileLoc)
550{
551 struct kbuild_object *pObj;
552 const char *pchVarNm;
553 size_t cchVarNm;
554
555 pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc,
556 &pchVarNm, &cchVarNm, NULL);
557 if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
558 {
559 assert(pObj != NULL);
560 if (!is_valid_kbuild_object_variable_name(pchVarNm, cchVarNm))
561 fatal(pFileLoc, _("Invalid kBuild object variable name: '%.*s' ('%s')"),
562 (int)cchVarNm, pchVarNm, (int)cchName, pchName);
563 return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm),
564 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive,
565 0 /*fNoSpecialAccessors*/, pFileLoc);
566 }
567
568 return VAR_NOT_KBUILD_ACCESSOR;
569}
570
571/**
572 * Define a kBuild object variable in the topmost kBuild object.
573 *
574 * This won't be an variable accessor.
575 *
576 * @returns Pointer to the defined variable on success.
577 *
578 * @param pchName The variable name, not cached.
579 * @param cchName The variable name length. This will not be ~0U.
580 * @param pszValue The variable value. If @a fDuplicateValue is clear,
581 * this should be assigned as the actual variable
582 * value, otherwise it will be duplicated. In the
583 * latter case it might not be properly null
584 * terminated.
585 * @param cchValue The value length.
586 * @param fDuplicateValue Whether @a pszValue need to be duplicated on the
587 * heap or is already there.
588 * @param enmOrigin The variable origin.
589 * @param fRecursive Whether it's a recursive variable.
590 * @param pFileLoc The location of the variable definition.
591 */
592struct variable *
593define_kbuild_object_variable_in_top_obj(const char *pchName, size_t cchName,
594 const char *pszValue, size_t cchValue, int fDuplicateValue,
595 enum variable_origin enmOrigin, int fRecursive,
596 struct floc const *pFileLoc)
597{
598 assert(g_pTopKbEvalData != NULL);
599
600 if (!is_valid_kbuild_object_variable_name(pchName, cchName))
601 fatal(pFileLoc, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName);
602
603 return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName),
604 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive,
605 0 /*fNoSpecialAccessors*/, pFileLoc);
606}
607
608/**
609 * Implements appending and prepending to a kBuild object variable.
610 *
611 * The variable is either accessed thru an accessor or by the topmost kBuild
612 * object.
613 *
614 * @returns Pointer to the defined variable on success.
615 *
616 * @param pchName The variable name, not cached.
617 * @param cchName The variable name length. This will not be ~0U.
618 * @param pszValue The variable value. Must be duplicated.
619 * @param cchValue The value length.
620 * @param fSimpleValue Whether we've already figured that it's a simple
621 * value. This is for optimizing appending/prepending
622 * to an existing simple value variable.
623 * @param enmOrigin The variable origin.
624 * @param fAppend Append if set, prepend if clear.
625 * @param pFileLoc The location of the variable definition.
626 */
627struct variable *
628kbuild_object_variable_pre_append(const char *pchName, size_t cchName,
629 const char *pchValue, size_t cchValue, int fSimpleValue,
630 enum variable_origin enmOrigin, int fAppend,
631 const struct floc *pFileLoc)
632{
633 struct kbuild_object *pObj;
634 struct variable VarKey;
635
636 /*
637 * Resolve the relevant kBuild object first.
638 */
639 if (cchName > 3 && pchName[0] == '[')
640 {
641 const char *pchVarNm;
642 size_t cchVarNm;
643 pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc,
644 &pchVarNm, &cchVarNm, NULL);
645 if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
646 {
647 pchName = pchVarNm;
648 cchName = cchVarNm;
649 }
650 else
651 pObj = g_pTopKbEvalData->pObj;
652 }
653 else
654 pObj = g_pTopKbEvalData->pObj;
655
656 /*
657 * Make sure the variable name is valid. Raise fatal error if not.
658 */
659 if (!is_valid_kbuild_object_variable_name(pchName, cchName))
660 fatal(pFileLoc, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName);
661
662 /*
663 * Get the cached name and look it up in the object's variables.
664 */
665 VarKey.name = strcache2_lookup(&variable_strcache, pchName, cchName);
666 if (VarKey.name)
667 {
668 struct variable *pVar;
669
670 VarKey.length = cchName;
671 pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey);
672 if (pVar)
673 {
674 /* Append/prepend to existing variable. */
675 int fDuplicateValue = 1;
676 if (pVar->recursive && !fSimpleValue)
677 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc);
678
679 pVar = do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend);
680
681 if (fDuplicateValue == 0)
682 free((char *)pchValue);
683 return pVar;
684 }
685
686 /*
687 * Not found. Check ancestors if the 'override' directive isn't applied.
688 */
689 if (pObj->pszParent && enmOrigin != o_override)
690 {
691 struct kbuild_object *pParent = pObj;
692 for (;;)
693 {
694 pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/);
695 if (!pParent)
696 break;
697
698 pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey);
699 if (pVar)
700 {
701 if (pVar->value_length != ~0U)
702 assert(pVar->value_length == strlen(pVar->value));
703 else
704 pVar->value_length = strlen(pVar->value);
705
706 /*
707 * Combine the two values and define the variable in the
708 * specified child object. We must disregard 'origin' a
709 * little here, so we must do the gritty stuff our selves.
710 */
711 if ( pVar->recursive
712 || fSimpleValue
713 || !cchValue
714 || memchr(pchValue, '$', cchValue) == NULL )
715 {
716 int fDuplicateValue = 1;
717 size_t cchNewValue;
718 char *pszNewValue;
719 char *pszTmp;
720
721 /* Just join up the two values. */
722 if (pVar->recursive && !fSimpleValue)
723 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc);
724 if (pVar->value_length == 0)
725 {
726 cchNewValue = cchValue;
727 pszNewValue = xstrndup(pchValue, cchValue);
728 }
729 else if (!cchValue)
730 {
731 cchNewValue = pVar->value_length;
732 pszNewValue = xmalloc(cchNewValue + 1);
733 memcpy(pszNewValue, pVar->value, cchNewValue + 1);
734 }
735 else
736 {
737 cchNewValue = pVar->value_length + 1 + cchValue;
738 pszNewValue = xmalloc(cchNewValue + 1);
739 if (fAppend)
740 {
741 memcpy(pszNewValue, pVar->value, pVar->value_length);
742 pszTmp = pszNewValue + pVar->value_length;
743 *pszTmp++ = ' ';
744 memcpy(pszTmp, pchValue, cchValue);
745 pszTmp[cchValue] = '\0';
746 }
747 else
748 {
749 memcpy(pszNewValue, pchValue, cchValue);
750 pszTmp = pszNewValue + cchValue;
751 *pszTmp++ = ' ';
752 memcpy(pszNewValue, pVar->value, pVar->value_length);
753 pszTmp[pVar->value_length] = '\0';
754 }
755 }
756
757 /* Define the new variable in the child. */
758 pVar = define_kbuild_object_variable_cached(pObj, VarKey.name,
759 pszNewValue, cchNewValue, 0 /*fDuplicateValue*/,
760 enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/,
761 pFileLoc);
762 if (fDuplicateValue == 0)
763 free((char *)pchValue);
764 }
765 else
766 {
767 /* Lazy bird: Copy the variable from the ancestor and
768 then do a normal append/prepend on it. */
769 pVar = define_kbuild_object_variable_cached(pObj, VarKey.name,
770 pVar->value, pVar->value_length, 1 /*fDuplicateValue*/,
771 enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/,
772 pFileLoc);
773 append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend);
774 }
775 return pVar;
776 }
777 }
778 }
779 }
780 else
781 VarKey.name = strcache2_add(&variable_strcache, pchName, cchName);
782
783 /* Variable not found. */
784 return define_kbuild_object_variable_cached(pObj, VarKey.name,
785 pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin,
786 1 /*fRecursive */, 0 /*fNoSpecialAccessors*/, pFileLoc);
787}
788
789/** @} */
790
791
792static char *
793allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, size_t *pcchToken, int fStrip)
794{
795 unsigned int cchToken;
796 char *pszToken = find_next_token_eos(ppszCursor, pszEos, &cchToken);
797 if (pszToken)
798 {
799 pszToken = allocated_variable_expand_2(pszToken, cchToken, &cchToken);
800 if (pszToken)
801 {
802 if (fStrip)
803 {
804 unsigned int off = 0;
805 while (MY_IS_BLANK(pszToken[off]))
806 off++;
807 if (off)
808 {
809 cchToken -= off;
810 memmove(pszToken, &pszToken[off], cchToken + 1);
811 }
812
813 while (cchToken > 0 && MY_IS_BLANK(pszToken[cchToken - 1]))
814 pszToken[--cchToken] = '\0';
815 }
816
817 assert(cchToken == strlen(pszToken));
818 if (pcchToken)
819 *pcchToken = cchToken;
820 return pszToken;
821 }
822 }
823
824 if (pcchToken)
825 *pcchToken = 0;
826 return NULL;
827}
828
829static struct kbuild_object *
830resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet)
831{
832 if ( !pObj->pParent
833 && pObj->pszParent)
834 {
835 struct kbuild_object *pCur = g_pHeadKbObjs;
836 while (pCur)
837 {
838 if ( pCur->enmType == pObj->enmType
839 && !strcmp(pCur->pszName, pObj->pszParent))
840 {
841 if ( pCur->pszParent
842 && ( pCur->pParent == pObj
843 || !strcmp(pCur->pszParent, pObj->pszName)) )
844 fatal(&pObj->FileLoc, _("'%s' and '%s' are both trying to be each other children..."),
845 pObj->pszName, pCur->pszName);
846
847 pObj->pParent = pCur;
848 pObj->pVariables->next = pObj->pVariables;
849 return pCur;
850 }
851
852 pCur = pCur->pGlobalNext;
853 }
854
855 /* Not found. */
856 if (!fQuiet)
857 error(&pObj->FileLoc, _("Could not locate parent '%s' of '%s'"), pObj->pszParent, pObj->pszName);
858 }
859 return pObj->pParent;
860}
861
862/**
863 * Get the parent of the given object, it is expected to have one.
864 *
865 * @returns Pointer to the parent. NULL if we survive failure.
866 * @param pObj The kBuild object.
867 * @param enmSeverity The severity of a missing parent.
868 */
869static struct kbuild_object *
870get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity)
871{
872 struct kbuild_object *pParent = pObj->pParent;
873 if (pParent)
874 return pParent;
875
876 pParent = resolve_kbuild_object_parent(pObj, 1 /*fQuiet - complain below */);
877 if (pParent)
878 return pParent;
879
880 if (pObj->pszParent)
881 kbuild_report_problem(enmSeverity, &pObj->FileLoc,
882 _("Could not local parent '%s' for kBuild object '%s'"),
883 pObj->pszParent, pObj->pszName);
884 else
885 kbuild_report_problem(enmSeverity, &pObj->FileLoc,
886 _("kBuild object '%s' has no parent ([@super])"),
887 pObj->pszName);
888 return NULL;
889}
890
891static int
892eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
893 const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType)
894{
895 unsigned int cch;
896 char ch;
897 char *psz;
898 const char *pszPrefix;
899 struct kbuild_object *pObj;
900 struct kbuild_eval_data *pData;
901
902 if (fIgnoring)
903 return 0;
904
905 /*
906 * Create a new kBuild object.
907 */
908 pObj = xmalloc(sizeof(*pObj));
909 pObj->enmType = enmType;
910 pObj->pszName = NULL;
911 pObj->cchName = 0;
912 pObj->FileLoc = *pFileLoc;
913
914 pObj->pGlobalNext = g_pHeadKbObjs;
915 g_pHeadKbObjs = pObj;
916
917 pObj->pVariables = create_new_variable_set();
918
919 pObj->pszParent = NULL;
920 pObj->cchParent = 0;
921 pObj->pParent = NULL;
922
923 pObj->pszTemplate = NULL;
924
925 pObj->pszVarPrefix = NULL;
926 pObj->cchVarPrefix = 0;
927
928 /*
929 * The first word is the name.
930 */
931 pObj->pszName = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchName, 1 /*strip*/);
932 if (!pObj->pszName || !*pObj->pszName)
933 fatal(pFileLoc, _("The kBuild define requires a name"));
934
935 psz = pObj->pszName;
936 while ((ch = *psz++) != '\0')
937 if (!isgraph(ch))
938 {
939 error(pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"),
940 eval_kbuild_type_to_string(enmType), pObj->pszName);
941 break;
942 }
943
944 /*
945 * Calc the variable prefix.
946 */
947 switch (enmType)
948 {
949 case kBuildType_Target: pszPrefix = ""; break;
950 case kBuildType_Template: pszPrefix = "TEMPLATE_"; break;
951 case kBuildType_Tool: pszPrefix = "TOOL_"; break;
952 case kBuildType_Sdk: pszPrefix = "SDK_"; break;
953 case kBuildType_Unit: pszPrefix = "UNIT_"; break;
954 default:
955 fatal(pFileLoc, _("enmType=%d"), enmType);
956 return -1;
957 }
958 cch = strlen(pszPrefix);
959 pObj->cchVarPrefix = cch + pObj->cchName;
960 pObj->pszVarPrefix = xmalloc(pObj->cchVarPrefix + 1);
961 memcpy(pObj->pszVarPrefix, pszPrefix, cch);
962 memcpy(&pObj->pszVarPrefix[cch], pObj->pszName, pObj->cchName);
963
964 /*
965 * Parse subsequent words.
966 */
967 psz = find_next_token_eos(&pszLine, pszEos, &cch);
968 while (psz)
969 {
970 if (WORD_IS(psz, cch, "extending"))
971 {
972 /* Inheritance directive. */
973 if (pObj->pszParent != NULL)
974 fatal(pFileLoc, _("'extending' can only occure once"));
975 pObj->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchParent, 1 /*strip*/);
976 if (!pObj->pszParent || !*pObj->pszParent)
977 fatal(pFileLoc, _("'extending' requires a parent name"));
978 }
979 else if (WORD_IS(psz, cch, "using"))
980 {
981 char *pszTemplate;
982 size_t cchTemplate;
983
984 /* Template directive. */
985 if (enmType != kBuildType_Target)
986 fatal(pFileLoc, _("'using <template>' can only be used with 'kBuild-define-target'"));
987 if (pObj->pszTemplate != NULL)
988 fatal(pFileLoc, _("'using' can only occure once"));
989
990 pszTemplate = allocate_expanded_next_token(&pszLine, pszEos, &cchTemplate, 1 /*fStrip*/);
991 if (!pszTemplate || !*pszTemplate)
992 fatal(pFileLoc, _("'using' requires a template name"));
993
994 define_kbuild_object_variable_cached(pObj, g_pszVarNmTemplate, pszTemplate, cchTemplate,
995 0 /*fDuplicateValue*/, o_default, 0 /*fRecursive*/,
996 1 /*fNoSpecialAccessors*/, pFileLoc);
997
998 }
999 else
1000 fatal(pFileLoc, _("Don't know what '%.*s' means"), (int)cch, psz);
1001
1002 /* next token */
1003 psz = find_next_token_eos(&pszLine, pszEos, &cch);
1004 }
1005
1006 /*
1007 * Try resolve the parent.
1008 */
1009 resolve_kbuild_object_parent(pObj, 1 /*fQuiet*/);
1010
1011 /*
1012 * Create an eval stack entry and change the current variable set.
1013 */
1014 pData = xmalloc(sizeof(*pData));
1015 pData->pObj = pObj;
1016 pData->pVariablesSaved = current_variable_set_list;
1017 current_variable_set_list = pObj->pVariables;
1018
1019 pData->pStackDown = *ppData;
1020 *ppData = pData;
1021 g_pTopKbEvalData = pData;
1022
1023 return 0;
1024}
1025
1026static int
1027eval_kbuild_endef_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc,
1028 const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType)
1029{
1030 struct kbuild_eval_data *pData;
1031 struct kbuild_object *pObj;
1032 size_t cchName;
1033 char *pszName;
1034
1035 if (fIgnoring)
1036 return 0;
1037
1038 /*
1039 * Is there something to pop?
1040 */
1041 pData = *ppData;
1042 if (!pData)
1043 {
1044 error(pFileLoc, _("kBuild-endef-%s is missing kBuild-define-%s"),
1045 eval_kbuild_type_to_string(enmType), eval_kbuild_type_to_string(enmType));
1046 return 0;
1047 }
1048
1049 /*
1050 * ... and does it have a matching kind?
1051 */
1052 pObj = pData->pObj;
1053 if (pObj->enmType != enmType)
1054 error(pFileLoc, _("'kBuild-endef-%s' does not match 'kBuild-define-%s %s'"),
1055 eval_kbuild_type_to_string(enmType), eval_kbuild_type_to_string(pObj->enmType), pObj->pszName);
1056
1057 /*
1058 * The endef-kbuild may optionally be followed by the target name.
1059 * It should match the name given to the kBuild-define.
1060 */
1061 pszName = allocate_expanded_next_token(&pszLine, pszEos, &cchName, 1 /*fStrip*/);
1062 if (pszName)
1063 {
1064 if ( cchName != pObj->cchName
1065 || strcmp(pszName, pObj->pszName))
1066 error(pFileLoc, _("'kBuild-endef-%s %s' does not match 'kBuild-define-%s %s'"),
1067 eval_kbuild_type_to_string(enmType), pszName,
1068 eval_kbuild_type_to_string(pObj->enmType), pObj->pszName);
1069 free(pszName);
1070 }
1071
1072 /*
1073 * Pop a define off the stack.
1074 */
1075 assert(pData == g_pTopKbEvalData);
1076 *ppData = g_pTopKbEvalData = pData->pStackDown;
1077 pData->pStackDown = NULL;
1078 current_variable_set_list = pData->pVariablesSaved;
1079 pData->pVariablesSaved = NULL;
1080 free(pData);
1081
1082 return 0;
1083}
1084
1085int eval_kbuild_read_hook(struct kbuild_eval_data **kdata, const struct floc *flocp,
1086 const char *pchWord, size_t cchWord, const char *line, const char *eos, int ignoring)
1087{
1088 enum kBuildType enmType;
1089
1090 /*
1091 * Skip the 'kBuild-' prefix that the caller already matched.
1092 */
1093 assert(memcmp(pchWord, "kBuild-", sizeof("kBuild-") - 1) == 0);
1094 pchWord += sizeof("kBuild-") - 1;
1095 cchWord -= sizeof("kBuild-") - 1;
1096
1097 /*
1098 * String switch.
1099 */
1100 if ( cchWord >= sizeof("define-") - 1
1101 && strneq(pchWord, "define-", sizeof("define-") - 1))
1102 {
1103 enmType = eval_kbuild_type_from_string(pchWord + sizeof("define-") - 1, cchWord - sizeof("define-") + 1);
1104 if (enmType != kBuildType_Invalid)
1105 return eval_kbuild_define_xxxx(kdata, flocp, line, eos, ignoring, enmType);
1106 }
1107 else if ( cchWord >= sizeof("endef-") - 1
1108 && strneq(pchWord, "endef-", sizeof("endef-") - 1))
1109 {
1110 enmType = eval_kbuild_type_from_string(pchWord + sizeof("endif-") - 1, cchWord - sizeof("endif-") + 1);
1111 if (enmType != kBuildType_Invalid)
1112 return eval_kbuild_endef_xxxx(kdata, flocp, line, eos, ignoring, enmType);
1113 }
1114 else if (WORD_IS(pchWord, cchWord, "endef"))
1115 {
1116 /* Terminate whatever definition is on top. */
1117
1118 }
1119
1120 /*
1121 * Everything that is prefixed with 'kBuild-' is reserved for language
1122 * extensions, at least until legacy assignments/whatever turns up.
1123 */
1124 error(flocp, _("Unknown syntax 'kBuild-%.*s'"), (int)cchWord, pchWord);
1125 return 0;
1126}
1127
1128
1129/** @name kBuild object variable accessor related functions
1130 * @{
1131 */
1132
1133/**
1134 * Checks if the given name is an object variable accessor.
1135 *
1136 * @returns 1 if it is, 0 if it isn't.
1137 * @param pchName The potential kBuild variable accessor
1138 * expression.
1139 * @param cchName Length of the expression.
1140 */
1141int is_kbuild_object_variable_accessor(const char *pchName, size_t cchName)
1142{
1143 char const *pchTmp;
1144
1145 /* See lookup_kbuild_object_variable for the rules. */
1146 if (cchName >= 1+1+1+1 && *pchName == '[')
1147 {
1148 pchName++;
1149 cchName--;
1150
1151 pchTmp = memchr(pchName, '@', cchName);
1152 if (pchTmp)
1153 {
1154 cchName -= pchTmp + 1 - pchName;
1155 pchName = pchTmp + 1;
1156 pchTmp = memchr(pchName, ']', cchName);
1157 if (pchTmp)
1158 {
1159 cchName -= pchTmp + 1 - pchName;
1160 if (cchName > 0)
1161 return 1;
1162 }
1163 }
1164 }
1165 return 0;
1166}
1167
1168/**
1169 * Parses a kBuild object variable accessor, resolving the object.
1170 *
1171 * @returns Pointer to the variable if found.
1172 * @retval NULL if the object (or type) couldn't be resolved.
1173 * @retval KOBJ_NOT_KBUILD_ACCESSOR if no a kBuild variable accessor.
1174 *
1175 * @param pchExpr The kBuild variable accessor expression.
1176 * @param cchExpr Length of the expression.
1177 * @param enmSeverity The minimum severity level for errors.
1178 * @param pFileLoc The file location any errors should be reported
1179 * at. Optional.
1180 * @param ppchVarNm Where to return the pointer to the start of the
1181 * variable name within the string @a pchExpr
1182 * points to. Mandatory.
1183 * @param pcchVarNm Where to return the length of the variable name.
1184 * Mandatory.
1185 * @param penmType Where to return the object type. Optional.
1186 */
1187static struct kbuild_object *
1188parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr,
1189 enum kBuildSeverity enmSeverity, const struct floc *pFileLoc,
1190 const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType)
1191{
1192 const char * const pchOrgExpr = pchExpr;
1193 size_t const cchOrgExpr = cchExpr;
1194 char const *pchTmp;
1195
1196 /*
1197 * To accept this as an kBuild accessor, we require:
1198 * 1. Open bracket.
1199 * 2. At sign separating the type from the name.
1200 * 3. Closing bracket.
1201 * 4. At least one character following it.
1202 */
1203 if (cchExpr >= 1+1+1+1 && *pchExpr == '[')
1204 {
1205 pchExpr++;
1206 cchExpr--;
1207
1208 pchTmp = memchr(pchExpr, '@', cchExpr);
1209 if (pchTmp)
1210 {
1211 const char * const pchType = pchExpr;
1212 size_t const cchType = pchTmp - pchExpr;
1213
1214 cchExpr -= cchType + 1;
1215 pchExpr = pchTmp + 1;
1216 pchTmp = memchr(pchExpr, ']', cchExpr);
1217 if (pchTmp)
1218 {
1219 const char * const pchObjName = pchExpr;
1220 size_t const cchObjName = pchTmp - pchExpr;
1221
1222 cchExpr -= cchObjName + 1;
1223 pchExpr = pchTmp + 1;
1224 if (cchExpr > 0)
1225 {
1226
1227 /*
1228 * It's an kBuild define variable accessor, alright.
1229 */
1230 *pcchVarNm = cchExpr;
1231 *ppchVarNm = pchExpr;
1232
1233 /* Deal with known special accessors: [@self]VAR, [@super]VAR. */
1234 if (cchType == 0)
1235 {
1236 int fSuper;
1237
1238 if (WORD_IS(pchObjName, cchObjName, "self"))
1239 fSuper = 0;
1240 else if (WORD_IS(pchObjName, cchObjName, "super"))
1241 fSuper = 1;
1242 else
1243 {
1244 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
1245 _("Invalid special kBuild object accessor: '%.*s'"),
1246 (int)cchOrgExpr, pchOrgExpr);
1247 if (penmType)
1248 *penmType = kBuildType_Invalid;
1249 return NULL;
1250 }
1251 if (g_pTopKbEvalData)
1252 {
1253 struct kbuild_object *pObj = g_pTopKbEvalData->pObj;
1254 struct kbuild_object *pParent;
1255
1256 if (penmType)
1257 *penmType = pObj->enmType;
1258
1259 if (!fSuper)
1260 return pObj;
1261
1262 pParent = get_kbuild_object_parent(pObj, MAX(enmSeverity, kBuildSeverity_Error));
1263 if (pParent)
1264 return pParent;
1265 }
1266 else
1267 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
1268 _("The '%.*s' accessor can only be used in the context of a kBuild object"),
1269 (int)cchOrgExpr, pchOrgExpr);
1270 if (penmType)
1271 *penmType = kBuildType_Invalid;
1272 }
1273 else
1274 {
1275 /* Genric accessor. Check the type and look up the object. */
1276 enum kBuildType enmType = eval_kbuild_type_from_string(pchType, cchType);
1277 if (penmType)
1278 *penmType = enmType;
1279 if (enmType != kBuildType_Invalid)
1280 {
1281 struct kbuild_object *pObj = lookup_kbuild_object(enmType, pchObjName, cchObjName);
1282 if (pObj)
1283 return pObj;
1284
1285 /* failed. */
1286 kbuild_report_problem(enmSeverity, pFileLoc,
1287 _("kBuild object '%s' not found in kBuild variable accessor '%.*s'"),
1288 (int)cchObjName, pchObjName, (int)cchOrgExpr, pchOrgExpr);
1289 }
1290 else
1291 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc,
1292 _("Invalid type '%.*s' specified in kBuild variable accessor '%.*s'"),
1293 (int)cchType, pchType, (int)cchOrgExpr, pchOrgExpr);
1294 }
1295 return NULL;
1296 }
1297 }
1298 }
1299 }
1300
1301 *ppchVarNm = NULL;
1302 *pcchVarNm = 0;
1303 if (penmType)
1304 *penmType = kBuildType_Invalid;
1305 return KOBJ_NOT_KBUILD_ACCESSOR;
1306}
1307
1308/**
1309 * Looks up a variable in a kBuild object.
1310 *
1311 * The caller has done minimal matching, i.e. starting square brackets and
1312 * minimum length. We do the rest here.
1313 *
1314 * @returns Pointer to the variable if found.
1315 * @retval NULL if not found.
1316 * @retval VAR_NOT_KBUILD_ACCESSOR if no a kBuild variable accessor.
1317 *
1318 * @param pchName The kBuild variable accessor expression.
1319 * @param cchName Length of the expression.
1320 */
1321struct variable *
1322lookup_kbuild_object_variable_accessor(const char *pchName, size_t cchName)
1323{
1324 const char * const pchOrgName = pchName;
1325 size_t const cchOrgName = cchName;
1326 const char * pchVarNm;
1327 size_t cchVarNm;
1328 struct kbuild_object *pObj;
1329
1330 pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Warning, NULL, &pchVarNm, &cchVarNm, NULL);
1331 if (pObj != KOBJ_NOT_KBUILD_ACCESSOR)
1332 {
1333 if (pObj)
1334 {
1335 /*
1336 * Do the variable lookup.
1337 */
1338 const char *pszCachedName = strcache2_lookup(&variable_strcache, pchVarNm, cchVarNm);
1339 if (pszCachedName)
1340 {
1341 struct variable VarKey;
1342 struct variable *pVar;
1343 VarKey.name = pszCachedName;
1344 VarKey.length = cchName;
1345
1346 pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey);
1347 if (pVar)
1348 return pVar;
1349
1350 /*
1351 * Not found, check ancestors if any.
1352 */
1353 if (pObj->pszParent || pObj->pszTemplate)
1354 {
1355 struct kbuild_object *pParent = pObj;
1356 for (;;)
1357 {
1358 pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/);
1359 if (!pParent)
1360 break;
1361 pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey);
1362 if (pVar)
1363 return pVar;
1364 }
1365 }
1366 }
1367 }
1368
1369 /* Not found one way or the other. */
1370 return NULL;
1371 }
1372
1373 /* Not a kBuild object variable accessor. */
1374 return VAR_NOT_KBUILD_ACCESSOR;
1375}
1376
1377/** @} */
1378
1379void print_kbuild_data_base(void)
1380{
1381 struct kbuild_object *pCur;
1382
1383 puts(_("\n# kBuild defines"));
1384
1385 for (pCur = g_pHeadKbObjs; pCur; pCur = pCur->pGlobalNext)
1386 {
1387 printf("\nkBuild-define-%s %s",
1388 eval_kbuild_type_to_string(pCur->enmType), pCur->pszName);
1389 if (pCur->pszParent)
1390 printf(" extending %s", pCur->pszParent);
1391 if (pCur->pszTemplate)
1392 printf(" using %s", pCur->pszTemplate);
1393 putchar('\n');
1394
1395 print_variable_set(pCur->pVariables->set, "");
1396
1397 printf("kBuild-endef-%s %s\n",
1398 eval_kbuild_type_to_string(pCur->enmType), pCur->pszName);
1399 }
1400 /** @todo hash stats. */
1401}
1402
1403void print_kbuild_define_stats(void)
1404{
1405 /* later when hashing stuff */
1406}
1407
Note: See TracBrowser for help on using the repository browser.

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