VirtualBox

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

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

kbuild_lookup_variable_n: Don't simplify SDK_ReorderCompilerIncs_INCS variables, they must be expanded dynamically all the time to support different compilers.

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

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