VirtualBox

source: kBuild/trunk/src/kmk/kbuild.c@ 2657

Last change on this file since 2657 was 2540, checked in by bird, 13 years ago

kbuild.c: For the time being, we'll defined two sets of local variables. The new ones are: kbsrc_cmds, kbsrc_output, kbsrc_output_maybe, kbsrc_depend & kbsrc_depord.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.5 KB
Line 
1/* $Id: kbuild.c 2540 2011-08-02 20:13:24Z bird $ */
2/** @file
3 * kBuild specific make functionality.
4 */
5
6/*
7 * Copyright (c) 2006-2010 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#ifdef WINDOWS32
37# include "pathstuff.h"
38# include <Windows.h>
39#endif
40#if defined(__APPLE__)
41# include <mach-o/dyld.h>
42#endif
43#if defined(__FreeBSD__)
44# include <dlfcn.h>
45# include <sys/link_elf.h>
46#endif
47
48#include "kbuild.h"
49
50#include <assert.h>
51
52
53/*******************************************************************************
54* Defined Constants And Macros *
55*******************************************************************************/
56/** Helper for passing a string constant to kbuild_get_variable_n. */
57#define ST(strconst) strconst, sizeof(strconst) - 1
58
59#if 1
60# define my_memcpy(dst, src, len) \
61 do { \
62 if (len > 8) \
63 memcpy(dst, src, len); \
64 else \
65 switch (len) \
66 { \
67 case 8: dst[7] = src[7]; \
68 case 7: dst[6] = src[6]; \
69 case 6: dst[5] = src[5]; \
70 case 5: dst[4] = src[4]; \
71 case 4: dst[3] = src[3]; \
72 case 3: dst[2] = src[2]; \
73 case 2: dst[1] = src[1]; \
74 case 1: dst[0] = src[0]; \
75 case 0: break; \
76 } \
77 } while (0)
78#elif defined(__GNUC__)
79# define my_memcpy __builtin_memcpy
80#elif defined(_MSC_VER)
81# pragma instrinic(memcpy)
82# define my_memcpy memcpy
83#endif
84
85
86/*******************************************************************************
87* Global Variables *
88*******************************************************************************/
89/** The argv[0] passed to main. */
90static const char *g_pszExeName;
91/** The initial working directory. */
92static char *g_pszInitialCwd;
93
94
95/**
96 * Initialize kBuild stuff.
97 *
98 * @param argc Number of arguments to main().
99 * @param argv The main() argument vector.
100 */
101void init_kbuild(int argc, char **argv)
102{
103 int rc;
104 PATH_VAR(szTmp);
105
106 /*
107 * Get the initial cwd for use in my_abspath.
108 */
109#ifdef WINDOWS32
110 if (getcwd_fs(szTmp, GET_PATH_MAX) != 0)
111#else
112 if (getcwd(szTmp, GET_PATH_MAX) != 0)
113#endif
114 g_pszInitialCwd = xstrdup(szTmp);
115 else
116 fatal(NILF, _("getcwd failed"));
117
118 /*
119 * Determin the executable name.
120 */
121 rc = -1;
122#if defined(__APPLE__)
123 {
124 const char *pszImageName = _dyld_get_image_name(0);
125 if (pszImageName)
126 {
127 size_t cchImageName = strlen(pszImageName);
128 if (cchImageName < GET_PATH_MAX)
129 {
130 memcpy(szTmp, pszImageName, cchImageName + 1);
131 rc = 0;
132 }
133 }
134 }
135
136#elif defined(__FreeBSD__)
137 rc = readlink("/proc/curproc/file", szTmp, GET_PATH_MAX - 1);
138 if (rc < 0 || rc == GET_PATH_MAX - 1)
139 {
140 rc = -1;
141# if 0 /* doesn't work because l_name isn't always absolute, it's just argv0 from exec or something. */
142 /* /proc is optional, try rtdl. */
143 void *hExe = dlopen(NULL, 0);
144 rc = -1;
145 if (hExe)
146 {
147 struct link_map const *pLinkMap = 0;
148 if (dlinfo(hExe, RTLD_DI_LINKMAP, &pLinkMap) == 0)
149 {
150 const char *pszImageName = pLinkMap->l_name;
151 size_t cchImageName = strlen(pszImageName);
152 if (cchImageName < GET_PATH_MAX)
153 {
154 memcpy(szTmp, pszImageName, cchImageName + 1);
155 rc = 0;
156 }
157 }
158
159 }
160# endif
161 }
162 else
163 szTmp[rc] = '\0';
164
165#elif defined(__gnu_linux__) || defined(__linux__)
166 rc = readlink("/proc/self/exe", szTmp, GET_PATH_MAX - 1);
167 if (rc < 0 || rc == GET_PATH_MAX - 1)
168 rc = -1;
169 else
170 szTmp[rc] = '\0';
171
172#elif defined(__OS2__)
173 _execname(szTmp, GET_PATH_MAX);
174 rc = 0;
175
176#elif defined(__sun__)
177 {
178 char szTmp2[64];
179 snprintf(szTmp2, sizeof(szTmp2), "/proc/%ld/path/a.out", (long)getpid());
180 rc = readlink(szTmp2, szTmp, GET_PATH_MAX - 1);
181 if (rc < 0 || rc == GET_PATH_MAX - 1)
182 rc = -1;
183 else
184 szTmp[rc] = '\0';
185 }
186
187#elif defined(WINDOWS32)
188 if (GetModuleFileName(GetModuleHandle(NULL), szTmp, GET_PATH_MAX))
189 rc = 0;
190
191#endif
192
193#if !defined(__OS2__) && !defined(WINDOWS32)
194 /* fallback, try use the path to locate the binary. */
195 if ( rc < 0
196 && access(argv[0], X_OK))
197 {
198 size_t cchArgv0 = strlen(argv[0]);
199 const char *pszPath = getenv("PATH");
200 char *pszCopy = xstrdup(pszPath ? pszPath : ".");
201 char *psz = pszCopy;
202 while (*psz)
203 {
204 size_t cch;
205 char *pszEnd = strchr(psz, PATH_SEPARATOR_CHAR);
206 if (!pszEnd)
207 pszEnd = strchr(psz, '\0');
208 cch = pszEnd - psz;
209 if (cch + cchArgv0 + 2 <= GET_PATH_MAX)
210 {
211 memcpy(szTmp, psz, cch);
212 szTmp[cch] = '/';
213 memcpy(&szTmp[cch + 1], argv[0], cchArgv0 + 1);
214 if (!access(szTmp, X_OK))
215 {
216 rc = 0;
217 break;
218 }
219 }
220
221 /* next */
222 psz = pszEnd;
223 while (*psz == PATH_SEPARATOR_CHAR)
224 psz++;
225 }
226 free(pszCopy);
227 }
228#endif
229
230 if (rc < 0)
231 g_pszExeName = argv[0];
232 else
233 g_pszExeName = xstrdup(szTmp);
234
235 (void)argc;
236}
237
238
239/**
240 * Wrapper that ensures correct starting_directory.
241 */
242static char *my_abspath(const char *pszIn, char *pszOut)
243{
244 char *pszSaved, *pszRet;
245
246 pszSaved = starting_directory;
247 starting_directory = g_pszInitialCwd;
248 pszRet = abspath(pszIn, pszOut);
249 starting_directory = pszSaved;
250
251 return pszRet;
252}
253
254
255/**
256 * Determin the KBUILD_PATH value.
257 *
258 * @returns Pointer to static a buffer containing the value (consider it read-only).
259 */
260const char *get_kbuild_path(void)
261{
262 static const char *s_pszPath = NULL;
263 if (!s_pszPath)
264 {
265 PATH_VAR(szTmpPath);
266 const char *pszEnvVar = getenv("KBUILD_PATH");
267 if ( !pszEnvVar
268 || !my_abspath(pszEnvVar, szTmpPath))
269 {
270 pszEnvVar = getenv("PATH_KBUILD");
271 if ( !pszEnvVar
272 || !my_abspath(pszEnvVar, szTmpPath))
273 {
274#ifdef KBUILD_PATH
275 return s_pszPath = KBUILD_PATH;
276#else
277 /* $(abspath $(KBUILD_BIN_PATH)/../..)*/
278 size_t cch = strlen(get_kbuild_bin_path());
279 char *pszTmp2 = alloca(cch + sizeof("/../.."));
280 strcat(strcpy(pszTmp2, get_kbuild_bin_path()), "/../..");
281 if (!my_abspath(pszTmp2, szTmpPath))
282 fatal(NILF, _("failed to determin KBUILD_PATH"));
283#endif
284 }
285 }
286 s_pszPath = xstrdup(szTmpPath);
287 }
288 return s_pszPath;
289}
290
291
292/**
293 * Determin the KBUILD_BIN_PATH value.
294 *
295 * @returns Pointer to static a buffer containing the value (consider it read-only).
296 */
297const char *get_kbuild_bin_path(void)
298{
299 static const char *s_pszPath = NULL;
300 if (!s_pszPath)
301 {
302 PATH_VAR(szTmpPath);
303
304 const char *pszEnvVar = getenv("KBUILD_BIN_PATH");
305 if ( !pszEnvVar
306 || !my_abspath(pszEnvVar, szTmpPath))
307 {
308 pszEnvVar = getenv("PATH_KBUILD_BIN");
309 if ( !pszEnvVar
310 || !my_abspath(pszEnvVar, szTmpPath))
311 {
312#ifdef KBUILD_PATH
313 return s_pszPath = KBUILD_BIN_PATH;
314#else
315 /* $(abspath $(dir $(ARGV0)).) */
316 size_t cch = strlen(g_pszExeName);
317 char *pszTmp2 = alloca(cch + sizeof("."));
318 char *pszSep = pszTmp2 + cch - 1;
319 memcpy(pszTmp2, g_pszExeName, cch);
320# ifdef HAVE_DOS_PATHS
321 while (pszSep >= pszTmp2 && *pszSep != '/' && *pszSep != '\\' && *pszSep != ':')
322# else
323 while (pszSep >= pszTmp2 && *pszSep != '/')
324# endif
325 pszSep--;
326 if (pszSep >= pszTmp2)
327 strcpy(pszSep + 1, ".");
328 else
329 strcpy(pszTmp2, ".");
330
331 if (!my_abspath(pszTmp2, szTmpPath))
332 fatal(NILF, _("failed to determin KBUILD_BIN_PATH (pszTmp2=%s szTmpPath=%s)"), pszTmp2, szTmpPath);
333#endif /* !KBUILD_PATH */
334 }
335 }
336 s_pszPath = xstrdup(szTmpPath);
337 }
338 return s_pszPath;
339}
340
341
342/**
343 * Determin the location of default kBuild shell.
344 *
345 * @returns Pointer to static a buffer containing the location (consider it read-only).
346 */
347const char *get_default_kbuild_shell(void)
348{
349 static char *s_pszDefaultShell = NULL;
350 if (!s_pszDefaultShell)
351 {
352#if defined(__OS2__) || defined(_WIN32) || defined(WINDOWS32)
353 static const char s_szShellName[] = "/kmk_ash.exe";
354#else
355 static const char s_szShellName[] = "/kmk_ash";
356#endif
357 const char *pszBin = get_kbuild_bin_path();
358 size_t cchBin = strlen(pszBin);
359 s_pszDefaultShell = xmalloc(cchBin + sizeof(s_szShellName));
360 memcpy(s_pszDefaultShell, pszBin, cchBin);
361 memcpy(&s_pszDefaultShell[cchBin], s_szShellName, sizeof(s_szShellName));
362 }
363 return s_pszDefaultShell;
364}
365
366#ifdef KMK_HELPERS
367
368/**
369 * Applies the specified default path to any relative paths in *ppsz.
370 *
371 * @param pDefPath The default path.
372 * @param ppsz Pointer to the string pointer. If we expand anything, *ppsz
373 * will be replaced and the caller is responsible for calling free() on it.
374 * @param pcch IN: *pcch contains the current string length.
375 * OUT: *pcch contains the new string length.
376 * @param pcchAlloc *pcchAlloc contains the length allocated for the string. Can be NULL.
377 * @param fCanFree Whether *ppsz should be freed when we replace it.
378 */
379static void
380kbuild_apply_defpath(struct variable *pDefPath, char **ppsz, unsigned int *pcch, unsigned int *pcchAlloc, int fCanFree)
381{
382 const char *pszIterator;
383 const char *pszInCur;
384 unsigned int cchInCur;
385 unsigned int cRelativePaths;
386
387 /*
388 * The first pass, count the relative paths.
389 */
390 cRelativePaths = 0;
391 pszIterator = *ppsz;
392 while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
393 {
394 /* is relative? */
395#ifdef HAVE_DOS_PATHS
396 if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':'))
397#else
398 if (pszInCur[0] != '/')
399#endif
400 cRelativePaths++;
401 }
402
403 /*
404 * The second pass construct the new string.
405 */
406 if (cRelativePaths)
407 {
408 const size_t cchOut = *pcch + cRelativePaths * (pDefPath->value_length + 1) + 1;
409 char *pszOut = xmalloc(cchOut);
410 char *pszOutCur = pszOut;
411 const char *pszInNextCopy = *ppsz;
412
413 cRelativePaths = 0;
414 pszIterator = *ppsz;
415 while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
416 {
417 /* is relative? */
418#ifdef HAVE_DOS_PATHS
419 if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':'))
420#else
421 if (pszInCur[0] != '/')
422#endif
423 {
424 PATH_VAR(szAbsPathIn);
425 PATH_VAR(szAbsPathOut);
426
427 if (pDefPath->value_length + cchInCur + 1 >= GET_PATH_MAX)
428 continue;
429
430 /* Create the abspath input. */
431 memcpy(szAbsPathIn, pDefPath->value, pDefPath->value_length);
432 szAbsPathIn[pDefPath->value_length] = '/';
433 memcpy(&szAbsPathIn[pDefPath->value_length + 1], pszInCur, cchInCur);
434 szAbsPathIn[pDefPath->value_length + 1 + cchInCur] = '\0';
435
436 if (abspath(szAbsPathIn, szAbsPathOut) != NULL)
437 {
438 const size_t cchAbsPathOut = strlen(szAbsPathOut);
439 assert(cchAbsPathOut <= pDefPath->value_length + 1 + cchInCur);
440
441 /* copy leading input */
442 if (pszInCur != pszInNextCopy)
443 {
444 const size_t cchCopy = pszInCur - pszInNextCopy;
445 memcpy(pszOutCur, pszInNextCopy, cchCopy);
446 pszOutCur += cchCopy;
447 }
448 pszInNextCopy = pszInCur + cchInCur;
449
450 /* copy out the abspath. */
451 memcpy(pszOutCur, szAbsPathOut, cchAbsPathOut);
452 pszOutCur += cchAbsPathOut;
453 }
454 }
455 }
456 /* the final copy (includes the nil). */
457 cchInCur = *ppsz + *pcch - pszInNextCopy;
458 memcpy(pszOutCur, pszInNextCopy, cchInCur);
459 pszOutCur += cchInCur;
460 *pszOutCur = '\0';
461 assert((size_t)(pszOutCur - pszOut) < cchOut);
462
463 /* set return values */
464 if (fCanFree)
465 free(*ppsz);
466 *ppsz = pszOut;
467 *pcch = pszOutCur - pszOut;
468 if (pcchAlloc)
469 *pcchAlloc = cchOut;
470 }
471}
472
473/**
474 * Gets a variable that must exist.
475 * Will cause a fatal failure if the variable doesn't exist.
476 *
477 * @returns Pointer to the variable.
478 * @param pszName The variable name.
479 * @param cchName The name length.
480 */
481MY_INLINE struct variable *
482kbuild_get_variable_n(const char *pszName, size_t cchName)
483{
484 struct variable *pVar = lookup_variable(pszName, cchName);
485 if (!pVar)
486 fatal(NILF, _("variable `%.*s' isn't defined!"), (int)cchName, pszName);
487 if (pVar->recursive)
488 fatal(NILF, _("variable `%.*s' is defined as `recursive' instead of `simple'!"), (int)cchName, pszName);
489
490 MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length,
491 ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name));
492 return pVar;
493}
494
495
496/**
497 * Gets a variable that must exist and can be recursive.
498 * Will cause a fatal failure if the variable doesn't exist.
499 *
500 * @returns Pointer to the variable.
501 * @param pszName The variable name.
502 */
503static struct variable *
504kbuild_get_recursive_variable(const char *pszName)
505{
506 struct variable *pVar = lookup_variable(pszName, strlen(pszName));
507 if (!pVar)
508 fatal(NILF, _("variable `%s' isn't defined!"), pszName);
509
510 MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length,
511 ("%u != %u %s\n", pVar->value_length, (unsigned int)strlen(pVar->value), pVar->name));
512 return pVar;
513}
514
515
516/**
517 * Gets a variable that doesn't have to exit, but if it does can be recursive.
518 *
519 * @returns Pointer to the variable.
520 * NULL if not found.
521 * @param pszName The variable name. Doesn't need to be terminated.
522 * @param cchName The name length.
523 */
524static struct variable *
525kbuild_query_recursive_variable_n(const char *pszName, size_t cchName)
526{
527 struct variable *pVar = lookup_variable(pszName, cchName);
528 MY_ASSERT_MSG(!pVar || strlen(pVar->value) == pVar->value_length,
529 ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name));
530 return pVar;
531}
532
533
534/**
535 * Gets a variable that doesn't have to exit, but if it does can be recursive.
536 *
537 * @returns Pointer to the variable.
538 * NULL if not found.
539 * @param pszName The variable name.
540 */
541static struct variable *
542kbuild_query_recursive_variable(const char *pszName)
543{
544 return kbuild_query_recursive_variable_n(pszName, strlen(pszName));
545}
546
547
548/**
549 * Converts the specified variable into a 'simple' one.
550 * @returns pVar.
551 * @param pVar The variable.
552 */
553static struct variable *
554kbuild_simplify_variable(struct variable *pVar)
555{
556 if (memchr(pVar->value, '$', pVar->value_length))
557 {
558 unsigned int value_len;
559 char *pszExpanded = allocated_variable_expand_2(pVar->value, pVar->value_length, &value_len);
560#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
561 if (pVar->rdonly_val)
562 pVar->rdonly_val = 0;
563 else
564#endif
565 free(pVar->value);
566 assert(pVar->origin != o_automatic);
567 pVar->value = pszExpanded;
568 pVar->value_length = value_len;
569 pVar->value_alloc_len = value_len + 1;
570 }
571 pVar->recursive = 0;
572 return pVar;
573}
574
575
576/**
577 * Looks up a variable.
578 * The value_length field is valid upon successful return.
579 *
580 * @returns Pointer to the variable. NULL if not found.
581 * @param pszName The variable name.
582 * @param cchName The name length.
583 */
584MY_INLINE struct variable *
585kbuild_lookup_variable_n(const char *pszName, size_t cchName)
586{
587 struct variable *pVar = lookup_variable(pszName, cchName);
588 if (pVar)
589 {
590 MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length,
591 ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name));
592
593 /* Make sure the variable is simple, convert it if necessary. */
594 if (pVar->recursive)
595 kbuild_simplify_variable(pVar);
596 }
597 return pVar;
598}
599
600
601/**
602 * Looks up a variable.
603 * The value_length field is valid upon successful return.
604 *
605 * @returns Pointer to the variable. NULL if not found.
606 * @param pszName The variable name.
607 */
608MY_INLINE struct variable *
609kbuild_lookup_variable(const char *pszName)
610{
611 return kbuild_lookup_variable_n(pszName, strlen(pszName));
612}
613
614
615/**
616 * Looks up a variable and applies default a path to all relative paths.
617 * The value_length field is valid upon successful return.
618 *
619 * @returns Pointer to the variable. NULL if not found.
620 * @param pDefPath The default path.
621 * @param pszName The variable name.
622 * @param cchName The name length.
623 */
624MY_INLINE struct variable *
625kbuild_lookup_variable_defpath_n(struct variable *pDefPath, const char *pszName, size_t cchName)
626{
627 struct variable *pVar = kbuild_lookup_variable_n(pszName, cchName);
628 if (pVar && pDefPath)
629 {
630 assert(pVar->origin != o_automatic);
631#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
632 assert(!pVar->rdonly_val);
633#endif
634 kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1);
635 }
636 return pVar;
637}
638
639
640/**
641 * Looks up a variable and applies default a path to all relative paths.
642 * The value_length field is valid upon successful return.
643 *
644 * @returns Pointer to the variable. NULL if not found.
645 * @param pDefPath The default path.
646 * @param pszName The variable name.
647 */
648MY_INLINE struct variable *
649kbuild_lookup_variable_defpath(struct variable *pDefPath, const char *pszName)
650{
651 struct variable *pVar = kbuild_lookup_variable(pszName);
652 if (pVar && pDefPath)
653 {
654 assert(pVar->origin != o_automatic);
655#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
656 assert(!pVar->rdonly_val);
657#endif
658 kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1);
659 }
660 return pVar;
661}
662
663
664/**
665 * Gets the first defined property variable.
666 */
667static struct variable *
668kbuild_first_prop(struct variable *pTarget, struct variable *pSource,
669 struct variable *pTool, struct variable *pType,
670 struct variable *pBldTrg, struct variable *pBldTrgArch,
671 const char *pszPropF1, char cchPropF1,
672 const char *pszPropF2, char cchPropF2,
673 const char *pszVarName)
674{
675 struct variable *pVar;
676 size_t cchBuf;
677 char *pszBuf;
678 char *psz, *psz1, *psz2, *psz3, *psz4, *pszEnd;
679
680 /* calc and allocate a too big name buffer. */
681 cchBuf = cchPropF2 + 1
682 + cchPropF1 + 1
683 + pTarget->value_length + 1
684 + pSource->value_length + 1
685 + (pTool ? pTool->value_length + 1 : 0)
686 + pType->value_length + 1
687 + pBldTrg->value_length + 1
688 + pBldTrgArch->value_length + 1;
689 pszBuf = xmalloc(cchBuf);
690
691#define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0)
692#define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0)
693#define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0)
694#define ADD_CH(ch) do { *psz++ = (ch); } while (0)
695
696 /*
697 * $(target)_$(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
698 */
699 psz = pszBuf;
700 ADD_VAR(pTarget);
701 ADD_CH('_');
702 ADD_VAR(pSource);
703 ADD_CH('_');
704 psz2 = psz;
705 ADD_VAR(pType);
706 ADD_STR(pszPropF2, cchPropF2);
707 psz3 = psz;
708 ADD_CH('.');
709 ADD_VAR(pBldTrg);
710 psz4 = psz;
711 ADD_CH('.');
712 ADD_VAR(pBldTrgArch);
713 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
714
715 /* $(target)_$(source)_$(type)$(propf2).$(bld_trg) */
716 if (!pVar)
717 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
718
719 /* $(target)_$(source)_$(type)$(propf2) */
720 if (!pVar)
721 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
722
723 /*
724 * $(target)_$(source)_$(propf2).$(bld_trg).$(bld_trg_arch)
725 */
726 if (!pVar)
727 {
728 psz = psz2;
729 ADD_STR(pszPropF2, cchPropF2);
730 psz3 = psz;
731 ADD_CH('.');
732 ADD_VAR(pBldTrg);
733 psz4 = psz;
734 ADD_CH('.');
735 ADD_VAR(pBldTrgArch);
736 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
737
738 /* $(target)_$(source)_$(propf2).$(bld_trg) */
739 if (!pVar)
740 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
741
742 /* $(target)_$(source)_$(propf2) */
743 if (!pVar)
744 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
745 }
746
747
748 /*
749 * $(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
750 */
751 if (!pVar)
752 {
753 psz = pszBuf;
754 ADD_VAR(pSource);
755 ADD_CH('_');
756 psz2 = psz;
757 ADD_VAR(pType);
758 ADD_STR(pszPropF2, cchPropF2);
759 psz3 = psz;
760 ADD_CH('.');
761 ADD_VAR(pBldTrg);
762 psz4 = psz;
763 ADD_CH('.');
764 ADD_VAR(pBldTrgArch);
765 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
766
767 /* $(source)_$(type)$(propf2).$(bld_trg) */
768 if (!pVar)
769 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
770
771 /* $(source)_$(type)$(propf2) */
772 if (!pVar)
773 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
774
775 /*
776 * $(source)_$(propf2).$(bld_trg).$(bld_trg_arch)
777 */
778 if (!pVar)
779 {
780 psz = psz2;
781 ADD_STR(pszPropF2, cchPropF2);
782 psz3 = psz;
783 ADD_CH('.');
784 ADD_VAR(pBldTrg);
785 psz4 = psz;
786 ADD_CH('.');
787 ADD_VAR(pBldTrgArch);
788 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
789
790 /* $(source)_$(propf2).$(bld_trg) */
791 if (!pVar)
792 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
793
794 /* $(source)_$(propf2) */
795 if (!pVar)
796 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
797 }
798 }
799
800 /*
801 * $(target)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
802 */
803 if (!pVar)
804 {
805 psz = pszBuf;
806 ADD_VAR(pTarget);
807 ADD_CH('_');
808 psz2 = psz;
809 ADD_VAR(pType);
810 ADD_STR(pszPropF2, cchPropF2);
811 psz3 = psz;
812 ADD_CH('.');
813 ADD_VAR(pBldTrg);
814 psz4 = psz;
815 ADD_CH('.');
816 ADD_VAR(pBldTrgArch);
817 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
818
819 /* $(target)_$(type)$(propf2).$(bld_trg) */
820 if (!pVar)
821 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
822
823 /* $(target)_$(type)$(propf2) */
824 if (!pVar)
825 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
826
827 /* $(target)_$(propf2).$(bld_trg).$(bld_trg_arch) */
828 if (!pVar)
829 {
830 psz = psz2;
831 ADD_STR(pszPropF2, cchPropF2);
832 psz3 = psz;
833 ADD_CH('.');
834 ADD_VAR(pBldTrg);
835 psz4 = psz;
836 ADD_CH('.');
837 ADD_VAR(pBldTrgArch);
838 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
839 }
840
841 /* $(target)_$(propf2).$(bld_trg) */
842 if (!pVar)
843 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
844
845 /* $(target)_$(propf2) */
846 if (!pVar)
847 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
848 }
849
850 /*
851 * TOOL_$(tool)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
852 */
853 if (!pVar && pTool)
854 {
855 psz = pszBuf;
856 ADD_CSTR("TOOL_");
857 ADD_VAR(pTool);
858 ADD_CH('_');
859 psz2 = psz;
860 ADD_VAR(pType);
861 ADD_STR(pszPropF2, cchPropF2);
862 psz3 = psz;
863 ADD_CH('.');
864 ADD_VAR(pBldTrg);
865 psz4 = psz;
866 ADD_CH('.');
867 ADD_VAR(pBldTrgArch);
868 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
869
870 /* TOOL_$(tool)_$(type)$(propf2).$(bld_trg) */
871 if (!pVar)
872 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
873
874 /* TOOL_$(tool)_$(type)$(propf2) */
875 if (!pVar)
876 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
877
878 /* TOOL_$(tool)_$(propf2).$(bld_trg).$(bld_trg_arch) */
879 if (!pVar)
880 {
881 psz = psz2;
882 ADD_STR(pszPropF2, cchPropF2);
883 psz3 = psz;
884 ADD_CH('.');
885 ADD_VAR(pBldTrg);
886 psz4 = psz;
887 ADD_CH('.');
888 ADD_VAR(pBldTrgArch);
889 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
890
891 /* TOOL_$(tool)_$(propf2).$(bld_trg) */
892 if (!pVar)
893 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
894
895 /* TOOL_$(tool)_$(propf2) */
896 if (!pVar)
897 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
898 }
899 }
900
901 /*
902 * $(type)$(propf1).$(bld_trg).$(bld_trg_arch)
903 */
904 if (!pVar)
905 {
906 psz = pszBuf;
907 ADD_VAR(pType);
908 ADD_STR(pszPropF1, cchPropF1);
909 psz3 = psz;
910 ADD_CH('.');
911 ADD_VAR(pBldTrg);
912 psz4 = psz;
913 ADD_CH('.');
914 ADD_VAR(pBldTrgArch);
915 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
916
917 /* $(type)$(propf1).$(bld_trg) */
918 if (!pVar)
919 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
920
921 /* $(type)$(propf1) */
922 if (!pVar)
923 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
924
925 /*
926 * $(propf1).$(bld_trg).$(bld_trg_arch)
927 */
928 if (!pVar)
929 {
930 psz1 = pszBuf + pType->value_length;
931 pVar = kbuild_lookup_variable_n(psz1, psz - psz1);
932
933 /* $(propf1).$(bld_trg) */
934 if (!pVar)
935 pVar = kbuild_lookup_variable_n(psz1, psz4 - psz1);
936
937 /* $(propf1) */
938 if (!pVar)
939 pVar = kbuild_lookup_variable_n(pszPropF1, cchPropF1);
940 }
941 }
942 free(pszBuf);
943#undef ADD_VAR
944#undef ADD_STR
945#undef ADD_CSTR
946#undef ADD_CH
947
948 if (pVar)
949 {
950 /* strip it */
951 psz = pVar->value;
952 pszEnd = psz + pVar->value_length;
953 while (isblank((unsigned char)*psz))
954 psz++;
955 while (pszEnd > psz && isblank((unsigned char)pszEnd[-1]))
956 pszEnd--;
957 if (pszEnd > psz)
958 {
959 char chSaved = *pszEnd;
960 *pszEnd = '\0';
961 pVar = define_variable_vl(pszVarName, strlen(pszVarName), psz, pszEnd - psz,
962 1 /* duplicate */, o_local, 0 /* !recursive */);
963 *pszEnd = chSaved;
964 if (pVar)
965 return pVar;
966 }
967 }
968 return NULL;
969}
970
971
972/*
973_SOURCE_TOOL = $(strip $(firstword \
974 $($(target)_$(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
975 $($(target)_$(source)_$(type)TOOL.$(bld_trg)) \
976 $($(target)_$(source)_$(type)TOOL) \
977 $($(target)_$(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \
978 $($(target)_$(source)_TOOL.$(bld_trg)) \
979 $($(target)_$(source)_TOOL) \
980 $($(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
981 $($(source)_$(type)TOOL.$(bld_trg)) \
982 $($(source)_$(type)TOOL) \
983 $($(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \
984 $($(source)_TOOL.$(bld_trg)) \
985 $($(source)_TOOL) \
986 $($(target)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
987 $($(target)_$(type)TOOL.$(bld_trg)) \
988 $($(target)_$(type)TOOL) \
989 $($(target)_TOOL.$(bld_trg).$(bld_trg_arch)) \
990 $($(target)_TOOL.$(bld_trg)) \
991 $($(target)_TOOL) \
992 $($(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
993 $($(type)TOOL.$(bld_trg)) \
994 $($(type)TOOL) \
995 $(TOOL.$(bld_trg).$(bld_trg_arch)) \
996 $(TOOL.$(bld_trg)) \
997 $(TOOL) ))
998*/
999static struct variable *
1000kbuild_get_source_tool(struct variable *pTarget, struct variable *pSource, struct variable *pType,
1001 struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName)
1002{
1003 struct variable *pVar = kbuild_first_prop(pTarget, pSource, NULL, pType, pBldTrg, pBldTrgArch,
1004 "TOOL", sizeof("TOOL") - 1,
1005 "TOOL", sizeof("TOOL") - 1,
1006 pszVarName);
1007 if (!pVar)
1008 fatal(NILF, _("no tool for source `%s' in target `%s'!"), pSource->value, pTarget->value);
1009 return pVar;
1010}
1011
1012
1013/* Implements _SOURCE_TOOL. */
1014char *
1015func_kbuild_source_tool(char *o, char **argv, const char *pszFuncName)
1016{
1017 struct variable *pVar = kbuild_get_source_tool(kbuild_get_variable_n(ST("target")),
1018 kbuild_get_variable_n(ST("source")),
1019 kbuild_get_variable_n(ST("type")),
1020 kbuild_get_variable_n(ST("bld_trg")),
1021 kbuild_get_variable_n(ST("bld_trg_arch")),
1022 argv[0]);
1023 if (pVar)
1024 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1025 (void)pszFuncName;
1026 return o;
1027
1028}
1029
1030
1031/* This has been extended a bit, it's now identical to _SOURCE_TOOL.
1032$(firstword \
1033 $($(target)_$(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1034 $($(target)_$(source)_OBJSUFF.$(bld_trg))\
1035 $($(target)_$(source)_OBJSUFF)\
1036 $($(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1037 $($(source)_OBJSUFF.$(bld_trg))\
1038 $($(source)_OBJSUFF)\
1039 $($(target)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1040 $($(target)_OBJSUFF.$(bld_trg))\
1041 $($(target)_OBJSUFF)\
1042 $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1043 $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg))\
1044 $(TOOL_$(tool)_$(type)OBJSUFF)\
1045 $(SUFF_OBJ))
1046*/
1047static struct variable *
1048kbuild_get_object_suffix(struct variable *pTarget, struct variable *pSource,
1049 struct variable *pTool, struct variable *pType,
1050 struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName)
1051{
1052 struct variable *pVar = kbuild_first_prop(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch,
1053 "SUFF_OBJ", sizeof("SUFF_OBJ") - 1,
1054 "OBJSUFF", sizeof("OBJSUFF") - 1,
1055 pszVarName);
1056 if (!pVar)
1057 fatal(NILF, _("no OBJSUFF attribute or SUFF_OBJ default for source `%s' in target `%s'!"), pSource->value, pTarget->value);
1058 return pVar;
1059}
1060
1061
1062/* */
1063char *
1064func_kbuild_object_suffix(char *o, char **argv, const char *pszFuncName)
1065{
1066 struct variable *pVar = kbuild_get_object_suffix(kbuild_get_variable_n(ST("target")),
1067 kbuild_get_variable_n(ST("source")),
1068 kbuild_get_variable_n(ST("tool")),
1069 kbuild_get_variable_n(ST("type")),
1070 kbuild_get_variable_n(ST("bld_trg")),
1071 kbuild_get_variable_n(ST("bld_trg_arch")),
1072 argv[0]);
1073 if (pVar)
1074 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1075 (void)pszFuncName;
1076 return o;
1077
1078}
1079
1080
1081/*
1082## Figure out where to put object files.
1083# @param $1 source file
1084# @param $2 normalized main target
1085# @remark There are two major hacks here:
1086# 1. Source files in the output directory are translated into a gen/ subdir.
1087# 2. Catch anyone specifying $(PATH_SUB_CURRENT)/sourcefile.c.
1088_OBJECT_BASE = $(PATH_TARGET)/$(2)/$(call no-root-slash,$(call no-drive,$(basename \
1089 $(patsubst $(PATH_ROOT)/%,%,$(patsubst $(PATH_SUB_CURRENT)/%,%,$(patsubst $(PATH_TARGET)/$(2)/%,gen/%,$(1)))))))
1090*/
1091static struct variable *
1092kbuild_get_object_base(struct variable *pTarget, struct variable *pSource, const char *pszVarName)
1093{
1094 struct variable *pPathTarget = kbuild_get_variable_n(ST("PATH_TARGET"));
1095 struct variable *pPathRoot = kbuild_get_variable_n(ST("PATH_ROOT"));
1096 struct variable *pPathSubCur = kbuild_get_variable_n(ST("PATH_SUB_CURRENT"));
1097 const char *pszSrcPrefix = NULL;
1098 size_t cchSrcPrefix = 0;
1099 size_t cchSrc = 0;
1100 const char *pszSrcEnd;
1101 char *pszSrc;
1102 char *pszResult;
1103 char *psz;
1104 char *pszDot;
1105 size_t cch;
1106
1107 /*
1108 * Strip the source filename of any uncessary leading path and root specs.
1109 */
1110 /* */
1111 if ( pSource->value_length > pPathTarget->value_length
1112 && !strncmp(pSource->value, pPathTarget->value, pPathTarget->value_length))
1113 {
1114 pszSrc = pSource->value + pPathTarget->value_length;
1115 pszSrcPrefix = "gen/";
1116 cchSrcPrefix = sizeof("gen/") - 1;
1117 if ( *pszSrc == '/'
1118 && !strncmp(pszSrc + 1, pTarget->value, pTarget->value_length)
1119 && ( pszSrc[pTarget->value_length + 1] == '/'
1120 || pszSrc[pTarget->value_length + 1] == '\0'))
1121 pszSrc += 1 + pTarget->value_length;
1122 }
1123 else if ( pSource->value_length > pPathRoot->value_length
1124 && !strncmp(pSource->value, pPathRoot->value, pPathRoot->value_length))
1125 {
1126 pszSrc = pSource->value + pPathRoot->value_length;
1127 if ( *pszSrc == '/'
1128 && !strncmp(pszSrc + 1, pPathSubCur->value, pPathSubCur->value_length)
1129 && ( pszSrc[pPathSubCur->value_length + 1] == '/'
1130 || pszSrc[pPathSubCur->value_length + 1] == '\0'))
1131 pszSrc += 1 + pPathSubCur->value_length;
1132 }
1133 else
1134 pszSrc = pSource->value;
1135
1136 /* skip root specification */
1137#ifdef HAVE_DOS_PATHS
1138 if (isalpha(pszSrc[0]) && pszSrc[1] == ':')
1139 pszSrc += 2;
1140#endif
1141 while (*pszSrc == '/'
1142#ifdef HAVE_DOS_PATHS
1143 || *pszSrc == '\\'
1144#endif
1145 )
1146 pszSrc++;
1147
1148 /* drop the source extension. */
1149 pszSrcEnd = pSource->value + pSource->value_length;
1150 for (;;)
1151 {
1152 pszSrcEnd--;
1153 if ( pszSrcEnd <= pszSrc
1154 || *pszSrcEnd == '/'
1155#ifdef HAVE_DOS_PATHS
1156 || *pszSrcEnd == '\\'
1157 || *pszSrcEnd == ':'
1158#endif
1159 )
1160 {
1161 pszSrcEnd = pSource->value + pSource->value_length;
1162 break;
1163 }
1164 if (*pszSrcEnd == '.')
1165 break;
1166 }
1167
1168 /*
1169 * Assemble the string on the heap and define the objbase variable
1170 * which we then return.
1171 */
1172 cchSrc = pszSrcEnd - pszSrc;
1173 cch = pPathTarget->value_length
1174 + 1 /* slash */
1175 + pTarget->value_length
1176 + 1 /* slash */
1177 + cchSrcPrefix
1178 + cchSrc
1179 + 1;
1180 psz = pszResult = xmalloc(cch);
1181
1182 memcpy(psz, pPathTarget->value, pPathTarget->value_length); psz += pPathTarget->value_length;
1183 *psz++ = '/';
1184 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
1185 *psz++ = '/';
1186 if (pszSrcPrefix)
1187 {
1188 memcpy(psz, pszSrcPrefix, cchSrcPrefix);
1189 psz += cchSrcPrefix;
1190 }
1191 pszDot = psz;
1192 memcpy(psz, pszSrc, cchSrc); psz += cchSrc;
1193 *psz = '\0';
1194
1195 /* convert '..' path elements in the source to 'dt'. */
1196 while ((pszDot = memchr(pszDot, '.', psz - pszDot)) != NULL)
1197 {
1198 if ( pszDot[1] == '.'
1199 && ( pszDot == psz
1200 || pszDot[-1] == '/'
1201#ifdef HAVE_DOS_PATHS
1202 || pszDot[-1] == '\\'
1203 || pszDot[-1] == ':'
1204#endif
1205 )
1206 && ( !pszDot[2]
1207 || pszDot[2] == '/'
1208#ifdef HAVE_DOS_PATHS
1209 || pszDot[2] == '\\'
1210 || pszDot[2] == ':'
1211#endif
1212 )
1213 )
1214 {
1215 *pszDot++ = 'd';
1216 *pszDot++ = 't';
1217 }
1218 else
1219 pszDot++;
1220 }
1221
1222 /*
1223 * Define the variable in the current set and return it.
1224 */
1225 return define_variable_vl(pszVarName, strlen(pszVarName), pszResult, cch - 1,
1226 0 /* use pszResult */, o_local, 0 /* !recursive */);
1227}
1228
1229
1230/* Implements _OBJECT_BASE. */
1231char *
1232func_kbuild_object_base(char *o, char **argv, const char *pszFuncName)
1233{
1234 struct variable *pVar = kbuild_get_object_base(kbuild_lookup_variable("target"),
1235 kbuild_lookup_variable("source"),
1236 argv[0]);
1237 if (pVar)
1238 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1239 (void)pszFuncName;
1240 return o;
1241
1242}
1243
1244
1245struct kbuild_sdks
1246{
1247 char *apsz[4];
1248 struct variable *pa;
1249 unsigned c;
1250 unsigned iGlobal;
1251 unsigned cGlobal;
1252 unsigned iTarget;
1253 unsigned cTarget;
1254 unsigned iSource;
1255 unsigned cSource;
1256 unsigned iTargetSource;
1257 unsigned cTargetSource;
1258 unsigned int cchMax;
1259};
1260
1261
1262/* Fills in the SDK struct (remember to free it). */
1263static void
1264kbuild_get_sdks(struct kbuild_sdks *pSdks, struct variable *pTarget, struct variable *pSource,
1265 struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch)
1266{
1267 unsigned i;
1268 unsigned j;
1269 size_t cchTmp, cch;
1270 char *pszTmp;
1271 unsigned cchCur;
1272 char *pszCur;
1273 const char *pszIterator;
1274
1275 /** @todo rewrite this to avoid sprintf and allocated_varaible_expand_2. */
1276
1277 /* basic init. */
1278 pSdks->cchMax = 0;
1279 pSdks->pa = NULL;
1280 pSdks->c = 0;
1281 i = 0;
1282
1283 /* determin required tmp variable name space. */
1284 cchTmp = sizeof("$(__SDKS) $(__SDKS.) $(__SDKS.) $(__SDKS.) $(__SDKS..)")
1285 + (pTarget->value_length + pSource->value_length) * 5
1286 + pBldType->value_length
1287 + pBldTrg->value_length
1288 + pBldTrgArch->value_length
1289 + pBldTrg->value_length + pBldTrgArch->value_length;
1290 pszTmp = alloca(cchTmp);
1291
1292 /* the global sdks. */
1293 pSdks->iGlobal = i;
1294 pSdks->cGlobal = 0;
1295 cch = sprintf(pszTmp, "$(SDKS) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s.%s)",
1296 pBldType->value,
1297 pBldTrg->value,
1298 pBldTrgArch->value,
1299 pBldTrg->value, pBldTrgArch->value);
1300 pszIterator = pSdks->apsz[0] = allocated_variable_expand_2(pszTmp, cch, NULL);
1301 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1302 pSdks->cGlobal++;
1303 i += pSdks->cGlobal;
1304
1305 /* the target sdks.*/
1306 pSdks->iTarget = i;
1307 pSdks->cTarget = 0;
1308 cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)",
1309 pTarget->value,
1310 pTarget->value, pBldType->value,
1311 pTarget->value, pBldTrg->value,
1312 pTarget->value, pBldTrgArch->value,
1313 pTarget->value, pBldTrg->value, pBldTrgArch->value);
1314 pszIterator = pSdks->apsz[1] = allocated_variable_expand_2(pszTmp, cch, NULL);
1315 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1316 pSdks->cTarget++;
1317 i += pSdks->cTarget;
1318
1319 /* the source sdks.*/
1320 pSdks->iSource = i;
1321 pSdks->cSource = 0;
1322 cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)",
1323 pSource->value,
1324 pSource->value, pBldType->value,
1325 pSource->value, pBldTrg->value,
1326 pSource->value, pBldTrgArch->value,
1327 pSource->value, pBldTrg->value, pBldTrgArch->value);
1328 pszIterator = pSdks->apsz[2] = allocated_variable_expand_2(pszTmp, cch, NULL);
1329 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1330 pSdks->cSource++;
1331 i += pSdks->cSource;
1332
1333 /* the target + source sdks. */
1334 pSdks->iTargetSource = i;
1335 pSdks->cTargetSource = 0;
1336 cch = sprintf(pszTmp, "$(%s_%s_SDKS) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s.%s)",
1337 pTarget->value, pSource->value,
1338 pTarget->value, pSource->value, pBldType->value,
1339 pTarget->value, pSource->value, pBldTrg->value,
1340 pTarget->value, pSource->value, pBldTrgArch->value,
1341 pTarget->value, pSource->value, pBldTrg->value, pBldTrgArch->value);
1342 assert(cch < cchTmp); (void)cch;
1343 pszIterator = pSdks->apsz[3] = allocated_variable_expand_2(pszTmp, cch, NULL);
1344 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1345 pSdks->cTargetSource++;
1346 i += pSdks->cTargetSource;
1347
1348 pSdks->c = i;
1349 if (!i)
1350 return;
1351
1352 /*
1353 * Allocate the variable array and create the variables.
1354 */
1355 pSdks->pa = (struct variable *)xmalloc(sizeof(pSdks->pa[0]) * i);
1356 memset(pSdks->pa, 0, sizeof(pSdks->pa[0]) * i);
1357 for (i = j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++)
1358 {
1359 pszIterator = pSdks->apsz[j];
1360 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1361 {
1362 pSdks->pa[i].value = pszCur;
1363 pSdks->pa[i].value_length = cchCur;
1364 i++;
1365 }
1366 }
1367 assert(i == pSdks->c);
1368
1369 /* terminate them (find_next_token won't work if we terminate them in the previous loop). */
1370 while (i-- > 0)
1371 {
1372 pSdks->pa[i].value[pSdks->pa[i].value_length] = '\0';
1373
1374 /* calc the max variable length too. */
1375 if (pSdks->cchMax < (unsigned int)pSdks->pa[i].value_length)
1376 pSdks->cchMax = pSdks->pa[i].value_length;
1377 }
1378}
1379
1380
1381/* releases resources allocated in the kbuild_get_sdks. */
1382static void
1383kbuild_put_sdks(struct kbuild_sdks *pSdks)
1384{
1385 unsigned j;
1386 for (j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++)
1387 free(pSdks->apsz[j]);
1388 free(pSdks->pa);
1389}
1390
1391
1392/* this kind of stuff:
1393
1394defs := $(kb-src-exp defs)
1395 $(TOOL_$(tool)_DEFS)\
1396 $(TOOL_$(tool)_DEFS.$(bld_type))\
1397 $(TOOL_$(tool)_DEFS.$(bld_trg))\
1398 $(TOOL_$(tool)_DEFS.$(bld_trg_arch))\
1399 $(TOOL_$(tool)_DEFS.$(bld_trg).$(bld_trg_arch))\
1400 $(TOOL_$(tool)_DEFS.$(bld_trg_cpu))\
1401 $(TOOL_$(tool)_$(type)DEFS)\
1402 $(TOOL_$(tool)_$(type)DEFS.$(bld_type))\
1403 $(foreach sdk, $(SDKS.$(bld_trg)) \
1404 $(SDKS.$(bld_trg).$(bld_trg_arch)) \
1405 $(SDKS.$(bld_type)) \
1406 $(SDKS),\
1407 $(SDK_$(sdk)_DEFS)\
1408 $(SDK_$(sdk)_DEFS.$(bld_type))\
1409 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1410 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1411 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1412 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1413 $(SDK_$(sdk)_$(type)DEFS)\
1414 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1415 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1416 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1417 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1418 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1419 $(DEFS)\
1420 $(DEFS.$(bld_type))\
1421 $(DEFS.$(bld_trg))\
1422 $(DEFS.$(bld_trg_arch))\
1423 $(DEFS.$(bld_trg).$(bld_trg_arch))\
1424 $(DEFS.$(bld_trg_cpu))\
1425 $($(type)DEFS)\
1426 $($(type)DEFS.$(bld_type))\
1427 $($(type)DEFS.$(bld_trg))\
1428 $($(type)DEFS.$(bld_trg_arch))\
1429 $($(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1430 $($(type)DEFS.$(bld_trg_cpu))\
1431 $(foreach sdk, $($(target)_SDKS.$(bld_trg)) \
1432 $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)) \
1433 $($(target)_SDKS.$(bld_type)) \
1434 $($(target)_SDKS),\
1435 $(SDK_$(sdk)_DEFS)\
1436 $(SDK_$(sdk)_DEFS.$(bld_type))\
1437 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1438 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1439 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1440 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1441 $(SDK_$(sdk)_$(type)DEFS)\
1442 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1443 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1444 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1445 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1446 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1447 $($(target)_DEFS)\
1448 $($(target)_DEFS.$(bld_type))\
1449 $($(target)_DEFS.$(bld_trg))\
1450 $($(target)_DEFS.$(bld_trg_arch))\
1451 $($(target)_DEFS.$(bld_trg).$(bld_trg_arch))\
1452 $($(target)_DEFS.$(bld_trg_cpu))\
1453 $($(target)_$(type)DEFS)\
1454 $($(target)_$(type)DEFS.$(bld_type))\
1455 $($(target)_$(type)DEFS.$(bld_trg))\
1456 $($(target)_$(type)DEFS.$(bld_trg_arch))\
1457 $($(target)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1458 $($(target)_$(type)DEFS.$(bld_trg_cpu))\
1459 $(foreach sdk, $($(source)_SDKS.$(bld_trg)) \
1460 $($(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \
1461 $($(source)_SDKS.$(bld_type)) \
1462 $($(source)_SDKS),\
1463 $(SDK_$(sdk)_DEFS)\
1464 $(SDK_$(sdk)_DEFS.$(bld_type))\
1465 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1466 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1467 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1468 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1469 $(SDK_$(sdk)_$(type)DEFS)\
1470 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1471 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1472 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1473 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1474 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1475 $($(source)_DEFS)\
1476 $($(source)_DEFS.$(bld_type))\
1477 $($(source)_DEFS.$(bld_trg))\
1478 $($(source)_DEFS.$(bld_trg_arch))\
1479 $($(source)_DEFS.$(bld_trg).$(bld_trg_arch))\
1480 $($(source)_DEFS.$(bld_trg_cpu))\
1481 $($(source)_$(type)DEFS)\
1482 $($(source)_$(type)DEFS.$(bld_type))\
1483 $($(source)_$(type)DEFS.$(bld_trg))\
1484 $($(source)_$(type)DEFS.$(bld_trg_arch))\
1485 $($(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1486 $($(source)_$(type)DEFS.$(bld_trg_cpu))\
1487 $(foreach sdk, $($(target)_$(source)_SDKS.$(bld_trg)) \
1488 $($(target)_$(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \
1489 $($(target)_$(source)_SDKS.$(bld_type)) \
1490 $($(target)_$(source)_SDKS),\
1491 $(SDK_$(sdk)_DEFS)\
1492 $(SDK_$(sdk)_DEFS.$(bld_type))\
1493 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1494 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1495 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1496 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1497 $(SDK_$(sdk)_$(type)DEFS)\
1498 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1499 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1500 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1501 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1502 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1503 $($(target)_$(source)_DEFS)\
1504 $($(target)_$(source)_DEFS.$(bld_type))\
1505 $($(target)_$(source)_DEFS.$(bld_trg))\
1506 $($(target)_$(source)_DEFS.$(bld_trg_arch))\
1507 $($(target)_$(source)_DEFS.$(bld_trg).$(bld_trg_arch))\
1508 $($(target)_$(source)_DEFS.$(bld_trg_cpu))\
1509 $($(target)_$(source)_$(type)DEFS)\
1510 $($(target)_$(source)_$(type)DEFS.$(bld_type))\
1511 $($(target)_$(source)_$(type)DEFS.$(bld_trg))\
1512 $($(target)_$(source)_$(type)DEFS.$(bld_trg_arch))\
1513 $($(target)_$(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1514 $($(target)_$(source)_$(type)DEFS.$(bld_trg_cpu))
1515*/
1516static struct variable *
1517kbuild_collect_source_prop(struct variable *pTarget, struct variable *pSource,
1518 struct variable *pTool, struct kbuild_sdks *pSdks,
1519 struct variable *pType, struct variable *pBldType,
1520 struct variable *pBldTrg, struct variable *pBldTrgArch, struct variable *pBldTrgCpu,
1521 struct variable *pDefPath,
1522 const char *pszProp, size_t cchProp,
1523 const char *pszVarName, size_t cchVarName,
1524 int iDirection)
1525{
1526 struct variable *pVar;
1527 unsigned iSdk, iSdkEnd;
1528 int cVars, iVar;
1529 size_t cchTotal, cchBuf;
1530 char *pszResult, *pszBuf, *psz, *psz2, *psz3;
1531 struct
1532 {
1533 struct variable *pVar;
1534 unsigned int cchExp;
1535 char *pszExp;
1536 } *paVars;
1537
1538 assert(iDirection == 1 || iDirection == -1);
1539
1540 /*
1541 * Calc and allocate a too big name buffer.
1542 */
1543 cchBuf = cchProp + 1
1544 + pTarget->value_length + 1
1545 + pSource->value_length + 1
1546 + pSdks->cchMax + 1
1547 + (pTool ? pTool->value_length + 1 : 0)
1548 + pType->value_length + 1
1549 + pBldTrg->value_length + 1
1550 + pBldTrgArch->value_length + 1
1551 + pBldTrgCpu->value_length + 1
1552 + pBldType->value_length + 1;
1553 pszBuf = xmalloc(cchBuf);
1554
1555 /*
1556 * Get the variables.
1557 *
1558 * The compiler will get a heart attack when it sees this code ... ;-)
1559 */
1560 cVars = 12 * (pSdks->c + 5);
1561 paVars = alloca(cVars * sizeof(paVars[0]));
1562
1563 iVar = 0;
1564 cchTotal = 0;
1565
1566#define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0)
1567#define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0)
1568#define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0)
1569#define ADD_CH(ch) do { *psz++ = (ch); } while (0)
1570#define DO_VAR_LOOKUP() \
1571 do { \
1572 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); \
1573 if (pVar) \
1574 { \
1575 paVars[iVar].pVar = pVar; \
1576 if ( !pVar->recursive \
1577 || !memchr(pVar->value, '$', pVar->value_length)) \
1578 { \
1579 paVars[iVar].pszExp = pVar->value; \
1580 paVars[iVar].cchExp = pVar->value_length; \
1581 if (pDefPath && paVars[iVar].cchExp) \
1582 kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 0); \
1583 if (paVars[iVar].cchExp) \
1584 { \
1585 cchTotal += paVars[iVar].cchExp + 1; \
1586 iVar++; \
1587 } \
1588 } \
1589 else \
1590 { \
1591 paVars[iVar].pszExp = allocated_variable_expand_2(pVar->value, pVar->value_length, &paVars[iVar].cchExp); \
1592 if (pDefPath && paVars[iVar].cchExp) \
1593 kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 1); \
1594 if (paVars[iVar].cchExp) \
1595 { \
1596 cchTotal += paVars[iVar].cchExp + 1; \
1597 iVar++; \
1598 } \
1599 else \
1600 free(paVars[iVar].pszExp); \
1601 } \
1602 } \
1603 } while (0)
1604#define DO_SINGLE_PSZ3_VARIATION() \
1605 do { \
1606 DO_VAR_LOOKUP(); \
1607 \
1608 ADD_CH('.'); \
1609 psz3 = psz; \
1610 ADD_VAR(pBldType); \
1611 DO_VAR_LOOKUP(); \
1612 \
1613 psz = psz3; \
1614 ADD_VAR(pBldTrg); \
1615 DO_VAR_LOOKUP(); \
1616 \
1617 psz = psz3; \
1618 ADD_VAR(pBldTrgArch); \
1619 DO_VAR_LOOKUP(); \
1620 \
1621 psz = psz3; \
1622 ADD_VAR(pBldTrg); \
1623 ADD_CH('.'); \
1624 ADD_VAR(pBldTrgArch); \
1625 DO_VAR_LOOKUP(); \
1626 \
1627 psz = psz3; \
1628 ADD_VAR(pBldTrgCpu); \
1629 DO_VAR_LOOKUP(); \
1630 } while (0)
1631
1632#define DO_DOUBLE_PSZ2_VARIATION() \
1633 do { \
1634 psz2 = psz; \
1635 ADD_STR(pszProp, cchProp); \
1636 DO_SINGLE_PSZ3_VARIATION(); \
1637 \
1638 /* add prop before type */ \
1639 psz = psz2; \
1640 ADD_VAR(pType); \
1641 ADD_STR(pszProp, cchProp); \
1642 DO_SINGLE_PSZ3_VARIATION(); \
1643 } while (0)
1644
1645 /* the tool (lowest priority). */
1646 psz = pszBuf;
1647 ADD_CSTR("TOOL_");
1648 ADD_VAR(pTool);
1649 ADD_CH('_');
1650 DO_DOUBLE_PSZ2_VARIATION();
1651
1652
1653 /* the global sdks. */
1654 iSdkEnd = iDirection == 1 ? pSdks->iGlobal + pSdks->cGlobal : pSdks->iGlobal - 1;
1655 for (iSdk = iDirection == 1 ? pSdks->iGlobal : pSdks->iGlobal + pSdks->cGlobal - 1;
1656 iSdk != iSdkEnd;
1657 iSdk += iDirection)
1658 {
1659 struct variable *pSdk = &pSdks->pa[iSdk];
1660 psz = pszBuf;
1661 ADD_CSTR("SDK_");
1662 ADD_VAR(pSdk);
1663 ADD_CH('_');
1664 DO_DOUBLE_PSZ2_VARIATION();
1665 }
1666
1667 /* the globals. */
1668 psz = pszBuf;
1669 DO_DOUBLE_PSZ2_VARIATION();
1670
1671
1672 /* the target sdks. */
1673 iSdkEnd = iDirection == 1 ? pSdks->iTarget + pSdks->cTarget : pSdks->iTarget - 1;
1674 for (iSdk = iDirection == 1 ? pSdks->iTarget : pSdks->iTarget + pSdks->cTarget - 1;
1675 iSdk != iSdkEnd;
1676 iSdk += iDirection)
1677 {
1678 struct variable *pSdk = &pSdks->pa[iSdk];
1679 psz = pszBuf;
1680 ADD_CSTR("SDK_");
1681 ADD_VAR(pSdk);
1682 ADD_CH('_');
1683 DO_DOUBLE_PSZ2_VARIATION();
1684 }
1685
1686 /* the target. */
1687 psz = pszBuf;
1688 ADD_VAR(pTarget);
1689 ADD_CH('_');
1690 DO_DOUBLE_PSZ2_VARIATION();
1691
1692 /* the source sdks. */
1693 iSdkEnd = iDirection == 1 ? pSdks->iSource + pSdks->cSource : pSdks->iSource - 1;
1694 for (iSdk = iDirection == 1 ? pSdks->iSource : pSdks->iSource + pSdks->cSource - 1;
1695 iSdk != iSdkEnd;
1696 iSdk += iDirection)
1697 {
1698 struct variable *pSdk = &pSdks->pa[iSdk];
1699 psz = pszBuf;
1700 ADD_CSTR("SDK_");
1701 ADD_VAR(pSdk);
1702 ADD_CH('_');
1703 DO_DOUBLE_PSZ2_VARIATION();
1704 }
1705
1706 /* the source. */
1707 psz = pszBuf;
1708 ADD_VAR(pSource);
1709 ADD_CH('_');
1710 DO_DOUBLE_PSZ2_VARIATION();
1711
1712 /* the target + source sdks. */
1713 iSdkEnd = iDirection == 1 ? pSdks->iTargetSource + pSdks->cTargetSource : pSdks->iTargetSource - 1;
1714 for (iSdk = iDirection == 1 ? pSdks->iTargetSource : pSdks->iTargetSource + pSdks->cTargetSource - 1;
1715 iSdk != iSdkEnd;
1716 iSdk += iDirection)
1717 {
1718 struct variable *pSdk = &pSdks->pa[iSdk];
1719 psz = pszBuf;
1720 ADD_CSTR("SDK_");
1721 ADD_VAR(pSdk);
1722 ADD_CH('_');
1723 DO_DOUBLE_PSZ2_VARIATION();
1724 }
1725
1726 /* the target + source. */
1727 psz = pszBuf;
1728 ADD_VAR(pTarget);
1729 ADD_CH('_');
1730 ADD_VAR(pSource);
1731 ADD_CH('_');
1732 DO_DOUBLE_PSZ2_VARIATION();
1733
1734 free(pszBuf);
1735
1736 assert(iVar <= cVars);
1737 cVars = iVar;
1738
1739 /*
1740 * Construct the result value.
1741 */
1742 if (!cVars || !cchTotal)
1743 pVar = define_variable_vl(pszVarName, cchVarName, "", 0,
1744 1 /* duplicate value */ , o_local, 0 /* !recursive */);
1745 else
1746 {
1747 psz = pszResult = xmalloc(cchTotal + 1);
1748 if (iDirection == 1)
1749 {
1750 for (iVar = 0; iVar < cVars; iVar++)
1751 {
1752 my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp);
1753 psz += paVars[iVar].cchExp;
1754 *psz++ = ' ';
1755 if (paVars[iVar].pszExp != paVars[iVar].pVar->value)
1756 free(paVars[iVar].pszExp);
1757 }
1758 }
1759 else
1760 {
1761 iVar = cVars;
1762 while (iVar-- > 0)
1763 {
1764 my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp);
1765 psz += paVars[iVar].cchExp;
1766 *psz++ = ' ';
1767 if (paVars[iVar].pszExp != paVars[iVar].pVar->value)
1768 free(paVars[iVar].pszExp);
1769 }
1770
1771 }
1772 assert(psz != pszResult);
1773 assert(cchTotal == (size_t)(psz - pszResult));
1774 psz[-1] = '\0';
1775 cchTotal--;
1776
1777 pVar = define_variable_vl(pszVarName, cchVarName, pszResult, cchTotal,
1778 0 /* take pszResult */ , o_local, 0 /* !recursive */);
1779 }
1780
1781 return pVar;
1782
1783#undef ADD_VAR
1784#undef ADD_STR
1785#undef ADD_CSTR
1786#undef ADD_CH
1787#undef DO_VAR_LOOKUP
1788#undef DO_DOUBLE_PSZ2_VARIATION
1789#undef DO_SINGLE_PSZ3_VARIATION
1790}
1791
1792
1793/* get a source property. */
1794char *
1795func_kbuild_source_prop(char *o, char **argv, const char *pszFuncName)
1796{
1797 struct variable *pTarget = kbuild_get_variable_n(ST("target"));
1798 struct variable *pSource = kbuild_get_variable_n(ST("source"));
1799 struct variable *pDefPath = NULL;
1800 struct variable *pType = kbuild_get_variable_n(ST("type"));
1801 struct variable *pTool = kbuild_get_variable_n(ST("tool"));
1802 struct variable *pBldType = kbuild_get_variable_n(ST("bld_type"));
1803 struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg"));
1804 struct variable *pBldTrgArch = kbuild_get_variable_n(ST("bld_trg_arch"));
1805 struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu"));
1806 struct variable *pVar;
1807 struct kbuild_sdks Sdks;
1808 int iDirection;
1809 if (!strcmp(argv[2], "left-to-right"))
1810 iDirection = 1;
1811 else if (!strcmp(argv[2], "right-to-left"))
1812 iDirection = -1;
1813 else
1814 fatal(NILF, _("incorrect direction argument `%s'!"), argv[2]);
1815 if (argv[3])
1816 {
1817 const char *psz = argv[3];
1818 while (isspace(*psz))
1819 psz++;
1820 if (*psz)
1821 pDefPath = kbuild_get_variable_n(ST("defpath"));
1822 }
1823
1824 kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch);
1825
1826 pVar = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType,
1827 pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu,
1828 pDefPath,
1829 argv[0], strlen(argv[0]),
1830 argv[1], strlen(argv[1]),
1831 iDirection);
1832 if (pVar)
1833 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1834
1835 kbuild_put_sdks(&Sdks);
1836 (void)pszFuncName;
1837 return o;
1838}
1839
1840
1841/*
1842dep := $(obj)$(SUFF_DEP)
1843obj := $(outbase)$(objsuff)
1844dirdep := $(call DIRDEP,$(dir $(outbase)))
1845PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase)))
1846*/
1847static struct variable *
1848kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(struct variable *pTarget, struct variable *pSource,
1849 struct variable *pOutBase, struct variable *pObjSuff,
1850 const char *pszVarName, struct variable **ppDep,
1851 struct variable **ppDirDep)
1852{
1853 struct variable *pDepSuff = kbuild_get_variable_n(ST("SUFF_DEP"));
1854 struct variable *pObj;
1855 size_t cch = pOutBase->value_length + pObjSuff->value_length + pDepSuff->value_length + 1;
1856 char *pszResult = alloca(cch);
1857 char *pszName, *psz;
1858
1859 /*
1860 * dep.
1861 */
1862 psz = pszResult;
1863 memcpy(psz, pOutBase->value, pOutBase->value_length); psz += pOutBase->value_length;
1864 memcpy(psz, pObjSuff->value, pObjSuff->value_length); psz += pObjSuff->value_length;
1865 memcpy(psz, pDepSuff->value, pDepSuff->value_length + 1);
1866 *ppDep = define_variable_vl("dep", 3, pszResult, cch - 1, 1 /*dup*/, o_local, 0 /* !recursive */);
1867
1868 /*
1869 * obj
1870 */
1871 *psz = '\0';
1872 pObj = define_variable_vl(pszVarName, strlen(pszVarName), pszResult, psz - pszResult,
1873 1/* dup */, o_local, 0 /* !recursive */);
1874
1875 /*
1876 * PATH_$(target)_$(source) - this is global!
1877 */
1878 /* calc variable name. */
1879 cch = sizeof("PATH_")-1 + pTarget->value_length + sizeof("_")-1 + pSource->value_length;
1880 psz = pszName = alloca(cch + 1);
1881 memcpy(psz, "PATH_", sizeof("PATH_") - 1); psz += sizeof("PATH_") - 1;
1882 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
1883 *psz++ = '_';
1884 memcpy(psz, pSource->value, pSource->value_length + 1);
1885
1886 /* strip off the filename. */
1887 psz = pszResult + pOutBase->value_length;
1888 for (;;)
1889 {
1890 psz--;
1891 if (psz <= pszResult)
1892 fatal(NULL, "whut!?! no path? result=`%s'", pszResult);
1893#ifdef HAVE_DOS_PATHS
1894 if (*psz == ':')
1895 {
1896 psz++;
1897 break;
1898 }
1899#endif
1900 if ( *psz == '/'
1901#ifdef HAVE_DOS_PATHS
1902 || *psz == '\\'
1903#endif
1904 )
1905 {
1906 while ( psz - 1 > pszResult
1907 && psz[-1] == '/'
1908#ifdef HAVE_DOS_PATHS
1909 || psz[-1] == '\\'
1910#endif
1911 )
1912 psz--;
1913#ifdef HAVE_DOS_PATHS
1914 if (psz == pszResult + 2 && pszResult[1] == ':')
1915 psz++;
1916#endif
1917 break;
1918 }
1919 }
1920 *psz = '\0';
1921
1922 /* set global variable */
1923 define_variable_vl_global(pszName, cch, pszResult, psz - pszResult, 1/*dup*/, o_file, 0 /* !recursive */, NILF);
1924
1925 /*
1926 * dirdep
1927 */
1928 if ( psz[-1] != '/'
1929#ifdef HAVE_DOS_PATHS
1930 && psz[-1] != '\\'
1931 && psz[-1] != ':'
1932#endif
1933 )
1934 {
1935 *psz++ = '/';
1936 *psz = '\0';
1937 }
1938 *ppDirDep = define_variable_vl("dirdep", 6, pszResult, psz - pszResult, 1/*dup*/, o_local, 0 /* !recursive */);
1939
1940 return pObj;
1941}
1942
1943
1944/* setup the base variables for def_target_source_c_cpp_asm_new:
1945
1946X := $(kb-src-tool tool)
1947x := $(kb-obj-base outbase)
1948x := $(kb-obj-suff objsuff)
1949obj := $(outbase)$(objsuff)
1950PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase)))
1951
1952x := $(kb-src-prop DEFS,defs,left-to-right)
1953x := $(kb-src-prop INCS,incs,right-to-left)
1954x := $(kb-src-prop FLAGS,flags,right-to-left)
1955
1956x := $(kb-src-prop DEPS,deps,left-to-right)
1957dirdep := $(call DIRDEP,$(dir $(outbase)))
1958dep := $(obj)$(SUFF_DEP)
1959*/
1960char *
1961func_kbuild_source_one(char *o, char **argv, const char *pszFuncName)
1962{
1963 static int s_fNoCompileCmdsDepsDefined = -1;
1964 struct variable *pTarget = kbuild_get_variable_n(ST("target"));
1965 struct variable *pSource = kbuild_get_variable_n(ST("source"));
1966 struct variable *pDefPath = kbuild_get_variable_n(ST("defpath"));
1967 struct variable *pType = kbuild_get_variable_n(ST("type"));
1968 struct variable *pBldType = kbuild_get_variable_n(ST("bld_type"));
1969 struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg"));
1970 struct variable *pBldTrgArch= kbuild_get_variable_n(ST("bld_trg_arch"));
1971 struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu"));
1972 struct variable *pTool = kbuild_get_source_tool(pTarget, pSource, pType, pBldTrg, pBldTrgArch, "tool");
1973 struct variable *pOutBase = kbuild_get_object_base(pTarget, pSource, "outbase");
1974 struct variable *pObjSuff = kbuild_get_object_suffix(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch, "objsuff");
1975 struct variable *pDefs, *pIncs, *pFlags, *pDeps, *pOrderDeps, *pDirDep, *pDep, *pVar, *pOutput, *pOutputMaybe;
1976 struct variable *pObj = kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(pTarget, pSource, pOutBase, pObjSuff, "obj", &pDep, &pDirDep);
1977 int fInstallOldVars = 0;
1978 char *pszDstVar, *pszDst, *pszSrcVar, *pszSrc, *pszVal, *psz;
1979 char *pszSavedVarBuf;
1980 unsigned cchSavedVarBuf;
1981 size_t cch;
1982 struct kbuild_sdks Sdks;
1983 int iVer;
1984
1985 /*
1986 * argv[0] is the function version. Prior to r1792 (early 0.1.5) this
1987 * was undefined and footer.kmk always passed an empty string.
1988 *
1989 * Version 2, as implemented in r1797, will make use of the async
1990 * includedep queue feature. This means the files will be read by one or
1991 * more background threads, leaving the eval'ing to be done later on by
1992 * the main thread (in snap_deps).
1993 */
1994 if (!argv[0][0])
1995 iVer = 0;
1996 else
1997 switch (argv[0][0] | (argv[0][1] << 8))
1998 {
1999 case '2': iVer = 2; break;
2000 case '3': iVer = 3; break;
2001 case '4': iVer = 4; break;
2002 case '5': iVer = 5; break;
2003 case '6': iVer = 6; break;
2004 case '7': iVer = 7; break;
2005 case '8': iVer = 8; break;
2006 case '9': iVer = 9; break;
2007 case '0': iVer = 0; break;
2008 case '1': iVer = 1; break;
2009 default:
2010 iVer = 0;
2011 psz = argv[0];
2012 while (isblank((unsigned char)*psz))
2013 psz++;
2014 if (*psz)
2015 iVer = atoi(psz);
2016 break;
2017 }
2018
2019 /*
2020 * Gather properties.
2021 */
2022 kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch);
2023
2024 if (pDefPath && !pDefPath->value_length)
2025 pDefPath = NULL;
2026 pDefs = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL,
2027 ST("DEFS"), ST("defs"), 1/* left-to-right */);
2028 pIncs = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath,
2029 ST("INCS"), ST("incs"), -1/* right-to-left */);
2030 pFlags = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL,
2031 ST("FLAGS"), ST("flags"), 1/* left-to-right */);
2032 pDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath,
2033 ST("DEPS"), ST("deps"), 1/* left-to-right */);
2034 pOrderDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath,
2035 ST("ORDERDEPS"), ST("orderdeps"), 1/* left-to-right */);
2036
2037 /*
2038 * If we've got a default path, we must expand the source now.
2039 * If we do this too early, "<source>_property = stuff" won't work becuase
2040 * our 'source' value isn't what the user expects.
2041 */
2042 if (pDefPath)
2043 {
2044 /** @todo assert(pSource->origin != o_automatic); We're changing 'source'
2045 * from the foreach loop! */
2046#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
2047 assert(!pSource->rdonly_val);
2048#endif
2049 kbuild_apply_defpath(pDefPath, &pSource->value, &pSource->value_length, &pSource->value_alloc_len, 1 /* can free */);
2050 }
2051
2052 /*
2053 # dependencies
2054 ifndef NO_COMPILE_CMDS_DEPS
2055 _DEPFILES_INCLUDED += $(dep)
2056 $(if $(wildcard $(dep)),$(eval include $(dep)))
2057 endif
2058 */
2059 if (s_fNoCompileCmdsDepsDefined == -1)
2060 s_fNoCompileCmdsDepsDefined = kbuild_lookup_variable_n(ST("NO_COMPILE_CMDS_DEPS")) != NULL;
2061 if (!s_fNoCompileCmdsDepsDefined)
2062 {
2063 pVar = kbuild_query_recursive_variable_n("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1);
2064 if (pVar)
2065 {
2066 if (pVar->recursive)
2067 pVar = kbuild_simplify_variable(pVar);
2068 append_string_to_variable(pVar, pDep->value, pDep->value_length, 1 /* append */);
2069 }
2070 else
2071 define_variable_vl_global("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1,
2072 pDep->value, pDep->value_length,
2073 1 /* duplicate_value */,
2074 o_file,
2075 0 /* recursive */,
2076 NULL /* flocp */);
2077
2078 eval_include_dep(pDep->value, NILF, iVer >= 2 ? incdep_queue : incdep_read_it);
2079 }
2080
2081 /*
2082 # call the tool
2083 $(target)_$(source)_CMDS_ := $(TOOL_$(tool)_COMPILE_$(type)_CMDS)
2084 $(target)_$(source)_OUTPUT_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT)
2085 $(target)_$(source)_OUTPUT_MAYBE_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT_MAYBE)
2086 $(target)_$(source)_DEPEND_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPEND) $(deps) $(source)
2087 $(target)_$(source)_DEPORD_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPORD) $(dirdep)
2088 */
2089 /** @todo Make all these local variables, if someone needs the info later it
2090 * can be recalculated. (Ticket #80.) */
2091 cch = sizeof("TOOL_") + pTool->value_length + sizeof("_COMPILE_") + pType->value_length + sizeof("_OUTPUT_MAYBE");
2092 if (cch < pTarget->value_length + sizeof("$(_2_OBJS)"))
2093 cch = pTarget->value_length + sizeof("$(_2_OBJS)");
2094 psz = pszSrcVar = alloca(cch);
2095 memcpy(psz, "TOOL_", sizeof("TOOL_") - 1); psz += sizeof("TOOL_") - 1;
2096 memcpy(psz, pTool->value, pTool->value_length); psz += pTool->value_length;
2097 memcpy(psz, "_COMPILE_", sizeof("_COMPILE_") - 1); psz += sizeof("_COMPILE_") - 1;
2098 memcpy(psz, pType->value, pType->value_length); psz += pType->value_length;
2099 pszSrc = psz;
2100
2101 cch = pTarget->value_length + 1 + pSource->value_length + sizeof("_OUTPUT_MAYBE_");
2102 psz = pszDstVar = alloca(cch);
2103 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
2104 *psz++ = '_';
2105 memcpy(psz, pSource->value, pSource->value_length); psz += pSource->value_length;
2106 pszDst = psz;
2107
2108 memcpy(pszSrc, "_CMDS", sizeof("_CMDS"));
2109 memcpy(pszDst, "_CMDS_", sizeof("_CMDS_"));
2110 pVar = kbuild_get_recursive_variable(pszSrcVar);
2111 do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2112 !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */);
2113 do_variable_definition_2(NILF, "kbsrc_cmds", pVar->value, pVar->value_length,
2114 !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */);
2115
2116 memcpy(pszSrc, "_OUTPUT", sizeof("_OUTPUT"));
2117 memcpy(pszDst, "_OUTPUT_", sizeof("_OUTPUT_"));
2118 pVar = kbuild_get_recursive_variable(pszSrcVar);
2119 pOutput = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2120 !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */);
2121 pOutput = do_variable_definition_2(NILF, "kbsrc_output", pVar->value, pVar->value_length,
2122 !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */);
2123
2124 memcpy(pszSrc, "_OUTPUT_MAYBE", sizeof("_OUTPUT_MAYBE"));
2125 memcpy(pszDst, "_OUTPUT_MAYBE_", sizeof("_OUTPUT_MAYBE_"));
2126 pVar = kbuild_query_recursive_variable(pszSrcVar);
2127 if (pVar)
2128 {
2129 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2130 !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */);
2131 pOutputMaybe = do_variable_definition_2(NILF, "kbsrc_output_maybe", pVar->value, pVar->value_length,
2132 !pVar->recursive, 0, o_local, f_simple, 0 /* !target_var */);
2133 }
2134 else
2135 {
2136 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, "", 0, 1, 0, o_local, f_simple, 0 /* !target_var */);
2137 pOutputMaybe = do_variable_definition_2(NILF, "kbsrc_output_maybe", "", 0, 1, 0, o_local, f_simple, 0 /* !target_var */);
2138 }
2139
2140 memcpy(pszSrc, "_DEPEND", sizeof("_DEPEND"));
2141 memcpy(pszDst, "_DEPEND_", sizeof("_DEPEND_"));
2142 pVar = kbuild_get_recursive_variable(pszSrcVar);
2143 psz = pszVal = xmalloc(pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length + 1);
2144 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2145 *psz++ = ' ';
2146 memcpy(psz, pDeps->value, pDeps->value_length); psz += pDeps->value_length;
2147 *psz++ = ' ';
2148 memcpy(psz, pSource->value, pSource->value_length + 1);
2149 do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length,
2150 !pVar->recursive && !pDeps->recursive && !pSource->recursive,
2151 NULL, o_local, f_simple, 0 /* !target_var */);
2152 do_variable_definition_2(NILF, "kbsrc_depend", pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length,
2153 !pVar->recursive && !pDeps->recursive && !pSource->recursive,
2154 pszVal, o_local, f_simple, 0 /* !target_var */);
2155
2156 memcpy(pszSrc, "_DEPORD", sizeof("_DEPORD"));
2157 memcpy(pszDst, "_DEPORD_", sizeof("_DEPORD_"));
2158 pVar = kbuild_get_recursive_variable(pszSrcVar);
2159 psz = pszVal = xmalloc(pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length + 1);
2160 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2161 *psz++ = ' ';
2162 memcpy(psz, pDirDep->value, pDirDep->value_length); psz += pDirDep->value_length;
2163 *psz++ = ' ';
2164 memcpy(psz, pOrderDeps->value, pOrderDeps->value_length + 1);
2165 do_variable_definition_2(NILF, pszDstVar, pszVal,
2166 pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length,
2167 !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive,
2168 NULL, o_local, f_simple, 0 /* !target_var */);
2169 do_variable_definition_2(NILF, "kbsrc_depord", pszVal,
2170 pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length,
2171 !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive,
2172 pszVal, o_local, f_simple, 0 /* !target_var */);
2173
2174 /*
2175 _OUT_FILES += $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_)
2176 */
2177 pVar = kbuild_get_variable_n(ST("_OUT_FILES"));
2178 append_string_to_variable(pVar, pOutput->value, pOutput->value_length, 1 /* append */);
2179 if (pOutputMaybe->value_length)
2180 append_string_to_variable(pVar, pOutputMaybe->value, pOutputMaybe->value_length, 1 /* append */);
2181
2182 /*
2183 $(target)_2_OBJS += $(obj)
2184 */
2185 memcpy(pszDstVar + pTarget->value_length, "_2_OBJS", sizeof("_2_OBJS"));
2186 pVar = kbuild_query_recursive_variable_n(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1);
2187 fInstallOldVars |= iVer <= 2 && (!pVar || !pVar->value_length);
2188 if (pVar)
2189 {
2190 if (pVar->recursive)
2191 pVar = kbuild_simplify_variable(pVar);
2192 append_string_to_variable(pVar, pObj->value, pObj->value_length, 1 /* append */);
2193 }
2194 else
2195 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1,
2196 pObj->value, pObj->value_length,
2197 1 /* duplicate_value */,
2198 o_file,
2199 0 /* recursive */,
2200 NULL /* flocp */);
2201
2202 /*
2203 * Install legacy variables.
2204 */
2205 if (fInstallOldVars)
2206 {
2207 /* $(target)_OBJS_ = $($(target)_2_OBJS)*/
2208 memcpy(pszDstVar + pTarget->value_length, "_OBJS_", sizeof("_OBJS_"));
2209
2210 pszSrcVar[0] = '$';
2211 pszSrcVar[1] = '(';
2212 memcpy(pszSrcVar + 2, pTarget->value, pTarget->value_length);
2213 psz = pszSrcVar + 2 + pTarget->value_length;
2214 memcpy(psz, "_2_OBJS)", sizeof("_2_OBJS)"));
2215
2216 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1,
2217 pszSrcVar, pTarget->value_length + sizeof("$(_2_OBJS)") - 1,
2218 1 /* duplicate_value */,
2219 o_file,
2220 1 /* recursive */,
2221 NULL /* flocp */);
2222 }
2223
2224 /*
2225 $(eval $(def_target_source_rule))
2226 */
2227 pVar = kbuild_get_recursive_variable("def_target_source_rule");
2228 pszVal = variable_expand_string_2 (o, pVar->value, pVar->value_length, &psz);
2229 assert(!((size_t)pszVal & 3));
2230
2231 install_variable_buffer(&pszSavedVarBuf, &cchSavedVarBuf);
2232 eval_buffer(pszVal, psz);
2233 restore_variable_buffer(pszSavedVarBuf, cchSavedVarBuf);
2234
2235 kbuild_put_sdks(&Sdks);
2236 (void)pszFuncName;
2237
2238 *pszVal = '\0';
2239 return pszVal;
2240}
2241
2242/*
2243
2244## Inherit one template property in a non-accumulative manner.
2245# @param $(prop) Property name
2246# @param $(target) Target name
2247# @todo fix the precedence order for some properties.
2248define def_inherit_template_one
2249ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2250ifndef $(target)_$(prop)
2251$(target)_$(prop) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2252endif
2253endif
2254ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2255ifndef $(target)_$(prop).$(bld_trg)
2256$(target)_$(prop).$(bld_trg) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2257endif
2258endif
2259ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2260ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2261$(target)_$(prop).$(bld_trg).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2262endif
2263endif
2264ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2265ifndef $(target)_$(prop).$(bld_trg_arch)
2266$(target)_$(prop).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2267endif
2268endif
2269ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2270ifndef $(target)_$(prop).$(bld_trg_cpu)
2271$(target)_$(prop).$(bld_trg_cpu) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2272endif
2273endif
2274endef
2275
2276## Inherit one template property in a non-accumulative manner, deferred expansion.
2277# @param 1: $(prop) Property name
2278# @param 2: $(target) Target name
2279# @todo fix the precedence order for some properties.
2280# @remark this define relies on double evaluation
2281define def_inherit_template_one_deferred
2282ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2283ifndef $(target)_$(prop)
2284$(target)_$(prop) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2285endif
2286endif
2287ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2288ifndef $(target)_$(prop).$(bld_trg)
2289$(target)_$(prop).$(bld_trg) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2290endif
2291endif
2292ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2293ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2294$(target)_$(prop).$(bld_trg).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2295endif
2296endif
2297ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2298ifndef $(target)_$(prop).$(bld_trg_arch)
2299$(target)_$(prop).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2300endif
2301endif
2302ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2303ifndef $(target)_$(prop).$(bld_trg_cpu)
2304$(target)_$(prop).$(bld_trg_cpu) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2305endif
2306endif
2307endef
2308
2309## Inherit one acculumlative template property where the 'most significant' items are at the left end.
2310# @param $(prop) Property name
2311# @param $(target) Target name
2312define def_inherit_template_one_accumulate_l
2313ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2314 ifeq ($$(flavor $(target)_$(prop)),simple)
2315 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2316 endif
2317$(target)_$(prop) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2318endif
2319ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2320 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2321 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2322 endif
2323$(target)_$(prop).$(KBUILD_TYPE) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2324endif
2325ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2326 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2327 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2328 endif
2329$(target)_$(prop).$(bld_trg) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2330endif
2331ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2332 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2333 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2334 endif
2335$(target)_$(prop).$(bld_trg).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2336endif
2337ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2338 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2339 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2340 endif
2341$(target)_$(prop).$(bld_trg_cpu) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2342endif
2343ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2344 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2345 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2346 endif
2347$(target)_$(prop).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2348endif
2349endef
2350
2351## Inherit one acculumlative template property where the 'most significant' items are at the right end.
2352# @param $(prop) Property name
2353# @param $(target) Target name
2354define def_inherit_template_one_accumulate_r
2355ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2356 ifeq ($$(flavor $(target)_$(prop)),simple)
2357 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2358 endif
2359$(target)_$(prop) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2360endif
2361ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2362 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2363 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2364 endif
2365$(target)_$(prop).$(KBUILD_TYPE) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2366endif
2367ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2368 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2369 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2370 endif
2371$(target)_$(prop).$(bld_trg) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2372endif
2373ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2374 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2375 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2376 endif
2377$(target)_$(prop).$(bld_trg).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2378endif
2379ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2380 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2381 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2382 endif
2383$(target)_$(prop).$(bld_trg_cpu) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2384endif
2385ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2386 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2387 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2388 endif
2389$(target)_$(prop).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2390endif
2391endef
2392
2393
2394## Inherit template properties for on target.
2395# @param $(target) Target name.
2396define def_inherit_template
2397# sanity check.
2398ifdef _$(target)_ALREADY_PROCESSED
2399 $(error kBuild: The target $(target) appears more than once in the target lists! Please correct the makefile(s))
2400endif
2401_$(target)_ALREADY_PROCESSED := 1
2402
2403# Inherit any default template.
2404ifdef TEMPLATE
2405ifeq ($($(target)_TEMPLATE),)
2406$(eval $(target)_TEMPLATE:=$(TEMPLATE))
2407endif
2408endif
2409# Expand the template if specified.
2410ifneq ($($(target)_TEMPLATE),)
2411$(foreach prop,$(PROPS_SINGLE),$(evalval def_inherit_template_one))
2412$(foreach prop,$(PROPS_DEFERRED),$(eval $(def_inherit_template_one_deferred))) # exploits the 2 evaluation, so no value!
2413$(foreach prop,$(PROPS_ACCUMULATE_L),$(eval $(def_inherit_template_one_accumulate_l))) # += works fine without value
2414$(foreach prop,$(PROPS_ACCUMULATE_R),$(eval $(def_inherit_template_one_accumulate_r))) # use <= (kmk addition)
2415endif
2416endef
2417
2418
2419Invoked like this:
2420 $(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE))
2421*/
2422char *
2423func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName)
2424{
2425 const char *pszVersion = argv[0];
2426 const char *pszBldTrg = argv[2];
2427 const char *pszBldTrgArch = argv[3];
2428 const char *pszBldTrgCpu = argv[4];
2429 const char *pszBldType = argv[5];
2430 size_t cchBldTrg = strlen(pszBldTrg);
2431 size_t cchBldTrgArch = strlen(pszBldTrgArch);
2432 size_t cchBldTrgCpu = strlen(pszBldTrgCpu);
2433 size_t cchBldType = strlen(pszBldType);
2434 size_t cchMaxBld = cchBldTrg + cchBldTrgArch + cchBldTrgCpu + cchBldType; /* too big, but so what. */
2435 struct kbet_key
2436 {
2437 unsigned int cch;
2438 char *psz;
2439 } aKeys[6];
2440 unsigned int const cKeys = 6;
2441 unsigned int iKey;
2442 struct variable *pDefTemplate;
2443 struct variable *pProps;
2444 struct kbet_prop
2445 {
2446 const char *pch;
2447 unsigned int cch;
2448 enum kbet_prop_enum { kPropSingle, kPropDeferred, kPropAccumulateL, kPropAccumulateR }
2449 enmType;
2450 } *paProps;
2451 unsigned int cProps;
2452 unsigned int iProp;
2453 size_t cchMaxProp;
2454 struct variable *pVarTrg;
2455 struct variable *pVarSrc;
2456 const char *pszIter;
2457 const char *pszTarget;
2458 unsigned int cchTarget;
2459 char *pszSrc = 0;
2460 char *pszSrcRef = 0;
2461 char *pszSrcBuf = 0;
2462 size_t cchSrcBuf = 0;
2463 char *pszTrg = 0;
2464 size_t cchTrg = 0;
2465
2466 /*
2467 * Validate input.
2468 */
2469 if (pszVersion[0] != '1' || pszVersion[1])
2470 fatal(NULL, "%s: Unsupported version `%s'", pszFuncName, pszVersion);
2471
2472 if (!cchBldTrg)
2473 fatal(NULL, "%s: missing bldtrg", pszFuncName);
2474
2475 if (!cchBldTrgArch)
2476 fatal(NULL, "%s: missing bld_trg_arch", pszFuncName);
2477
2478 if (!cchBldTrgCpu)
2479 fatal(NULL, "%s: missing bld_trg_cpu", pszFuncName);
2480
2481 if (!cchBldType)
2482 fatal(NULL, "%s: missing bld_type", pszFuncName);
2483
2484 /*
2485 * Prepare the keywords, prepending dots for quicker copying.
2486 * This allows for an inner loop when processing properties, saving code
2487 * at the expense of a few xmallocs.
2488 */
2489 /* the first entry is empty. */
2490 aKeys[0].cch = 0;
2491 aKeys[0].psz = NULL;
2492
2493 /* .$(bld_type) */
2494 aKeys[1].cch = cchBldType + 1;
2495 aKeys[1].psz = xmalloc (aKeys[1].cch + 1);
2496 aKeys[1].psz[0] = '.';
2497 memcpy(aKeys[1].psz + 1, pszBldType, cchBldType + 1);
2498
2499 /* .$(bld_trg) */
2500 aKeys[2].cch = cchBldTrg + 1;
2501 aKeys[2].psz = xmalloc (aKeys[2].cch + 1);
2502 aKeys[2].psz[0] = '.';
2503 memcpy(aKeys[2].psz + 1, pszBldTrg, cchBldTrg + 1);
2504
2505 /* .$(bld_trg).$(bld_trg_arch) */
2506 aKeys[3].cch = cchBldTrg + 1 + cchBldTrgArch + 1;
2507 aKeys[3].psz = xmalloc (aKeys[3].cch + 1);
2508 aKeys[3].psz[0] = '.';
2509 memcpy(aKeys[3].psz + 1, pszBldTrg, cchBldTrg);
2510 aKeys[3].psz[1 + cchBldTrg] = '.';
2511 memcpy(aKeys[3].psz + 1 + cchBldTrg + 1, pszBldTrgArch, cchBldTrgArch + 1);
2512
2513 /* .$(bld_trg_cpu) */
2514 aKeys[4].cch = cchBldTrgCpu + 1;
2515 aKeys[4].psz = xmalloc (aKeys[4].cch + 1);
2516 aKeys[4].psz[0] = '.';
2517 memcpy(aKeys[4].psz + 1, pszBldTrgCpu, cchBldTrgCpu + 1);
2518
2519 /* .$(bld_trg_arch) */
2520 aKeys[5].cch = cchBldTrgArch + 1;
2521 aKeys[5].psz = xmalloc (aKeys[5].cch + 1);
2522 aKeys[5].psz[0] = '.';
2523 memcpy(aKeys[5].psz + 1, pszBldTrgArch, cchBldTrgArch + 1);
2524
2525
2526 /*
2527 * Prepare the properties, folding them into an array.
2528 * This way we won't have to reparse them for each an every target, though
2529 * it comes at the expense of one or more heap calls.
2530 */
2531#define PROP_ALLOC_INC 128
2532 iProp = 0;
2533 cProps = PROP_ALLOC_INC;
2534 paProps = xmalloc(sizeof(*pProps) * cProps);
2535
2536 pProps = kbuild_get_variable_n(ST("PROPS_SINGLE"));
2537 pszIter = pProps->value;
2538 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2539 {
2540 paProps[iProp].enmType = kPropSingle;
2541 if (++iProp >= cProps)
2542 {
2543 cProps += PROP_ALLOC_INC;
2544 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2545 }
2546
2547 }
2548
2549 pProps = kbuild_get_variable_n(ST("PROPS_DEFERRED"));
2550 pszIter = pProps->value;
2551 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2552 {
2553 paProps[iProp].enmType = kPropDeferred;
2554 if (++iProp >= cProps)
2555 {
2556 cProps += PROP_ALLOC_INC;
2557 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2558 }
2559 }
2560
2561 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_L"));
2562 pszIter = pProps->value;
2563 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2564 {
2565 paProps[iProp].enmType = kPropAccumulateL;
2566 if (++iProp >= cProps)
2567 {
2568 cProps += PROP_ALLOC_INC;
2569 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2570 }
2571 }
2572
2573 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_R"));
2574 pszIter = pProps->value;
2575 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2576 {
2577 paProps[iProp].enmType = kPropAccumulateR;
2578 if (++iProp >= cProps)
2579 {
2580 cProps += PROP_ALLOC_INC;
2581 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2582 }
2583 }
2584#undef PROP_ALLOC_INC
2585 cProps = iProp;
2586
2587 /* find the max prop length. */
2588 cchMaxProp = paProps[0].cch;
2589 while (--iProp > 0)
2590 if (paProps[iProp].cch > cchMaxProp)
2591 cchMaxProp = paProps[iProp].cch;
2592
2593 /*
2594 * Query and prepare (strip) the default template
2595 * (given by the TEMPLATE variable).
2596 */
2597 pDefTemplate = kbuild_lookup_variable_n(ST("TEMPLATE"));
2598 if (pDefTemplate)
2599 {
2600 if ( pDefTemplate->value_length
2601 && ( isspace(pDefTemplate->value[0])
2602 || isspace(pDefTemplate->value[pDefTemplate->value_length - 1])))
2603 {
2604 unsigned int off;
2605 if (pDefTemplate->rdonly_val)
2606 fatal(NULL, "%s: TEMPLATE is read-only", pszFuncName);
2607
2608 /* head */
2609 for (off = 0; isspace(pDefTemplate->value[off]); off++)
2610 /* nothing */;
2611 if (off)
2612 {
2613 pDefTemplate->value_length -= off;
2614 memmove(pDefTemplate->value, pDefTemplate->value + off, pDefTemplate->value_length + 1);
2615 }
2616
2617 /* tail */
2618 off = pDefTemplate->value_length;
2619 while (off > 0 && isspace(pDefTemplate->value[off - 1]))
2620 off--;
2621 pDefTemplate->value_length = off;
2622 pDefTemplate->value[off] = '\0';
2623 }
2624
2625 if (!pDefTemplate->value_length)
2626 pDefTemplate = NULL;
2627 }
2628
2629 /*
2630 * Iterate the target list.
2631 */
2632 pszIter = argv[1];
2633 while ((pszTarget = find_next_token(&pszIter, &cchTarget)))
2634 {
2635 char *pszTrgProp, *pszSrcProp;
2636 char *pszTrgKey, *pszSrcKey;
2637 struct variable *pTmpl;
2638 const char *pszTmpl;
2639 size_t cchTmpl, cchMax;
2640
2641 /* resize the target buffer. */
2642 cchMax = cchTarget + cchMaxProp + cchMaxBld + 10;
2643 if (cchTrg < cchMax)
2644 {
2645 cchTrg = (cchMax + 31U) & ~(size_t)31;
2646 pszTrg = xrealloc(pszTrg, cchTrg);
2647 }
2648
2649 /*
2650 * Query the TEMPLATE property, if not found or zero-length fall back on the default.
2651 */
2652 memcpy(pszTrg, pszTarget, cchTarget);
2653 pszTrgProp = pszTrg + cchTarget;
2654 memcpy(pszTrgProp, "_TEMPLATE", sizeof("_TEMPLATE"));
2655 pszTrgProp++; /* after '_'. */
2656
2657 /** @todo Change this to a recursive lookup with simplification below. That
2658 * will allow target_TEMPLATE = $(NO_SUCH_TEMPLATE) instead of having
2659 * to use target_TEMPLATE = DUMMY */
2660 pTmpl = kbuild_lookup_variable_n(pszTrg, cchTarget + sizeof("_TEMPLATE") - 1);
2661 if (!pTmpl || !pTmpl->value_length)
2662 {
2663 if (!pDefTemplate)
2664 continue; /* no template */
2665 pszTmpl = pDefTemplate->value;
2666 cchTmpl = pDefTemplate->value_length;
2667 }
2668 else
2669 {
2670 pszTmpl = pTmpl->value;
2671 cchTmpl = pTmpl->value_length;
2672 while (isspace(*pszTmpl))
2673 cchTmpl--, pszTmpl++;
2674 if (!cchTmpl)
2675 continue; /* no template */
2676 }
2677
2678 /* resize the source buffer. */
2679 cchMax = sizeof("TEMPLATE_") + cchTmpl + cchMaxProp + cchMaxBld + 10 + sizeof(void *);
2680 if (cchSrcBuf < cchMax)
2681 {
2682 cchSrcBuf = (cchMax + 31U) & ~(size_t)31;
2683 pszSrcBuf = xrealloc(pszSrcBuf, cchSrcBuf);
2684 pszSrc = pszSrcBuf + sizeof(void *); assert(sizeof(void *) >= 2);
2685 pszSrcRef = pszSrc - 2;
2686 pszSrcRef[0] = '$';
2687 pszSrcRef[1] = '(';
2688 }
2689
2690 /* prepare the source buffer */
2691 memcpy(pszSrc, "TEMPLATE_", sizeof("TEMPLATE_") - 1);
2692 pszSrcProp = pszSrc + sizeof("TEMPLATE_") - 1;
2693 memcpy(pszSrcProp, pszTmpl, cchTmpl);
2694 pszSrcProp += cchTmpl;
2695 *pszSrcProp++ = '_';
2696
2697 /*
2698 * Process properties.
2699 * Note! The single and deferred are handled in the same way now.
2700 */
2701#define BY_REF_LIMIT 64 /*(cchSrcVar * 4 > 64 ? cchSrcVar * 4 : 64)*/
2702
2703 for (iProp = 0; iProp < cProps; iProp++)
2704 {
2705 memcpy(pszTrgProp, paProps[iProp].pch, paProps[iProp].cch);
2706 pszTrgKey = pszTrgProp + paProps[iProp].cch;
2707
2708 memcpy(pszSrcProp, paProps[iProp].pch, paProps[iProp].cch);
2709 pszSrcKey = pszSrcProp + paProps[iProp].cch;
2710
2711 for (iKey = 0; iKey < cKeys; iKey++)
2712 {
2713 char *pszTrgEnd;
2714 size_t cchSrcVar;
2715
2716 /* lookup source, skip ahead if it doesn't exist. */
2717 memcpy(pszSrcKey, aKeys[iKey].psz, aKeys[iKey].cch);
2718 cchSrcVar = pszSrcKey - pszSrc + aKeys[iKey].cch;
2719 pszSrc[cchSrcVar] = '\0';
2720 pVarSrc = kbuild_query_recursive_variable_n(pszSrc, cchSrcVar);
2721 if (!pVarSrc)
2722 continue;
2723
2724 /* lookup target, skip ahead if it exists. */
2725 memcpy(pszTrgKey, aKeys[iKey].psz, aKeys[iKey].cch);
2726 pszTrgEnd = pszTrgKey + aKeys[iKey].cch;
2727 *pszTrgEnd = '\0';
2728 pVarTrg = kbuild_query_recursive_variable_n(pszTrg, pszTrgEnd - pszTrg);
2729
2730 switch (paProps[iProp].enmType)
2731 {
2732 case kPropAccumulateL:
2733 case kPropAccumulateR:
2734 if (pVarTrg)
2735 {
2736 /* Append to existing variable. If the source is recursive,
2737 or we append by reference, we'll have to make sure the
2738 target is recusive as well. */
2739 if ( !pVarTrg->recursive
2740 && ( pVarSrc->value_length >= BY_REF_LIMIT
2741 || pVarSrc->recursive))
2742 pVarTrg->recursive = 1;
2743
2744 if (pVarSrc->value_length < BY_REF_LIMIT)
2745 append_string_to_variable(pVarTrg, pVarSrc->value, pVarSrc->value_length,
2746 paProps[iProp].enmType == kPropAccumulateL /* append */);
2747 else
2748 {
2749 pszSrc[cchSrcVar] = ')';
2750 pszSrc[cchSrcVar + 1] = '\0';
2751 append_string_to_variable(pVarTrg, pszSrcRef, 2 + cchSrcVar + 1,
2752 paProps[iProp].enmType == kPropAccumulateL /* append */);
2753 }
2754 break;
2755 }
2756 /* else: the target variable doesn't exist, create it. */
2757 /* fall thru */
2758
2759 case kPropSingle:
2760 case kPropDeferred:
2761 if (pVarTrg)
2762 continue; /* skip ahead if it already exists. */
2763
2764 /* copy the variable if its short, otherwise reference it. */
2765 if (pVarSrc->value_length < BY_REF_LIMIT)
2766 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2767 pVarSrc->value, pVarSrc->value_length,
2768 1 /* duplicate_value */,
2769 o_file,
2770 pVarSrc->recursive,
2771 NULL /* flocp */);
2772 else
2773 {
2774 pszSrc[cchSrcVar] = ')';
2775 pszSrc[cchSrcVar + 1] = '\0';
2776 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2777 pszSrcRef, 2 + cchSrcVar + 1,
2778 1 /* duplicate_value */,
2779 o_file,
2780 1 /* recursive */,
2781 NULL /* flocp */);
2782 }
2783 break;
2784
2785 }
2786
2787 } /* foreach key */
2788 } /* foreach prop */
2789#undef BY_REF_LIMIT
2790 } /* foreach target */
2791
2792 /*
2793 * Cleanup.
2794 */
2795 free(pszSrcBuf);
2796 free(pszTrg);
2797 free(paProps);
2798 for (iKey = 1; iKey < cKeys; iKey++)
2799 free(aKeys[iKey].psz);
2800
2801 return o;
2802}
2803
2804#endif /* KMK_HELPERS */
2805
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