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

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

kbuild.c: Use append_string_to_variable in one more place.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 93.2 KB
Line 
1/* $Id: kbuild.c 2014 2008-11-01 14:50:42Z bird $ */
2/** @file
3 * kBuild specific make functionality.
4 */
5
6/*
7 * Copyright (c) 2006-2008 knut st. osmundsen <bird-kBuild-spam@anduin.net>
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, (unsigned int)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, (unsigned int)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, (unsigned int)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, (unsigned int)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 pVar = kbuild_query_recursive_variable_n("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1);
2039 if (pVar)
2040 {
2041 if (pVar->recursive)
2042 pVar = kbuild_simplify_variable(pVar);
2043 append_string_to_variable(pVar, pDep->value, pDep->value_length, 1 /* append */);
2044 }
2045 else
2046 define_variable_vl_global("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1,
2047 pDep->value, pDep->value_length,
2048 1 /* duplicate_value */,
2049 o_file,
2050 0 /* recursive */,
2051 NULL /* flocp */);
2052
2053 eval_include_dep(pDep->value, NILF, iVer >= 2 ? incdep_queue : incdep_read_it);
2054 }
2055
2056 /*
2057 # call the tool
2058 $(target)_$(source)_CMDS_ := $(TOOL_$(tool)_COMPILE_$(type)_CMDS)
2059 $(target)_$(source)_OUTPUT_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT)
2060 $(target)_$(source)_OUTPUT_MAYBE_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT_MAYBE)
2061 $(target)_$(source)_DEPEND_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPEND) $(deps) $(source)
2062 $(target)_$(source)_DEPORD_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPORD) $(dirdep)
2063 */
2064 cch = sizeof("TOOL_") + pTool->value_length + sizeof("_COMPILE_") + pType->value_length + sizeof("_OUTPUT_MAYBE");
2065 psz = pszSrcVar = alloca(cch);
2066 memcpy(psz, "TOOL_", sizeof("TOOL_") - 1); psz += sizeof("TOOL_") - 1;
2067 memcpy(psz, pTool->value, pTool->value_length); psz += pTool->value_length;
2068 memcpy(psz, "_COMPILE_", sizeof("_COMPILE_") - 1); psz += sizeof("_COMPILE_") - 1;
2069 memcpy(psz, pType->value, pType->value_length); psz += pType->value_length;
2070 pszSrc = psz;
2071
2072 cch = pTarget->value_length + 1 + pSource->value_length + sizeof("_OUTPUT_MAYBE_");
2073 psz = pszDstVar = alloca(cch);
2074 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
2075 *psz++ = '_';
2076 memcpy(psz, pSource->value, pSource->value_length); psz += pSource->value_length;
2077 pszDst = psz;
2078
2079 memcpy(pszSrc, "_CMDS", sizeof("_CMDS"));
2080 memcpy(pszDst, "_CMDS_", sizeof("_CMDS_"));
2081 pVar = kbuild_get_recursive_variable(pszSrcVar);
2082 do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2083 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2084
2085 memcpy(pszSrc, "_OUTPUT", sizeof("_OUTPUT"));
2086 memcpy(pszDst, "_OUTPUT_", sizeof("_OUTPUT_"));
2087 pVar = kbuild_get_recursive_variable(pszSrcVar);
2088 pOutput = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2089 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2090
2091 memcpy(pszSrc, "_OUTPUT_MAYBE", sizeof("_OUTPUT_MAYBE"));
2092 memcpy(pszDst, "_OUTPUT_MAYBE_", sizeof("_OUTPUT_MAYBE_"));
2093 pVar = kbuild_query_recursive_variable(pszSrcVar);
2094 if (pVar)
2095 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2096 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2097 else
2098 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, "", 0, 1, 0, o_file, f_simple, 0 /* !target_var */);
2099
2100 memcpy(pszSrc, "_DEPEND", sizeof("_DEPEND"));
2101 memcpy(pszDst, "_DEPEND_", sizeof("_DEPEND_"));
2102 pVar = kbuild_get_recursive_variable(pszSrcVar);
2103 psz = pszVal = xmalloc(pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length + 1);
2104 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2105 *psz++ = ' ';
2106 memcpy(psz, pDeps->value, pDeps->value_length); psz += pDeps->value_length;
2107 *psz++ = ' ';
2108 memcpy(psz, pSource->value, pSource->value_length + 1);
2109 do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length,
2110 !pVar->recursive && !pDeps->recursive && !pSource->recursive,
2111 pszVal, o_file, f_simple, 0 /* !target_var */);
2112
2113 memcpy(pszSrc, "_DEPORD", sizeof("_DEPORD"));
2114 memcpy(pszDst, "_DEPORD_", sizeof("_DEPORD_"));
2115 pVar = kbuild_get_recursive_variable(pszSrcVar);
2116 psz = pszVal = xmalloc(pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length + 1);
2117 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2118 *psz++ = ' ';
2119 memcpy(psz, pDirDep->value, pDirDep->value_length); psz += pDirDep->value_length;
2120 *psz++ = ' ';
2121 memcpy(psz, pOrderDeps->value, pOrderDeps->value_length + 1);
2122 do_variable_definition_2(NILF, pszDstVar, pszVal,
2123 pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length,
2124 !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive,
2125 pszVal, o_file, f_simple, 0 /* !target_var */);
2126
2127 /*
2128 _OUT_FILES += $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_)
2129 */
2130 pVar = kbuild_get_variable_n(ST("_OUT_FILES"));
2131 append_string_to_variable(pVar, pOutput->value, pOutput->value_length, 1 /* append */);
2132 if (pOutputMaybe->value_length)
2133 append_string_to_variable(pVar, pOutputMaybe->value, pOutputMaybe->value_length, 1 /* append */);
2134
2135 /*
2136 $(target)_OBJS_ += $(obj)
2137 */
2138 memcpy(pszDstVar + pTarget->value_length, "_OBJS_", sizeof("_OBJS_"));
2139 pVar = kbuild_query_recursive_variable_n(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1);
2140 if (pVar)
2141 {
2142 if (pVar->recursive)
2143 pVar = kbuild_simplify_variable(pVar);
2144 append_string_to_variable(pVar, pObj->value, pObj->value_length, 1 /* append */);
2145 }
2146 else
2147 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1,
2148 pObj->value, pObj->value_length,
2149 1 /* duplicate_value */,
2150 o_file,
2151 0 /* recursive */,
2152 NULL /* flocp */);
2153
2154 /*
2155 $(eval $(def_target_source_rule))
2156 */
2157 pVar = kbuild_get_recursive_variable("def_target_source_rule");
2158 pszVal = variable_expand_string_2 (o, pVar->value, pVar->value_length, &psz);
2159 assert(!((size_t)pszVal & 3));
2160
2161 install_variable_buffer(&pszSavedVarBuf, &cchSavedVarBuf);
2162 eval_buffer(pszVal, psz);
2163 restore_variable_buffer(pszSavedVarBuf, cchSavedVarBuf);
2164
2165 kbuild_put_sdks(&Sdks);
2166 (void)pszFuncName;
2167
2168 *pszVal = '\0';
2169 return pszVal;
2170}
2171
2172/*
2173
2174## Inherit one template property in a non-accumulative manner.
2175# @param $(prop) Property name
2176# @param $(target) Target name
2177# @todo fix the precedence order for some properties.
2178define def_inherit_template_one
2179ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2180ifndef $(target)_$(prop)
2181$(target)_$(prop) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2182endif
2183endif
2184ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2185ifndef $(target)_$(prop).$(bld_trg)
2186$(target)_$(prop).$(bld_trg) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2187endif
2188endif
2189ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2190ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2191$(target)_$(prop).$(bld_trg).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2192endif
2193endif
2194ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2195ifndef $(target)_$(prop).$(bld_trg_arch)
2196$(target)_$(prop).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2197endif
2198endif
2199ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2200ifndef $(target)_$(prop).$(bld_trg_cpu)
2201$(target)_$(prop).$(bld_trg_cpu) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2202endif
2203endif
2204endef
2205
2206## Inherit one template property in a non-accumulative manner, deferred expansion.
2207# @param 1: $(prop) Property name
2208# @param 2: $(target) Target name
2209# @todo fix the precedence order for some properties.
2210# @remark this define relies on double evaluation
2211define def_inherit_template_one_deferred
2212ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2213ifndef $(target)_$(prop)
2214$(target)_$(prop) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2215endif
2216endif
2217ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2218ifndef $(target)_$(prop).$(bld_trg)
2219$(target)_$(prop).$(bld_trg) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2220endif
2221endif
2222ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2223ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2224$(target)_$(prop).$(bld_trg).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2225endif
2226endif
2227ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2228ifndef $(target)_$(prop).$(bld_trg_arch)
2229$(target)_$(prop).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2230endif
2231endif
2232ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2233ifndef $(target)_$(prop).$(bld_trg_cpu)
2234$(target)_$(prop).$(bld_trg_cpu) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2235endif
2236endif
2237endef
2238
2239## Inherit one acculumlative template property where the 'most significant' items are at the left end.
2240# @param $(prop) Property name
2241# @param $(target) Target name
2242define def_inherit_template_one_accumulate_l
2243ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2244 ifeq ($$(flavor $(target)_$(prop)),simple)
2245 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2246 endif
2247$(target)_$(prop) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2248endif
2249ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2250 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2251 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2252 endif
2253$(target)_$(prop).$(KBUILD_TYPE) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2254endif
2255ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2256 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2257 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2258 endif
2259$(target)_$(prop).$(bld_trg) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2260endif
2261ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2262 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2263 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2264 endif
2265$(target)_$(prop).$(bld_trg).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2266endif
2267ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2268 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2269 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2270 endif
2271$(target)_$(prop).$(bld_trg_cpu) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2272endif
2273ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2274 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2275 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2276 endif
2277$(target)_$(prop).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2278endif
2279endef
2280
2281## Inherit one acculumlative template property where the 'most significant' items are at the right end.
2282# @param $(prop) Property name
2283# @param $(target) Target name
2284define def_inherit_template_one_accumulate_r
2285ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2286 ifeq ($$(flavor $(target)_$(prop)),simple)
2287 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2288 endif
2289$(target)_$(prop) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2290endif
2291ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2292 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2293 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2294 endif
2295$(target)_$(prop).$(KBUILD_TYPE) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2296endif
2297ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2298 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2299 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2300 endif
2301$(target)_$(prop).$(bld_trg) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2302endif
2303ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2304 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2305 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2306 endif
2307$(target)_$(prop).$(bld_trg).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2308endif
2309ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2310 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2311 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2312 endif
2313$(target)_$(prop).$(bld_trg_cpu) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2314endif
2315ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2316 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2317 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2318 endif
2319$(target)_$(prop).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2320endif
2321endef
2322
2323
2324## Inherit template properties for on target.
2325# @param $(target) Target name.
2326define def_inherit_template
2327# sanity check.
2328ifdef _$(target)_ALREADY_PROCESSED
2329 $(error kBuild: The target $(target) appears more than once in the target lists! Please correct the makefile(s))
2330endif
2331_$(target)_ALREADY_PROCESSED := 1
2332
2333# Inherit any default template.
2334ifdef TEMPLATE
2335ifeq ($($(target)_TEMPLATE),)
2336$(eval $(target)_TEMPLATE:=$(TEMPLATE))
2337endif
2338endif
2339# Expand the template if specified.
2340ifneq ($($(target)_TEMPLATE),)
2341$(foreach prop,$(PROPS_SINGLE),$(evalval def_inherit_template_one))
2342$(foreach prop,$(PROPS_DEFERRED),$(eval $(def_inherit_template_one_deferred))) # exploits the 2 evaluation, so no value!
2343$(foreach prop,$(PROPS_ACCUMULATE_L),$(eval $(def_inherit_template_one_accumulate_l))) # += works fine without value
2344$(foreach prop,$(PROPS_ACCUMULATE_R),$(eval $(def_inherit_template_one_accumulate_r))) # use <= (kmk addition)
2345endif
2346endef
2347
2348
2349Invoked like this:
2350 $(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE))
2351*/
2352char *
2353func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName)
2354{
2355 const char *pszVersion = argv[0];
2356 const char *pszBldTrg = argv[2];
2357 const char *pszBldTrgArch = argv[3];
2358 const char *pszBldTrgCpu = argv[4];
2359 const char *pszBldType = argv[5];
2360 size_t cchBldTrg = strlen(pszBldTrg);
2361 size_t cchBldTrgArch = strlen(pszBldTrgArch);
2362 size_t cchBldTrgCpu = strlen(pszBldTrgCpu);
2363 size_t cchBldType = strlen(pszBldType);
2364 size_t cchMaxBld = cchBldTrg + cchBldTrgArch + cchBldTrgCpu + cchBldType; /* too big, but so what. */
2365 struct kbet_key
2366 {
2367 unsigned int cch;
2368 char *psz;
2369 } aKeys[6];
2370 unsigned int const cKeys = 6;
2371 unsigned int iKey;
2372 struct variable *pDefTemplate;
2373 struct variable *pProps;
2374 struct kbet_prop
2375 {
2376 const char *pch;
2377 unsigned int cch;
2378 enum kbet_prop_enum { kPropSingle, kPropDeferred, kPropAccumulateL, kPropAccumulateR }
2379 enmType;
2380 } *paProps;
2381 unsigned int cProps;
2382 unsigned int iProp;
2383 size_t cchMaxProp;
2384 struct variable *pVarTrg;
2385 struct variable *pVarSrc;
2386 const char *pszIter;
2387 const char *pszTarget;
2388 unsigned int cchTarget;
2389 char *pszSrc = 0;
2390 char *pszSrcRef = 0;
2391 char *pszSrcBuf = 0;
2392 size_t cchSrcBuf = 0;
2393 char *pszTrg = 0;
2394 size_t cchTrg = 0;
2395
2396 /*
2397 * Validate input.
2398 */
2399 if (pszVersion[0] != '1' || pszVersion[1])
2400 fatal(NULL, "%s: Unsupported version `%s'", pszFuncName, pszVersion);
2401
2402 if (!cchBldTrg)
2403 fatal(NULL, "%s: missing bldtrg", pszFuncName);
2404
2405 if (!cchBldTrgArch)
2406 fatal(NULL, "%s: missing bld_trg_arch", pszFuncName);
2407
2408 if (!cchBldTrgCpu)
2409 fatal(NULL, "%s: missing bld_trg_cpu", pszFuncName);
2410
2411 if (!cchBldType)
2412 fatal(NULL, "%s: missing bld_type", pszFuncName);
2413
2414 /*
2415 * Prepare the keywords, prepending dots for quicker copying.
2416 * This allows for an inner loop when processing properties, saving code
2417 * at the expense of a few xmallocs.
2418 */
2419 /* the first entry is empty. */
2420 aKeys[0].cch = 0;
2421 aKeys[0].psz = NULL;
2422
2423 aKeys[1].cch = cchBldType + 1;
2424 aKeys[1].psz = xmalloc (aKeys[1].cch + 1);
2425 aKeys[1].psz[0] = '.';
2426 memcpy(aKeys[1].psz + 1, pszBldType, cchBldType + 1);
2427
2428 aKeys[2].cch = cchBldTrg + 1;
2429 aKeys[2].psz = xmalloc (aKeys[2].cch + 1);
2430 aKeys[2].psz[0] = '.';
2431 memcpy(aKeys[2].psz + 1, pszBldTrg, cchBldTrg + 1);
2432
2433 aKeys[3].cch = cchBldTrg + 1 + cchBldTrgArch + 1;
2434 aKeys[3].psz = xmalloc (aKeys[3].cch + 1);
2435 aKeys[3].psz[0] = '.';
2436 memcpy(aKeys[3].psz + 1, pszBldTrg, cchBldTrg);
2437 aKeys[3].psz[1 + cchBldTrg] = '.';
2438 memcpy(aKeys[3].psz + 1 + cchBldTrg + 1, pszBldTrgArch, cchBldTrgArch + 1);
2439
2440 aKeys[4].cch = cchBldTrgCpu + 1;
2441 aKeys[4].psz = xmalloc (aKeys[4].cch + 1);
2442 aKeys[4].psz[0] = '.';
2443 memcpy(aKeys[4].psz + 1, pszBldTrgCpu, cchBldTrgCpu + 1);
2444
2445 aKeys[5].cch = cchBldTrgArch + 1;
2446 aKeys[5].psz = xmalloc (aKeys[5].cch + 1);
2447 aKeys[5].psz[0] = '.';
2448 memcpy(aKeys[5].psz + 1, pszBldTrgArch, cchBldTrgArch + 1);
2449
2450
2451 /*
2452 * Prepare the properties, folding them into an array.
2453 * This way we won't have to reparse them for each an every target, though
2454 * it comes at the expense of one or more heap calls.
2455 */
2456#define PROP_ALLOC_INC 128
2457 iProp = 0;
2458 cProps = PROP_ALLOC_INC;
2459 paProps = xmalloc(sizeof(*pProps) * cProps);
2460
2461 pProps = kbuild_get_variable_n(ST("PROPS_SINGLE"));
2462 pszIter = pProps->value;
2463 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2464 {
2465 paProps[iProp].enmType = kPropSingle;
2466 if (++iProp >= cProps)
2467 {
2468 cProps += PROP_ALLOC_INC;
2469 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2470 }
2471
2472 }
2473
2474 pProps = kbuild_get_variable_n(ST("PROPS_DEFERRED"));
2475 pszIter = pProps->value;
2476 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2477 {
2478 paProps[iProp].enmType = kPropDeferred;
2479 if (++iProp >= cProps)
2480 {
2481 cProps += PROP_ALLOC_INC;
2482 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2483 }
2484 }
2485
2486 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_L"));
2487 pszIter = pProps->value;
2488 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2489 {
2490 paProps[iProp].enmType = kPropAccumulateL;
2491 if (++iProp >= cProps)
2492 {
2493 cProps += PROP_ALLOC_INC;
2494 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2495 }
2496 }
2497
2498 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_R"));
2499 pszIter = pProps->value;
2500 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2501 {
2502 paProps[iProp].enmType = kPropAccumulateR;
2503 if (++iProp >= cProps)
2504 {
2505 cProps += PROP_ALLOC_INC;
2506 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2507 }
2508 }
2509#undef PROP_ALLOC_INC
2510 cProps = iProp;
2511
2512 /* find the max prop length. */
2513 cchMaxProp = paProps[0].cch;
2514 while (--iProp > 0)
2515 if (paProps[iProp].cch > cchMaxProp)
2516 cchMaxProp = paProps[iProp].cch;
2517
2518 /*
2519 * Query and prepare (strip) the default template
2520 * (given by the TEMPLATE variable).
2521 */
2522 pDefTemplate = kbuild_lookup_variable_n(ST("TEMPLATE"));
2523 if (pDefTemplate)
2524 {
2525 if ( pDefTemplate->value_length
2526 && ( isspace(pDefTemplate->value[0])
2527 || isspace(pDefTemplate->value[pDefTemplate->value_length - 1])))
2528 {
2529 unsigned int off;
2530 if (pDefTemplate->rdonly_val)
2531 fatal(NULL, "%s: TEMPLATE is read-only", pszFuncName);
2532
2533 /* head */
2534 for (off = 0; isspace(pDefTemplate->value[off]); off++)
2535 /* nothing */;
2536 if (off)
2537 {
2538 pDefTemplate->value_length -= off;
2539 memmove(pDefTemplate->value, pDefTemplate->value + off, pDefTemplate->value_length + 1);
2540 }
2541
2542 /* tail */
2543 off = pDefTemplate->value_length;
2544 while (off > 0 && isspace(pDefTemplate->value[off - 1]))
2545 off--;
2546 pDefTemplate->value_length = off;
2547 pDefTemplate->value[off] = '\0';
2548 }
2549
2550 if (!pDefTemplate->value_length)
2551 pDefTemplate = NULL;
2552 }
2553
2554 /*
2555 * Iterate the target list.
2556 */
2557 pszIter = argv[1];
2558 while ((pszTarget = find_next_token(&pszIter, &cchTarget)))
2559 {
2560 char *pszTrgProp, *pszSrcProp;
2561 char *pszTrgKey, *pszSrcKey;
2562 struct variable *pTmpl;
2563 const char *pszTmpl;
2564 size_t cchTmpl, cchMax;
2565
2566 /* resize the target buffer. */
2567 cchMax = cchTarget + cchMaxProp + cchMaxBld + 10;
2568 if (cchTrg < cchMax)
2569 {
2570 cchTrg = (cchMax + 31U) & ~(size_t)31;
2571 pszTrg = xrealloc(pszTrg, cchTrg);
2572 }
2573
2574 /*
2575 * Query the TEMPLATE property, if not found or zero-length fall back on the default.
2576 */
2577 memcpy(pszTrg, pszTarget, cchTarget);
2578 pszTrgProp = pszTrg + cchTarget;
2579 memcpy(pszTrgProp, "_TEMPLATE", sizeof("_TEMPLATE"));
2580 pszTrgProp++; /* after '_'. */
2581
2582 /** @todo Change this to a recursive lookup with simplification below. That
2583 * will allow target_TEMPLATE = $(NO_SUCH_TEMPLATE) instead of having
2584 * to use target_TEMPLATE = DUMMY */
2585 pTmpl = kbuild_lookup_variable_n(pszTrg, cchTarget + sizeof("_TEMPLATE") - 1);
2586 if (!pTmpl || !pTmpl->value_length)
2587 {
2588 if (!pDefTemplate)
2589 continue; /* no template */
2590 pszTmpl = pDefTemplate->value;
2591 cchTmpl = pDefTemplate->value_length;
2592 }
2593 else
2594 {
2595 pszTmpl = pTmpl->value;
2596 cchTmpl = pTmpl->value_length;
2597 while (isspace(*pszTmpl))
2598 cchTmpl--, pszTmpl++;
2599 if (!cchTmpl)
2600 continue; /* no template */
2601 }
2602
2603 /* resize the source buffer. */
2604 cchMax = sizeof("TEMPLATE_") + cchTmpl + cchMaxProp + cchMaxBld + 10 + sizeof(void *);
2605 if (cchSrcBuf < cchMax)
2606 {
2607 cchSrcBuf = (cchMax + 31U) & ~(size_t)31;
2608 pszSrcBuf = xrealloc(pszSrcBuf, cchSrcBuf);
2609 pszSrc = pszSrcBuf + sizeof(void *); assert(sizeof(void *) >= 2);
2610 pszSrcRef = pszSrc - 2;
2611 pszSrcRef[0] = '$';
2612 pszSrcRef[1] = '(';
2613 }
2614
2615 /* prepare the source buffer */
2616 memcpy(pszSrc, "TEMPLATE_", sizeof("TEMPLATE_") - 1);
2617 pszSrcProp = pszSrc + sizeof("TEMPLATE_") - 1;
2618 memcpy(pszSrcProp, pszTmpl, cchTmpl);
2619 pszSrcProp += cchTmpl;
2620 *pszSrcProp++ = '_';
2621
2622 /*
2623 * Process properties.
2624 * Note! The single and deferred are handled in the same way now.
2625 */
2626#define BY_REF_LIMIT 64 /*(cchSrcVar * 4 > 64 ? cchSrcVar * 4 : 64)*/
2627
2628 for (iProp = 0; iProp < cProps; iProp++)
2629 {
2630 memcpy(pszTrgProp, paProps[iProp].pch, paProps[iProp].cch);
2631 pszTrgKey = pszTrgProp + paProps[iProp].cch;
2632
2633 memcpy(pszSrcProp, paProps[iProp].pch, paProps[iProp].cch);
2634 pszSrcKey = pszSrcProp + paProps[iProp].cch;
2635
2636 for (iKey = 0; iKey < cKeys; iKey++)
2637 {
2638 char *pszTrgEnd;
2639 size_t cchSrcVar;
2640
2641 /* lookup source, skip ahead if it doesn't exist. */
2642 memcpy(pszSrcKey, aKeys[iKey].psz, aKeys[iKey].cch);
2643 cchSrcVar = pszSrcKey - pszSrc + aKeys[iKey].cch;
2644 pszSrc[cchSrcVar] = '\0';
2645 pVarSrc = kbuild_query_recursive_variable_n(pszSrc, cchSrcVar);
2646 if (!pVarSrc)
2647 continue;
2648
2649 /* lookup target, skip ahead if it exists. */
2650 memcpy(pszTrgKey, aKeys[iKey].psz, aKeys[iKey].cch);
2651 pszTrgEnd = pszTrgKey + aKeys[iKey].cch;
2652 *pszTrgEnd = '\0';
2653 pVarTrg = kbuild_query_recursive_variable_n(pszTrg, pszTrgEnd - pszTrg);
2654
2655 switch (paProps[iProp].enmType)
2656 {
2657 case kPropAccumulateL:
2658 case kPropAccumulateR:
2659 if (pVarTrg)
2660 {
2661 /* Append to existing variable. If the source is recursive,
2662 or we append by reference, we'll have to make sure the
2663 target is recusive as well. */
2664 if ( !pVarTrg->recursive
2665 && ( pVarSrc->value_length >= BY_REF_LIMIT
2666 || pVarSrc->recursive))
2667 pVarTrg->recursive = 1;
2668
2669 if (pVarSrc->value_length < BY_REF_LIMIT)
2670 append_string_to_variable(pVarTrg, pVarSrc->value, pVarSrc->value_length,
2671 paProps[iProp].enmType == kPropAccumulateL /* append */);
2672 else
2673 {
2674 pszSrc[cchSrcVar] = ')';
2675 pszSrc[cchSrcVar + 1] = '\0';
2676 append_string_to_variable(pVarTrg, pszSrcRef, 2 + cchSrcVar + 1,
2677 paProps[iProp].enmType == kPropAccumulateL /* append */);
2678 }
2679 break;
2680 }
2681 /* else: the target variable doesn't exist, create it. */
2682 /* fall thru */
2683
2684 case kPropSingle:
2685 case kPropDeferred:
2686 if (pVarTrg)
2687 continue; /* skip ahead if it already exists. */
2688
2689 /* copy the variable if its short, otherwise reference it. */
2690 if (pVarSrc->value_length < BY_REF_LIMIT)
2691 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2692 pVarSrc->value, pVarSrc->value_length,
2693 1 /* duplicate_value */,
2694 o_file,
2695 pVarSrc->recursive,
2696 NULL /* flocp */);
2697 else
2698 {
2699 pszSrc[cchSrcVar] = ')';
2700 pszSrc[cchSrcVar + 1] = '\0';
2701 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2702 pszSrcRef, 2 + cchSrcVar + 1,
2703 1 /* duplicate_value */,
2704 o_file,
2705 1 /* recursive */,
2706 NULL /* flocp */);
2707 }
2708 break;
2709
2710 }
2711
2712 } /* foreach key */
2713 } /* foreach prop */
2714#undef BY_REF_LIMIT
2715 } /* foreach target */
2716
2717 /*
2718 * Cleanup.
2719 */
2720 free(pszSrcBuf);
2721 free(pszTrg);
2722 free(paProps);
2723 for (iKey = 1; iKey < cKeys; iKey++)
2724 free(aKeys[iKey].psz);
2725
2726 return o;
2727}
2728
2729#endif /* KMK_HELPERS */
2730
Note: See TracBrowser for help on using the repository browser.