kbuild.c: added todo for #80.
[kbuild-mirror.git] / src / kmk / kbuild.c
blobad107427c6ec745a686778ab3fa637cb28daca09
1 /* $Id$ */
2 /** @file
3 * kBuild specific make functionality.
4 */
6 /*
7 * Copyright (c) 2006-2008 knut st. osmundsen <bird-src-spam@anduin.net>
9 * This file is part of kBuild.
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.
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.
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/>
26 /* No GNU coding style here! */
28 /*******************************************************************************
29 * Header Files *
30 *******************************************************************************/
31 #include "make.h"
32 #include "filedef.h"
33 #include "variable.h"
34 #include "dep.h"
35 #include "debug.h"
36 #ifdef WINDOWS32
37 # include "pathstuff.h"
38 # include <Windows.h>
39 #endif
40 #if defined(__APPLE__)
41 # include <mach-o/dyld.h>
42 #endif
44 #include "kbuild.h"
46 #include <assert.h>
49 /*******************************************************************************
50 * Defined Constants And Macros *
51 *******************************************************************************/
52 /** Helper for passing a string constant to kbuild_get_variable_n. */
53 #define ST(strconst) strconst, sizeof(strconst) - 1
55 #if 1
56 # define my_memcpy(dst, src, len) \
57 do { \
58 if (len > 8) \
59 memcpy(dst, src, len); \
60 else \
61 switch (len) \
62 { \
63 case 8: dst[7] = src[7]; \
64 case 7: dst[6] = src[6]; \
65 case 6: dst[5] = src[5]; \
66 case 5: dst[4] = src[4]; \
67 case 4: dst[3] = src[3]; \
68 case 3: dst[2] = src[2]; \
69 case 2: dst[1] = src[1]; \
70 case 1: dst[0] = src[0]; \
71 case 0: break; \
72 } \
73 } while (0)
74 #elif defined(__GNUC__)
75 # define my_memcpy __builtin_memcpy
76 #elif defined(_MSC_VER)
77 # pragma instrinic(memcpy)
78 # define my_memcpy memcpy
79 #endif
82 /*******************************************************************************
83 * Global Variables *
84 *******************************************************************************/
85 /** The argv[0] passed to main. */
86 static const char *g_pszExeName;
87 /** The initial working directory. */
88 static char *g_pszInitialCwd;
91 /**
92 * Initialize kBuild stuff.
94 * @param argc Number of arguments to main().
95 * @param argv The main() argument vector.
97 void init_kbuild(int argc, char **argv)
99 int rc;
100 PATH_VAR(szTmp);
103 * Get the initial cwd for use in my_abspath.
105 #ifdef WINDOWS32
106 if (getcwd_fs(szTmp, GET_PATH_MAX) != 0)
107 #else
108 if (getcwd(szTmp, GET_PATH_MAX) != 0)
109 #endif
110 g_pszInitialCwd = xstrdup(szTmp);
111 else
112 fatal(NILF, _("getcwd failed"));
115 * Determin the executable name.
117 rc = -1;
118 #if defined(__APPLE__)
120 const char *pszImageName = _dyld_get_image_name(0);
121 if (pszImageName)
123 size_t cchImageName = strlen(pszImageName);
124 if (cchImageName < GET_PATH_MAX)
126 memcpy(szTmp, pszImageName, cchImageName + 1);
127 rc = 0;
132 #elif defined(__FreeBSD__)
133 rc = readlink("/proc/curproc/file", szTmp, GET_PATH_MAX - 1);
134 if (rc < 0 || rc == GET_PATH_MAX - 1)
135 rc = -1;
136 else
137 szTmp[rc] = '\0';
139 #elif defined(__gnu_linux__) /** @todo find proper define... */
140 rc = readlink("/proc/self/exe", szTmp, GET_PATH_MAX - 1);
141 if (rc < 0 || rc == GET_PATH_MAX - 1)
142 rc = -1;
143 else
144 szTmp[rc] = '\0';
146 #elif defined(__OS2__)
147 _execname(szTmp, GET_PATH_MAX);
148 rc = 0;
150 #elif defined(__sun__)
152 char szTmp2[64];
153 snprintf(szTmp2, sizeof(szTmp2), "/proc/%ld/path/a.out", (long)getpid());
154 rc = readlink(szTmp2, szTmp, GET_PATH_MAX - 1);
155 if (rc < 0 || rc == GET_PATH_MAX - 1)
156 rc = -1;
157 else
158 szTmp[rc] = '\0';
161 #elif defined(WINDOWS32)
162 if (GetModuleFileName(GetModuleHandle(NULL), szTmp, GET_PATH_MAX))
163 rc = 0;
165 #endif
167 #if !defined(__OS2__) && !defined(WINDOWS32)
168 /* fallback, try use the path to locate the binary. */
169 if ( rc < 0
170 && access(argv[0], X_OK))
172 size_t cchArgv0 = strlen(argv[0]);
173 const char *pszPath = getenv("PATH");
174 char *pszCopy = xstrdup(pszPath ? pszPath : ".");
175 char *psz = pszCopy;
176 while (*psz)
178 size_t cch;
179 char *pszEnd = strchr(psz, PATH_SEPARATOR_CHAR);
180 if (!pszEnd)
181 pszEnd = strchr(psz, '\0');
182 cch = pszEnd - psz;
183 if (cch + cchArgv0 + 2 <= GET_PATH_MAX)
185 memcpy(szTmp, psz, cch);
186 szTmp[cch] = '/';
187 memcpy(&szTmp[cch + 1], argv[0], cchArgv0 + 1);
188 if (!access(szTmp, X_OK))
190 rc = 0;
191 break;
195 /* next */
196 psz = pszEnd;
197 while (*psz == PATH_SEPARATOR_CHAR)
198 psz++;
200 free(pszCopy);
202 #endif
204 if (rc < 0)
205 g_pszExeName = argv[0];
206 else
207 g_pszExeName = xstrdup(szTmp);
209 (void)argc;
214 * Wrapper that ensures correct starting_directory.
216 static char *my_abspath(const char *pszIn, char *pszOut)
218 char *pszSaved, *pszRet;
220 pszSaved = starting_directory;
221 starting_directory = g_pszInitialCwd;
222 pszRet = abspath(pszIn, pszOut);
223 starting_directory = pszSaved;
225 return pszRet;
230 * Determin the KBUILD_PATH value.
232 * @returns Pointer to static a buffer containing the value (consider it read-only).
234 const char *get_kbuild_path(void)
236 static const char *s_pszPath = NULL;
237 if (!s_pszPath)
239 PATH_VAR(szTmpPath);
240 const char *pszEnvVar = getenv("KBUILD_PATH");
241 if ( !pszEnvVar
242 || !my_abspath(pszEnvVar, szTmpPath))
244 pszEnvVar = getenv("PATH_KBUILD");
245 if ( !pszEnvVar
246 || !my_abspath(pszEnvVar, szTmpPath))
248 #ifdef KBUILD_PATH
249 return s_pszPath = KBUILD_PATH;
250 #else
251 /* $(abspath $(KBUILD_BIN_PATH)/../..)*/
252 size_t cch = strlen(get_kbuild_bin_path());
253 char *pszTmp2 = alloca(cch + sizeof("/../.."));
254 strcat(strcpy(pszTmp2, get_kbuild_bin_path()), "/../..");
255 if (!my_abspath(pszTmp2, szTmpPath))
256 fatal(NILF, _("failed to determin KBUILD_PATH"));
257 #endif
260 s_pszPath = xstrdup(szTmpPath);
262 return s_pszPath;
267 * Determin the KBUILD_BIN_PATH value.
269 * @returns Pointer to static a buffer containing the value (consider it read-only).
271 const char *get_kbuild_bin_path(void)
273 static const char *s_pszPath = NULL;
274 if (!s_pszPath)
276 PATH_VAR(szTmpPath);
278 const char *pszEnvVar = getenv("KBUILD_BIN_PATH");
279 if ( !pszEnvVar
280 || !my_abspath(pszEnvVar, szTmpPath))
282 pszEnvVar = getenv("PATH_KBUILD_BIN");
283 if ( !pszEnvVar
284 || !my_abspath(pszEnvVar, szTmpPath))
286 #ifdef KBUILD_PATH
287 return s_pszPath = KBUILD_BIN_PATH;
288 #else
289 /* $(abspath $(dir $(ARGV0)).) */
290 size_t cch = strlen(g_pszExeName);
291 char *pszTmp2 = alloca(cch + sizeof("."));
292 char *pszSep = pszTmp2 + cch - 1;
293 memcpy(pszTmp2, g_pszExeName, cch);
294 # ifdef HAVE_DOS_PATHS
295 while (pszSep >= pszTmp2 && *pszSep != '/' && *pszSep != '\\' && *pszSep != ':')
296 # else
297 while (pszSep >= pszTmp2 && *pszSep != '/')
298 # endif
299 pszSep--;
300 if (pszSep >= pszTmp2)
301 strcpy(pszSep + 1, ".");
302 else
303 strcpy(pszTmp2, ".");
305 if (!my_abspath(pszTmp2, szTmpPath))
306 fatal(NILF, _("failed to determin KBUILD_BIN_PATH (pszTmp2=%s szTmpPath=%s)"), pszTmp2, szTmpPath);
307 #endif /* !KBUILD_PATH */
310 s_pszPath = xstrdup(szTmpPath);
312 return s_pszPath;
317 * Determin the location of default kBuild shell.
319 * @returns Pointer to static a buffer containing the location (consider it read-only).
321 const char *get_default_kbuild_shell(void)
323 static char *s_pszDefaultShell = NULL;
324 if (!s_pszDefaultShell)
326 #if defined(__OS2__) || defined(_WIN32) || defined(WINDOWS32)
327 static const char s_szShellName[] = "/kmk_ash.exe";
328 #else
329 static const char s_szShellName[] = "/kmk_ash";
330 #endif
331 const char *pszBin = get_kbuild_bin_path();
332 size_t cchBin = strlen(pszBin);
333 s_pszDefaultShell = xmalloc(cchBin + sizeof(s_szShellName));
334 memcpy(s_pszDefaultShell, pszBin, cchBin);
335 memcpy(&s_pszDefaultShell[cchBin], s_szShellName, sizeof(s_szShellName));
337 return s_pszDefaultShell;
340 #ifdef KMK_HELPERS
343 * Applies the specified default path to any relative paths in *ppsz.
345 * @param pDefPath The default path.
346 * @param ppsz Pointer to the string pointer. If we expand anything, *ppsz
347 * will be replaced and the caller is responsible for calling free() on it.
348 * @param pcch IN: *pcch contains the current string length.
349 * OUT: *pcch contains the new string length.
350 * @param pcchAlloc *pcchAlloc contains the length allocated for the string. Can be NULL.
351 * @param fCanFree Whether *ppsz should be freed when we replace it.
353 static void
354 kbuild_apply_defpath(struct variable *pDefPath, char **ppsz, unsigned int *pcch, unsigned int *pcchAlloc, int fCanFree)
356 const char *pszIterator;
357 const char *pszInCur;
358 unsigned int cchInCur;
359 unsigned int cRelativePaths;
362 * The first pass, count the relative paths.
364 cRelativePaths = 0;
365 pszIterator = *ppsz;
366 while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
368 /* is relative? */
369 #ifdef HAVE_DOS_PATHS
370 if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':'))
371 #else
372 if (pszInCur[0] != '/')
373 #endif
374 cRelativePaths++;
378 * The second pass construct the new string.
380 if (cRelativePaths)
382 const size_t cchOut = *pcch + cRelativePaths * (pDefPath->value_length + 1) + 1;
383 char *pszOut = xmalloc(cchOut);
384 char *pszOutCur = pszOut;
385 const char *pszInNextCopy = *ppsz;
387 cRelativePaths = 0;
388 pszIterator = *ppsz;
389 while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
391 /* is relative? */
392 #ifdef HAVE_DOS_PATHS
393 if (pszInCur[0] != '/' && pszInCur[0] != '\\' && (cchInCur < 2 || pszInCur[1] != ':'))
394 #else
395 if (pszInCur[0] != '/')
396 #endif
398 PATH_VAR(szAbsPathIn);
399 PATH_VAR(szAbsPathOut);
401 if (pDefPath->value_length + cchInCur + 1 >= GET_PATH_MAX)
402 continue;
404 /* Create the abspath input. */
405 memcpy(szAbsPathIn, pDefPath->value, pDefPath->value_length);
406 szAbsPathIn[pDefPath->value_length] = '/';
407 memcpy(&szAbsPathIn[pDefPath->value_length + 1], pszInCur, cchInCur);
408 szAbsPathIn[pDefPath->value_length + 1 + cchInCur] = '\0';
410 if (abspath(szAbsPathIn, szAbsPathOut) != NULL)
412 const size_t cchAbsPathOut = strlen(szAbsPathOut);
413 assert(cchAbsPathOut <= pDefPath->value_length + 1 + cchInCur);
415 /* copy leading input */
416 if (pszInCur != pszInNextCopy)
418 const size_t cchCopy = pszInCur - pszInNextCopy;
419 memcpy(pszOutCur, pszInNextCopy, cchCopy);
420 pszOutCur += cchCopy;
422 pszInNextCopy = pszInCur + cchInCur;
424 /* copy out the abspath. */
425 memcpy(pszOutCur, szAbsPathOut, cchAbsPathOut);
426 pszOutCur += cchAbsPathOut;
430 /* the final copy (includes the nil). */
431 cchInCur = *ppsz + *pcch - pszInNextCopy;
432 memcpy(pszOutCur, pszInNextCopy, cchInCur);
433 pszOutCur += cchInCur;
434 *pszOutCur = '\0';
435 assert((size_t)(pszOutCur - pszOut) < cchOut);
437 /* set return values */
438 if (fCanFree)
439 free(*ppsz);
440 *ppsz = pszOut;
441 *pcch = pszOutCur - pszOut;
442 if (pcchAlloc)
443 *pcchAlloc = cchOut;
448 * Gets a variable that must exist.
449 * Will cause a fatal failure if the variable doesn't exist.
451 * @returns Pointer to the variable.
452 * @param pszName The variable name.
453 * @param cchName The name length.
455 MY_INLINE struct variable *
456 kbuild_get_variable_n(const char *pszName, size_t cchName)
458 struct variable *pVar = lookup_variable(pszName, cchName);
459 if (!pVar)
460 fatal(NILF, _("variable `%.*s' isn't defined!"), (int)cchName, pszName);
461 if (pVar->recursive)
462 fatal(NILF, _("variable `%.*s' is defined as `recursive' instead of `simple'!"), (int)cchName, pszName);
464 MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length,
465 ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name));
466 return pVar;
471 * Gets a variable that must exist and can be recursive.
472 * Will cause a fatal failure if the variable doesn't exist.
474 * @returns Pointer to the variable.
475 * @param pszName The variable name.
477 static struct variable *
478 kbuild_get_recursive_variable(const char *pszName)
480 struct variable *pVar = lookup_variable(pszName, strlen(pszName));
481 if (!pVar)
482 fatal(NILF, _("variable `%s' isn't defined!"), pszName);
484 MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length,
485 ("%u != %u %s\n", pVar->value_length, (unsigned int)strlen(pVar->value), pVar->name));
486 return pVar;
491 * Gets a variable that doesn't have to exit, but if it does can be recursive.
493 * @returns Pointer to the variable.
494 * NULL if not found.
495 * @param pszName The variable name. Doesn't need to be terminated.
496 * @param cchName The name length.
498 static struct variable *
499 kbuild_query_recursive_variable_n(const char *pszName, size_t cchName)
501 struct variable *pVar = lookup_variable(pszName, cchName);
502 MY_ASSERT_MSG(!pVar || strlen(pVar->value) == pVar->value_length,
503 ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name));
504 return pVar;
509 * Gets a variable that doesn't have to exit, but if it does can be recursive.
511 * @returns Pointer to the variable.
512 * NULL if not found.
513 * @param pszName The variable name.
515 static struct variable *
516 kbuild_query_recursive_variable(const char *pszName)
518 return kbuild_query_recursive_variable_n(pszName, strlen(pszName));
523 * Converts the specified variable into a 'simple' one.
524 * @returns pVar.
525 * @param pVar The variable.
527 static struct variable *
528 kbuild_simplify_variable(struct variable *pVar)
530 if (memchr(pVar->value, '$', pVar->value_length))
532 unsigned int value_len;
533 char *pszExpanded = allocated_variable_expand_2(pVar->value, pVar->value_length, &value_len);
534 #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
535 if (pVar->rdonly_val)
536 pVar->rdonly_val = 0;
537 else
538 #endif
539 free(pVar->value);
540 assert(pVar->origin != o_automatic);
541 pVar->value = pszExpanded;
542 pVar->value_length = value_len;
543 pVar->value_alloc_len = value_len + 1;
545 pVar->recursive = 0;
546 return pVar;
551 * Looks up a variable.
552 * The value_length field is valid upon successful return.
554 * @returns Pointer to the variable. NULL if not found.
555 * @param pszName The variable name.
556 * @param cchName The name length.
558 MY_INLINE struct variable *
559 kbuild_lookup_variable_n(const char *pszName, size_t cchName)
561 struct variable *pVar = lookup_variable(pszName, cchName);
562 if (pVar)
564 MY_ASSERT_MSG(strlen(pVar->value) == pVar->value_length,
565 ("%u != %u %.*s\n", pVar->value_length, (unsigned int)strlen(pVar->value), (int)cchName, pVar->name));
567 /* Make sure the variable is simple, convert it if necessary. */
568 if (pVar->recursive)
569 kbuild_simplify_variable(pVar);
571 return pVar;
576 * Looks up a variable.
577 * The value_length field is valid upon successful return.
579 * @returns Pointer to the variable. NULL if not found.
580 * @param pszName The variable name.
582 MY_INLINE struct variable *
583 kbuild_lookup_variable(const char *pszName)
585 return kbuild_lookup_variable_n(pszName, strlen(pszName));
590 * Looks up a variable and applies default a path to all relative paths.
591 * The value_length field is valid upon successful return.
593 * @returns Pointer to the variable. NULL if not found.
594 * @param pDefPath The default path.
595 * @param pszName The variable name.
596 * @param cchName The name length.
598 MY_INLINE struct variable *
599 kbuild_lookup_variable_defpath_n(struct variable *pDefPath, const char *pszName, size_t cchName)
601 struct variable *pVar = kbuild_lookup_variable_n(pszName, cchName);
602 if (pVar && pDefPath)
604 assert(pVar->origin != o_automatic);
605 #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
606 assert(!pVar->rdonly_val);
607 #endif
608 kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1);
610 return pVar;
615 * Looks up a variable and applies default a path to all relative paths.
616 * The value_length field is valid upon successful return.
618 * @returns Pointer to the variable. NULL if not found.
619 * @param pDefPath The default path.
620 * @param pszName The variable name.
622 MY_INLINE struct variable *
623 kbuild_lookup_variable_defpath(struct variable *pDefPath, const char *pszName)
625 struct variable *pVar = kbuild_lookup_variable(pszName);
626 if (pVar && pDefPath)
628 assert(pVar->origin != o_automatic);
629 #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
630 assert(!pVar->rdonly_val);
631 #endif
632 kbuild_apply_defpath(pDefPath, &pVar->value, &pVar->value_length, &pVar->value_alloc_len, 1);
634 return pVar;
639 * Gets the first defined property variable.
641 static struct variable *
642 kbuild_first_prop(struct variable *pTarget, struct variable *pSource,
643 struct variable *pTool, struct variable *pType,
644 struct variable *pBldTrg, struct variable *pBldTrgArch,
645 const char *pszPropF1, char cchPropF1,
646 const char *pszPropF2, char cchPropF2,
647 const char *pszVarName)
649 struct variable *pVar;
650 size_t cchBuf;
651 char *pszBuf;
652 char *psz, *psz1, *psz2, *psz3, *psz4, *pszEnd;
654 /* calc and allocate a too big name buffer. */
655 cchBuf = cchPropF2 + 1
656 + cchPropF1 + 1
657 + pTarget->value_length + 1
658 + pSource->value_length + 1
659 + (pTool ? pTool->value_length + 1 : 0)
660 + pType->value_length + 1
661 + pBldTrg->value_length + 1
662 + pBldTrgArch->value_length + 1;
663 pszBuf = xmalloc(cchBuf);
665 #define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0)
666 #define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0)
667 #define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0)
668 #define ADD_CH(ch) do { *psz++ = (ch); } while (0)
671 * $(target)_$(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
673 psz = pszBuf;
674 ADD_VAR(pTarget);
675 ADD_CH('_');
676 ADD_VAR(pSource);
677 ADD_CH('_');
678 psz2 = psz;
679 ADD_VAR(pType);
680 ADD_STR(pszPropF2, cchPropF2);
681 psz3 = psz;
682 ADD_CH('.');
683 ADD_VAR(pBldTrg);
684 psz4 = psz;
685 ADD_CH('.');
686 ADD_VAR(pBldTrgArch);
687 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
689 /* $(target)_$(source)_$(type)$(propf2).$(bld_trg) */
690 if (!pVar)
691 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
693 /* $(target)_$(source)_$(type)$(propf2) */
694 if (!pVar)
695 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
698 * $(target)_$(source)_$(propf2).$(bld_trg).$(bld_trg_arch)
700 if (!pVar)
702 psz = psz2;
703 ADD_STR(pszPropF2, cchPropF2);
704 psz3 = psz;
705 ADD_CH('.');
706 ADD_VAR(pBldTrg);
707 psz4 = psz;
708 ADD_CH('.');
709 ADD_VAR(pBldTrgArch);
710 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
712 /* $(target)_$(source)_$(propf2).$(bld_trg) */
713 if (!pVar)
714 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
716 /* $(target)_$(source)_$(propf2) */
717 if (!pVar)
718 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
723 * $(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
725 if (!pVar)
727 psz = pszBuf;
728 ADD_VAR(pSource);
729 ADD_CH('_');
730 psz2 = psz;
731 ADD_VAR(pType);
732 ADD_STR(pszPropF2, cchPropF2);
733 psz3 = psz;
734 ADD_CH('.');
735 ADD_VAR(pBldTrg);
736 psz4 = psz;
737 ADD_CH('.');
738 ADD_VAR(pBldTrgArch);
739 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
741 /* $(source)_$(type)$(propf2).$(bld_trg) */
742 if (!pVar)
743 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
745 /* $(source)_$(type)$(propf2) */
746 if (!pVar)
747 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
750 * $(source)_$(propf2).$(bld_trg).$(bld_trg_arch)
752 if (!pVar)
754 psz = psz2;
755 ADD_STR(pszPropF2, cchPropF2);
756 psz3 = psz;
757 ADD_CH('.');
758 ADD_VAR(pBldTrg);
759 psz4 = psz;
760 ADD_CH('.');
761 ADD_VAR(pBldTrgArch);
762 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
764 /* $(source)_$(propf2).$(bld_trg) */
765 if (!pVar)
766 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
768 /* $(source)_$(propf2) */
769 if (!pVar)
770 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
775 * $(target)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
777 if (!pVar)
779 psz = pszBuf;
780 ADD_VAR(pTarget);
781 ADD_CH('_');
782 psz2 = psz;
783 ADD_VAR(pType);
784 ADD_STR(pszPropF2, cchPropF2);
785 psz3 = psz;
786 ADD_CH('.');
787 ADD_VAR(pBldTrg);
788 psz4 = psz;
789 ADD_CH('.');
790 ADD_VAR(pBldTrgArch);
791 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
793 /* $(target)_$(type)$(propf2).$(bld_trg) */
794 if (!pVar)
795 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
797 /* $(target)_$(type)$(propf2) */
798 if (!pVar)
799 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
801 /* $(target)_$(propf2).$(bld_trg).$(bld_trg_arch) */
802 if (!pVar)
804 psz = psz2;
805 ADD_STR(pszPropF2, cchPropF2);
806 psz3 = psz;
807 ADD_CH('.');
808 ADD_VAR(pBldTrg);
809 psz4 = psz;
810 ADD_CH('.');
811 ADD_VAR(pBldTrgArch);
812 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
815 /* $(target)_$(propf2).$(bld_trg) */
816 if (!pVar)
817 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
819 /* $(target)_$(propf2) */
820 if (!pVar)
821 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
825 * TOOL_$(tool)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
827 if (!pVar && pTool)
829 psz = pszBuf;
830 ADD_CSTR("TOOL_");
831 ADD_VAR(pTool);
832 ADD_CH('_');
833 psz2 = psz;
834 ADD_VAR(pType);
835 ADD_STR(pszPropF2, cchPropF2);
836 psz3 = psz;
837 ADD_CH('.');
838 ADD_VAR(pBldTrg);
839 psz4 = psz;
840 ADD_CH('.');
841 ADD_VAR(pBldTrgArch);
842 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
844 /* TOOL_$(tool)_$(type)$(propf2).$(bld_trg) */
845 if (!pVar)
846 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
848 /* TOOL_$(tool)_$(type)$(propf2) */
849 if (!pVar)
850 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
852 /* TOOL_$(tool)_$(propf2).$(bld_trg).$(bld_trg_arch) */
853 if (!pVar)
855 psz = psz2;
856 ADD_STR(pszPropF2, cchPropF2);
857 psz3 = psz;
858 ADD_CH('.');
859 ADD_VAR(pBldTrg);
860 psz4 = psz;
861 ADD_CH('.');
862 ADD_VAR(pBldTrgArch);
863 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
865 /* TOOL_$(tool)_$(propf2).$(bld_trg) */
866 if (!pVar)
867 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
869 /* TOOL_$(tool)_$(propf2) */
870 if (!pVar)
871 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
876 * $(type)$(propf1).$(bld_trg).$(bld_trg_arch)
878 if (!pVar)
880 psz = pszBuf;
881 ADD_VAR(pType);
882 ADD_STR(pszPropF1, cchPropF1);
883 psz3 = psz;
884 ADD_CH('.');
885 ADD_VAR(pBldTrg);
886 psz4 = psz;
887 ADD_CH('.');
888 ADD_VAR(pBldTrgArch);
889 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf);
891 /* $(type)$(propf1).$(bld_trg) */
892 if (!pVar)
893 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
895 /* $(type)$(propf1) */
896 if (!pVar)
897 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
900 * $(propf1).$(bld_trg).$(bld_trg_arch)
902 if (!pVar)
904 psz1 = pszBuf + pType->value_length;
905 pVar = kbuild_lookup_variable_n(psz1, psz - psz1);
907 /* $(propf1).$(bld_trg) */
908 if (!pVar)
909 pVar = kbuild_lookup_variable_n(psz1, psz4 - psz1);
911 /* $(propf1) */
912 if (!pVar)
913 pVar = kbuild_lookup_variable_n(pszPropF1, cchPropF1);
916 free(pszBuf);
917 #undef ADD_VAR
918 #undef ADD_STR
919 #undef ADD_CSTR
920 #undef ADD_CH
922 if (pVar)
924 /* strip it */
925 psz = pVar->value;
926 pszEnd = psz + pVar->value_length;
927 while (isblank((unsigned char)*psz))
928 psz++;
929 while (pszEnd > psz && isblank((unsigned char)pszEnd[-1]))
930 pszEnd--;
931 if (pszEnd > psz)
933 char chSaved = *pszEnd;
934 *pszEnd = '\0';
935 pVar = define_variable_vl(pszVarName, strlen(pszVarName), psz, pszEnd - psz,
936 1 /* duplicate */, o_local, 0 /* !recursive */);
937 *pszEnd = chSaved;
938 if (pVar)
939 return pVar;
942 return NULL;
947 _SOURCE_TOOL = $(strip $(firstword \
948 $($(target)_$(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
949 $($(target)_$(source)_$(type)TOOL.$(bld_trg)) \
950 $($(target)_$(source)_$(type)TOOL) \
951 $($(target)_$(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \
952 $($(target)_$(source)_TOOL.$(bld_trg)) \
953 $($(target)_$(source)_TOOL) \
954 $($(source)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
955 $($(source)_$(type)TOOL.$(bld_trg)) \
956 $($(source)_$(type)TOOL) \
957 $($(source)_TOOL.$(bld_trg).$(bld_trg_arch)) \
958 $($(source)_TOOL.$(bld_trg)) \
959 $($(source)_TOOL) \
960 $($(target)_$(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
961 $($(target)_$(type)TOOL.$(bld_trg)) \
962 $($(target)_$(type)TOOL) \
963 $($(target)_TOOL.$(bld_trg).$(bld_trg_arch)) \
964 $($(target)_TOOL.$(bld_trg)) \
965 $($(target)_TOOL) \
966 $($(type)TOOL.$(bld_trg).$(bld_trg_arch)) \
967 $($(type)TOOL.$(bld_trg)) \
968 $($(type)TOOL) \
969 $(TOOL.$(bld_trg).$(bld_trg_arch)) \
970 $(TOOL.$(bld_trg)) \
971 $(TOOL) ))
973 static struct variable *
974 kbuild_get_source_tool(struct variable *pTarget, struct variable *pSource, struct variable *pType,
975 struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName)
977 struct variable *pVar = kbuild_first_prop(pTarget, pSource, NULL, pType, pBldTrg, pBldTrgArch,
978 "TOOL", sizeof("TOOL") - 1,
979 "TOOL", sizeof("TOOL") - 1,
980 pszVarName);
981 if (!pVar)
982 fatal(NILF, _("no tool for source `%s' in target `%s'!"), pSource->value, pTarget->value);
983 return pVar;
987 /* Implements _SOURCE_TOOL. */
988 char *
989 func_kbuild_source_tool(char *o, char **argv, const char *pszFuncName)
991 struct variable *pVar = kbuild_get_source_tool(kbuild_get_variable_n(ST("target")),
992 kbuild_get_variable_n(ST("source")),
993 kbuild_get_variable_n(ST("type")),
994 kbuild_get_variable_n(ST("bld_trg")),
995 kbuild_get_variable_n(ST("bld_trg_arch")),
996 argv[0]);
997 if (pVar)
998 o = variable_buffer_output(o, pVar->value, pVar->value_length);
999 (void)pszFuncName;
1000 return o;
1005 /* This has been extended a bit, it's now identical to _SOURCE_TOOL.
1006 $(firstword \
1007 $($(target)_$(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1008 $($(target)_$(source)_OBJSUFF.$(bld_trg))\
1009 $($(target)_$(source)_OBJSUFF)\
1010 $($(source)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1011 $($(source)_OBJSUFF.$(bld_trg))\
1012 $($(source)_OBJSUFF)\
1013 $($(target)_OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1014 $($(target)_OBJSUFF.$(bld_trg))\
1015 $($(target)_OBJSUFF)\
1016 $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg).$(bld_trg_arch))\
1017 $(TOOL_$(tool)_$(type)OBJSUFF.$(bld_trg))\
1018 $(TOOL_$(tool)_$(type)OBJSUFF)\
1019 $(SUFF_OBJ))
1021 static struct variable *
1022 kbuild_get_object_suffix(struct variable *pTarget, struct variable *pSource,
1023 struct variable *pTool, struct variable *pType,
1024 struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName)
1026 struct variable *pVar = kbuild_first_prop(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch,
1027 "SUFF_OBJ", sizeof("SUFF_OBJ") - 1,
1028 "OBJSUFF", sizeof("OBJSUFF") - 1,
1029 pszVarName);
1030 if (!pVar)
1031 fatal(NILF, _("no OBJSUFF attribute or SUFF_OBJ default for source `%s' in target `%s'!"), pSource->value, pTarget->value);
1032 return pVar;
1036 /* */
1037 char *
1038 func_kbuild_object_suffix(char *o, char **argv, const char *pszFuncName)
1040 struct variable *pVar = kbuild_get_object_suffix(kbuild_get_variable_n(ST("target")),
1041 kbuild_get_variable_n(ST("source")),
1042 kbuild_get_variable_n(ST("tool")),
1043 kbuild_get_variable_n(ST("type")),
1044 kbuild_get_variable_n(ST("bld_trg")),
1045 kbuild_get_variable_n(ST("bld_trg_arch")),
1046 argv[0]);
1047 if (pVar)
1048 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1049 (void)pszFuncName;
1050 return o;
1056 ## Figure out where to put object files.
1057 # @param $1 source file
1058 # @param $2 normalized main target
1059 # @remark There are two major hacks here:
1060 # 1. Source files in the output directory are translated into a gen/ subdir.
1061 # 2. Catch anyone specifying $(PATH_SUB_CURRENT)/sourcefile.c.
1062 _OBJECT_BASE = $(PATH_TARGET)/$(2)/$(call no-root-slash,$(call no-drive,$(basename \
1063 $(patsubst $(PATH_ROOT)/%,%,$(patsubst $(PATH_SUB_CURRENT)/%,%,$(patsubst $(PATH_TARGET)/$(2)/%,gen/%,$(1)))))))
1065 static struct variable *
1066 kbuild_get_object_base(struct variable *pTarget, struct variable *pSource, const char *pszVarName)
1068 struct variable *pPathTarget = kbuild_get_variable_n(ST("PATH_TARGET"));
1069 struct variable *pPathRoot = kbuild_get_variable_n(ST("PATH_ROOT"));
1070 struct variable *pPathSubCur = kbuild_get_variable_n(ST("PATH_SUB_CURRENT"));
1071 const char *pszSrcPrefix = NULL;
1072 size_t cchSrcPrefix = 0;
1073 size_t cchSrc = 0;
1074 const char *pszSrcEnd;
1075 char *pszSrc;
1076 char *pszResult;
1077 char *psz;
1078 char *pszDot;
1079 size_t cch;
1082 * Strip the source filename of any uncessary leading path and root specs.
1084 /* */
1085 if ( pSource->value_length > pPathTarget->value_length
1086 && !strncmp(pSource->value, pPathTarget->value, pPathTarget->value_length))
1088 pszSrc = pSource->value + pPathTarget->value_length;
1089 pszSrcPrefix = "gen/";
1090 cchSrcPrefix = sizeof("gen/") - 1;
1091 if ( *pszSrc == '/'
1092 && !strncmp(pszSrc + 1, pTarget->value, pTarget->value_length)
1093 && ( pszSrc[pTarget->value_length + 1] == '/'
1094 || pszSrc[pTarget->value_length + 1] == '\0'))
1095 pszSrc += 1 + pTarget->value_length;
1097 else if ( pSource->value_length > pPathRoot->value_length
1098 && !strncmp(pSource->value, pPathRoot->value, pPathRoot->value_length))
1100 pszSrc = pSource->value + pPathRoot->value_length;
1101 if ( *pszSrc == '/'
1102 && !strncmp(pszSrc + 1, pPathSubCur->value, pPathSubCur->value_length)
1103 && ( pszSrc[pPathSubCur->value_length + 1] == '/'
1104 || pszSrc[pPathSubCur->value_length + 1] == '\0'))
1105 pszSrc += 1 + pPathSubCur->value_length;
1107 else
1108 pszSrc = pSource->value;
1110 /* skip root specification */
1111 #ifdef HAVE_DOS_PATHS
1112 if (isalpha(pszSrc[0]) && pszSrc[1] == ':')
1113 pszSrc += 2;
1114 #endif
1115 while (*pszSrc == '/'
1116 #ifdef HAVE_DOS_PATHS
1117 || *pszSrc == '\\'
1118 #endif
1120 pszSrc++;
1122 /* drop the source extension. */
1123 pszSrcEnd = pSource->value + pSource->value_length;
1124 for (;;)
1126 pszSrcEnd--;
1127 if ( pszSrcEnd <= pszSrc
1128 || *pszSrcEnd == '/'
1129 #ifdef HAVE_DOS_PATHS
1130 || *pszSrcEnd == '\\'
1131 || *pszSrcEnd == ':'
1132 #endif
1135 pszSrcEnd = pSource->value + pSource->value_length;
1136 break;
1138 if (*pszSrcEnd == '.')
1139 break;
1143 * Assemble the string on the heap and define the objbase variable
1144 * which we then return.
1146 cchSrc = pszSrcEnd - pszSrc;
1147 cch = pPathTarget->value_length
1148 + 1 /* slash */
1149 + pTarget->value_length
1150 + 1 /* slash */
1151 + cchSrcPrefix
1152 + cchSrc
1153 + 1;
1154 psz = pszResult = xmalloc(cch);
1156 memcpy(psz, pPathTarget->value, pPathTarget->value_length); psz += pPathTarget->value_length;
1157 *psz++ = '/';
1158 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
1159 *psz++ = '/';
1160 if (pszSrcPrefix)
1162 memcpy(psz, pszSrcPrefix, cchSrcPrefix);
1163 psz += cchSrcPrefix;
1165 pszDot = psz;
1166 memcpy(psz, pszSrc, cchSrc); psz += cchSrc;
1167 *psz = '\0';
1169 /* convert '..' path elements in the source to 'dt'. */
1170 while ((pszDot = memchr(pszDot, '.', psz - pszDot)) != NULL)
1172 if ( pszDot[1] == '.'
1173 && ( pszDot == psz
1174 || pszDot[-1] == '/'
1175 #ifdef HAVE_DOS_PATHS
1176 || pszDot[-1] == '\\'
1177 || pszDot[-1] == ':'
1178 #endif
1180 && ( !pszDot[2]
1181 || pszDot[2] == '/'
1182 #ifdef HAVE_DOS_PATHS
1183 || pszDot[2] == '\\'
1184 || pszDot[2] == ':'
1185 #endif
1189 *pszDot++ = 'd';
1190 *pszDot++ = 't';
1192 else
1193 pszDot++;
1197 * Define the variable in the current set and return it.
1199 return define_variable_vl(pszVarName, strlen(pszVarName), pszResult, cch - 1,
1200 0 /* use pszResult */, o_local, 0 /* !recursive */);
1204 /* Implements _OBJECT_BASE. */
1205 char *
1206 func_kbuild_object_base(char *o, char **argv, const char *pszFuncName)
1208 struct variable *pVar = kbuild_get_object_base(kbuild_lookup_variable("target"),
1209 kbuild_lookup_variable("source"),
1210 argv[0]);
1211 if (pVar)
1212 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1213 (void)pszFuncName;
1214 return o;
1219 struct kbuild_sdks
1221 char *apsz[4];
1222 struct variable *pa;
1223 unsigned c;
1224 unsigned iGlobal;
1225 unsigned cGlobal;
1226 unsigned iTarget;
1227 unsigned cTarget;
1228 unsigned iSource;
1229 unsigned cSource;
1230 unsigned iTargetSource;
1231 unsigned cTargetSource;
1232 unsigned int cchMax;
1236 /* Fills in the SDK struct (remember to free it). */
1237 static void
1238 kbuild_get_sdks(struct kbuild_sdks *pSdks, struct variable *pTarget, struct variable *pSource,
1239 struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch)
1241 unsigned i;
1242 unsigned j;
1243 size_t cchTmp, cch;
1244 char *pszTmp;
1245 unsigned cchCur;
1246 char *pszCur;
1247 const char *pszIterator;
1249 /** @todo rewrite this to avoid sprintf and allocated_varaible_expand_2. */
1251 /* basic init. */
1252 pSdks->cchMax = 0;
1253 pSdks->pa = NULL;
1254 pSdks->c = 0;
1255 i = 0;
1257 /* determin required tmp variable name space. */
1258 cchTmp = sizeof("$(__SDKS) $(__SDKS.) $(__SDKS.) $(__SDKS.) $(__SDKS..)")
1259 + (pTarget->value_length + pSource->value_length) * 5
1260 + pBldType->value_length
1261 + pBldTrg->value_length
1262 + pBldTrgArch->value_length
1263 + pBldTrg->value_length + pBldTrgArch->value_length;
1264 pszTmp = alloca(cchTmp);
1266 /* the global sdks. */
1267 pSdks->iGlobal = i;
1268 pSdks->cGlobal = 0;
1269 cch = sprintf(pszTmp, "$(SDKS) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s) $(SDKS.%s.%s)",
1270 pBldType->value,
1271 pBldTrg->value,
1272 pBldTrgArch->value,
1273 pBldTrg->value, pBldTrgArch->value);
1274 pszIterator = pSdks->apsz[0] = allocated_variable_expand_2(pszTmp, cch, NULL);
1275 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1276 pSdks->cGlobal++;
1277 i += pSdks->cGlobal;
1279 /* the target sdks.*/
1280 pSdks->iTarget = i;
1281 pSdks->cTarget = 0;
1282 cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)",
1283 pTarget->value,
1284 pTarget->value, pBldType->value,
1285 pTarget->value, pBldTrg->value,
1286 pTarget->value, pBldTrgArch->value,
1287 pTarget->value, pBldTrg->value, pBldTrgArch->value);
1288 pszIterator = pSdks->apsz[1] = allocated_variable_expand_2(pszTmp, cch, NULL);
1289 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1290 pSdks->cTarget++;
1291 i += pSdks->cTarget;
1293 /* the source sdks.*/
1294 pSdks->iSource = i;
1295 pSdks->cSource = 0;
1296 cch = sprintf(pszTmp, "$(%s_SDKS) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s) $(%s_SDKS.%s.%s)",
1297 pSource->value,
1298 pSource->value, pBldType->value,
1299 pSource->value, pBldTrg->value,
1300 pSource->value, pBldTrgArch->value,
1301 pSource->value, pBldTrg->value, pBldTrgArch->value);
1302 pszIterator = pSdks->apsz[2] = allocated_variable_expand_2(pszTmp, cch, NULL);
1303 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1304 pSdks->cSource++;
1305 i += pSdks->cSource;
1307 /* the target + source sdks. */
1308 pSdks->iTargetSource = i;
1309 pSdks->cTargetSource = 0;
1310 cch = sprintf(pszTmp, "$(%s_%s_SDKS) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s) $(%s_%s_SDKS.%s.%s)",
1311 pTarget->value, pSource->value,
1312 pTarget->value, pSource->value, pBldType->value,
1313 pTarget->value, pSource->value, pBldTrg->value,
1314 pTarget->value, pSource->value, pBldTrgArch->value,
1315 pTarget->value, pSource->value, pBldTrg->value, pBldTrgArch->value);
1316 assert(cch < cchTmp); (void)cch;
1317 pszIterator = pSdks->apsz[3] = allocated_variable_expand_2(pszTmp, cch, NULL);
1318 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1319 pSdks->cTargetSource++;
1320 i += pSdks->cTargetSource;
1322 pSdks->c = i;
1323 if (!i)
1324 return;
1327 * Allocate the variable array and create the variables.
1329 pSdks->pa = (struct variable *)xmalloc(sizeof(pSdks->pa[0]) * i);
1330 memset(pSdks->pa, 0, sizeof(pSdks->pa[0]) * i);
1331 for (i = j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++)
1333 pszIterator = pSdks->apsz[j];
1334 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1336 pSdks->pa[i].value = pszCur;
1337 pSdks->pa[i].value_length = cchCur;
1338 i++;
1341 assert(i == pSdks->c);
1343 /* terminate them (find_next_token won't work if we terminate them in the previous loop). */
1344 while (i-- > 0)
1346 pSdks->pa[i].value[pSdks->pa[i].value_length] = '\0';
1348 /* calc the max variable length too. */
1349 if (pSdks->cchMax < (unsigned int)pSdks->pa[i].value_length)
1350 pSdks->cchMax = pSdks->pa[i].value_length;
1355 /* releases resources allocated in the kbuild_get_sdks. */
1356 static void
1357 kbuild_put_sdks(struct kbuild_sdks *pSdks)
1359 unsigned j;
1360 for (j = 0; j < sizeof(pSdks->apsz) / sizeof(pSdks->apsz[0]); j++)
1361 free(pSdks->apsz[j]);
1362 free(pSdks->pa);
1366 /* this kind of stuff:
1368 defs := $(kb-src-exp defs)
1369 $(TOOL_$(tool)_DEFS)\
1370 $(TOOL_$(tool)_DEFS.$(bld_type))\
1371 $(TOOL_$(tool)_DEFS.$(bld_trg))\
1372 $(TOOL_$(tool)_DEFS.$(bld_trg_arch))\
1373 $(TOOL_$(tool)_DEFS.$(bld_trg).$(bld_trg_arch))\
1374 $(TOOL_$(tool)_DEFS.$(bld_trg_cpu))\
1375 $(TOOL_$(tool)_$(type)DEFS)\
1376 $(TOOL_$(tool)_$(type)DEFS.$(bld_type))\
1377 $(foreach sdk, $(SDKS.$(bld_trg)) \
1378 $(SDKS.$(bld_trg).$(bld_trg_arch)) \
1379 $(SDKS.$(bld_type)) \
1380 $(SDKS),\
1381 $(SDK_$(sdk)_DEFS)\
1382 $(SDK_$(sdk)_DEFS.$(bld_type))\
1383 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1384 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1385 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1386 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1387 $(SDK_$(sdk)_$(type)DEFS)\
1388 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1389 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1390 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1391 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1392 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1393 $(DEFS)\
1394 $(DEFS.$(bld_type))\
1395 $(DEFS.$(bld_trg))\
1396 $(DEFS.$(bld_trg_arch))\
1397 $(DEFS.$(bld_trg).$(bld_trg_arch))\
1398 $(DEFS.$(bld_trg_cpu))\
1399 $($(type)DEFS)\
1400 $($(type)DEFS.$(bld_type))\
1401 $($(type)DEFS.$(bld_trg))\
1402 $($(type)DEFS.$(bld_trg_arch))\
1403 $($(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1404 $($(type)DEFS.$(bld_trg_cpu))\
1405 $(foreach sdk, $($(target)_SDKS.$(bld_trg)) \
1406 $($(target)_SDKS.$(bld_trg).$(bld_trg_arch)) \
1407 $($(target)_SDKS.$(bld_type)) \
1408 $($(target)_SDKS),\
1409 $(SDK_$(sdk)_DEFS)\
1410 $(SDK_$(sdk)_DEFS.$(bld_type))\
1411 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1412 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1413 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1414 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1415 $(SDK_$(sdk)_$(type)DEFS)\
1416 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1417 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1418 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1419 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1420 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1421 $($(target)_DEFS)\
1422 $($(target)_DEFS.$(bld_type))\
1423 $($(target)_DEFS.$(bld_trg))\
1424 $($(target)_DEFS.$(bld_trg_arch))\
1425 $($(target)_DEFS.$(bld_trg).$(bld_trg_arch))\
1426 $($(target)_DEFS.$(bld_trg_cpu))\
1427 $($(target)_$(type)DEFS)\
1428 $($(target)_$(type)DEFS.$(bld_type))\
1429 $($(target)_$(type)DEFS.$(bld_trg))\
1430 $($(target)_$(type)DEFS.$(bld_trg_arch))\
1431 $($(target)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1432 $($(target)_$(type)DEFS.$(bld_trg_cpu))\
1433 $(foreach sdk, $($(source)_SDKS.$(bld_trg)) \
1434 $($(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \
1435 $($(source)_SDKS.$(bld_type)) \
1436 $($(source)_SDKS),\
1437 $(SDK_$(sdk)_DEFS)\
1438 $(SDK_$(sdk)_DEFS.$(bld_type))\
1439 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1440 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1441 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1442 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1443 $(SDK_$(sdk)_$(type)DEFS)\
1444 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1445 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1446 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1447 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1448 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1449 $($(source)_DEFS)\
1450 $($(source)_DEFS.$(bld_type))\
1451 $($(source)_DEFS.$(bld_trg))\
1452 $($(source)_DEFS.$(bld_trg_arch))\
1453 $($(source)_DEFS.$(bld_trg).$(bld_trg_arch))\
1454 $($(source)_DEFS.$(bld_trg_cpu))\
1455 $($(source)_$(type)DEFS)\
1456 $($(source)_$(type)DEFS.$(bld_type))\
1457 $($(source)_$(type)DEFS.$(bld_trg))\
1458 $($(source)_$(type)DEFS.$(bld_trg_arch))\
1459 $($(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1460 $($(source)_$(type)DEFS.$(bld_trg_cpu))\
1461 $(foreach sdk, $($(target)_$(source)_SDKS.$(bld_trg)) \
1462 $($(target)_$(source)_SDKS.$(bld_trg).$(bld_trg_arch)) \
1463 $($(target)_$(source)_SDKS.$(bld_type)) \
1464 $($(target)_$(source)_SDKS),\
1465 $(SDK_$(sdk)_DEFS)\
1466 $(SDK_$(sdk)_DEFS.$(bld_type))\
1467 $(SDK_$(sdk)_DEFS.$(bld_trg))\
1468 $(SDK_$(sdk)_DEFS.$(bld_trg_arch))\
1469 $(SDK_$(sdk)_DEFS.$(bld_trg).$(bld_trg_arch))\
1470 $(SDK_$(sdk)_DEFS.$(bld_trg_cpu))\
1471 $(SDK_$(sdk)_$(type)DEFS)\
1472 $(SDK_$(sdk)_$(type)DEFS.$(bld_type))\
1473 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg))\
1474 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_arch))\
1475 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1476 $(SDK_$(sdk)_$(type)DEFS.$(bld_trg_cpu)))\
1477 $($(target)_$(source)_DEFS)\
1478 $($(target)_$(source)_DEFS.$(bld_type))\
1479 $($(target)_$(source)_DEFS.$(bld_trg))\
1480 $($(target)_$(source)_DEFS.$(bld_trg_arch))\
1481 $($(target)_$(source)_DEFS.$(bld_trg).$(bld_trg_arch))\
1482 $($(target)_$(source)_DEFS.$(bld_trg_cpu))\
1483 $($(target)_$(source)_$(type)DEFS)\
1484 $($(target)_$(source)_$(type)DEFS.$(bld_type))\
1485 $($(target)_$(source)_$(type)DEFS.$(bld_trg))\
1486 $($(target)_$(source)_$(type)DEFS.$(bld_trg_arch))\
1487 $($(target)_$(source)_$(type)DEFS.$(bld_trg).$(bld_trg_arch))\
1488 $($(target)_$(source)_$(type)DEFS.$(bld_trg_cpu))
1490 static struct variable *
1491 kbuild_collect_source_prop(struct variable *pTarget, struct variable *pSource,
1492 struct variable *pTool, struct kbuild_sdks *pSdks,
1493 struct variable *pType, struct variable *pBldType,
1494 struct variable *pBldTrg, struct variable *pBldTrgArch, struct variable *pBldTrgCpu,
1495 struct variable *pDefPath,
1496 const char *pszProp, size_t cchProp,
1497 const char *pszVarName, size_t cchVarName,
1498 int iDirection)
1500 struct variable *pVar;
1501 unsigned iSdk, iSdkEnd;
1502 int cVars, iVar;
1503 size_t cchTotal, cchBuf;
1504 char *pszResult, *pszBuf, *psz, *psz2, *psz3;
1505 struct
1507 struct variable *pVar;
1508 unsigned int cchExp;
1509 char *pszExp;
1510 } *paVars;
1512 assert(iDirection == 1 || iDirection == -1);
1515 * Calc and allocate a too big name buffer.
1517 cchBuf = cchProp + 1
1518 + pTarget->value_length + 1
1519 + pSource->value_length + 1
1520 + pSdks->cchMax + 1
1521 + (pTool ? pTool->value_length + 1 : 0)
1522 + pType->value_length + 1
1523 + pBldTrg->value_length + 1
1524 + pBldTrgArch->value_length + 1
1525 + pBldTrgCpu->value_length + 1
1526 + pBldType->value_length + 1;
1527 pszBuf = xmalloc(cchBuf);
1530 * Get the variables.
1532 * The compiler will get a heart attack when it sees this code ... ;-)
1534 cVars = 12 * (pSdks->c + 5);
1535 paVars = alloca(cVars * sizeof(paVars[0]));
1537 iVar = 0;
1538 cchTotal = 0;
1540 #define ADD_VAR(pVar) do { my_memcpy(psz, (pVar)->value, (pVar)->value_length); psz += (pVar)->value_length; } while (0)
1541 #define ADD_STR(pszStr, cchStr) do { my_memcpy(psz, (pszStr), (cchStr)); psz += (cchStr); } while (0)
1542 #define ADD_CSTR(pszStr) do { my_memcpy(psz, pszStr, sizeof(pszStr) - 1); psz += sizeof(pszStr) - 1; } while (0)
1543 #define ADD_CH(ch) do { *psz++ = (ch); } while (0)
1544 #define DO_VAR_LOOKUP() \
1545 do { \
1546 pVar = kbuild_lookup_variable_n(pszBuf, psz - pszBuf); \
1547 if (pVar) \
1549 paVars[iVar].pVar = pVar; \
1550 if ( !pVar->recursive \
1551 || !memchr(pVar->value, '$', pVar->value_length)) \
1553 paVars[iVar].pszExp = pVar->value; \
1554 paVars[iVar].cchExp = pVar->value_length; \
1555 if (pDefPath && paVars[iVar].cchExp) \
1556 kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 0); \
1557 if (paVars[iVar].cchExp) \
1559 cchTotal += paVars[iVar].cchExp + 1; \
1560 iVar++; \
1563 else \
1565 paVars[iVar].pszExp = allocated_variable_expand_2(pVar->value, pVar->value_length, &paVars[iVar].cchExp); \
1566 if (pDefPath && paVars[iVar].cchExp) \
1567 kbuild_apply_defpath(pDefPath, &paVars[iVar].pszExp, &paVars[iVar].cchExp, NULL, 1); \
1568 if (paVars[iVar].cchExp) \
1570 cchTotal += paVars[iVar].cchExp + 1; \
1571 iVar++; \
1573 else \
1574 free(paVars[iVar].pszExp); \
1577 } while (0)
1578 #define DO_SINGLE_PSZ3_VARIATION() \
1579 do { \
1580 DO_VAR_LOOKUP(); \
1582 ADD_CH('.'); \
1583 psz3 = psz; \
1584 ADD_VAR(pBldType); \
1585 DO_VAR_LOOKUP(); \
1587 psz = psz3; \
1588 ADD_VAR(pBldTrg); \
1589 DO_VAR_LOOKUP(); \
1591 psz = psz3; \
1592 ADD_VAR(pBldTrgArch); \
1593 DO_VAR_LOOKUP(); \
1595 psz = psz3; \
1596 ADD_VAR(pBldTrg); \
1597 ADD_CH('.'); \
1598 ADD_VAR(pBldTrgArch); \
1599 DO_VAR_LOOKUP(); \
1601 psz = psz3; \
1602 ADD_VAR(pBldTrgCpu); \
1603 DO_VAR_LOOKUP(); \
1604 } while (0)
1606 #define DO_DOUBLE_PSZ2_VARIATION() \
1607 do { \
1608 psz2 = psz; \
1609 ADD_STR(pszProp, cchProp); \
1610 DO_SINGLE_PSZ3_VARIATION(); \
1612 /* add prop before type */ \
1613 psz = psz2; \
1614 ADD_VAR(pType); \
1615 ADD_STR(pszProp, cchProp); \
1616 DO_SINGLE_PSZ3_VARIATION(); \
1617 } while (0)
1619 /* the tool (lowest priority). */
1620 psz = pszBuf;
1621 ADD_CSTR("TOOL_");
1622 ADD_VAR(pTool);
1623 ADD_CH('_');
1624 DO_DOUBLE_PSZ2_VARIATION();
1627 /* the global sdks. */
1628 iSdkEnd = iDirection == 1 ? pSdks->iGlobal + pSdks->cGlobal : pSdks->iGlobal - 1;
1629 for (iSdk = iDirection == 1 ? pSdks->iGlobal : pSdks->iGlobal + pSdks->cGlobal - 1;
1630 iSdk != iSdkEnd;
1631 iSdk += iDirection)
1633 struct variable *pSdk = &pSdks->pa[iSdk];
1634 psz = pszBuf;
1635 ADD_CSTR("SDK_");
1636 ADD_VAR(pSdk);
1637 ADD_CH('_');
1638 DO_DOUBLE_PSZ2_VARIATION();
1641 /* the globals. */
1642 psz = pszBuf;
1643 DO_DOUBLE_PSZ2_VARIATION();
1646 /* the target sdks. */
1647 iSdkEnd = iDirection == 1 ? pSdks->iTarget + pSdks->cTarget : pSdks->iTarget - 1;
1648 for (iSdk = iDirection == 1 ? pSdks->iTarget : pSdks->iTarget + pSdks->cTarget - 1;
1649 iSdk != iSdkEnd;
1650 iSdk += iDirection)
1652 struct variable *pSdk = &pSdks->pa[iSdk];
1653 psz = pszBuf;
1654 ADD_CSTR("SDK_");
1655 ADD_VAR(pSdk);
1656 ADD_CH('_');
1657 DO_DOUBLE_PSZ2_VARIATION();
1660 /* the target. */
1661 psz = pszBuf;
1662 ADD_VAR(pTarget);
1663 ADD_CH('_');
1664 DO_DOUBLE_PSZ2_VARIATION();
1666 /* the source sdks. */
1667 iSdkEnd = iDirection == 1 ? pSdks->iSource + pSdks->cSource : pSdks->iSource - 1;
1668 for (iSdk = iDirection == 1 ? pSdks->iSource : pSdks->iSource + pSdks->cSource - 1;
1669 iSdk != iSdkEnd;
1670 iSdk += iDirection)
1672 struct variable *pSdk = &pSdks->pa[iSdk];
1673 psz = pszBuf;
1674 ADD_CSTR("SDK_");
1675 ADD_VAR(pSdk);
1676 ADD_CH('_');
1677 DO_DOUBLE_PSZ2_VARIATION();
1680 /* the source. */
1681 psz = pszBuf;
1682 ADD_VAR(pSource);
1683 ADD_CH('_');
1684 DO_DOUBLE_PSZ2_VARIATION();
1686 /* the target + source sdks. */
1687 iSdkEnd = iDirection == 1 ? pSdks->iTargetSource + pSdks->cTargetSource : pSdks->iTargetSource - 1;
1688 for (iSdk = iDirection == 1 ? pSdks->iTargetSource : pSdks->iTargetSource + pSdks->cTargetSource - 1;
1689 iSdk != iSdkEnd;
1690 iSdk += iDirection)
1692 struct variable *pSdk = &pSdks->pa[iSdk];
1693 psz = pszBuf;
1694 ADD_CSTR("SDK_");
1695 ADD_VAR(pSdk);
1696 ADD_CH('_');
1697 DO_DOUBLE_PSZ2_VARIATION();
1700 /* the target + source. */
1701 psz = pszBuf;
1702 ADD_VAR(pTarget);
1703 ADD_CH('_');
1704 ADD_VAR(pSource);
1705 ADD_CH('_');
1706 DO_DOUBLE_PSZ2_VARIATION();
1708 free(pszBuf);
1710 assert(iVar <= cVars);
1711 cVars = iVar;
1714 * Construct the result value.
1716 if (!cVars || !cchTotal)
1717 pVar = define_variable_vl(pszVarName, cchVarName, "", 0,
1718 1 /* duplicate value */ , o_local, 0 /* !recursive */);
1719 else
1721 psz = pszResult = xmalloc(cchTotal + 1);
1722 if (iDirection == 1)
1724 for (iVar = 0; iVar < cVars; iVar++)
1726 my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp);
1727 psz += paVars[iVar].cchExp;
1728 *psz++ = ' ';
1729 if (paVars[iVar].pszExp != paVars[iVar].pVar->value)
1730 free(paVars[iVar].pszExp);
1733 else
1735 iVar = cVars;
1736 while (iVar-- > 0)
1738 my_memcpy(psz, paVars[iVar].pszExp, paVars[iVar].cchExp);
1739 psz += paVars[iVar].cchExp;
1740 *psz++ = ' ';
1741 if (paVars[iVar].pszExp != paVars[iVar].pVar->value)
1742 free(paVars[iVar].pszExp);
1746 assert(psz != pszResult);
1747 assert(cchTotal == (size_t)(psz - pszResult));
1748 psz[-1] = '\0';
1749 cchTotal--;
1751 pVar = define_variable_vl(pszVarName, cchVarName, pszResult, cchTotal,
1752 0 /* take pszResult */ , o_local, 0 /* !recursive */);
1755 return pVar;
1757 #undef ADD_VAR
1758 #undef ADD_STR
1759 #undef ADD_CSTR
1760 #undef ADD_CH
1761 #undef DO_VAR_LOOKUP
1762 #undef DO_DOUBLE_PSZ2_VARIATION
1763 #undef DO_SINGLE_PSZ3_VARIATION
1767 /* get a source property. */
1768 char *
1769 func_kbuild_source_prop(char *o, char **argv, const char *pszFuncName)
1771 struct variable *pTarget = kbuild_get_variable_n(ST("target"));
1772 struct variable *pSource = kbuild_get_variable_n(ST("source"));
1773 struct variable *pDefPath = NULL;
1774 struct variable *pType = kbuild_get_variable_n(ST("type"));
1775 struct variable *pTool = kbuild_get_variable_n(ST("tool"));
1776 struct variable *pBldType = kbuild_get_variable_n(ST("bld_type"));
1777 struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg"));
1778 struct variable *pBldTrgArch = kbuild_get_variable_n(ST("bld_trg_arch"));
1779 struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu"));
1780 struct variable *pVar;
1781 struct kbuild_sdks Sdks;
1782 int iDirection;
1783 if (!strcmp(argv[2], "left-to-right"))
1784 iDirection = 1;
1785 else if (!strcmp(argv[2], "right-to-left"))
1786 iDirection = -1;
1787 else
1788 fatal(NILF, _("incorrect direction argument `%s'!"), argv[2]);
1789 if (argv[3])
1791 const char *psz = argv[3];
1792 while (isspace(*psz))
1793 psz++;
1794 if (*psz)
1795 pDefPath = kbuild_get_variable_n(ST("defpath"));
1798 kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch);
1800 pVar = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType,
1801 pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu,
1802 pDefPath,
1803 argv[0], strlen(argv[0]),
1804 argv[1], strlen(argv[1]),
1805 iDirection);
1806 if (pVar)
1807 o = variable_buffer_output(o, pVar->value, pVar->value_length);
1809 kbuild_put_sdks(&Sdks);
1810 (void)pszFuncName;
1811 return o;
1816 dep := $(obj)$(SUFF_DEP)
1817 obj := $(outbase)$(objsuff)
1818 dirdep := $(call DIRDEP,$(dir $(outbase)))
1819 PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase)))
1821 static struct variable *
1822 kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(struct variable *pTarget, struct variable *pSource,
1823 struct variable *pOutBase, struct variable *pObjSuff,
1824 const char *pszVarName, struct variable **ppDep,
1825 struct variable **ppDirDep)
1827 struct variable *pDepSuff = kbuild_get_variable_n(ST("SUFF_DEP"));
1828 struct variable *pObj;
1829 size_t cch = pOutBase->value_length + pObjSuff->value_length + pDepSuff->value_length + 1;
1830 char *pszResult = alloca(cch);
1831 char *pszName, *psz;
1834 * dep.
1836 psz = pszResult;
1837 memcpy(psz, pOutBase->value, pOutBase->value_length); psz += pOutBase->value_length;
1838 memcpy(psz, pObjSuff->value, pObjSuff->value_length); psz += pObjSuff->value_length;
1839 memcpy(psz, pDepSuff->value, pDepSuff->value_length + 1);
1840 *ppDep = define_variable_vl("dep", 3, pszResult, cch - 1, 1 /*dup*/, o_local, 0 /* !recursive */);
1843 * obj
1845 *psz = '\0';
1846 pObj = define_variable_vl(pszVarName, strlen(pszVarName), pszResult, psz - pszResult,
1847 1/* dup */, o_local, 0 /* !recursive */);
1850 * PATH_$(target)_$(source) - this is global!
1852 /* calc variable name. */
1853 cch = sizeof("PATH_")-1 + pTarget->value_length + sizeof("_")-1 + pSource->value_length;
1854 psz = pszName = alloca(cch + 1);
1855 memcpy(psz, "PATH_", sizeof("PATH_") - 1); psz += sizeof("PATH_") - 1;
1856 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
1857 *psz++ = '_';
1858 memcpy(psz, pSource->value, pSource->value_length + 1);
1860 /* strip off the filename. */
1861 psz = pszResult + pOutBase->value_length;
1862 for (;;)
1864 psz--;
1865 if (psz <= pszResult)
1866 fatal(NULL, "whut!?! no path? result=`%s'", pszResult);
1867 #ifdef HAVE_DOS_PATHS
1868 if (*psz == ':')
1870 psz++;
1871 break;
1873 #endif
1874 if ( *psz == '/'
1875 #ifdef HAVE_DOS_PATHS
1876 || *psz == '\\'
1877 #endif
1880 while ( psz - 1 > pszResult
1881 && psz[-1] == '/'
1882 #ifdef HAVE_DOS_PATHS
1883 || psz[-1] == '\\'
1884 #endif
1886 psz--;
1887 #ifdef HAVE_DOS_PATHS
1888 if (psz == pszResult + 2 && pszResult[1] == ':')
1889 psz++;
1890 #endif
1891 break;
1894 *psz = '\0';
1896 /* set global variable */
1897 define_variable_vl_global(pszName, cch, pszResult, psz - pszResult, 1/*dup*/, o_file, 0 /* !recursive */, NILF);
1900 * dirdep
1902 if ( psz[-1] != '/'
1903 #ifdef HAVE_DOS_PATHS
1904 && psz[-1] != '\\'
1905 && psz[-1] != ':'
1906 #endif
1909 *psz++ = '/';
1910 *psz = '\0';
1912 *ppDirDep = define_variable_vl("dirdep", 6, pszResult, psz - pszResult, 1/*dup*/, o_local, 0 /* !recursive */);
1914 return pObj;
1918 /* setup the base variables for def_target_source_c_cpp_asm_new:
1920 X := $(kb-src-tool tool)
1921 x := $(kb-obj-base outbase)
1922 x := $(kb-obj-suff objsuff)
1923 obj := $(outbase)$(objsuff)
1924 PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase)))
1926 x := $(kb-src-prop DEFS,defs,left-to-right)
1927 x := $(kb-src-prop INCS,incs,right-to-left)
1928 x := $(kb-src-prop FLAGS,flags,right-to-left)
1930 x := $(kb-src-prop DEPS,deps,left-to-right)
1931 dirdep := $(call DIRDEP,$(dir $(outbase)))
1932 dep := $(obj)$(SUFF_DEP)
1934 char *
1935 func_kbuild_source_one(char *o, char **argv, const char *pszFuncName)
1937 static int s_fNoCompileCmdsDepsDefined = -1;
1938 struct variable *pTarget = kbuild_get_variable_n(ST("target"));
1939 struct variable *pSource = kbuild_get_variable_n(ST("source"));
1940 struct variable *pDefPath = kbuild_get_variable_n(ST("defpath"));
1941 struct variable *pType = kbuild_get_variable_n(ST("type"));
1942 struct variable *pBldType = kbuild_get_variable_n(ST("bld_type"));
1943 struct variable *pBldTrg = kbuild_get_variable_n(ST("bld_trg"));
1944 struct variable *pBldTrgArch= kbuild_get_variable_n(ST("bld_trg_arch"));
1945 struct variable *pBldTrgCpu = kbuild_get_variable_n(ST("bld_trg_cpu"));
1946 struct variable *pTool = kbuild_get_source_tool(pTarget, pSource, pType, pBldTrg, pBldTrgArch, "tool");
1947 struct variable *pOutBase = kbuild_get_object_base(pTarget, pSource, "outbase");
1948 struct variable *pObjSuff = kbuild_get_object_suffix(pTarget, pSource, pTool, pType, pBldTrg, pBldTrgArch, "objsuff");
1949 struct variable *pDefs, *pIncs, *pFlags, *pDeps, *pOrderDeps, *pDirDep, *pDep, *pVar, *pOutput, *pOutputMaybe;
1950 struct variable *pObj = kbuild_set_object_name_and_dep_and_dirdep_and_PATH_target_source(pTarget, pSource, pOutBase, pObjSuff, "obj", &pDep, &pDirDep);
1951 int fInstallOldVars = 0;
1952 char *pszDstVar, *pszDst, *pszSrcVar, *pszSrc, *pszVal, *psz;
1953 char *pszSavedVarBuf;
1954 unsigned cchSavedVarBuf;
1955 size_t cch;
1956 struct kbuild_sdks Sdks;
1957 int iVer;
1960 * argv[0] is the function version. Prior to r1792 (early 0.1.5) this
1961 * was undefined and footer.kmk always passed an empty string.
1963 * Version 2, as implemented in r1797, will make use of the async
1964 * includedep queue feature. This means the files will be read by one or
1965 * more background threads, leaving the eval'ing to be done later on by
1966 * the main thread (in snap_deps).
1968 if (!argv[0][0])
1969 iVer = 0;
1970 else
1971 switch (argv[0][0] | (argv[0][1] << 8))
1973 case '2': iVer = 2; break;
1974 case '3': iVer = 3; break;
1975 case '4': iVer = 4; break;
1976 case '5': iVer = 5; break;
1977 case '6': iVer = 6; break;
1978 case '7': iVer = 7; break;
1979 case '8': iVer = 8; break;
1980 case '9': iVer = 9; break;
1981 case '0': iVer = 0; break;
1982 case '1': iVer = 1; break;
1983 default:
1984 iVer = 0;
1985 psz = argv[0];
1986 while (isblank((unsigned char)*psz))
1987 psz++;
1988 if (*psz)
1989 iVer = atoi(psz);
1990 break;
1994 * Gather properties.
1996 kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch);
1998 if (pDefPath && !pDefPath->value_length)
1999 pDefPath = NULL;
2000 pDefs = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL,
2001 ST("DEFS"), ST("defs"), 1/* left-to-right */);
2002 pIncs = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath,
2003 ST("INCS"), ST("incs"), -1/* right-to-left */);
2004 pFlags = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, NULL,
2005 ST("FLAGS"), ST("flags"), 1/* left-to-right */);
2006 pDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath,
2007 ST("DEPS"), ST("deps"), 1/* left-to-right */);
2008 pOrderDeps = kbuild_collect_source_prop(pTarget, pSource, pTool, &Sdks, pType, pBldType, pBldTrg, pBldTrgArch, pBldTrgCpu, pDefPath,
2009 ST("ORDERDEPS"), ST("orderdeps"), 1/* left-to-right */);
2012 * If we've got a default path, we must expand the source now.
2013 * If we do this too early, "<source>_property = stuff" won't work becuase
2014 * our 'source' value isn't what the user expects.
2016 if (pDefPath)
2018 /** @todo assert(pSource->origin != o_automatic); We're changing 'source'
2019 * from the foreach loop! */
2020 #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
2021 assert(!pSource->rdonly_val);
2022 #endif
2023 kbuild_apply_defpath(pDefPath, &pSource->value, &pSource->value_length, &pSource->value_alloc_len, 1 /* can free */);
2027 # dependencies
2028 ifndef NO_COMPILE_CMDS_DEPS
2029 _DEPFILES_INCLUDED += $(dep)
2030 $(if $(wildcard $(dep)),$(eval include $(dep)))
2031 endif
2033 if (s_fNoCompileCmdsDepsDefined == -1)
2034 s_fNoCompileCmdsDepsDefined = kbuild_lookup_variable_n(ST("NO_COMPILE_CMDS_DEPS")) != NULL;
2035 if (!s_fNoCompileCmdsDepsDefined)
2037 pVar = kbuild_query_recursive_variable_n("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1);
2038 if (pVar)
2040 if (pVar->recursive)
2041 pVar = kbuild_simplify_variable(pVar);
2042 append_string_to_variable(pVar, pDep->value, pDep->value_length, 1 /* append */);
2044 else
2045 define_variable_vl_global("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1,
2046 pDep->value, pDep->value_length,
2047 1 /* duplicate_value */,
2048 o_file,
2049 0 /* recursive */,
2050 NULL /* flocp */);
2052 eval_include_dep(pDep->value, NILF, iVer >= 2 ? incdep_queue : incdep_read_it);
2056 # call the tool
2057 $(target)_$(source)_CMDS_ := $(TOOL_$(tool)_COMPILE_$(type)_CMDS)
2058 $(target)_$(source)_OUTPUT_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT)
2059 $(target)_$(source)_OUTPUT_MAYBE_ := $(TOOL_$(tool)_COMPILE_$(type)_OUTPUT_MAYBE)
2060 $(target)_$(source)_DEPEND_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPEND) $(deps) $(source)
2061 $(target)_$(source)_DEPORD_ := $(TOOL_$(tool)_COMPILE_$(type)_DEPORD) $(dirdep)
2063 /** @todo Make all these local variables, if someone needs the info later it
2064 * can be recalculated. (Ticket #80.) */
2065 cch = sizeof("TOOL_") + pTool->value_length + sizeof("_COMPILE_") + pType->value_length + sizeof("_OUTPUT_MAYBE");
2066 if (cch < pTarget->value_length + sizeof("$(_2_OBJS)"))
2067 cch = pTarget->value_length + sizeof("$(_2_OBJS)");
2068 psz = pszSrcVar = alloca(cch);
2069 memcpy(psz, "TOOL_", sizeof("TOOL_") - 1); psz += sizeof("TOOL_") - 1;
2070 memcpy(psz, pTool->value, pTool->value_length); psz += pTool->value_length;
2071 memcpy(psz, "_COMPILE_", sizeof("_COMPILE_") - 1); psz += sizeof("_COMPILE_") - 1;
2072 memcpy(psz, pType->value, pType->value_length); psz += pType->value_length;
2073 pszSrc = psz;
2075 cch = pTarget->value_length + 1 + pSource->value_length + sizeof("_OUTPUT_MAYBE_");
2076 psz = pszDstVar = alloca(cch);
2077 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
2078 *psz++ = '_';
2079 memcpy(psz, pSource->value, pSource->value_length); psz += pSource->value_length;
2080 pszDst = psz;
2082 memcpy(pszSrc, "_CMDS", sizeof("_CMDS"));
2083 memcpy(pszDst, "_CMDS_", sizeof("_CMDS_"));
2084 pVar = kbuild_get_recursive_variable(pszSrcVar);
2085 do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2086 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2088 memcpy(pszSrc, "_OUTPUT", sizeof("_OUTPUT"));
2089 memcpy(pszDst, "_OUTPUT_", sizeof("_OUTPUT_"));
2090 pVar = kbuild_get_recursive_variable(pszSrcVar);
2091 pOutput = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2092 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2094 memcpy(pszSrc, "_OUTPUT_MAYBE", sizeof("_OUTPUT_MAYBE"));
2095 memcpy(pszDst, "_OUTPUT_MAYBE_", sizeof("_OUTPUT_MAYBE_"));
2096 pVar = kbuild_query_recursive_variable(pszSrcVar);
2097 if (pVar)
2098 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2099 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2100 else
2101 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, "", 0, 1, 0, o_file, f_simple, 0 /* !target_var */);
2103 memcpy(pszSrc, "_DEPEND", sizeof("_DEPEND"));
2104 memcpy(pszDst, "_DEPEND_", sizeof("_DEPEND_"));
2105 pVar = kbuild_get_recursive_variable(pszSrcVar);
2106 psz = pszVal = xmalloc(pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length + 1);
2107 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2108 *psz++ = ' ';
2109 memcpy(psz, pDeps->value, pDeps->value_length); psz += pDeps->value_length;
2110 *psz++ = ' ';
2111 memcpy(psz, pSource->value, pSource->value_length + 1);
2112 do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length,
2113 !pVar->recursive && !pDeps->recursive && !pSource->recursive,
2114 pszVal, o_file, f_simple, 0 /* !target_var */);
2116 memcpy(pszSrc, "_DEPORD", sizeof("_DEPORD"));
2117 memcpy(pszDst, "_DEPORD_", sizeof("_DEPORD_"));
2118 pVar = kbuild_get_recursive_variable(pszSrcVar);
2119 psz = pszVal = xmalloc(pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length + 1);
2120 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2121 *psz++ = ' ';
2122 memcpy(psz, pDirDep->value, pDirDep->value_length); psz += pDirDep->value_length;
2123 *psz++ = ' ';
2124 memcpy(psz, pOrderDeps->value, pOrderDeps->value_length + 1);
2125 do_variable_definition_2(NILF, pszDstVar, pszVal,
2126 pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length,
2127 !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive,
2128 pszVal, o_file, f_simple, 0 /* !target_var */);
2131 _OUT_FILES += $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_)
2133 pVar = kbuild_get_variable_n(ST("_OUT_FILES"));
2134 append_string_to_variable(pVar, pOutput->value, pOutput->value_length, 1 /* append */);
2135 if (pOutputMaybe->value_length)
2136 append_string_to_variable(pVar, pOutputMaybe->value, pOutputMaybe->value_length, 1 /* append */);
2139 $(target)_2_OBJS += $(obj)
2141 memcpy(pszDstVar + pTarget->value_length, "_2_OBJS", sizeof("_2_OBJS"));
2142 pVar = kbuild_query_recursive_variable_n(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1);
2143 fInstallOldVars |= iVer <= 2 && (!pVar || !pVar->value_length);
2144 if (pVar)
2146 if (pVar->recursive)
2147 pVar = kbuild_simplify_variable(pVar);
2148 append_string_to_variable(pVar, pObj->value, pObj->value_length, 1 /* append */);
2150 else
2151 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1,
2152 pObj->value, pObj->value_length,
2153 1 /* duplicate_value */,
2154 o_file,
2155 0 /* recursive */,
2156 NULL /* flocp */);
2159 * Install legacy variables.
2161 if (fInstallOldVars)
2163 /* $(target)_OBJS_ = $($(target)_2_OBJS)*/
2164 memcpy(pszDstVar + pTarget->value_length, "_OBJS_", sizeof("_OBJS_"));
2166 pszSrcVar[0] = '$';
2167 pszSrcVar[1] = '(';
2168 memcpy(pszSrcVar + 2, pTarget->value, pTarget->value_length);
2169 psz = pszSrcVar + 2 + pTarget->value_length;
2170 memcpy(psz, "_2_OBJS)", sizeof("_2_OBJS)"));
2172 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1,
2173 pszSrcVar, pTarget->value_length + sizeof("$(_2_OBJS)") - 1,
2174 1 /* duplicate_value */,
2175 o_file,
2176 1 /* recursive */,
2177 NULL /* flocp */);
2181 $(eval $(def_target_source_rule))
2183 pVar = kbuild_get_recursive_variable("def_target_source_rule");
2184 pszVal = variable_expand_string_2 (o, pVar->value, pVar->value_length, &psz);
2185 assert(!((size_t)pszVal & 3));
2187 install_variable_buffer(&pszSavedVarBuf, &cchSavedVarBuf);
2188 eval_buffer(pszVal, psz);
2189 restore_variable_buffer(pszSavedVarBuf, cchSavedVarBuf);
2191 kbuild_put_sdks(&Sdks);
2192 (void)pszFuncName;
2194 *pszVal = '\0';
2195 return pszVal;
2200 ## Inherit one template property in a non-accumulative manner.
2201 # @param $(prop) Property name
2202 # @param $(target) Target name
2203 # @todo fix the precedence order for some properties.
2204 define def_inherit_template_one
2205 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2206 ifndef $(target)_$(prop)
2207 $(target)_$(prop) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2208 endif
2209 endif
2210 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2211 ifndef $(target)_$(prop).$(bld_trg)
2212 $(target)_$(prop).$(bld_trg) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2213 endif
2214 endif
2215 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2216 ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2217 $(target)_$(prop).$(bld_trg).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2218 endif
2219 endif
2220 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2221 ifndef $(target)_$(prop).$(bld_trg_arch)
2222 $(target)_$(prop).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2223 endif
2224 endif
2225 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2226 ifndef $(target)_$(prop).$(bld_trg_cpu)
2227 $(target)_$(prop).$(bld_trg_cpu) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2228 endif
2229 endif
2230 endef
2232 ## Inherit one template property in a non-accumulative manner, deferred expansion.
2233 # @param 1: $(prop) Property name
2234 # @param 2: $(target) Target name
2235 # @todo fix the precedence order for some properties.
2236 # @remark this define relies on double evaluation
2237 define def_inherit_template_one_deferred
2238 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2239 ifndef $(target)_$(prop)
2240 $(target)_$(prop) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2241 endif
2242 endif
2243 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2244 ifndef $(target)_$(prop).$(bld_trg)
2245 $(target)_$(prop).$(bld_trg) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2246 endif
2247 endif
2248 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2249 ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2250 $(target)_$(prop).$(bld_trg).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2251 endif
2252 endif
2253 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2254 ifndef $(target)_$(prop).$(bld_trg_arch)
2255 $(target)_$(prop).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2256 endif
2257 endif
2258 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2259 ifndef $(target)_$(prop).$(bld_trg_cpu)
2260 $(target)_$(prop).$(bld_trg_cpu) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2261 endif
2262 endif
2263 endef
2265 ## Inherit one acculumlative template property where the 'most significant' items are at the left end.
2266 # @param $(prop) Property name
2267 # @param $(target) Target name
2268 define def_inherit_template_one_accumulate_l
2269 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2270 ifeq ($$(flavor $(target)_$(prop)),simple)
2271 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2272 endif
2273 $(target)_$(prop) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2274 endif
2275 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2276 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2277 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2278 endif
2279 $(target)_$(prop).$(KBUILD_TYPE) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2280 endif
2281 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2282 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2283 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2284 endif
2285 $(target)_$(prop).$(bld_trg) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2286 endif
2287 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2288 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2289 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2290 endif
2291 $(target)_$(prop).$(bld_trg).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2292 endif
2293 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2294 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2295 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2296 endif
2297 $(target)_$(prop).$(bld_trg_cpu) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2298 endif
2299 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2300 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2301 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2302 endif
2303 $(target)_$(prop).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2304 endif
2305 endef
2307 ## Inherit one acculumlative template property where the 'most significant' items are at the right end.
2308 # @param $(prop) Property name
2309 # @param $(target) Target name
2310 define def_inherit_template_one_accumulate_r
2311 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2312 ifeq ($$(flavor $(target)_$(prop)),simple)
2313 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2314 endif
2315 $(target)_$(prop) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2316 endif
2317 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2318 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2319 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2320 endif
2321 $(target)_$(prop).$(KBUILD_TYPE) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2322 endif
2323 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2324 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2325 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2326 endif
2327 $(target)_$(prop).$(bld_trg) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2328 endif
2329 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2330 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2331 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2332 endif
2333 $(target)_$(prop).$(bld_trg).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2334 endif
2335 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2336 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2337 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2338 endif
2339 $(target)_$(prop).$(bld_trg_cpu) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2340 endif
2341 ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2342 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2343 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2344 endif
2345 $(target)_$(prop).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2346 endif
2347 endef
2350 ## Inherit template properties for on target.
2351 # @param $(target) Target name.
2352 define def_inherit_template
2353 # sanity check.
2354 ifdef _$(target)_ALREADY_PROCESSED
2355 $(error kBuild: The target $(target) appears more than once in the target lists! Please correct the makefile(s))
2356 endif
2357 _$(target)_ALREADY_PROCESSED := 1
2359 # Inherit any default template.
2360 ifdef TEMPLATE
2361 ifeq ($($(target)_TEMPLATE),)
2362 $(eval $(target)_TEMPLATE:=$(TEMPLATE))
2363 endif
2364 endif
2365 # Expand the template if specified.
2366 ifneq ($($(target)_TEMPLATE),)
2367 $(foreach prop,$(PROPS_SINGLE),$(evalval def_inherit_template_one))
2368 $(foreach prop,$(PROPS_DEFERRED),$(eval $(def_inherit_template_one_deferred))) # exploits the 2 evaluation, so no value!
2369 $(foreach prop,$(PROPS_ACCUMULATE_L),$(eval $(def_inherit_template_one_accumulate_l))) # += works fine without value
2370 $(foreach prop,$(PROPS_ACCUMULATE_R),$(eval $(def_inherit_template_one_accumulate_r))) # use <= (kmk addition)
2371 endif
2372 endef
2375 Invoked like this:
2376 $(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE))
2378 char *
2379 func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName)
2381 const char *pszVersion = argv[0];
2382 const char *pszBldTrg = argv[2];
2383 const char *pszBldTrgArch = argv[3];
2384 const char *pszBldTrgCpu = argv[4];
2385 const char *pszBldType = argv[5];
2386 size_t cchBldTrg = strlen(pszBldTrg);
2387 size_t cchBldTrgArch = strlen(pszBldTrgArch);
2388 size_t cchBldTrgCpu = strlen(pszBldTrgCpu);
2389 size_t cchBldType = strlen(pszBldType);
2390 size_t cchMaxBld = cchBldTrg + cchBldTrgArch + cchBldTrgCpu + cchBldType; /* too big, but so what. */
2391 struct kbet_key
2393 unsigned int cch;
2394 char *psz;
2395 } aKeys[6];
2396 unsigned int const cKeys = 6;
2397 unsigned int iKey;
2398 struct variable *pDefTemplate;
2399 struct variable *pProps;
2400 struct kbet_prop
2402 const char *pch;
2403 unsigned int cch;
2404 enum kbet_prop_enum { kPropSingle, kPropDeferred, kPropAccumulateL, kPropAccumulateR }
2405 enmType;
2406 } *paProps;
2407 unsigned int cProps;
2408 unsigned int iProp;
2409 size_t cchMaxProp;
2410 struct variable *pVarTrg;
2411 struct variable *pVarSrc;
2412 const char *pszIter;
2413 const char *pszTarget;
2414 unsigned int cchTarget;
2415 char *pszSrc = 0;
2416 char *pszSrcRef = 0;
2417 char *pszSrcBuf = 0;
2418 size_t cchSrcBuf = 0;
2419 char *pszTrg = 0;
2420 size_t cchTrg = 0;
2423 * Validate input.
2425 if (pszVersion[0] != '1' || pszVersion[1])
2426 fatal(NULL, "%s: Unsupported version `%s'", pszFuncName, pszVersion);
2428 if (!cchBldTrg)
2429 fatal(NULL, "%s: missing bldtrg", pszFuncName);
2431 if (!cchBldTrgArch)
2432 fatal(NULL, "%s: missing bld_trg_arch", pszFuncName);
2434 if (!cchBldTrgCpu)
2435 fatal(NULL, "%s: missing bld_trg_cpu", pszFuncName);
2437 if (!cchBldType)
2438 fatal(NULL, "%s: missing bld_type", pszFuncName);
2441 * Prepare the keywords, prepending dots for quicker copying.
2442 * This allows for an inner loop when processing properties, saving code
2443 * at the expense of a few xmallocs.
2445 /* the first entry is empty. */
2446 aKeys[0].cch = 0;
2447 aKeys[0].psz = NULL;
2449 aKeys[1].cch = cchBldType + 1;
2450 aKeys[1].psz = xmalloc (aKeys[1].cch + 1);
2451 aKeys[1].psz[0] = '.';
2452 memcpy(aKeys[1].psz + 1, pszBldType, cchBldType + 1);
2454 aKeys[2].cch = cchBldTrg + 1;
2455 aKeys[2].psz = xmalloc (aKeys[2].cch + 1);
2456 aKeys[2].psz[0] = '.';
2457 memcpy(aKeys[2].psz + 1, pszBldTrg, cchBldTrg + 1);
2459 aKeys[3].cch = cchBldTrg + 1 + cchBldTrgArch + 1;
2460 aKeys[3].psz = xmalloc (aKeys[3].cch + 1);
2461 aKeys[3].psz[0] = '.';
2462 memcpy(aKeys[3].psz + 1, pszBldTrg, cchBldTrg);
2463 aKeys[3].psz[1 + cchBldTrg] = '.';
2464 memcpy(aKeys[3].psz + 1 + cchBldTrg + 1, pszBldTrgArch, cchBldTrgArch + 1);
2466 aKeys[4].cch = cchBldTrgCpu + 1;
2467 aKeys[4].psz = xmalloc (aKeys[4].cch + 1);
2468 aKeys[4].psz[0] = '.';
2469 memcpy(aKeys[4].psz + 1, pszBldTrgCpu, cchBldTrgCpu + 1);
2471 aKeys[5].cch = cchBldTrgArch + 1;
2472 aKeys[5].psz = xmalloc (aKeys[5].cch + 1);
2473 aKeys[5].psz[0] = '.';
2474 memcpy(aKeys[5].psz + 1, pszBldTrgArch, cchBldTrgArch + 1);
2478 * Prepare the properties, folding them into an array.
2479 * This way we won't have to reparse them for each an every target, though
2480 * it comes at the expense of one or more heap calls.
2482 #define PROP_ALLOC_INC 128
2483 iProp = 0;
2484 cProps = PROP_ALLOC_INC;
2485 paProps = xmalloc(sizeof(*pProps) * cProps);
2487 pProps = kbuild_get_variable_n(ST("PROPS_SINGLE"));
2488 pszIter = pProps->value;
2489 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2491 paProps[iProp].enmType = kPropSingle;
2492 if (++iProp >= cProps)
2494 cProps += PROP_ALLOC_INC;
2495 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2500 pProps = kbuild_get_variable_n(ST("PROPS_DEFERRED"));
2501 pszIter = pProps->value;
2502 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2504 paProps[iProp].enmType = kPropDeferred;
2505 if (++iProp >= cProps)
2507 cProps += PROP_ALLOC_INC;
2508 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2512 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_L"));
2513 pszIter = pProps->value;
2514 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2516 paProps[iProp].enmType = kPropAccumulateL;
2517 if (++iProp >= cProps)
2519 cProps += PROP_ALLOC_INC;
2520 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2524 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_R"));
2525 pszIter = pProps->value;
2526 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2528 paProps[iProp].enmType = kPropAccumulateR;
2529 if (++iProp >= cProps)
2531 cProps += PROP_ALLOC_INC;
2532 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2535 #undef PROP_ALLOC_INC
2536 cProps = iProp;
2538 /* find the max prop length. */
2539 cchMaxProp = paProps[0].cch;
2540 while (--iProp > 0)
2541 if (paProps[iProp].cch > cchMaxProp)
2542 cchMaxProp = paProps[iProp].cch;
2545 * Query and prepare (strip) the default template
2546 * (given by the TEMPLATE variable).
2548 pDefTemplate = kbuild_lookup_variable_n(ST("TEMPLATE"));
2549 if (pDefTemplate)
2551 if ( pDefTemplate->value_length
2552 && ( isspace(pDefTemplate->value[0])
2553 || isspace(pDefTemplate->value[pDefTemplate->value_length - 1])))
2555 unsigned int off;
2556 if (pDefTemplate->rdonly_val)
2557 fatal(NULL, "%s: TEMPLATE is read-only", pszFuncName);
2559 /* head */
2560 for (off = 0; isspace(pDefTemplate->value[off]); off++)
2561 /* nothing */;
2562 if (off)
2564 pDefTemplate->value_length -= off;
2565 memmove(pDefTemplate->value, pDefTemplate->value + off, pDefTemplate->value_length + 1);
2568 /* tail */
2569 off = pDefTemplate->value_length;
2570 while (off > 0 && isspace(pDefTemplate->value[off - 1]))
2571 off--;
2572 pDefTemplate->value_length = off;
2573 pDefTemplate->value[off] = '\0';
2576 if (!pDefTemplate->value_length)
2577 pDefTemplate = NULL;
2581 * Iterate the target list.
2583 pszIter = argv[1];
2584 while ((pszTarget = find_next_token(&pszIter, &cchTarget)))
2586 char *pszTrgProp, *pszSrcProp;
2587 char *pszTrgKey, *pszSrcKey;
2588 struct variable *pTmpl;
2589 const char *pszTmpl;
2590 size_t cchTmpl, cchMax;
2592 /* resize the target buffer. */
2593 cchMax = cchTarget + cchMaxProp + cchMaxBld + 10;
2594 if (cchTrg < cchMax)
2596 cchTrg = (cchMax + 31U) & ~(size_t)31;
2597 pszTrg = xrealloc(pszTrg, cchTrg);
2601 * Query the TEMPLATE property, if not found or zero-length fall back on the default.
2603 memcpy(pszTrg, pszTarget, cchTarget);
2604 pszTrgProp = pszTrg + cchTarget;
2605 memcpy(pszTrgProp, "_TEMPLATE", sizeof("_TEMPLATE"));
2606 pszTrgProp++; /* after '_'. */
2608 /** @todo Change this to a recursive lookup with simplification below. That
2609 * will allow target_TEMPLATE = $(NO_SUCH_TEMPLATE) instead of having
2610 * to use target_TEMPLATE = DUMMY */
2611 pTmpl = kbuild_lookup_variable_n(pszTrg, cchTarget + sizeof("_TEMPLATE") - 1);
2612 if (!pTmpl || !pTmpl->value_length)
2614 if (!pDefTemplate)
2615 continue; /* no template */
2616 pszTmpl = pDefTemplate->value;
2617 cchTmpl = pDefTemplate->value_length;
2619 else
2621 pszTmpl = pTmpl->value;
2622 cchTmpl = pTmpl->value_length;
2623 while (isspace(*pszTmpl))
2624 cchTmpl--, pszTmpl++;
2625 if (!cchTmpl)
2626 continue; /* no template */
2629 /* resize the source buffer. */
2630 cchMax = sizeof("TEMPLATE_") + cchTmpl + cchMaxProp + cchMaxBld + 10 + sizeof(void *);
2631 if (cchSrcBuf < cchMax)
2633 cchSrcBuf = (cchMax + 31U) & ~(size_t)31;
2634 pszSrcBuf = xrealloc(pszSrcBuf, cchSrcBuf);
2635 pszSrc = pszSrcBuf + sizeof(void *); assert(sizeof(void *) >= 2);
2636 pszSrcRef = pszSrc - 2;
2637 pszSrcRef[0] = '$';
2638 pszSrcRef[1] = '(';
2641 /* prepare the source buffer */
2642 memcpy(pszSrc, "TEMPLATE_", sizeof("TEMPLATE_") - 1);
2643 pszSrcProp = pszSrc + sizeof("TEMPLATE_") - 1;
2644 memcpy(pszSrcProp, pszTmpl, cchTmpl);
2645 pszSrcProp += cchTmpl;
2646 *pszSrcProp++ = '_';
2649 * Process properties.
2650 * Note! The single and deferred are handled in the same way now.
2652 #define BY_REF_LIMIT 64 /*(cchSrcVar * 4 > 64 ? cchSrcVar * 4 : 64)*/
2654 for (iProp = 0; iProp < cProps; iProp++)
2656 memcpy(pszTrgProp, paProps[iProp].pch, paProps[iProp].cch);
2657 pszTrgKey = pszTrgProp + paProps[iProp].cch;
2659 memcpy(pszSrcProp, paProps[iProp].pch, paProps[iProp].cch);
2660 pszSrcKey = pszSrcProp + paProps[iProp].cch;
2662 for (iKey = 0; iKey < cKeys; iKey++)
2664 char *pszTrgEnd;
2665 size_t cchSrcVar;
2667 /* lookup source, skip ahead if it doesn't exist. */
2668 memcpy(pszSrcKey, aKeys[iKey].psz, aKeys[iKey].cch);
2669 cchSrcVar = pszSrcKey - pszSrc + aKeys[iKey].cch;
2670 pszSrc[cchSrcVar] = '\0';
2671 pVarSrc = kbuild_query_recursive_variable_n(pszSrc, cchSrcVar);
2672 if (!pVarSrc)
2673 continue;
2675 /* lookup target, skip ahead if it exists. */
2676 memcpy(pszTrgKey, aKeys[iKey].psz, aKeys[iKey].cch);
2677 pszTrgEnd = pszTrgKey + aKeys[iKey].cch;
2678 *pszTrgEnd = '\0';
2679 pVarTrg = kbuild_query_recursive_variable_n(pszTrg, pszTrgEnd - pszTrg);
2681 switch (paProps[iProp].enmType)
2683 case kPropAccumulateL:
2684 case kPropAccumulateR:
2685 if (pVarTrg)
2687 /* Append to existing variable. If the source is recursive,
2688 or we append by reference, we'll have to make sure the
2689 target is recusive as well. */
2690 if ( !pVarTrg->recursive
2691 && ( pVarSrc->value_length >= BY_REF_LIMIT
2692 || pVarSrc->recursive))
2693 pVarTrg->recursive = 1;
2695 if (pVarSrc->value_length < BY_REF_LIMIT)
2696 append_string_to_variable(pVarTrg, pVarSrc->value, pVarSrc->value_length,
2697 paProps[iProp].enmType == kPropAccumulateL /* append */);
2698 else
2700 pszSrc[cchSrcVar] = ')';
2701 pszSrc[cchSrcVar + 1] = '\0';
2702 append_string_to_variable(pVarTrg, pszSrcRef, 2 + cchSrcVar + 1,
2703 paProps[iProp].enmType == kPropAccumulateL /* append */);
2705 break;
2707 /* else: the target variable doesn't exist, create it. */
2708 /* fall thru */
2710 case kPropSingle:
2711 case kPropDeferred:
2712 if (pVarTrg)
2713 continue; /* skip ahead if it already exists. */
2715 /* copy the variable if its short, otherwise reference it. */
2716 if (pVarSrc->value_length < BY_REF_LIMIT)
2717 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2718 pVarSrc->value, pVarSrc->value_length,
2719 1 /* duplicate_value */,
2720 o_file,
2721 pVarSrc->recursive,
2722 NULL /* flocp */);
2723 else
2725 pszSrc[cchSrcVar] = ')';
2726 pszSrc[cchSrcVar + 1] = '\0';
2727 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2728 pszSrcRef, 2 + cchSrcVar + 1,
2729 1 /* duplicate_value */,
2730 o_file,
2731 1 /* recursive */,
2732 NULL /* flocp */);
2734 break;
2738 } /* foreach key */
2739 } /* foreach prop */
2740 #undef BY_REF_LIMIT
2741 } /* foreach target */
2744 * Cleanup.
2746 free(pszSrcBuf);
2747 free(pszTrg);
2748 free(paProps);
2749 for (iKey = 1; iKey < cKeys; iKey++)
2750 free(aKeys[iKey].psz);
2752 return o;
2755 #endif /* KMK_HELPERS */