VirtualBox

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

Last change on this file was 3425, checked in by bird, 4 years ago

kmk: Optimized func_kbuild_source_one by caching the target level part of the result in $(target)_2_TTPROP_TYPE variables. We'll do this regardless of caller version (lazy bird).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use