VirtualBox

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

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

Updates

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