VirtualBox

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

Last change on this file since 3387 was 3322, checked in by bird, 4 years ago

kmk/kbuild: kbuild_apply_defpath must walk quoted file tokens rather than simple space separated tokens. Added find_next_file_token to do the parsing. Updated find_next_token_eos with correct variable expansion skipping.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use