VirtualBox

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

Last change on this file since 2837 was 2837, checked in by bird, 8 years ago

kbuild_apply_defpath: Fixed heap corruption when DEFPATH isn't absolute.

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