VirtualBox

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

最後變更 在這個檔案從2247是 2247,由 bird 提交於 16 年 前

kbuild.c/FreeBSD: Alternative method for obtaining the executable address.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette