Changeset 2720 in kBuild
- Timestamp:
- Jan 1, 2014 10:59:50 PM (11 years ago)
- Location:
- trunk/src/kmk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kbuild-object.c
r2719 r2720 1 1 /* $Id$ */ 2 2 /** @file 3 * kBuild specific make functionality related to read.c.3 * kBuild objects. 4 4 */ 5 5 6 6 /* 7 * Copyright (c) 2011-201 3knut st. osmundsen <[email protected]>7 * Copyright (c) 2011-2014 knut st. osmundsen <[email protected]> 8 8 * 9 9 * This file is part of kBuild. … … 125 125 126 126 /******************************************************************************* 127 * Header Files*127 * Global Variables * 128 128 *******************************************************************************/ 129 129 /** Linked list (LIFO) of kBuild defines. … … 147 147 *******************************************************************************/ 148 148 static struct kbuild_object * 149 eval_kbuild_resolve_parent(struct kbuild_object *pObj, int fQuiet); 149 resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet); 150 static struct kbuild_object * 151 get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity); 150 152 151 153 static struct kbuild_object * … … 204 206 205 207 208 static const char * 209 eval_kbuild_type_to_string(enum kBuildType enmType) 210 { 211 switch (enmType) 212 { 213 case kBuildType_Target: return "target"; 214 case kBuildType_Template: return "template"; 215 case kBuildType_Tool: return "tool"; 216 case kBuildType_Sdk: return "sdk"; 217 case kBuildType_Unit: return "unit"; 218 default: 219 case kBuildType_Invalid: return "invalid"; 220 } 221 } 222 223 /** 224 * Gets the length of the string representation of the given type. 225 * 226 * @returns The string length. 227 * @param enmType The kBuild object type in question. 228 */ 229 static unsigned 230 eval_kbuild_type_to_string_length(enum kBuildType enmType) 231 { 232 switch (enmType) 233 { 234 case kBuildType_Target: return sizeof("target") - 1; 235 case kBuildType_Template: return sizeof("template") - 1; 236 case kBuildType_Tool: return sizeof("tool") - 1; 237 case kBuildType_Sdk: return sizeof("sdk") - 1; 238 case kBuildType_Unit: return sizeof("unit") - 1; 239 default: 240 case kBuildType_Invalid: return sizeof("invalid") - 1; 241 } 242 } 243 244 /** 245 * Converts a string into an kBuild object type. 246 * 247 * @returns The type on success, kBuildType_Invalid on failure. 248 * @param pchWord The pchWord. Not necessarily zero terminated. 249 * @param cchWord The length of the word. 250 */ 251 static enum kBuildType 252 eval_kbuild_type_from_string(const char *pchWord, size_t cchWord) 253 { 254 if (cchWord >= 3) 255 { 256 if (*pchWord == 't') 257 { 258 if (WORD_IS(pchWord, cchWord, "target")) 259 return kBuildType_Target; 260 if (WORD_IS(pchWord, cchWord, "template")) 261 return kBuildType_Template; 262 if (WORD_IS(pchWord, cchWord, "tool")) 263 return kBuildType_Tool; 264 } 265 else 266 { 267 if (WORD_IS(pchWord, cchWord, "sdk")) 268 return kBuildType_Sdk; 269 if (WORD_IS(pchWord, cchWord, "unit")) 270 return kBuildType_Unit; 271 } 272 } 273 274 return kBuildType_Invalid; 275 } 276 277 278 206 279 /** 207 280 * Helper function for caching variable name strings. … … 263 336 } 264 337 338 static const char * 339 kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue, 340 const struct floc *pFileLoc) 341 { 342 size_t cchValue = *pcchValue; 343 size_t cbAllocated = *pfDuplicateValue ? 0 : cchValue + 1; 344 345 /* 346 * Loop thru each potential special accessor occurance in the string. 347 * 348 * Unfortunately, we don't have a strnstr function in the C library, so 349 * we'll using memchr and doing a few more rounds in this loop. 350 */ 351 size_t cchLeft = cchValue; 352 char *pchLeft = (char *)pchValue; 353 for (;;) 354 { 355 int fSuper; 356 char *pch = (char *)memchr(pchLeft, '$', cchLeft); 357 if (!pch) 358 break; 359 360 pch++; 361 cchLeft -= pch - pchLeft; 362 pchLeft = pch; 363 364 /* [@self] is the shorter, quit if there isn't enough room for even it. */ 365 if (cchLeft < sizeof("([@self]") - 1) 366 break; 367 368 /* We don't care how many dollars there are in front of a special accessor. */ 369 if (*pchLeft == '$') 370 { 371 do 372 { 373 cchLeft--; 374 pchLeft++; 375 } while (cchLeft >= sizeof("([@self]") - 1 && *pchLeft == '$'); 376 if (cchLeft < sizeof("([@self]") - 1) 377 break; 378 } 379 380 /* Is it a special accessor? */ 381 if ( pchLeft[2] != '@' 382 || pchLeft[1] != '[' 383 || pchLeft[0] != '(') 384 continue; 385 pchLeft += 2; 386 cchLeft -= 2; 387 if (!memcmp(pchLeft, STRING_SIZE_TUPLE("@self]"))) 388 fSuper = 0; 389 else if ( cchLeft >= sizeof("@super]") 390 && !memcmp(pchLeft, STRING_SIZE_TUPLE("@super]"))) 391 fSuper = 1; 392 else 393 continue; 394 395 /* 396 * We've got something to replace. First figure what with and then 397 * resize the value buffer. 398 */ 399 if (g_pTopKbEvalData) 400 { 401 struct kbuild_object *pObj = g_pTopKbEvalData->pObj; 402 size_t const cchSpecial = fSuper ? sizeof("@super") - 1 : sizeof("@self") - 1; 403 size_t cchName; 404 size_t cchType; 405 long cchDelta; 406 const char *pszName; 407 408 if (fSuper) 409 { 410 pObj = get_kbuild_object_parent(pObj, kBuildSeverity_Error); 411 if (!pObj) 412 continue; 413 } 414 pszName = pObj->pszName; 415 cchName = pObj->cchName; 416 cchType = eval_kbuild_type_to_string_length(pObj->enmType); 417 cchDelta = cchType + 1 + cchName - cchSpecial; 418 419 if (cchValue + cchDelta >= cbAllocated) 420 { 421 size_t offLeft = pchLeft - pchValue; 422 char *pszNewValue; 423 424 cbAllocated = cchValue + cchDelta + 1; 425 if (cchValue < 1024) 426 cbAllocated = (cbAllocated + 31) & ~(size_t)31; 427 else 428 cbAllocated = (cbAllocated + 255) & ~(size_t)255; 429 pszNewValue = (char *)xmalloc(cbAllocated); 430 431 memcpy(pszNewValue, pchValue, offLeft); 432 memcpy(pszNewValue + offLeft + cchSpecial + cchDelta, 433 pchLeft + cchSpecial, 434 cchLeft - cchSpecial + 1); 435 436 if (*pfDuplicateValue == 0) 437 free((char *)pchValue); 438 else 439 *pfDuplicateValue = 0; 440 441 pchValue = pszNewValue; 442 pchLeft = pszNewValue + offLeft; 443 } 444 else 445 { 446 assert(*pfDuplicateValue == 0); 447 memmove(pchLeft + cchSpecial + cchDelta, 448 pchLeft + cchSpecial, 449 cchLeft - cchSpecial + 1); 450 } 451 452 cchLeft += cchDelta; 453 cchValue += cchDelta; 454 *pcchValue = cchValue; 455 456 memcpy(pchLeft, eval_kbuild_type_to_string(pObj->enmType), cchType); 457 pchLeft += cchType; 458 *pchLeft++ = '@'; 459 memcpy(pchLeft, pszName, cchName); 460 pchLeft += cchName; 461 cchLeft -= cchType + 1 + cchName; 462 } 463 else 464 error(pFileLoc, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"), 465 MAX(cchLeft, 20), pchLeft); 466 } 467 468 return pchValue; 469 } 470 265 471 static struct variable * 266 472 define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName, 267 473 const char *pchValue, size_t cchValue, 268 474 int fDuplicateValue, enum variable_origin enmOrigin, 269 int fRecursive, const struct floc *pFileLoc)475 int fRecursive, int fNoSpecialAccessors, const struct floc *pFileLoc) 270 476 { 271 477 struct variable *pVar; 272 478 size_t cchName = strcache2_get_len(&variable_strcache, pszName); 273 479 480 if (fRecursive && !fNoSpecialAccessors) 481 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); 274 482 275 483 pVar = define_variable_in_set(pszName, cchName, … … 354 562 (int)cchVarNm, pchVarNm, (int)cchName, pchName); 355 563 return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm), 356 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pFileLoc); 564 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, 565 0 /*fNoSpecialAccessors*/, pFileLoc); 357 566 } 358 567 … … 393 602 394 603 return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName), 395 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, pFileLoc); 604 pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, 605 0 /*fNoSpecialAccessors*/, pFileLoc); 396 606 } 397 607 … … 463 673 { 464 674 /* Append/prepend to existing variable. */ 465 return do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend); 675 int fDuplicateValue = 1; 676 if (pVar->recursive && !fSimpleValue) 677 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); 678 679 pVar = do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend); 680 681 if (fDuplicateValue == 0) 682 free((char *)pchValue); 683 return pVar; 466 684 } 467 685 … … 474 692 for (;;) 475 693 { 476 pParent = eval_kbuild_resolve_parent(pParent, 0 /*fQuiet*/);694 pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/); 477 695 if (!pParent) 478 696 break; … … 496 714 || memchr(pchValue, '$', cchValue) == NULL ) 497 715 { 716 int fDuplicateValue = 1; 498 717 size_t cchNewValue; 499 718 char *pszNewValue; … … 501 720 502 721 /* Just join up the two values. */ 722 if (pVar->recursive && !fSimpleValue) 723 pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); 503 724 if (pVar->value_length == 0) 504 725 { … … 535 756 536 757 /* Define the new variable in the child. */ 537 returndefine_kbuild_object_variable_cached(pObj, VarKey.name,758 pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, 538 759 pszNewValue, cchNewValue, 0 /*fDuplicateValue*/, 539 enmOrigin, pVar->recursive, pFileLoc); 540 760 enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, 761 pFileLoc); 762 if (fDuplicateValue == 0) 763 free((char *)pchValue); 541 764 } 542 765 else … … 546 769 pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, 547 770 pVar->value, pVar->value_length, 1 /*fDuplicateValue*/, 548 enmOrigin, pVar->recursive, pFileLoc); 771 enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, 772 pFileLoc); 549 773 append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend); 550 return pVar;551 774 } 775 return pVar; 552 776 } 553 777 } … … 560 784 return define_kbuild_object_variable_cached(pObj, VarKey.name, 561 785 pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin, 562 1 /*fRecursive */, pFileLoc);786 1 /*fRecursive */, 0 /*fNoSpecialAccessors*/, pFileLoc); 563 787 } 564 788 565 789 /** @} */ 566 567 568 static const char *569 eval_kbuild_type_to_string(enum kBuildType enmType)570 {571 switch (enmType)572 {573 case kBuildType_Target: return "target";574 case kBuildType_Template: return "template";575 case kBuildType_Tool: return "tool";576 case kBuildType_Sdk: return "sdk";577 case kBuildType_Unit: return "unit";578 default:579 case kBuildType_Invalid: return "invalid";580 }581 }582 583 /**584 * Converts a string into an kBuild object type.585 *586 * @returns The type on success, kBuildType_Invalid on failure.587 * @param pchWord The pchWord. Not necessarily zero terminated.588 * @param cchWord The length of the word.589 */590 static enum kBuildType591 eval_kbuild_type_from_string(const char *pchWord, size_t cchWord)592 {593 if (cchWord >= 3)594 {595 if (*pchWord == 't')596 {597 if (WORD_IS(pchWord, cchWord, "target"))598 return kBuildType_Target;599 if (WORD_IS(pchWord, cchWord, "template"))600 return kBuildType_Template;601 if (WORD_IS(pchWord, cchWord, "tool"))602 return kBuildType_Tool;603 }604 else605 {606 if (WORD_IS(pchWord, cchWord, "sdk"))607 return kBuildType_Sdk;608 if (WORD_IS(pchWord, cchWord, "unit"))609 return kBuildType_Unit;610 }611 }612 613 return kBuildType_Invalid;614 }615 790 616 791 … … 653 828 654 829 static struct kbuild_object * 655 eval_kbuild_resolve_parent(struct kbuild_object *pObj, int fQuiet)830 resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet) 656 831 { 657 832 if ( !pObj->pParent … … 685 860 } 686 861 862 /** 863 * Get the parent of the given object, it is expected to have one. 864 * 865 * @returns Pointer to the parent. NULL if we survive failure. 866 * @param pObj The kBuild object. 867 * @param enmSeverity The severity of a missing parent. 868 */ 869 static struct kbuild_object * 870 get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity) 871 { 872 struct kbuild_object *pParent = pObj->pParent; 873 if (pParent) 874 return pParent; 875 876 pParent = resolve_kbuild_object_parent(pObj, 1 /*fQuiet - complain below */); 877 if (pParent) 878 return pParent; 879 880 if (pObj->pszParent) 881 kbuild_report_problem(enmSeverity, &pObj->FileLoc, 882 _("Could not local parent '%s' for kBuild object '%s'"), 883 pObj->pszParent, pObj->pszName); 884 else 885 kbuild_report_problem(enmSeverity, &pObj->FileLoc, 886 _("kBuild object '%s' has no parent ([@super])"), 887 pObj->pszName); 888 return NULL; 889 } 890 687 891 static int 688 892 eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const struct floc *pFileLoc, … … 789 993 790 994 define_kbuild_object_variable_cached(pObj, g_pszVarNmTemplate, pszTemplate, cchTemplate, 791 0 /*fDuplicateValue*/, o_default, 0 /*fRecursive*/, pFileLoc), 792 793 /* next token */ 794 psz = find_next_token_eos(&pszLine, pszEos, &cch); 995 0 /*fDuplicateValue*/, o_default, 0 /*fRecursive*/, 996 1 /*fNoSpecialAccessors*/, pFileLoc); 997 795 998 } 796 999 else 797 1000 fatal(pFileLoc, _("Don't know what '%.*s' means"), (int)cch, psz); 1001 1002 /* next token */ 1003 psz = find_next_token_eos(&pszLine, pszEos, &cch); 798 1004 } 799 1005 … … 801 1007 * Try resolve the parent. 802 1008 */ 803 eval_kbuild_resolve_parent(pObj, 1 /*fQuiet*/);1009 resolve_kbuild_object_parent(pObj, 1 /*fQuiet*/); 804 1010 805 1011 /* … … 1018 1224 if (cchExpr > 0) 1019 1225 { 1020 enum kBuildType enmType;1021 1022 *pcchVarNm = cchExpr;1023 *ppchVarNm = pchExpr;1024 1226 1025 1227 /* 1026 1228 * It's an kBuild define variable accessor, alright. 1027 1229 */ 1028 enmType = eval_kbuild_type_from_string(pchType, cchType); 1029 if (penmType) 1030 *penmType = enmType; 1031 if (enmType != kBuildType_Invalid) 1230 *pcchVarNm = cchExpr; 1231 *ppchVarNm = pchExpr; 1232 1233 /* Deal with known special accessors: [@self]VAR, [@super]VAR. */ 1234 if (cchType == 0) 1032 1235 { 1033 struct kbuild_object *pObj = lookup_kbuild_object(enmType, pchObjName, cchObjName); 1034 if (pObj) 1035 return pObj; 1036 1037 /* failed. */ 1038 kbuild_report_problem(enmSeverity, pFileLoc, 1039 _("kBuild object '%s' not found in kBuild variable accessor '%.*s'"), 1040 (int)cchObjName, pchObjName, (int)cchOrgExpr, pchOrgExpr); 1236 int fSuper; 1237 1238 if (WORD_IS(pchObjName, cchObjName, "self")) 1239 fSuper = 0; 1240 else if (WORD_IS(pchObjName, cchObjName, "super")) 1241 fSuper = 1; 1242 else 1243 { 1244 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc, 1245 _("Invalid special kBuild object accessor: '%.*s'"), 1246 (int)cchOrgExpr, pchOrgExpr); 1247 if (penmType) 1248 *penmType = kBuildType_Invalid; 1249 return NULL; 1250 } 1251 if (g_pTopKbEvalData) 1252 { 1253 struct kbuild_object *pObj = g_pTopKbEvalData->pObj; 1254 struct kbuild_object *pParent; 1255 1256 if (penmType) 1257 *penmType = pObj->enmType; 1258 1259 if (!fSuper) 1260 return pObj; 1261 1262 pParent = get_kbuild_object_parent(pObj, MAX(enmSeverity, kBuildSeverity_Error)); 1263 if (pParent) 1264 return pParent; 1265 } 1266 else 1267 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc, 1268 _("The '%.*s' accessor can only be used in the context of a kBuild object"), 1269 (int)cchOrgExpr, pchOrgExpr); 1270 if (penmType) 1271 *penmType = kBuildType_Invalid; 1041 1272 } 1042 1273 else 1043 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc, 1044 _("Invalid type '%.*s' specified in kBuild variable accessor '%.*s'"), 1045 (int)cchType, pchType, (int)cchOrgExpr, pchOrgExpr); 1274 { 1275 /* Genric accessor. Check the type and look up the object. */ 1276 enum kBuildType enmType = eval_kbuild_type_from_string(pchType, cchType); 1277 if (penmType) 1278 *penmType = enmType; 1279 if (enmType != kBuildType_Invalid) 1280 { 1281 struct kbuild_object *pObj = lookup_kbuild_object(enmType, pchObjName, cchObjName); 1282 if (pObj) 1283 return pObj; 1284 1285 /* failed. */ 1286 kbuild_report_problem(enmSeverity, pFileLoc, 1287 _("kBuild object '%s' not found in kBuild variable accessor '%.*s'"), 1288 (int)cchObjName, pchObjName, (int)cchOrgExpr, pchOrgExpr); 1289 } 1290 else 1291 kbuild_report_problem(MAX(enmSeverity, kBuildSeverity_Error), pFileLoc, 1292 _("Invalid type '%.*s' specified in kBuild variable accessor '%.*s'"), 1293 (int)cchType, pchType, (int)cchOrgExpr, pchOrgExpr); 1294 } 1046 1295 return NULL; 1047 1296 } … … 1107 1356 for (;;) 1108 1357 { 1109 pParent = eval_kbuild_resolve_parent(pParent, 0 /*fQuiet*/);1358 pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/); 1110 1359 if (!pParent) 1111 1360 break; -
trunk/src/kmk/testcase-kBuild-define.kmk
r2718 r2720 26 26 #DEPTH = ../.. 27 27 #include $(PATH_KBUILD)/header.kmk 28 29 ## 30 # Test if $($1) == $2 and raises an error if it isn't. 31 # 32 # @param 1 Something to apply '$' to. 33 # @param 2 The expected value. 34 TEST_EQ = $(if-expr "$($1)" == "$2",,$(error $1 is '$($1)' not '$2')) 28 35 29 36 if 0 … … 97 104 $(if-expr "$(OutsideMod_OTHER)" == "outside-value",,$(error OutsideMod_OTHER is '$(OutsideMod_OTHER)' not 'outside-value')) 98 105 106 # Test #4 107 kBuild-define-target SpecialBase 108 _SOURCES = file1.c file2.c 109 _DEFS.win.x86 = XXX YYY 110 _DEFS.win.amd64 = $(filter-out YYY,$([@self]_DEFS.win.x86)) 111 # Unnecessary use of [@self]. 112 [@self]_LIBS = MyLib 113 kBuild-endef-target 114 115 kBuild-define-target SpecialChild extending SpecialBase 116 _SOURCES = file1-child.c $(filter-out file1.c,$([@super]_SOURCES)) 117 # Rare use of [@super]. 118 [@super]_SET_BY_CHILD = 42 119 kBuild-endef-target 120 121 $(call TEST_EQ,[target@SpecialBase]_LIBS,MyLib) 122 $(call TEST_EQ,SpecialBase_LIBS,MyLib) 123 124 $(call TEST_EQ,[target@SpecialBase]_SET_BY_CHILD,42) 125 $(call TEST_EQ,SpecialBase_SET_BY_CHILD,42) 126 $(call TEST_EQ,[target@SpecialChild]_SET_BY_CHILD,42) 127 #$(call TEST_EQ,SpecialChild_SET_BY_CHILD,42) ## @todo 128 129 $(call TEST_EQ,[target@SpecialBase]_DEFS.win.x86,XXX YYY) 130 $(call TEST_EQ,[target@SpecialBase]_DEFS.win.amd64,XXX) 131 $(call TEST_EQ,SpecialBase_DEFS.win.amd64,XXX) 132 $(call TEST_EQ,[target@SpecialChild]_DEFS.win.x86,XXX YYY) 133 $(call TEST_EQ,[target@SpecialChild]_DEFS.win.amd64,XXX) 134 #$(call TEST_EQ,SpecialChild_DEFS.win.amd64,XXX) ## @todo 135 136 $(call TEST_EQ,[target@SpecialChild]_SOURCES,file1-child.c file2.c) 137 $(call TEST_EQ,SpecialChild_SOURCES,file1-child.c file2.c) 138 99 139 all_recursive: 100 140 @kmk_echo "kBuild-define-xxxx works fine"
Note:
See TracChangeset
for help on using the changeset viewer.