source: trunk/src/kmk/kbuild.c@ 2011

Last change on this file since 2011 was 2011, checked in by bird, 17 years ago

kmk,footer.kmk: New helper function 'kb-exp-tmpl', 10x faster than the gnu make script.

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