VirtualBox

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

Last change on this file since 2129 was 2124, checked in by bird, 16 years ago

kbuild.c: more warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 94.2 KB
Line 
1/* $Id: kbuild.c 2124 2008-12-25 14:19:59Z bird $ */
2/** @file
3 * kBuild specific make functionality.
4 */
5
6/*
7 * Copyright (c) 2006-2008 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
44#include "kbuild.h"
45
46#include <assert.h>
47
48
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
54
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
80
81
82/*******************************************************************************
83* Global Variables *
84*******************************************************************************/
85/** The argv[0] passed to main. */
86static const char *g_pszExeName;
87/** The initial working directory. */
88static char *g_pszInitialCwd;
89
90
91/**
92 * Initialize kBuild stuff.
93 *
94 * @param argc Number of arguments to main().
95 * @param argv The main() argument vector.
96 */
97void init_kbuild(int argc, char **argv)
98{
99 int rc;
100 PATH_VAR(szTmp);
101
102 /*
103 * Get the initial cwd for use in my_abspath.
104 */
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"));
113
114 /*
115 * Determin the executable name.
116 */
117 rc = -1;
118#if defined(__APPLE__)
119 {
120 const char *pszImageName = _dyld_get_image_name(0);
121 if (pszImageName)
122 {
123 size_t cchImageName = strlen(pszImageName);
124 if (cchImageName < GET_PATH_MAX)
125 {
126 memcpy(szTmp, pszImageName, cchImageName + 1);
127 rc = 0;
128 }
129 }
130 }
131
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';
138
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';
145
146#elif defined(__OS2__)
147 _execname(szTmp, GET_PATH_MAX);
148 rc = 0;
149
150#elif defined(__sun__)
151 {
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';
159 }
160
161#elif defined(WINDOWS32)
162 if (GetModuleFileName(GetModuleHandle(NULL), szTmp, GET_PATH_MAX))
163 rc = 0;
164
165#endif
166
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))
171 {
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)
177 {
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)
184 {
185 memcpy(szTmp, psz, cch);
186 szTmp[cch] = '/';
187 memcpy(&szTmp[cch + 1], argv[0], cchArgv0 + 1);
188 if (!access(szTmp, X_OK))
189 {
190 rc = 0;
191 break;
192 }
193 }
194
195 /* next */
196 psz = pszEnd;
197 while (*psz == PATH_SEPARATOR_CHAR)
198 psz++;
199 }
200 free(pszCopy);
201 }
202#endif
203
204 if (rc < 0)
205 g_pszExeName = argv[0];
206 else
207 g_pszExeName = xstrdup(szTmp);
208
209 (void)argc;
210}
211
212
213/**
214 * Wrapper that ensures correct starting_directory.
215 */
216static char *my_abspath(const char *pszIn, char *pszOut)
217{
218 char *pszSaved, *pszRet;
219
220 pszSaved = starting_directory;
221 starting_directory = g_pszInitialCwd;
222 pszRet = abspath(pszIn, pszOut);
223 starting_directory = pszSaved;
224
225 return pszRet;
226}
227
228
229/**
230 * Determin the KBUILD_PATH value.
231 *
232 * @returns Pointer to static a buffer containing the value (consider it read-only).
233 */
234const char *get_kbuild_path(void)
235{
236 static const char *s_pszPath = NULL;
237 if (!s_pszPath)
238 {
239 PATH_VAR(szTmpPath);
240 const char *pszEnvVar = getenv("KBUILD_PATH");
241 if ( !pszEnvVar
242 || !my_abspath(pszEnvVar, szTmpPath))
243 {
244 pszEnvVar = getenv("PATH_KBUILD");
245 if ( !pszEnvVar
246 || !my_abspath(pszEnvVar, szTmpPath))
247 {
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
258 }
259 }
260 s_pszPath = xstrdup(szTmpPath);
261 }
262 return s_pszPath;
263}
264
265
266/**
267 * Determin the KBUILD_BIN_PATH value.
268 *
269 * @returns Pointer to static a buffer containing the value (consider it read-only).
270 */
271const char *get_kbuild_bin_path(void)
272{
273 static const char *s_pszPath = NULL;
274 if (!s_pszPath)
275 {
276 PATH_VAR(szTmpPath);
277
278 const char *pszEnvVar = getenv("KBUILD_BIN_PATH");
279 if ( !pszEnvVar
280 || !my_abspath(pszEnvVar, szTmpPath))
281 {
282 pszEnvVar = getenv("PATH_KBUILD_BIN");
283 if ( !pszEnvVar
284 || !my_abspath(pszEnvVar, szTmpPath))
285 {
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, ".");
304
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 */
308 }
309 }
310 s_pszPath = xstrdup(szTmpPath);
311 }
312 return s_pszPath;
313}
314
315
316/**
317 * Determin the location of default kBuild shell.
318 *
319 * @returns Pointer to static a buffer containing the location (consider it read-only).
320 */
321const char *get_default_kbuild_shell(void)
322{
323 static char *s_pszDefaultShell = NULL;
324 if (!s_pszDefaultShell)
325 {
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));
336 }
337 return s_pszDefaultShell;
338}
339
340#ifdef KMK_HELPERS
341
342/**
343 * Applies the specified default path to any relative paths in *ppsz.
344 *
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.
352 */
353static void
354kbuild_apply_defpath(struct variable *pDefPath, char **ppsz, unsigned int *pcch, unsigned int *pcchAlloc, int fCanFree)
355{
356 const char *pszIterator;
357 const char *pszInCur;
358 unsigned int cchInCur;
359 unsigned int cRelativePaths;
360
361 /*
362 * The first pass, count the relative paths.
363 */
364 cRelativePaths = 0;
365 pszIterator = *ppsz;
366 while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
367 {
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++;
375 }
376
377 /*
378 * The second pass construct the new string.
379 */
380 if (cRelativePaths)
381 {
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;
386
387 cRelativePaths = 0;
388 pszIterator = *ppsz;
389 while ((pszInCur = find_next_token(&pszIterator, &cchInCur)))
390 {
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
397 {
398 PATH_VAR(szAbsPathIn);
399 PATH_VAR(szAbsPathOut);
400
401 if (pDefPath->value_length + cchInCur + 1 >= GET_PATH_MAX)
402 continue;
403
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';
409
410 if (abspath(szAbsPathIn, szAbsPathOut) != NULL)
411 {
412 const size_t cchAbsPathOut = strlen(szAbsPathOut);
413 assert(cchAbsPathOut <= pDefPath->value_length + 1 + cchInCur);
414
415 /* copy leading input */
416 if (pszInCur != pszInNextCopy)
417 {
418 const size_t cchCopy = pszInCur - pszInNextCopy;
419 memcpy(pszOutCur, pszInNextCopy, cchCopy);
420 pszOutCur += cchCopy;
421 }
422 pszInNextCopy = pszInCur + cchInCur;
423
424 /* copy out the abspath. */
425 memcpy(pszOutCur, szAbsPathOut, cchAbsPathOut);
426 pszOutCur += cchAbsPathOut;
427 }
428 }
429 }
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);
436
437 /* set return values */
438 if (fCanFree)
439 free(*ppsz);
440 *ppsz = pszOut;
441 *pcch = pszOutCur - pszOut;
442 if (pcchAlloc)
443 *pcchAlloc = cchOut;
444 }
445}
446
447/**
448 * Gets a variable that must exist.
449 * Will cause a fatal failure if the variable doesn't exist.
450 *
451 * @returns Pointer to the variable.
452 * @param pszName The variable name.
453 * @param cchName The name length.
454 */
455MY_INLINE struct variable *
456kbuild_get_variable_n(const char *pszName, size_t cchName)
457{
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);
463
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;
467}
468
469
470/**
471 * Gets a variable that must exist and can be recursive.
472 * Will cause a fatal failure if the variable doesn't exist.
473 *
474 * @returns Pointer to the variable.
475 * @param pszName The variable name.
476 */
477static struct variable *
478kbuild_get_recursive_variable(const char *pszName)
479{
480 struct variable *pVar = lookup_variable(pszName, strlen(pszName));
481 if (!pVar)
482 fatal(NILF, _("variable `%s' isn't defined!"), pszName);
483
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;
487}
488
489
490/**
491 * Gets a variable that doesn't have to exit, but if it does can be recursive.
492 *
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.
497 */
498static struct variable *
499kbuild_query_recursive_variable_n(const char *pszName, size_t cchName)
500{
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;
505}
506
507
508/**
509 * Gets a variable that doesn't have to exit, but if it does can be recursive.
510 *
511 * @returns Pointer to the variable.
512 * NULL if not found.
513 * @param pszName The variable name.
514 */
515static struct variable *
516kbuild_query_recursive_variable(const char *pszName)
517{
518 return kbuild_query_recursive_variable_n(pszName, strlen(pszName));
519}
520
521
522/**
523 * Converts the specified variable into a 'simple' one.
524 * @returns pVar.
525 * @param pVar The variable.
526 */
527static struct variable *
528kbuild_simplify_variable(struct variable *pVar)
529{
530 if (memchr(pVar->value, '$', pVar->value_length))
531 {
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;
544 }
545 pVar->recursive = 0;
546 return pVar;
547}
548
549
550/**
551 * Looks up a variable.
552 * The value_length field is valid upon successful return.
553 *
554 * @returns Pointer to the variable. NULL if not found.
555 * @param pszName The variable name.
556 * @param cchName The name length.
557 */
558MY_INLINE struct variable *
559kbuild_lookup_variable_n(const char *pszName, size_t cchName)
560{
561 struct variable *pVar = lookup_variable(pszName, cchName);
562 if (pVar)
563 {
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));
566
567 /* Make sure the variable is simple, convert it if necessary. */
568 if (pVar->recursive)
569 kbuild_simplify_variable(pVar);
570 }
571 return pVar;
572}
573
574
575/**
576 * Looks up a variable.
577 * The value_length field is valid upon successful return.
578 *
579 * @returns Pointer to the variable. NULL if not found.
580 * @param pszName The variable name.
581 */
582MY_INLINE struct variable *
583kbuild_lookup_variable(const char *pszName)
584{
585 return kbuild_lookup_variable_n(pszName, strlen(pszName));
586}
587
588
589/**
590 * Looks up a variable and applies default a path to all relative paths.
591 * The value_length field is valid upon successful return.
592 *
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.
597 */
598MY_INLINE struct variable *
599kbuild_lookup_variable_defpath_n(struct variable *pDefPath, const char *pszName, size_t cchName)
600{
601 struct variable *pVar = kbuild_lookup_variable_n(pszName, cchName);
602 if (pVar && pDefPath)
603 {
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);
609 }
610 return pVar;
611}
612
613
614/**
615 * Looks up a variable and applies default a path to all relative paths.
616 * The value_length field is valid upon successful return.
617 *
618 * @returns Pointer to the variable. NULL if not found.
619 * @param pDefPath The default path.
620 * @param pszName The variable name.
621 */
622MY_INLINE struct variable *
623kbuild_lookup_variable_defpath(struct variable *pDefPath, const char *pszName)
624{
625 struct variable *pVar = kbuild_lookup_variable(pszName);
626 if (pVar && pDefPath)
627 {
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);
633 }
634 return pVar;
635}
636
637
638/**
639 * Gets the first defined property variable.
640 */
641static struct variable *
642kbuild_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)
648{
649 struct variable *pVar;
650 size_t cchBuf;
651 char *pszBuf;
652 char *psz, *psz1, *psz2, *psz3, *psz4, *pszEnd;
653
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);
664
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)
669
670 /*
671 * $(target)_$(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
672 */
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);
688
689 /* $(target)_$(source)_$(type)$(propf2).$(bld_trg) */
690 if (!pVar)
691 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
692
693 /* $(target)_$(source)_$(type)$(propf2) */
694 if (!pVar)
695 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
696
697 /*
698 * $(target)_$(source)_$(propf2).$(bld_trg).$(bld_trg_arch)
699 */
700 if (!pVar)
701 {
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);
711
712 /* $(target)_$(source)_$(propf2).$(bld_trg) */
713 if (!pVar)
714 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
715
716 /* $(target)_$(source)_$(propf2) */
717 if (!pVar)
718 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
719 }
720
721
722 /*
723 * $(source)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
724 */
725 if (!pVar)
726 {
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);
740
741 /* $(source)_$(type)$(propf2).$(bld_trg) */
742 if (!pVar)
743 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
744
745 /* $(source)_$(type)$(propf2) */
746 if (!pVar)
747 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
748
749 /*
750 * $(source)_$(propf2).$(bld_trg).$(bld_trg_arch)
751 */
752 if (!pVar)
753 {
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);
763
764 /* $(source)_$(propf2).$(bld_trg) */
765 if (!pVar)
766 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
767
768 /* $(source)_$(propf2) */
769 if (!pVar)
770 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
771 }
772 }
773
774 /*
775 * $(target)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
776 */
777 if (!pVar)
778 {
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);
792
793 /* $(target)_$(type)$(propf2).$(bld_trg) */
794 if (!pVar)
795 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
796
797 /* $(target)_$(type)$(propf2) */
798 if (!pVar)
799 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
800
801 /* $(target)_$(propf2).$(bld_trg).$(bld_trg_arch) */
802 if (!pVar)
803 {
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);
813 }
814
815 /* $(target)_$(propf2).$(bld_trg) */
816 if (!pVar)
817 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
818
819 /* $(target)_$(propf2) */
820 if (!pVar)
821 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
822 }
823
824 /*
825 * TOOL_$(tool)_$(type)$(propf2).$(bld_trg).$(bld_trg_arch)
826 */
827 if (!pVar && pTool)
828 {
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);
843
844 /* TOOL_$(tool)_$(type)$(propf2).$(bld_trg) */
845 if (!pVar)
846 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
847
848 /* TOOL_$(tool)_$(type)$(propf2) */
849 if (!pVar)
850 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
851
852 /* TOOL_$(tool)_$(propf2).$(bld_trg).$(bld_trg_arch) */
853 if (!pVar)
854 {
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);
864
865 /* TOOL_$(tool)_$(propf2).$(bld_trg) */
866 if (!pVar)
867 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
868
869 /* TOOL_$(tool)_$(propf2) */
870 if (!pVar)
871 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
872 }
873 }
874
875 /*
876 * $(type)$(propf1).$(bld_trg).$(bld_trg_arch)
877 */
878 if (!pVar)
879 {
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);
890
891 /* $(type)$(propf1).$(bld_trg) */
892 if (!pVar)
893 pVar = kbuild_lookup_variable_n(pszBuf, psz4 - pszBuf);
894
895 /* $(type)$(propf1) */
896 if (!pVar)
897 pVar = kbuild_lookup_variable_n(pszBuf, psz3 - pszBuf);
898
899 /*
900 * $(propf1).$(bld_trg).$(bld_trg_arch)
901 */
902 if (!pVar)
903 {
904 psz1 = pszBuf + pType->value_length;
905 pVar = kbuild_lookup_variable_n(psz1, psz - psz1);
906
907 /* $(propf1).$(bld_trg) */
908 if (!pVar)
909 pVar = kbuild_lookup_variable_n(psz1, psz4 - psz1);
910
911 /* $(propf1) */
912 if (!pVar)
913 pVar = kbuild_lookup_variable_n(pszPropF1, cchPropF1);
914 }
915 }
916 free(pszBuf);
917#undef ADD_VAR
918#undef ADD_STR
919#undef ADD_CSTR
920#undef ADD_CH
921
922 if (pVar)
923 {
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)
932 {
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;
940 }
941 }
942 return NULL;
943}
944
945
946/*
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) ))
972*/
973static struct variable *
974kbuild_get_source_tool(struct variable *pTarget, struct variable *pSource, struct variable *pType,
975 struct variable *pBldTrg, struct variable *pBldTrgArch, const char *pszVarName)
976{
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;
984}
985
986
987/* Implements _SOURCE_TOOL. */
988char *
989func_kbuild_source_tool(char *o, char **argv, const char *pszFuncName)
990{
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;
1001
1002}
1003
1004
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))
1020*/
1021static struct variable *
1022kbuild_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)
1025{
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;
1033}
1034
1035
1036/* */
1037char *
1038func_kbuild_object_suffix(char *o, char **argv, const char *pszFuncName)
1039{
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;
1051
1052}
1053
1054
1055/*
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)))))))
1064*/
1065static struct variable *
1066kbuild_get_object_base(struct variable *pTarget, struct variable *pSource, const char *pszVarName)
1067{
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;
1080
1081 /*
1082 * Strip the source filename of any uncessary leading path and root specs.
1083 */
1084 /* */
1085 if ( pSource->value_length > pPathTarget->value_length
1086 && !strncmp(pSource->value, pPathTarget->value, pPathTarget->value_length))
1087 {
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;
1096 }
1097 else if ( pSource->value_length > pPathRoot->value_length
1098 && !strncmp(pSource->value, pPathRoot->value, pPathRoot->value_length))
1099 {
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;
1106 }
1107 else
1108 pszSrc = pSource->value;
1109
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
1119 )
1120 pszSrc++;
1121
1122 /* drop the source extension. */
1123 pszSrcEnd = pSource->value + pSource->value_length;
1124 for (;;)
1125 {
1126 pszSrcEnd--;
1127 if ( pszSrcEnd <= pszSrc
1128 || *pszSrcEnd == '/'
1129#ifdef HAVE_DOS_PATHS
1130 || *pszSrcEnd == '\\'
1131 || *pszSrcEnd == ':'
1132#endif
1133 )
1134 {
1135 pszSrcEnd = pSource->value + pSource->value_length;
1136 break;
1137 }
1138 if (*pszSrcEnd == '.')
1139 break;
1140 }
1141
1142 /*
1143 * Assemble the string on the heap and define the objbase variable
1144 * which we then return.
1145 */
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);
1155
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)
1161 {
1162 memcpy(psz, pszSrcPrefix, cchSrcPrefix);
1163 psz += cchSrcPrefix;
1164 }
1165 pszDot = psz;
1166 memcpy(psz, pszSrc, cchSrc); psz += cchSrc;
1167 *psz = '\0';
1168
1169 /* convert '..' path elements in the source to 'dt'. */
1170 while ((pszDot = memchr(pszDot, '.', psz - pszDot)) != NULL)
1171 {
1172 if ( pszDot[1] == '.'
1173 && ( pszDot == psz
1174 || pszDot[-1] == '/'
1175#ifdef HAVE_DOS_PATHS
1176 || pszDot[-1] == '\\'
1177 || pszDot[-1] == ':'
1178#endif
1179 )
1180 && ( !pszDot[2]
1181 || pszDot[2] == '/'
1182#ifdef HAVE_DOS_PATHS
1183 || pszDot[2] == '\\'
1184 || pszDot[2] == ':'
1185#endif
1186 )
1187 )
1188 {
1189 *pszDot++ = 'd';
1190 *pszDot++ = 't';
1191 }
1192 else
1193 pszDot++;
1194 }
1195
1196 /*
1197 * Define the variable in the current set and return it.
1198 */
1199 return define_variable_vl(pszVarName, strlen(pszVarName), pszResult, cch - 1,
1200 0 /* use pszResult */, o_local, 0 /* !recursive */);
1201}
1202
1203
1204/* Implements _OBJECT_BASE. */
1205char *
1206func_kbuild_object_base(char *o, char **argv, const char *pszFuncName)
1207{
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;
1215
1216}
1217
1218
1219struct kbuild_sdks
1220{
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;
1233};
1234
1235
1236/* Fills in the SDK struct (remember to free it). */
1237static void
1238kbuild_get_sdks(struct kbuild_sdks *pSdks, struct variable *pTarget, struct variable *pSource,
1239 struct variable *pBldType, struct variable *pBldTrg, struct variable *pBldTrgArch)
1240{
1241 unsigned i;
1242 unsigned j;
1243 size_t cchTmp, cch;
1244 char *pszTmp;
1245 unsigned cchCur;
1246 char *pszCur;
1247 const char *pszIterator;
1248
1249 /** @todo rewrite this to avoid sprintf and allocated_varaible_expand_2. */
1250
1251 /* basic init. */
1252 pSdks->cchMax = 0;
1253 pSdks->pa = NULL;
1254 pSdks->c = 0;
1255 i = 0;
1256
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);
1265
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;
1278
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;
1292
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;
1306
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;
1321
1322 pSdks->c = i;
1323 if (!i)
1324 return;
1325
1326 /*
1327 * Allocate the variable array and create the variables.
1328 */
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++)
1332 {
1333 pszIterator = pSdks->apsz[j];
1334 while ((pszCur = find_next_token(&pszIterator, &cchCur)) != 0)
1335 {
1336 pSdks->pa[i].value = pszCur;
1337 pSdks->pa[i].value_length = cchCur;
1338 i++;
1339 }
1340 }
1341 assert(i == pSdks->c);
1342
1343 /* terminate them (find_next_token won't work if we terminate them in the previous loop). */
1344 while (i-- > 0)
1345 {
1346 pSdks->pa[i].value[pSdks->pa[i].value_length] = '\0';
1347
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;
1351 }
1352}
1353
1354
1355/* releases resources allocated in the kbuild_get_sdks. */
1356static void
1357kbuild_put_sdks(struct kbuild_sdks *pSdks)
1358{
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);
1363}
1364
1365
1366/* this kind of stuff:
1367
1368defs := $(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))
1489*/
1490static struct variable *
1491kbuild_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)
1499{
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
1506 {
1507 struct variable *pVar;
1508 unsigned int cchExp;
1509 char *pszExp;
1510 } *paVars;
1511
1512 assert(iDirection == 1 || iDirection == -1);
1513
1514 /*
1515 * Calc and allocate a too big name buffer.
1516 */
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);
1528
1529 /*
1530 * Get the variables.
1531 *
1532 * The compiler will get a heart attack when it sees this code ... ;-)
1533 */
1534 cVars = 12 * (pSdks->c + 5);
1535 paVars = alloca(cVars * sizeof(paVars[0]));
1536
1537 iVar = 0;
1538 cchTotal = 0;
1539
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) \
1548 { \
1549 paVars[iVar].pVar = pVar; \
1550 if ( !pVar->recursive \
1551 || !memchr(pVar->value, '$', pVar->value_length)) \
1552 { \
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) \
1558 { \
1559 cchTotal += paVars[iVar].cchExp + 1; \
1560 iVar++; \
1561 } \
1562 } \
1563 else \
1564 { \
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) \
1569 { \
1570 cchTotal += paVars[iVar].cchExp + 1; \
1571 iVar++; \
1572 } \
1573 else \
1574 free(paVars[iVar].pszExp); \
1575 } \
1576 } \
1577 } while (0)
1578#define DO_SINGLE_PSZ3_VARIATION() \
1579 do { \
1580 DO_VAR_LOOKUP(); \
1581 \
1582 ADD_CH('.'); \
1583 psz3 = psz; \
1584 ADD_VAR(pBldType); \
1585 DO_VAR_LOOKUP(); \
1586 \
1587 psz = psz3; \
1588 ADD_VAR(pBldTrg); \
1589 DO_VAR_LOOKUP(); \
1590 \
1591 psz = psz3; \
1592 ADD_VAR(pBldTrgArch); \
1593 DO_VAR_LOOKUP(); \
1594 \
1595 psz = psz3; \
1596 ADD_VAR(pBldTrg); \
1597 ADD_CH('.'); \
1598 ADD_VAR(pBldTrgArch); \
1599 DO_VAR_LOOKUP(); \
1600 \
1601 psz = psz3; \
1602 ADD_VAR(pBldTrgCpu); \
1603 DO_VAR_LOOKUP(); \
1604 } while (0)
1605
1606#define DO_DOUBLE_PSZ2_VARIATION() \
1607 do { \
1608 psz2 = psz; \
1609 ADD_STR(pszProp, cchProp); \
1610 DO_SINGLE_PSZ3_VARIATION(); \
1611 \
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)
1618
1619 /* the tool (lowest priority). */
1620 psz = pszBuf;
1621 ADD_CSTR("TOOL_");
1622 ADD_VAR(pTool);
1623 ADD_CH('_');
1624 DO_DOUBLE_PSZ2_VARIATION();
1625
1626
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)
1632 {
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();
1639 }
1640
1641 /* the globals. */
1642 psz = pszBuf;
1643 DO_DOUBLE_PSZ2_VARIATION();
1644
1645
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)
1651 {
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();
1658 }
1659
1660 /* the target. */
1661 psz = pszBuf;
1662 ADD_VAR(pTarget);
1663 ADD_CH('_');
1664 DO_DOUBLE_PSZ2_VARIATION();
1665
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)
1671 {
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();
1678 }
1679
1680 /* the source. */
1681 psz = pszBuf;
1682 ADD_VAR(pSource);
1683 ADD_CH('_');
1684 DO_DOUBLE_PSZ2_VARIATION();
1685
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)
1691 {
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();
1698 }
1699
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();
1707
1708 free(pszBuf);
1709
1710 assert(iVar <= cVars);
1711 cVars = iVar;
1712
1713 /*
1714 * Construct the result value.
1715 */
1716 if (!cVars || !cchTotal)
1717 pVar = define_variable_vl(pszVarName, cchVarName, "", 0,
1718 1 /* duplicate value */ , o_local, 0 /* !recursive */);
1719 else
1720 {
1721 psz = pszResult = xmalloc(cchTotal + 1);
1722 if (iDirection == 1)
1723 {
1724 for (iVar = 0; iVar < cVars; iVar++)
1725 {
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);
1731 }
1732 }
1733 else
1734 {
1735 iVar = cVars;
1736 while (iVar-- > 0)
1737 {
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);
1743 }
1744
1745 }
1746 assert(psz != pszResult);
1747 assert(cchTotal == (size_t)(psz - pszResult));
1748 psz[-1] = '\0';
1749 cchTotal--;
1750
1751 pVar = define_variable_vl(pszVarName, cchVarName, pszResult, cchTotal,
1752 0 /* take pszResult */ , o_local, 0 /* !recursive */);
1753 }
1754
1755 return pVar;
1756
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
1764}
1765
1766
1767/* get a source property. */
1768char *
1769func_kbuild_source_prop(char *o, char **argv, const char *pszFuncName)
1770{
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])
1790 {
1791 const char *psz = argv[3];
1792 while (isspace(*psz))
1793 psz++;
1794 if (*psz)
1795 pDefPath = kbuild_get_variable_n(ST("defpath"));
1796 }
1797
1798 kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch);
1799
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);
1808
1809 kbuild_put_sdks(&Sdks);
1810 (void)pszFuncName;
1811 return o;
1812}
1813
1814
1815/*
1816dep := $(obj)$(SUFF_DEP)
1817obj := $(outbase)$(objsuff)
1818dirdep := $(call DIRDEP,$(dir $(outbase)))
1819PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase)))
1820*/
1821static struct variable *
1822kbuild_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)
1826{
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;
1832
1833 /*
1834 * dep.
1835 */
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 */);
1841
1842 /*
1843 * obj
1844 */
1845 *psz = '\0';
1846 pObj = define_variable_vl(pszVarName, strlen(pszVarName), pszResult, psz - pszResult,
1847 1/* dup */, o_local, 0 /* !recursive */);
1848
1849 /*
1850 * PATH_$(target)_$(source) - this is global!
1851 */
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);
1859
1860 /* strip off the filename. */
1861 psz = pszResult + pOutBase->value_length;
1862 for (;;)
1863 {
1864 psz--;
1865 if (psz <= pszResult)
1866 fatal(NULL, "whut!?! no path? result=`%s'", pszResult);
1867#ifdef HAVE_DOS_PATHS
1868 if (*psz == ':')
1869 {
1870 psz++;
1871 break;
1872 }
1873#endif
1874 if ( *psz == '/'
1875#ifdef HAVE_DOS_PATHS
1876 || *psz == '\\'
1877#endif
1878 )
1879 {
1880 while ( psz - 1 > pszResult
1881 && psz[-1] == '/'
1882#ifdef HAVE_DOS_PATHS
1883 || psz[-1] == '\\'
1884#endif
1885 )
1886 psz--;
1887#ifdef HAVE_DOS_PATHS
1888 if (psz == pszResult + 2 && pszResult[1] == ':')
1889 psz++;
1890#endif
1891 break;
1892 }
1893 }
1894 *psz = '\0';
1895
1896 /* set global variable */
1897 define_variable_vl_global(pszName, cch, pszResult, psz - pszResult, 1/*dup*/, o_file, 0 /* !recursive */, NILF);
1898
1899 /*
1900 * dirdep
1901 */
1902 if ( psz[-1] != '/'
1903#ifdef HAVE_DOS_PATHS
1904 && psz[-1] != '\\'
1905 && psz[-1] != ':'
1906#endif
1907 )
1908 {
1909 *psz++ = '/';
1910 *psz = '\0';
1911 }
1912 *ppDirDep = define_variable_vl("dirdep", 6, pszResult, psz - pszResult, 1/*dup*/, o_local, 0 /* !recursive */);
1913
1914 return pObj;
1915}
1916
1917
1918/* setup the base variables for def_target_source_c_cpp_asm_new:
1919
1920X := $(kb-src-tool tool)
1921x := $(kb-obj-base outbase)
1922x := $(kb-obj-suff objsuff)
1923obj := $(outbase)$(objsuff)
1924PATH_$(target)_$(source) := $(patsubst %/,%,$(dir $(outbase)))
1925
1926x := $(kb-src-prop DEFS,defs,left-to-right)
1927x := $(kb-src-prop INCS,incs,right-to-left)
1928x := $(kb-src-prop FLAGS,flags,right-to-left)
1929
1930x := $(kb-src-prop DEPS,deps,left-to-right)
1931dirdep := $(call DIRDEP,$(dir $(outbase)))
1932dep := $(obj)$(SUFF_DEP)
1933*/
1934char *
1935func_kbuild_source_one(char *o, char **argv, const char *pszFuncName)
1936{
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;
1958
1959 /*
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.
1962 *
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).
1967 */
1968 if (!argv[0][0])
1969 iVer = 0;
1970 else
1971 switch (argv[0][0] | (argv[0][1] << 8))
1972 {
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;
1991 }
1992
1993 /*
1994 * Gather properties.
1995 */
1996 kbuild_get_sdks(&Sdks, pTarget, pSource, pBldType, pBldTrg, pBldTrgArch);
1997
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 */);
2010
2011 /*
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.
2015 */
2016 if (pDefPath)
2017 {
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 */);
2024 }
2025
2026 /*
2027 # dependencies
2028 ifndef NO_COMPILE_CMDS_DEPS
2029 _DEPFILES_INCLUDED += $(dep)
2030 $(if $(wildcard $(dep)),$(eval include $(dep)))
2031 endif
2032 */
2033 if (s_fNoCompileCmdsDepsDefined == -1)
2034 s_fNoCompileCmdsDepsDefined = kbuild_lookup_variable_n(ST("NO_COMPILE_CMDS_DEPS")) != NULL;
2035 if (!s_fNoCompileCmdsDepsDefined)
2036 {
2037 pVar = kbuild_query_recursive_variable_n("_DEPFILES_INCLUDED", sizeof("_DEPFILES_INCLUDED") - 1);
2038 if (pVar)
2039 {
2040 if (pVar->recursive)
2041 pVar = kbuild_simplify_variable(pVar);
2042 append_string_to_variable(pVar, pDep->value, pDep->value_length, 1 /* append */);
2043 }
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 */);
2051
2052 eval_include_dep(pDep->value, NILF, iVer >= 2 ? incdep_queue : incdep_read_it);
2053 }
2054
2055 /*
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)
2062 */
2063 cch = sizeof("TOOL_") + pTool->value_length + sizeof("_COMPILE_") + pType->value_length + sizeof("_OUTPUT_MAYBE");
2064 if (cch < pTarget->value_length + sizeof("$(_2_OBJS)"))
2065 cch = pTarget->value_length + sizeof("$(_2_OBJS)");
2066 psz = pszSrcVar = alloca(cch);
2067 memcpy(psz, "TOOL_", sizeof("TOOL_") - 1); psz += sizeof("TOOL_") - 1;
2068 memcpy(psz, pTool->value, pTool->value_length); psz += pTool->value_length;
2069 memcpy(psz, "_COMPILE_", sizeof("_COMPILE_") - 1); psz += sizeof("_COMPILE_") - 1;
2070 memcpy(psz, pType->value, pType->value_length); psz += pType->value_length;
2071 pszSrc = psz;
2072
2073 cch = pTarget->value_length + 1 + pSource->value_length + sizeof("_OUTPUT_MAYBE_");
2074 psz = pszDstVar = alloca(cch);
2075 memcpy(psz, pTarget->value, pTarget->value_length); psz += pTarget->value_length;
2076 *psz++ = '_';
2077 memcpy(psz, pSource->value, pSource->value_length); psz += pSource->value_length;
2078 pszDst = psz;
2079
2080 memcpy(pszSrc, "_CMDS", sizeof("_CMDS"));
2081 memcpy(pszDst, "_CMDS_", sizeof("_CMDS_"));
2082 pVar = kbuild_get_recursive_variable(pszSrcVar);
2083 do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2084 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2085
2086 memcpy(pszSrc, "_OUTPUT", sizeof("_OUTPUT"));
2087 memcpy(pszDst, "_OUTPUT_", sizeof("_OUTPUT_"));
2088 pVar = kbuild_get_recursive_variable(pszSrcVar);
2089 pOutput = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2090 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2091
2092 memcpy(pszSrc, "_OUTPUT_MAYBE", sizeof("_OUTPUT_MAYBE"));
2093 memcpy(pszDst, "_OUTPUT_MAYBE_", sizeof("_OUTPUT_MAYBE_"));
2094 pVar = kbuild_query_recursive_variable(pszSrcVar);
2095 if (pVar)
2096 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, pVar->value, pVar->value_length,
2097 !pVar->recursive, 0, o_file, f_simple, 0 /* !target_var */);
2098 else
2099 pOutputMaybe = do_variable_definition_2(NILF, pszDstVar, "", 0, 1, 0, o_file, f_simple, 0 /* !target_var */);
2100
2101 memcpy(pszSrc, "_DEPEND", sizeof("_DEPEND"));
2102 memcpy(pszDst, "_DEPEND_", sizeof("_DEPEND_"));
2103 pVar = kbuild_get_recursive_variable(pszSrcVar);
2104 psz = pszVal = xmalloc(pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length + 1);
2105 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2106 *psz++ = ' ';
2107 memcpy(psz, pDeps->value, pDeps->value_length); psz += pDeps->value_length;
2108 *psz++ = ' ';
2109 memcpy(psz, pSource->value, pSource->value_length + 1);
2110 do_variable_definition_2(NILF, pszDstVar, pszVal, pVar->value_length + 1 + pDeps->value_length + 1 + pSource->value_length,
2111 !pVar->recursive && !pDeps->recursive && !pSource->recursive,
2112 pszVal, o_file, f_simple, 0 /* !target_var */);
2113
2114 memcpy(pszSrc, "_DEPORD", sizeof("_DEPORD"));
2115 memcpy(pszDst, "_DEPORD_", sizeof("_DEPORD_"));
2116 pVar = kbuild_get_recursive_variable(pszSrcVar);
2117 psz = pszVal = xmalloc(pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length + 1);
2118 memcpy(psz, pVar->value, pVar->value_length); psz += pVar->value_length;
2119 *psz++ = ' ';
2120 memcpy(psz, pDirDep->value, pDirDep->value_length); psz += pDirDep->value_length;
2121 *psz++ = ' ';
2122 memcpy(psz, pOrderDeps->value, pOrderDeps->value_length + 1);
2123 do_variable_definition_2(NILF, pszDstVar, pszVal,
2124 pVar->value_length + 1 + pDirDep->value_length + 1 + pOrderDeps->value_length,
2125 !pVar->recursive && !pDirDep->recursive && !pOrderDeps->recursive,
2126 pszVal, o_file, f_simple, 0 /* !target_var */);
2127
2128 /*
2129 _OUT_FILES += $($(target)_$(source)_OUTPUT_) $($(target)_$(source)_OUTPUT_MAYBE_)
2130 */
2131 pVar = kbuild_get_variable_n(ST("_OUT_FILES"));
2132 append_string_to_variable(pVar, pOutput->value, pOutput->value_length, 1 /* append */);
2133 if (pOutputMaybe->value_length)
2134 append_string_to_variable(pVar, pOutputMaybe->value, pOutputMaybe->value_length, 1 /* append */);
2135
2136 /*
2137 $(target)_2_OBJS += $(obj)
2138 */
2139 memcpy(pszDstVar + pTarget->value_length, "_2_OBJS", sizeof("_2_OBJS"));
2140 pVar = kbuild_query_recursive_variable_n(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1);
2141 fInstallOldVars |= iVer <= 2 && (!pVar || !pVar->value_length);
2142 if (pVar)
2143 {
2144 if (pVar->recursive)
2145 pVar = kbuild_simplify_variable(pVar);
2146 append_string_to_variable(pVar, pObj->value, pObj->value_length, 1 /* append */);
2147 }
2148 else
2149 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_2_OBJS") - 1,
2150 pObj->value, pObj->value_length,
2151 1 /* duplicate_value */,
2152 o_file,
2153 0 /* recursive */,
2154 NULL /* flocp */);
2155
2156 /*
2157 * Install legacy variables.
2158 */
2159 if (fInstallOldVars)
2160 {
2161 /* $(target)_OBJS_ = $($(target)_2_OBJS)*/
2162 memcpy(pszDstVar + pTarget->value_length, "_OBJS_", sizeof("_OBJS_"));
2163
2164 pszSrcVar[0] = '$';
2165 pszSrcVar[1] = '(';
2166 memcpy(pszSrcVar + 2, pTarget->value, pTarget->value_length);
2167 psz = pszSrcVar + 2 + pTarget->value_length;
2168 memcpy(psz, "_2_OBJS)", sizeof("_2_OBJS)"));
2169
2170 define_variable_vl_global(pszDstVar, pTarget->value_length + sizeof("_OBJS_") - 1,
2171 pszSrcVar, pTarget->value_length + sizeof("$(_2_OBJS)") - 1,
2172 1 /* duplicate_value */,
2173 o_file,
2174 1 /* recursive */,
2175 NULL /* flocp */);
2176 }
2177
2178 /*
2179 $(eval $(def_target_source_rule))
2180 */
2181 pVar = kbuild_get_recursive_variable("def_target_source_rule");
2182 pszVal = variable_expand_string_2 (o, pVar->value, pVar->value_length, &psz);
2183 assert(!((size_t)pszVal & 3));
2184
2185 install_variable_buffer(&pszSavedVarBuf, &cchSavedVarBuf);
2186 eval_buffer(pszVal, psz);
2187 restore_variable_buffer(pszSavedVarBuf, cchSavedVarBuf);
2188
2189 kbuild_put_sdks(&Sdks);
2190 (void)pszFuncName;
2191
2192 *pszVal = '\0';
2193 return pszVal;
2194}
2195
2196/*
2197
2198## Inherit one template property in a non-accumulative manner.
2199# @param $(prop) Property name
2200# @param $(target) Target name
2201# @todo fix the precedence order for some properties.
2202define def_inherit_template_one
2203ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2204ifndef $(target)_$(prop)
2205$(target)_$(prop) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2206endif
2207endif
2208ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2209ifndef $(target)_$(prop).$(bld_trg)
2210$(target)_$(prop).$(bld_trg) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2211endif
2212endif
2213ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2214ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2215$(target)_$(prop).$(bld_trg).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2216endif
2217endif
2218ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2219ifndef $(target)_$(prop).$(bld_trg_arch)
2220$(target)_$(prop).$(bld_trg_arch) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2221endif
2222endif
2223ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2224ifndef $(target)_$(prop).$(bld_trg_cpu)
2225$(target)_$(prop).$(bld_trg_cpu) := $(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2226endif
2227endif
2228endef
2229
2230## Inherit one template property in a non-accumulative manner, deferred expansion.
2231# @param 1: $(prop) Property name
2232# @param 2: $(target) Target name
2233# @todo fix the precedence order for some properties.
2234# @remark this define relies on double evaluation
2235define def_inherit_template_one_deferred
2236ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2237ifndef $(target)_$(prop)
2238$(target)_$(prop) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2239endif
2240endif
2241ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2242ifndef $(target)_$(prop).$(bld_trg)
2243$(target)_$(prop).$(bld_trg) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2244endif
2245endif
2246ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2247ifndef $(target)_$(prop).$(bld_trg).$(bld_trg_arch)
2248$(target)_$(prop).$(bld_trg).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2249endif
2250endif
2251ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2252ifndef $(target)_$(prop).$(bld_trg_arch)
2253$(target)_$(prop).$(bld_trg_arch) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2254endif
2255endif
2256ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2257ifndef $(target)_$(prop).$(bld_trg_cpu)
2258$(target)_$(prop).$(bld_trg_cpu) = $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2259endif
2260endif
2261endef
2262
2263## Inherit one acculumlative template property where the 'most significant' items are at the left end.
2264# @param $(prop) Property name
2265# @param $(target) Target name
2266define def_inherit_template_one_accumulate_l
2267ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2268 ifeq ($$(flavor $(target)_$(prop)),simple)
2269 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2270 endif
2271$(target)_$(prop) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2272endif
2273ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2274 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2275 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2276 endif
2277$(target)_$(prop).$(KBUILD_TYPE) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2278endif
2279ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2280 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2281 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2282 endif
2283$(target)_$(prop).$(bld_trg) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2284endif
2285ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2286 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2287 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2288 endif
2289$(target)_$(prop).$(bld_trg).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2290endif
2291ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2292 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2293 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2294 endif
2295$(target)_$(prop).$(bld_trg_cpu) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2296endif
2297ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2298 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2299 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2300 endif
2301$(target)_$(prop).$(bld_trg_arch) += $$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2302endif
2303endef
2304
2305## Inherit one acculumlative template property where the 'most significant' items are at the right end.
2306# @param $(prop) Property name
2307# @param $(target) Target name
2308define def_inherit_template_one_accumulate_r
2309ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop)
2310 ifeq ($$(flavor $(target)_$(prop)),simple)
2311 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop))
2312 endif
2313$(target)_$(prop) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop))
2314endif
2315ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE)
2316 ifeq ($$(flavor $(target)_$(prop).$(KBUILD_TYPE)),simple)
2317 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(KBUILD_TYPE))
2318 endif
2319$(target)_$(prop).$(KBUILD_TYPE) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(KBUILD_TYPE))
2320endif
2321ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg)
2322 ifeq ($$(flavor $(target)_$(prop).$(bld_trg)),simple)
2323 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg))
2324 endif
2325$(target)_$(prop).$(bld_trg) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg))
2326endif
2327ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch)
2328 ifeq ($$(flavor $(target)_$(prop).$(bld_trg).$(bld_trg_arch)),simple)
2329 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg).$(bld_trg_arch))
2330 endif
2331$(target)_$(prop).$(bld_trg).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg).$(bld_trg_arch))
2332endif
2333ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu)
2334 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_cpu)),simple)
2335 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_cpu))
2336 endif
2337$(target)_$(prop).$(bld_trg_cpu) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_cpu))
2338endif
2339ifdef TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch)
2340 ifeq ($$(flavor $(target)_$(prop).$(bld_trg_arch)),simple)
2341 $$(evalcall2 def_simple_2_recursive,$(target)_$(prop).$(bld_trg_arch))
2342 endif
2343$(target)_$(prop).$(bld_trg_arch) <=$$(TEMPLATE_$($(target)_TEMPLATE)_$(prop).$(bld_trg_arch))
2344endif
2345endef
2346
2347
2348## Inherit template properties for on target.
2349# @param $(target) Target name.
2350define def_inherit_template
2351# sanity check.
2352ifdef _$(target)_ALREADY_PROCESSED
2353 $(error kBuild: The target $(target) appears more than once in the target lists! Please correct the makefile(s))
2354endif
2355_$(target)_ALREADY_PROCESSED := 1
2356
2357# Inherit any default template.
2358ifdef TEMPLATE
2359ifeq ($($(target)_TEMPLATE),)
2360$(eval $(target)_TEMPLATE:=$(TEMPLATE))
2361endif
2362endif
2363# Expand the template if specified.
2364ifneq ($($(target)_TEMPLATE),)
2365$(foreach prop,$(PROPS_SINGLE),$(evalval def_inherit_template_one))
2366$(foreach prop,$(PROPS_DEFERRED),$(eval $(def_inherit_template_one_deferred))) # exploits the 2 evaluation, so no value!
2367$(foreach prop,$(PROPS_ACCUMULATE_L),$(eval $(def_inherit_template_one_accumulate_l))) # += works fine without value
2368$(foreach prop,$(PROPS_ACCUMULATE_R),$(eval $(def_inherit_template_one_accumulate_r))) # use <= (kmk addition)
2369endif
2370endef
2371
2372
2373Invoked like this:
2374 $(kb-exp-tmpl 1,$(_ALL_TARGET_TARGETS),$(KBUILD_TARGET),$(KBUILD_TARGET_ARCH),$(KBUILD_TARGET_CPU),$(KBUILD_TYPE))
2375*/
2376char *
2377func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName)
2378{
2379 const char *pszVersion = argv[0];
2380 const char *pszBldTrg = argv[2];
2381 const char *pszBldTrgArch = argv[3];
2382 const char *pszBldTrgCpu = argv[4];
2383 const char *pszBldType = argv[5];
2384 size_t cchBldTrg = strlen(pszBldTrg);
2385 size_t cchBldTrgArch = strlen(pszBldTrgArch);
2386 size_t cchBldTrgCpu = strlen(pszBldTrgCpu);
2387 size_t cchBldType = strlen(pszBldType);
2388 size_t cchMaxBld = cchBldTrg + cchBldTrgArch + cchBldTrgCpu + cchBldType; /* too big, but so what. */
2389 struct kbet_key
2390 {
2391 unsigned int cch;
2392 char *psz;
2393 } aKeys[6];
2394 unsigned int const cKeys = 6;
2395 unsigned int iKey;
2396 struct variable *pDefTemplate;
2397 struct variable *pProps;
2398 struct kbet_prop
2399 {
2400 const char *pch;
2401 unsigned int cch;
2402 enum kbet_prop_enum { kPropSingle, kPropDeferred, kPropAccumulateL, kPropAccumulateR }
2403 enmType;
2404 } *paProps;
2405 unsigned int cProps;
2406 unsigned int iProp;
2407 size_t cchMaxProp;
2408 struct variable *pVarTrg;
2409 struct variable *pVarSrc;
2410 const char *pszIter;
2411 const char *pszTarget;
2412 unsigned int cchTarget;
2413 char *pszSrc = 0;
2414 char *pszSrcRef = 0;
2415 char *pszSrcBuf = 0;
2416 size_t cchSrcBuf = 0;
2417 char *pszTrg = 0;
2418 size_t cchTrg = 0;
2419
2420 /*
2421 * Validate input.
2422 */
2423 if (pszVersion[0] != '1' || pszVersion[1])
2424 fatal(NULL, "%s: Unsupported version `%s'", pszFuncName, pszVersion);
2425
2426 if (!cchBldTrg)
2427 fatal(NULL, "%s: missing bldtrg", pszFuncName);
2428
2429 if (!cchBldTrgArch)
2430 fatal(NULL, "%s: missing bld_trg_arch", pszFuncName);
2431
2432 if (!cchBldTrgCpu)
2433 fatal(NULL, "%s: missing bld_trg_cpu", pszFuncName);
2434
2435 if (!cchBldType)
2436 fatal(NULL, "%s: missing bld_type", pszFuncName);
2437
2438 /*
2439 * Prepare the keywords, prepending dots for quicker copying.
2440 * This allows for an inner loop when processing properties, saving code
2441 * at the expense of a few xmallocs.
2442 */
2443 /* the first entry is empty. */
2444 aKeys[0].cch = 0;
2445 aKeys[0].psz = NULL;
2446
2447 aKeys[1].cch = cchBldType + 1;
2448 aKeys[1].psz = xmalloc (aKeys[1].cch + 1);
2449 aKeys[1].psz[0] = '.';
2450 memcpy(aKeys[1].psz + 1, pszBldType, cchBldType + 1);
2451
2452 aKeys[2].cch = cchBldTrg + 1;
2453 aKeys[2].psz = xmalloc (aKeys[2].cch + 1);
2454 aKeys[2].psz[0] = '.';
2455 memcpy(aKeys[2].psz + 1, pszBldTrg, cchBldTrg + 1);
2456
2457 aKeys[3].cch = cchBldTrg + 1 + cchBldTrgArch + 1;
2458 aKeys[3].psz = xmalloc (aKeys[3].cch + 1);
2459 aKeys[3].psz[0] = '.';
2460 memcpy(aKeys[3].psz + 1, pszBldTrg, cchBldTrg);
2461 aKeys[3].psz[1 + cchBldTrg] = '.';
2462 memcpy(aKeys[3].psz + 1 + cchBldTrg + 1, pszBldTrgArch, cchBldTrgArch + 1);
2463
2464 aKeys[4].cch = cchBldTrgCpu + 1;
2465 aKeys[4].psz = xmalloc (aKeys[4].cch + 1);
2466 aKeys[4].psz[0] = '.';
2467 memcpy(aKeys[4].psz + 1, pszBldTrgCpu, cchBldTrgCpu + 1);
2468
2469 aKeys[5].cch = cchBldTrgArch + 1;
2470 aKeys[5].psz = xmalloc (aKeys[5].cch + 1);
2471 aKeys[5].psz[0] = '.';
2472 memcpy(aKeys[5].psz + 1, pszBldTrgArch, cchBldTrgArch + 1);
2473
2474
2475 /*
2476 * Prepare the properties, folding them into an array.
2477 * This way we won't have to reparse them for each an every target, though
2478 * it comes at the expense of one or more heap calls.
2479 */
2480#define PROP_ALLOC_INC 128
2481 iProp = 0;
2482 cProps = PROP_ALLOC_INC;
2483 paProps = xmalloc(sizeof(*pProps) * cProps);
2484
2485 pProps = kbuild_get_variable_n(ST("PROPS_SINGLE"));
2486 pszIter = pProps->value;
2487 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2488 {
2489 paProps[iProp].enmType = kPropSingle;
2490 if (++iProp >= cProps)
2491 {
2492 cProps += PROP_ALLOC_INC;
2493 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2494 }
2495
2496 }
2497
2498 pProps = kbuild_get_variable_n(ST("PROPS_DEFERRED"));
2499 pszIter = pProps->value;
2500 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2501 {
2502 paProps[iProp].enmType = kPropDeferred;
2503 if (++iProp >= cProps)
2504 {
2505 cProps += PROP_ALLOC_INC;
2506 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2507 }
2508 }
2509
2510 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_L"));
2511 pszIter = pProps->value;
2512 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2513 {
2514 paProps[iProp].enmType = kPropAccumulateL;
2515 if (++iProp >= cProps)
2516 {
2517 cProps += PROP_ALLOC_INC;
2518 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2519 }
2520 }
2521
2522 pProps = kbuild_get_variable_n(ST("PROPS_ACCUMULATE_R"));
2523 pszIter = pProps->value;
2524 while ((paProps[iProp].pch = find_next_token(&pszIter, &paProps[iProp].cch)))
2525 {
2526 paProps[iProp].enmType = kPropAccumulateR;
2527 if (++iProp >= cProps)
2528 {
2529 cProps += PROP_ALLOC_INC;
2530 paProps = xrealloc(paProps, sizeof(*paProps) * cProps);
2531 }
2532 }
2533#undef PROP_ALLOC_INC
2534 cProps = iProp;
2535
2536 /* find the max prop length. */
2537 cchMaxProp = paProps[0].cch;
2538 while (--iProp > 0)
2539 if (paProps[iProp].cch > cchMaxProp)
2540 cchMaxProp = paProps[iProp].cch;
2541
2542 /*
2543 * Query and prepare (strip) the default template
2544 * (given by the TEMPLATE variable).
2545 */
2546 pDefTemplate = kbuild_lookup_variable_n(ST("TEMPLATE"));
2547 if (pDefTemplate)
2548 {
2549 if ( pDefTemplate->value_length
2550 && ( isspace(pDefTemplate->value[0])
2551 || isspace(pDefTemplate->value[pDefTemplate->value_length - 1])))
2552 {
2553 unsigned int off;
2554 if (pDefTemplate->rdonly_val)
2555 fatal(NULL, "%s: TEMPLATE is read-only", pszFuncName);
2556
2557 /* head */
2558 for (off = 0; isspace(pDefTemplate->value[off]); off++)
2559 /* nothing */;
2560 if (off)
2561 {
2562 pDefTemplate->value_length -= off;
2563 memmove(pDefTemplate->value, pDefTemplate->value + off, pDefTemplate->value_length + 1);
2564 }
2565
2566 /* tail */
2567 off = pDefTemplate->value_length;
2568 while (off > 0 && isspace(pDefTemplate->value[off - 1]))
2569 off--;
2570 pDefTemplate->value_length = off;
2571 pDefTemplate->value[off] = '\0';
2572 }
2573
2574 if (!pDefTemplate->value_length)
2575 pDefTemplate = NULL;
2576 }
2577
2578 /*
2579 * Iterate the target list.
2580 */
2581 pszIter = argv[1];
2582 while ((pszTarget = find_next_token(&pszIter, &cchTarget)))
2583 {
2584 char *pszTrgProp, *pszSrcProp;
2585 char *pszTrgKey, *pszSrcKey;
2586 struct variable *pTmpl;
2587 const char *pszTmpl;
2588 size_t cchTmpl, cchMax;
2589
2590 /* resize the target buffer. */
2591 cchMax = cchTarget + cchMaxProp + cchMaxBld + 10;
2592 if (cchTrg < cchMax)
2593 {
2594 cchTrg = (cchMax + 31U) & ~(size_t)31;
2595 pszTrg = xrealloc(pszTrg, cchTrg);
2596 }
2597
2598 /*
2599 * Query the TEMPLATE property, if not found or zero-length fall back on the default.
2600 */
2601 memcpy(pszTrg, pszTarget, cchTarget);
2602 pszTrgProp = pszTrg + cchTarget;
2603 memcpy(pszTrgProp, "_TEMPLATE", sizeof("_TEMPLATE"));
2604 pszTrgProp++; /* after '_'. */
2605
2606 /** @todo Change this to a recursive lookup with simplification below. That
2607 * will allow target_TEMPLATE = $(NO_SUCH_TEMPLATE) instead of having
2608 * to use target_TEMPLATE = DUMMY */
2609 pTmpl = kbuild_lookup_variable_n(pszTrg, cchTarget + sizeof("_TEMPLATE") - 1);
2610 if (!pTmpl || !pTmpl->value_length)
2611 {
2612 if (!pDefTemplate)
2613 continue; /* no template */
2614 pszTmpl = pDefTemplate->value;
2615 cchTmpl = pDefTemplate->value_length;
2616 }
2617 else
2618 {
2619 pszTmpl = pTmpl->value;
2620 cchTmpl = pTmpl->value_length;
2621 while (isspace(*pszTmpl))
2622 cchTmpl--, pszTmpl++;
2623 if (!cchTmpl)
2624 continue; /* no template */
2625 }
2626
2627 /* resize the source buffer. */
2628 cchMax = sizeof("TEMPLATE_") + cchTmpl + cchMaxProp + cchMaxBld + 10 + sizeof(void *);
2629 if (cchSrcBuf < cchMax)
2630 {
2631 cchSrcBuf = (cchMax + 31U) & ~(size_t)31;
2632 pszSrcBuf = xrealloc(pszSrcBuf, cchSrcBuf);
2633 pszSrc = pszSrcBuf + sizeof(void *); assert(sizeof(void *) >= 2);
2634 pszSrcRef = pszSrc - 2;
2635 pszSrcRef[0] = '$';
2636 pszSrcRef[1] = '(';
2637 }
2638
2639 /* prepare the source buffer */
2640 memcpy(pszSrc, "TEMPLATE_", sizeof("TEMPLATE_") - 1);
2641 pszSrcProp = pszSrc + sizeof("TEMPLATE_") - 1;
2642 memcpy(pszSrcProp, pszTmpl, cchTmpl);
2643 pszSrcProp += cchTmpl;
2644 *pszSrcProp++ = '_';
2645
2646 /*
2647 * Process properties.
2648 * Note! The single and deferred are handled in the same way now.
2649 */
2650#define BY_REF_LIMIT 64 /*(cchSrcVar * 4 > 64 ? cchSrcVar * 4 : 64)*/
2651
2652 for (iProp = 0; iProp < cProps; iProp++)
2653 {
2654 memcpy(pszTrgProp, paProps[iProp].pch, paProps[iProp].cch);
2655 pszTrgKey = pszTrgProp + paProps[iProp].cch;
2656
2657 memcpy(pszSrcProp, paProps[iProp].pch, paProps[iProp].cch);
2658 pszSrcKey = pszSrcProp + paProps[iProp].cch;
2659
2660 for (iKey = 0; iKey < cKeys; iKey++)
2661 {
2662 char *pszTrgEnd;
2663 size_t cchSrcVar;
2664
2665 /* lookup source, skip ahead if it doesn't exist. */
2666 memcpy(pszSrcKey, aKeys[iKey].psz, aKeys[iKey].cch);
2667 cchSrcVar = pszSrcKey - pszSrc + aKeys[iKey].cch;
2668 pszSrc[cchSrcVar] = '\0';
2669 pVarSrc = kbuild_query_recursive_variable_n(pszSrc, cchSrcVar);
2670 if (!pVarSrc)
2671 continue;
2672
2673 /* lookup target, skip ahead if it exists. */
2674 memcpy(pszTrgKey, aKeys[iKey].psz, aKeys[iKey].cch);
2675 pszTrgEnd = pszTrgKey + aKeys[iKey].cch;
2676 *pszTrgEnd = '\0';
2677 pVarTrg = kbuild_query_recursive_variable_n(pszTrg, pszTrgEnd - pszTrg);
2678
2679 switch (paProps[iProp].enmType)
2680 {
2681 case kPropAccumulateL:
2682 case kPropAccumulateR:
2683 if (pVarTrg)
2684 {
2685 /* Append to existing variable. If the source is recursive,
2686 or we append by reference, we'll have to make sure the
2687 target is recusive as well. */
2688 if ( !pVarTrg->recursive
2689 && ( pVarSrc->value_length >= BY_REF_LIMIT
2690 || pVarSrc->recursive))
2691 pVarTrg->recursive = 1;
2692
2693 if (pVarSrc->value_length < BY_REF_LIMIT)
2694 append_string_to_variable(pVarTrg, pVarSrc->value, pVarSrc->value_length,
2695 paProps[iProp].enmType == kPropAccumulateL /* append */);
2696 else
2697 {
2698 pszSrc[cchSrcVar] = ')';
2699 pszSrc[cchSrcVar + 1] = '\0';
2700 append_string_to_variable(pVarTrg, pszSrcRef, 2 + cchSrcVar + 1,
2701 paProps[iProp].enmType == kPropAccumulateL /* append */);
2702 }
2703 break;
2704 }
2705 /* else: the target variable doesn't exist, create it. */
2706 /* fall thru */
2707
2708 case kPropSingle:
2709 case kPropDeferred:
2710 if (pVarTrg)
2711 continue; /* skip ahead if it already exists. */
2712
2713 /* copy the variable if its short, otherwise reference it. */
2714 if (pVarSrc->value_length < BY_REF_LIMIT)
2715 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2716 pVarSrc->value, pVarSrc->value_length,
2717 1 /* duplicate_value */,
2718 o_file,
2719 pVarSrc->recursive,
2720 NULL /* flocp */);
2721 else
2722 {
2723 pszSrc[cchSrcVar] = ')';
2724 pszSrc[cchSrcVar + 1] = '\0';
2725 define_variable_vl_global(pszTrg, pszTrgEnd - pszTrg,
2726 pszSrcRef, 2 + cchSrcVar + 1,
2727 1 /* duplicate_value */,
2728 o_file,
2729 1 /* recursive */,
2730 NULL /* flocp */);
2731 }
2732 break;
2733
2734 }
2735
2736 } /* foreach key */
2737 } /* foreach prop */
2738#undef BY_REF_LIMIT
2739 } /* foreach target */
2740
2741 /*
2742 * Cleanup.
2743 */
2744 free(pszSrcBuf);
2745 free(pszTrg);
2746 free(paProps);
2747 for (iKey = 1; iKey < cKeys; iKey++)
2748 free(aKeys[iKey].psz);
2749
2750 return o;
2751}
2752
2753#endif /* KMK_HELPERS */
2754
Note: See TracBrowser for help on using the repository browser.

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