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